diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-08-06 20:03:35 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-08-13 19:39:07 -0400 |
commit | 83053f7fe3eb0b6b1634d24ede87f1daa01ae60c (patch) | |
tree | 8f7fd35cd235f9bbfce3a4f56a756359e5facb51 /drivers | |
parent | 93b999239c418cf5c668fd966ac2c5c27b8180dd (diff) |
V4L/DVB (12399): mt9v011: Add support for controlling frame rates
Implement g_parm/s_parm ioctls. Those are used to check the current
frame rate (in fps) and to set it to a value. In practice, there are
only 15 possible different speeds, due to chip limits.
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/media/video/mt9v011.c | 89 |
1 files changed, 87 insertions, 2 deletions
diff --git a/drivers/media/video/mt9v011.c b/drivers/media/video/mt9v011.c index c14bf47d6928..8de1316a276d 100644 --- a/drivers/media/video/mt9v011.c +++ b/drivers/media/video/mt9v011.c | |||
@@ -156,7 +156,7 @@ static void set_balance(struct v4l2_subdev *sd) | |||
156 | mt9v011_write(sd, R2D_MT9V011_RED_GAIN, red_gain); | 156 | mt9v011_write(sd, R2D_MT9V011_RED_GAIN, red_gain); |
157 | } | 157 | } |
158 | 158 | ||
159 | static void calc_fps(struct v4l2_subdev *sd) | 159 | static void calc_fps(struct v4l2_subdev *sd, u32 *numerator, u32 *denominator) |
160 | { | 160 | { |
161 | struct mt9v011 *core = to_mt9v011(sd); | 161 | struct mt9v011 *core = to_mt9v011(sd); |
162 | unsigned height, width, hblank, vblank, speed; | 162 | unsigned height, width, hblank, vblank, speed; |
@@ -179,6 +179,51 @@ static void calc_fps(struct v4l2_subdev *sd) | |||
179 | 179 | ||
180 | v4l2_dbg(1, debug, sd, "Programmed to %u.%03u fps (%d pixel clcks)\n", | 180 | v4l2_dbg(1, debug, sd, "Programmed to %u.%03u fps (%d pixel clcks)\n", |
181 | tmp / 1000, tmp % 1000, t_time); | 181 | tmp / 1000, tmp % 1000, t_time); |
182 | |||
183 | if (numerator && denominator) { | ||
184 | *numerator = 1000; | ||
185 | *denominator = (u32)frames_per_ms; | ||
186 | } | ||
187 | } | ||
188 | |||
189 | static u16 calc_speed(struct v4l2_subdev *sd, u32 numerator, u32 denominator) | ||
190 | { | ||
191 | struct mt9v011 *core = to_mt9v011(sd); | ||
192 | unsigned height, width, hblank, vblank; | ||
193 | unsigned row_time, line_time; | ||
194 | u64 t_time, speed; | ||
195 | |||
196 | /* Avoid bogus calculus */ | ||
197 | if (!numerator || !denominator) | ||
198 | return 0; | ||
199 | |||
200 | height = mt9v011_read(sd, R03_MT9V011_HEIGHT); | ||
201 | width = mt9v011_read(sd, R04_MT9V011_WIDTH); | ||
202 | hblank = mt9v011_read(sd, R05_MT9V011_HBLANK); | ||
203 | vblank = mt9v011_read(sd, R06_MT9V011_VBLANK); | ||
204 | |||
205 | row_time = width + 113 + hblank; | ||
206 | line_time = height + vblank + 1; | ||
207 | |||
208 | t_time = core->xtal * ((u64)numerator); | ||
209 | /* round to the closest value */ | ||
210 | t_time += denominator / 2; | ||
211 | do_div(t_time, denominator); | ||
212 | |||
213 | speed = t_time; | ||
214 | do_div(speed, row_time * line_time); | ||
215 | |||
216 | /* Avoid having a negative value for speed */ | ||
217 | if (speed < 2) | ||
218 | speed = 0; | ||
219 | else | ||
220 | speed -= 2; | ||
221 | |||
222 | /* Avoid speed overflow */ | ||
223 | if (speed > 15) | ||
224 | return 15; | ||
225 | |||
226 | return (u16)speed; | ||
182 | } | 227 | } |
183 | 228 | ||
184 | static void set_res(struct v4l2_subdev *sd) | 229 | static void set_res(struct v4l2_subdev *sd) |
@@ -207,7 +252,7 @@ static void set_res(struct v4l2_subdev *sd) | |||
207 | mt9v011_write(sd, R03_MT9V011_HEIGHT, core->height); | 252 | mt9v011_write(sd, R03_MT9V011_HEIGHT, core->height); |
208 | mt9v011_write(sd, R06_MT9V011_VBLANK, 508 - core->height); | 253 | mt9v011_write(sd, R06_MT9V011_VBLANK, 508 - core->height); |
209 | 254 | ||
210 | calc_fps(sd); | 255 | calc_fps(sd, NULL, NULL); |
211 | }; | 256 | }; |
212 | 257 | ||
213 | static int mt9v011_reset(struct v4l2_subdev *sd, u32 val) | 258 | static int mt9v011_reset(struct v4l2_subdev *sd, u32 val) |
@@ -322,6 +367,44 @@ static int mt9v011_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) | |||
322 | return 0; | 367 | return 0; |
323 | } | 368 | } |
324 | 369 | ||
370 | static int mt9v011_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) | ||
371 | { | ||
372 | struct v4l2_captureparm *cp = &parms->parm.capture; | ||
373 | |||
374 | if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
375 | return -EINVAL; | ||
376 | |||
377 | memset(cp, 0, sizeof(struct v4l2_captureparm)); | ||
378 | cp->capability = V4L2_CAP_TIMEPERFRAME; | ||
379 | calc_fps(sd, | ||
380 | &cp->timeperframe.numerator, | ||
381 | &cp->timeperframe.denominator); | ||
382 | |||
383 | return 0; | ||
384 | } | ||
385 | |||
386 | static int mt9v011_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) | ||
387 | { | ||
388 | struct v4l2_captureparm *cp = &parms->parm.capture; | ||
389 | struct v4l2_fract *tpf = &cp->timeperframe; | ||
390 | u16 speed; | ||
391 | |||
392 | if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
393 | return -EINVAL; | ||
394 | if (cp->extendedmode != 0) | ||
395 | return -EINVAL; | ||
396 | |||
397 | speed = calc_speed(sd, tpf->numerator, tpf->denominator); | ||
398 | |||
399 | mt9v011_write(sd, R0A_MT9V011_CLK_SPEED, speed); | ||
400 | v4l2_dbg(1, debug, sd, "Setting speed to %d\n", speed); | ||
401 | |||
402 | /* Recalculate and update fps info */ | ||
403 | calc_fps(sd, &tpf->numerator, &tpf->denominator); | ||
404 | |||
405 | return 0; | ||
406 | } | ||
407 | |||
325 | static int mt9v011_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) | 408 | static int mt9v011_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) |
326 | { | 409 | { |
327 | struct v4l2_pix_format *pix = &fmt->fmt.pix; | 410 | struct v4l2_pix_format *pix = &fmt->fmt.pix; |
@@ -419,6 +502,8 @@ static const struct v4l2_subdev_video_ops mt9v011_video_ops = { | |||
419 | .enum_fmt = mt9v011_enum_fmt, | 502 | .enum_fmt = mt9v011_enum_fmt, |
420 | .try_fmt = mt9v011_try_fmt, | 503 | .try_fmt = mt9v011_try_fmt, |
421 | .s_fmt = mt9v011_s_fmt, | 504 | .s_fmt = mt9v011_s_fmt, |
505 | .g_parm = mt9v011_g_parm, | ||
506 | .s_parm = mt9v011_s_parm, | ||
422 | }; | 507 | }; |
423 | 508 | ||
424 | static const struct v4l2_subdev_ops mt9v011_ops = { | 509 | static const struct v4l2_subdev_ops mt9v011_ops = { |