aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/mt9v011.c
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@redhat.com>2009-08-06 20:03:35 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-08-13 19:39:07 -0400
commit83053f7fe3eb0b6b1634d24ede87f1daa01ae60c (patch)
tree8f7fd35cd235f9bbfce3a4f56a756359e5facb51 /drivers/media/video/mt9v011.c
parent93b999239c418cf5c668fd966ac2c5c27b8180dd (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/media/video/mt9v011.c')
-rw-r--r--drivers/media/video/mt9v011.c89
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
159static void calc_fps(struct v4l2_subdev *sd) 159static 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
189static 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
184static void set_res(struct v4l2_subdev *sd) 229static 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
213static int mt9v011_reset(struct v4l2_subdev *sd, u32 val) 258static 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
370static 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
386static 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
325static int mt9v011_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) 408static 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
424static const struct v4l2_subdev_ops mt9v011_ops = { 509static const struct v4l2_subdev_ops mt9v011_ops = {