diff options
| -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 = { |
