diff options
author | Jonathan Corbet <corbet@lwn.net> | 2006-12-01 13:50:59 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2006-12-10 06:05:31 -0500 |
commit | c8f5b2f5607e78c61df229259c539a5d9488a013 (patch) | |
tree | 918f87bf2f2a85e020bac3f45297a1f4c05a6208 | |
parent | a66d23368068d6027feedc010304d510e6d1fe56 (diff) |
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 <corbet@lwn.net>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
-rw-r--r-- | drivers/media/video/cafe_ccic.c | 34 | ||||
-rw-r--r-- | 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 9d9844e22951..e347c7ebc984 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) | |||
1671 | return 0; | 1671 | return 0; |
1672 | } | 1672 | } |
1673 | 1673 | ||
1674 | /* | ||
1675 | * G/S_PARM. Most of this is done by the sensor, but we are | ||
1676 | * the level which controls the number of read buffers. | ||
1677 | */ | ||
1678 | static int cafe_vidioc_g_parm(struct file *filp, void *priv, | ||
1679 | struct v4l2_streamparm *parms) | ||
1680 | { | ||
1681 | struct cafe_camera *cam = priv; | ||
1682 | int ret; | ||
1683 | |||
1684 | mutex_lock(&cam->s_mutex); | ||
1685 | ret = __cafe_cam_cmd(cam, VIDIOC_G_PARM, parms); | ||
1686 | mutex_unlock(&cam->s_mutex); | ||
1687 | parms->parm.capture.readbuffers = n_dma_bufs; | ||
1688 | return ret; | ||
1689 | } | ||
1690 | |||
1691 | static int cafe_vidioc_s_parm(struct file *filp, void *priv, | ||
1692 | struct v4l2_streamparm *parms) | ||
1693 | { | ||
1694 | struct cafe_camera *cam = priv; | ||
1695 | int ret; | ||
1696 | |||
1697 | mutex_lock(&cam->s_mutex); | ||
1698 | ret = __cafe_cam_cmd(cam, VIDIOC_S_PARM, parms); | ||
1699 | mutex_unlock(&cam->s_mutex); | ||
1700 | parms->parm.capture.readbuffers = n_dma_bufs; | ||
1701 | return ret; | ||
1702 | } | ||
1703 | |||
1704 | |||
1674 | static void cafe_v4l_dev_release(struct video_device *vd) | 1705 | static void cafe_v4l_dev_release(struct video_device *vd) |
1675 | { | 1706 | { |
1676 | struct cafe_camera *cam = container_of(vd, struct cafe_camera, v4ldev); | 1707 | struct cafe_camera *cam = container_of(vd, struct cafe_camera, v4ldev); |
@@ -1724,7 +1755,8 @@ static struct video_device cafe_v4l_template = { | |||
1724 | .vidioc_queryctrl = cafe_vidioc_queryctrl, | 1755 | .vidioc_queryctrl = cafe_vidioc_queryctrl, |
1725 | .vidioc_g_ctrl = cafe_vidioc_g_ctrl, | 1756 | .vidioc_g_ctrl = cafe_vidioc_g_ctrl, |
1726 | .vidioc_s_ctrl = cafe_vidioc_s_ctrl, | 1757 | .vidioc_s_ctrl = cafe_vidioc_s_ctrl, |
1727 | /* Do cropping someday */ | 1758 | .vidioc_g_parm = cafe_vidioc_g_parm, |
1759 | .vidioc_s_parm = cafe_vidioc_s_parm, | ||
1728 | }; | 1760 | }; |
1729 | 1761 | ||
1730 | 1762 | ||
diff --git a/drivers/media/video/ov7670.c b/drivers/media/video/ov7670.c index 7d380d76338a..89dd18c3c5cc 100644 --- a/drivers/media/video/ov7670.c +++ b/drivers/media/video/ov7670.c | |||
@@ -36,6 +36,11 @@ MODULE_LICENSE("GPL"); | |||
36 | #define QCIF_HEIGHT 144 | 36 | #define QCIF_HEIGHT 144 |
37 | 37 | ||
38 | /* | 38 | /* |
39 | * Our nominal (default) frame rate. | ||
40 | */ | ||
41 | #define OV7670_FRAME_RATE 30 | ||
42 | |||
43 | /* | ||
39 | * The 7670 sits on i2c with ID 0x42 | 44 | * The 7670 sits on i2c with ID 0x42 |
40 | */ | 45 | */ |
41 | #define OV7670_I2C_ADDR 0x42 | 46 | #define OV7670_I2C_ADDR 0x42 |
@@ -291,7 +296,7 @@ static struct regval_list ov7670_default_regs[] = { | |||
291 | { 0xc9, 0x60 }, { REG_COM16, 0x38 }, | 296 | { 0xc9, 0x60 }, { REG_COM16, 0x38 }, |
292 | { 0x56, 0x40 }, | 297 | { 0x56, 0x40 }, |
293 | 298 | ||
294 | { 0x34, 0x11 }, { REG_COM11, COM11_EXP }, | 299 | { 0x34, 0x11 }, { REG_COM11, COM11_EXP|COM11_HZAUTO }, |
295 | { 0xa4, 0x88 }, { 0x96, 0 }, | 300 | { 0xa4, 0x88 }, { 0x96, 0 }, |
296 | { 0x97, 0x30 }, { 0x98, 0x20 }, | 301 | { 0x97, 0x30 }, { 0x98, 0x20 }, |
297 | { 0x99, 0x30 }, { 0x9a, 0x84 }, | 302 | { 0x99, 0x30 }, { 0x9a, 0x84 }, |
@@ -722,6 +727,63 @@ static int ov7670_s_fmt(struct i2c_client *c, struct v4l2_format *fmt) | |||
722 | } | 727 | } |
723 | 728 | ||
724 | /* | 729 | /* |
730 | * Implement G/S_PARM. There is a "high quality" mode we could try | ||
731 | * to do someday; for now, we just do the frame rate tweak. | ||
732 | */ | ||
733 | static int ov7670_g_parm(struct i2c_client *c, struct v4l2_streamparm *parms) | ||
734 | { | ||
735 | struct v4l2_captureparm *cp = &parms->parm.capture; | ||
736 | unsigned char clkrc; | ||
737 | int ret; | ||
738 | |||
739 | if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
740 | return -EINVAL; | ||
741 | ret = ov7670_read(c, REG_CLKRC, &clkrc); | ||
742 | if (ret < 0) | ||
743 | return ret; | ||
744 | memset(cp, 0, sizeof(struct v4l2_captureparm)); | ||
745 | cp->capability = V4L2_CAP_TIMEPERFRAME; | ||
746 | cp->timeperframe.numerator = 1; | ||
747 | cp->timeperframe.denominator = OV7670_FRAME_RATE; | ||
748 | if ((clkrc & CLK_EXT) == 0 && (clkrc & CLK_SCALE) > 1) | ||
749 | cp->timeperframe.denominator /= (clkrc & CLK_SCALE); | ||
750 | return 0; | ||
751 | } | ||
752 | |||
753 | static int ov7670_s_parm(struct i2c_client *c, struct v4l2_streamparm *parms) | ||
754 | { | ||
755 | struct v4l2_captureparm *cp = &parms->parm.capture; | ||
756 | struct v4l2_fract *tpf = &cp->timeperframe; | ||
757 | unsigned char clkrc; | ||
758 | int ret, div; | ||
759 | |||
760 | if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
761 | return -EINVAL; | ||
762 | if (cp->extendedmode != 0) | ||
763 | return -EINVAL; | ||
764 | /* | ||
765 | * CLKRC has a reserved bit, so let's preserve it. | ||
766 | */ | ||
767 | ret = ov7670_read(c, REG_CLKRC, &clkrc); | ||
768 | if (ret < 0) | ||
769 | return ret; | ||
770 | if (tpf->numerator == 0 || tpf->denominator == 0) | ||
771 | div = 1; /* Reset to full rate */ | ||
772 | else | ||
773 | div = (tpf->numerator*OV7670_FRAME_RATE)/tpf->denominator; | ||
774 | if (div == 0) | ||
775 | div = 1; | ||
776 | else if (div > CLK_SCALE) | ||
777 | div = CLK_SCALE; | ||
778 | clkrc = (clkrc & 0x80) | div; | ||
779 | tpf->numerator = 1; | ||
780 | tpf->denominator = OV7670_FRAME_RATE/div; | ||
781 | return ov7670_write(c, REG_CLKRC, clkrc); | ||
782 | } | ||
783 | |||
784 | |||
785 | |||
786 | /* | ||
725 | * Code for dealing with controls. | 787 | * Code for dealing with controls. |
726 | */ | 788 | */ |
727 | 789 | ||
@@ -1231,10 +1293,10 @@ static int ov7670_command(struct i2c_client *client, unsigned int cmd, | |||
1231 | return ov7670_s_ctrl(client, (struct v4l2_control *) arg); | 1293 | return ov7670_s_ctrl(client, (struct v4l2_control *) arg); |
1232 | case VIDIOC_G_CTRL: | 1294 | case VIDIOC_G_CTRL: |
1233 | return ov7670_g_ctrl(client, (struct v4l2_control *) arg); | 1295 | return ov7670_g_ctrl(client, (struct v4l2_control *) arg); |
1234 | /* Todo: | 1296 | case VIDIOC_S_PARM: |
1235 | g/s_parm | 1297 | return ov7670_s_parm(client, (struct v4l2_streamparm *) arg); |
1236 | initialization | 1298 | case VIDIOC_G_PARM: |
1237 | */ | 1299 | return ov7670_g_parm(client, (struct v4l2_streamparm *) arg); |
1238 | } | 1300 | } |
1239 | return -EINVAL; | 1301 | return -EINVAL; |
1240 | } | 1302 | } |