diff options
author | Guennadi Liakhovetski <g.liakhovetski@gmx.de> | 2009-03-13 05:08:20 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-03-30 11:43:21 -0400 |
commit | 09e231b35173313cd92e27532e5028f2042dcee4 (patch) | |
tree | 3ecda063aa52f954d2f797921bdce131d7f1cc28 /drivers | |
parent | 1cd3c0fa927084549005fc22e54d99684b314f14 (diff) |
V4L/DVB (11024): soc-camera: separate S_FMT and S_CROP operations
As host and camera drivers become more complex, differences between S_FMT and
S_CROP functionality grow, this patch separates them.
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/media/video/mt9m001.c | 19 | ||||
-rw-r--r-- | drivers/media/video/mt9m111.c | 56 | ||||
-rw-r--r-- | drivers/media/video/mt9t031.c | 84 | ||||
-rw-r--r-- | drivers/media/video/mt9v022.c | 62 | ||||
-rw-r--r-- | drivers/media/video/mx3_camera.c | 157 | ||||
-rw-r--r-- | drivers/media/video/ov772x.c | 31 | ||||
-rw-r--r-- | drivers/media/video/pxa_camera.c | 67 | ||||
-rw-r--r-- | drivers/media/video/sh_mobile_ceu_camera.c | 17 | ||||
-rw-r--r-- | drivers/media/video/soc_camera.c | 20 | ||||
-rw-r--r-- | drivers/media/video/soc_camera_platform.c | 9 | ||||
-rw-r--r-- | drivers/media/video/tw9910.c | 45 |
11 files changed, 377 insertions, 190 deletions
diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c index 2d1034dad495..a6703d25227f 100644 --- a/drivers/media/video/mt9m001.c +++ b/drivers/media/video/mt9m001.c | |||
@@ -284,8 +284,8 @@ static unsigned long mt9m001_query_bus_param(struct soc_camera_device *icd) | |||
284 | return soc_camera_apply_sensor_flags(icl, flags); | 284 | return soc_camera_apply_sensor_flags(icl, flags); |
285 | } | 285 | } |
286 | 286 | ||
287 | static int mt9m001_set_fmt(struct soc_camera_device *icd, | 287 | static int mt9m001_set_crop(struct soc_camera_device *icd, |
288 | __u32 pixfmt, struct v4l2_rect *rect) | 288 | struct v4l2_rect *rect) |
289 | { | 289 | { |
290 | struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd); | 290 | struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd); |
291 | int ret; | 291 | int ret; |
@@ -324,6 +324,20 @@ static int mt9m001_set_fmt(struct soc_camera_device *icd, | |||
324 | return ret; | 324 | return ret; |
325 | } | 325 | } |
326 | 326 | ||
327 | static int mt9m001_set_fmt(struct soc_camera_device *icd, | ||
328 | struct v4l2_format *f) | ||
329 | { | ||
330 | struct v4l2_rect rect = { | ||
331 | .left = icd->x_current, | ||
332 | .top = icd->y_current, | ||
333 | .width = f->fmt.pix.width, | ||
334 | .height = f->fmt.pix.height, | ||
335 | }; | ||
336 | |||
337 | /* No support for scaling so far, just crop. TODO: use skipping */ | ||
338 | return mt9m001_set_crop(icd, &rect); | ||
339 | } | ||
340 | |||
327 | static int mt9m001_try_fmt(struct soc_camera_device *icd, | 341 | static int mt9m001_try_fmt(struct soc_camera_device *icd, |
328 | struct v4l2_format *f) | 342 | struct v4l2_format *f) |
329 | { | 343 | { |
@@ -449,6 +463,7 @@ static struct soc_camera_ops mt9m001_ops = { | |||
449 | .release = mt9m001_release, | 463 | .release = mt9m001_release, |
450 | .start_capture = mt9m001_start_capture, | 464 | .start_capture = mt9m001_start_capture, |
451 | .stop_capture = mt9m001_stop_capture, | 465 | .stop_capture = mt9m001_stop_capture, |
466 | .set_crop = mt9m001_set_crop, | ||
452 | .set_fmt = mt9m001_set_fmt, | 467 | .set_fmt = mt9m001_set_fmt, |
453 | .try_fmt = mt9m001_try_fmt, | 468 | .try_fmt = mt9m001_try_fmt, |
454 | .set_bus_param = mt9m001_set_bus_param, | 469 | .set_bus_param = mt9m001_set_bus_param, |
diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c index 7e6be36f0855..cdd1ddb51388 100644 --- a/drivers/media/video/mt9m111.c +++ b/drivers/media/video/mt9m111.c | |||
@@ -152,7 +152,7 @@ struct mt9m111 { | |||
152 | struct soc_camera_device icd; | 152 | struct soc_camera_device icd; |
153 | int model; /* V4L2_IDENT_MT9M11x* codes from v4l2-chip-ident.h */ | 153 | int model; /* V4L2_IDENT_MT9M11x* codes from v4l2-chip-ident.h */ |
154 | enum mt9m111_context context; | 154 | enum mt9m111_context context; |
155 | unsigned int left, top, width, height; | 155 | struct v4l2_rect rect; |
156 | u32 pixfmt; | 156 | u32 pixfmt; |
157 | unsigned char autoexposure; | 157 | unsigned char autoexposure; |
158 | unsigned char datawidth; | 158 | unsigned char datawidth; |
@@ -249,12 +249,13 @@ static int mt9m111_set_context(struct soc_camera_device *icd, | |||
249 | return reg_write(CONTEXT_CONTROL, valA); | 249 | return reg_write(CONTEXT_CONTROL, valA); |
250 | } | 250 | } |
251 | 251 | ||
252 | static int mt9m111_setup_rect(struct soc_camera_device *icd) | 252 | static int mt9m111_setup_rect(struct soc_camera_device *icd, |
253 | struct v4l2_rect *rect) | ||
253 | { | 254 | { |
254 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | 255 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); |
255 | int ret, is_raw_format; | 256 | int ret, is_raw_format; |
256 | int width = mt9m111->width; | 257 | int width = rect->width; |
257 | int height = mt9m111->height; | 258 | int height = rect->height; |
258 | 259 | ||
259 | if ((mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR8) | 260 | if ((mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR8) |
260 | || (mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR16)) | 261 | || (mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR16)) |
@@ -262,9 +263,9 @@ static int mt9m111_setup_rect(struct soc_camera_device *icd) | |||
262 | else | 263 | else |
263 | is_raw_format = 0; | 264 | is_raw_format = 0; |
264 | 265 | ||
265 | ret = reg_write(COLUMN_START, mt9m111->left); | 266 | ret = reg_write(COLUMN_START, rect->left); |
266 | if (!ret) | 267 | if (!ret) |
267 | ret = reg_write(ROW_START, mt9m111->top); | 268 | ret = reg_write(ROW_START, rect->top); |
268 | 269 | ||
269 | if (is_raw_format) { | 270 | if (is_raw_format) { |
270 | if (!ret) | 271 | if (!ret) |
@@ -436,6 +437,22 @@ static int mt9m111_set_bus_param(struct soc_camera_device *icd, unsigned long f) | |||
436 | return 0; | 437 | return 0; |
437 | } | 438 | } |
438 | 439 | ||
440 | static int mt9m111_set_crop(struct soc_camera_device *icd, | ||
441 | struct v4l2_rect *rect) | ||
442 | { | ||
443 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | ||
444 | int ret; | ||
445 | |||
446 | dev_dbg(&icd->dev, "%s left=%d, top=%d, width=%d, height=%d\n", | ||
447 | __func__, rect->left, rect->top, rect->width, | ||
448 | rect->height); | ||
449 | |||
450 | ret = mt9m111_setup_rect(icd, rect); | ||
451 | if (!ret) | ||
452 | mt9m111->rect = *rect; | ||
453 | return ret; | ||
454 | } | ||
455 | |||
439 | static int mt9m111_set_pixfmt(struct soc_camera_device *icd, u32 pixfmt) | 456 | static int mt9m111_set_pixfmt(struct soc_camera_device *icd, u32 pixfmt) |
440 | { | 457 | { |
441 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | 458 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); |
@@ -486,23 +503,27 @@ static int mt9m111_set_pixfmt(struct soc_camera_device *icd, u32 pixfmt) | |||
486 | } | 503 | } |
487 | 504 | ||
488 | static int mt9m111_set_fmt(struct soc_camera_device *icd, | 505 | static int mt9m111_set_fmt(struct soc_camera_device *icd, |
489 | __u32 pixfmt, struct v4l2_rect *rect) | 506 | struct v4l2_format *f) |
490 | { | 507 | { |
491 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | 508 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); |
509 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
510 | struct v4l2_rect rect = { | ||
511 | .left = mt9m111->rect.left, | ||
512 | .top = mt9m111->rect.top, | ||
513 | .width = pix->width, | ||
514 | .height = pix->height, | ||
515 | }; | ||
492 | int ret; | 516 | int ret; |
493 | 517 | ||
494 | mt9m111->left = rect->left; | ||
495 | mt9m111->top = rect->top; | ||
496 | mt9m111->width = rect->width; | ||
497 | mt9m111->height = rect->height; | ||
498 | |||
499 | dev_dbg(&icd->dev, "%s fmt=%x left=%d, top=%d, width=%d, height=%d\n", | 518 | dev_dbg(&icd->dev, "%s fmt=%x left=%d, top=%d, width=%d, height=%d\n", |
500 | __func__, pixfmt, mt9m111->left, mt9m111->top, mt9m111->width, | 519 | __func__, pix->pixelformat, rect.left, rect.top, rect.width, |
501 | mt9m111->height); | 520 | rect.height); |
502 | 521 | ||
503 | ret = mt9m111_setup_rect(icd); | 522 | ret = mt9m111_setup_rect(icd, &rect); |
523 | if (!ret) | ||
524 | ret = mt9m111_set_pixfmt(icd, pix->pixelformat); | ||
504 | if (!ret) | 525 | if (!ret) |
505 | ret = mt9m111_set_pixfmt(icd, pixfmt); | 526 | mt9m111->rect = rect; |
506 | return ret; | 527 | return ret; |
507 | } | 528 | } |
508 | 529 | ||
@@ -633,6 +654,7 @@ static struct soc_camera_ops mt9m111_ops = { | |||
633 | .release = mt9m111_release, | 654 | .release = mt9m111_release, |
634 | .start_capture = mt9m111_start_capture, | 655 | .start_capture = mt9m111_start_capture, |
635 | .stop_capture = mt9m111_stop_capture, | 656 | .stop_capture = mt9m111_stop_capture, |
657 | .set_crop = mt9m111_set_crop, | ||
636 | .set_fmt = mt9m111_set_fmt, | 658 | .set_fmt = mt9m111_set_fmt, |
637 | .try_fmt = mt9m111_try_fmt, | 659 | .try_fmt = mt9m111_try_fmt, |
638 | .query_bus_param = mt9m111_query_bus_param, | 660 | .query_bus_param = mt9m111_query_bus_param, |
@@ -817,7 +839,7 @@ static int mt9m111_restore_state(struct soc_camera_device *icd) | |||
817 | 839 | ||
818 | mt9m111_set_context(icd, mt9m111->context); | 840 | mt9m111_set_context(icd, mt9m111->context); |
819 | mt9m111_set_pixfmt(icd, mt9m111->pixfmt); | 841 | mt9m111_set_pixfmt(icd, mt9m111->pixfmt); |
820 | mt9m111_setup_rect(icd); | 842 | mt9m111_setup_rect(icd, &mt9m111->rect); |
821 | mt9m111_set_flip(icd, mt9m111->hflip, MT9M111_RMB_MIRROR_COLS); | 843 | mt9m111_set_flip(icd, mt9m111->hflip, MT9M111_RMB_MIRROR_COLS); |
822 | mt9m111_set_flip(icd, mt9m111->vflip, MT9M111_RMB_MIRROR_ROWS); | 844 | mt9m111_set_flip(icd, mt9m111->vflip, MT9M111_RMB_MIRROR_ROWS); |
823 | mt9m111_set_global_gain(icd, icd->gain); | 845 | mt9m111_set_global_gain(icd, icd->gain); |
diff --git a/drivers/media/video/mt9t031.c b/drivers/media/video/mt9t031.c index acc1fa9db67d..677be18df9b3 100644 --- a/drivers/media/video/mt9t031.c +++ b/drivers/media/video/mt9t031.c | |||
@@ -213,36 +213,14 @@ static void recalculate_limits(struct soc_camera_device *icd, | |||
213 | icd->height_max = MT9T031_MAX_HEIGHT / yskip; | 213 | icd->height_max = MT9T031_MAX_HEIGHT / yskip; |
214 | } | 214 | } |
215 | 215 | ||
216 | static int mt9t031_set_fmt(struct soc_camera_device *icd, | 216 | static int mt9t031_set_params(struct soc_camera_device *icd, |
217 | __u32 pixfmt, struct v4l2_rect *rect) | 217 | struct v4l2_rect *rect, u16 xskip, u16 yskip) |
218 | { | 218 | { |
219 | struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd); | 219 | struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd); |
220 | int ret; | 220 | int ret; |
221 | u16 xbin, ybin, width, height, left, top; | ||
221 | const u16 hblank = MT9T031_HORIZONTAL_BLANK, | 222 | const u16 hblank = MT9T031_HORIZONTAL_BLANK, |
222 | vblank = MT9T031_VERTICAL_BLANK; | 223 | vblank = MT9T031_VERTICAL_BLANK; |
223 | u16 xbin, xskip, ybin, yskip, width, height, left, top; | ||
224 | |||
225 | if (pixfmt) { | ||
226 | /* | ||
227 | * try_fmt has put rectangle within limits. | ||
228 | * S_FMT - use binning and skipping for scaling, recalculate | ||
229 | * limits, used for cropping | ||
230 | */ | ||
231 | /* Is this more optimal than just a division? */ | ||
232 | for (xskip = 8; xskip > 1; xskip--) | ||
233 | if (rect->width * xskip <= MT9T031_MAX_WIDTH) | ||
234 | break; | ||
235 | |||
236 | for (yskip = 8; yskip > 1; yskip--) | ||
237 | if (rect->height * yskip <= MT9T031_MAX_HEIGHT) | ||
238 | break; | ||
239 | |||
240 | recalculate_limits(icd, xskip, yskip); | ||
241 | } else { | ||
242 | /* CROP - no change in scaling, or in limits */ | ||
243 | xskip = mt9t031->xskip; | ||
244 | yskip = mt9t031->yskip; | ||
245 | } | ||
246 | 224 | ||
247 | /* Make sure we don't exceed sensor limits */ | 225 | /* Make sure we don't exceed sensor limits */ |
248 | if (rect->left + rect->width > icd->width_max) | 226 | if (rect->left + rect->width > icd->width_max) |
@@ -289,7 +267,7 @@ static int mt9t031_set_fmt(struct soc_camera_device *icd, | |||
289 | if (ret >= 0) | 267 | if (ret >= 0) |
290 | ret = reg_write(icd, MT9T031_VERTICAL_BLANKING, vblank); | 268 | ret = reg_write(icd, MT9T031_VERTICAL_BLANKING, vblank); |
291 | 269 | ||
292 | if (pixfmt) { | 270 | if (yskip != mt9t031->yskip || xskip != mt9t031->xskip) { |
293 | /* Binning, skipping */ | 271 | /* Binning, skipping */ |
294 | if (ret >= 0) | 272 | if (ret >= 0) |
295 | ret = reg_write(icd, MT9T031_COLUMN_ADDRESS_MODE, | 273 | ret = reg_write(icd, MT9T031_COLUMN_ADDRESS_MODE, |
@@ -325,15 +303,58 @@ static int mt9t031_set_fmt(struct soc_camera_device *icd, | |||
325 | } | 303 | } |
326 | } | 304 | } |
327 | 305 | ||
328 | if (!ret && pixfmt) { | 306 | /* Re-enable register update, commit all changes */ |
307 | if (ret >= 0) | ||
308 | ret = reg_clear(icd, MT9T031_OUTPUT_CONTROL, 1); | ||
309 | |||
310 | return ret < 0 ? ret : 0; | ||
311 | } | ||
312 | |||
313 | static int mt9t031_set_crop(struct soc_camera_device *icd, | ||
314 | struct v4l2_rect *rect) | ||
315 | { | ||
316 | struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd); | ||
317 | |||
318 | /* CROP - no change in scaling, or in limits */ | ||
319 | return mt9t031_set_params(icd, rect, mt9t031->xskip, mt9t031->yskip); | ||
320 | } | ||
321 | |||
322 | static int mt9t031_set_fmt(struct soc_camera_device *icd, | ||
323 | struct v4l2_format *f) | ||
324 | { | ||
325 | struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd); | ||
326 | int ret; | ||
327 | u16 xskip, yskip; | ||
328 | struct v4l2_rect rect = { | ||
329 | .left = icd->x_current, | ||
330 | .top = icd->y_current, | ||
331 | .width = f->fmt.pix.width, | ||
332 | .height = f->fmt.pix.height, | ||
333 | }; | ||
334 | |||
335 | /* | ||
336 | * try_fmt has put rectangle within limits. | ||
337 | * S_FMT - use binning and skipping for scaling, recalculate | ||
338 | * limits, used for cropping | ||
339 | */ | ||
340 | /* Is this more optimal than just a division? */ | ||
341 | for (xskip = 8; xskip > 1; xskip--) | ||
342 | if (rect.width * xskip <= MT9T031_MAX_WIDTH) | ||
343 | break; | ||
344 | |||
345 | for (yskip = 8; yskip > 1; yskip--) | ||
346 | if (rect.height * yskip <= MT9T031_MAX_HEIGHT) | ||
347 | break; | ||
348 | |||
349 | recalculate_limits(icd, xskip, yskip); | ||
350 | |||
351 | ret = mt9t031_set_params(icd, &rect, xskip, yskip); | ||
352 | if (!ret) { | ||
329 | mt9t031->xskip = xskip; | 353 | mt9t031->xskip = xskip; |
330 | mt9t031->yskip = yskip; | 354 | mt9t031->yskip = yskip; |
331 | } | 355 | } |
332 | 356 | ||
333 | /* Re-enable register update, commit all changes */ | 357 | return ret; |
334 | reg_clear(icd, MT9T031_OUTPUT_CONTROL, 1); | ||
335 | |||
336 | return ret < 0 ? ret : 0; | ||
337 | } | 358 | } |
338 | 359 | ||
339 | static int mt9t031_try_fmt(struct soc_camera_device *icd, | 360 | static int mt9t031_try_fmt(struct soc_camera_device *icd, |
@@ -470,6 +491,7 @@ static struct soc_camera_ops mt9t031_ops = { | |||
470 | .release = mt9t031_release, | 491 | .release = mt9t031_release, |
471 | .start_capture = mt9t031_start_capture, | 492 | .start_capture = mt9t031_start_capture, |
472 | .stop_capture = mt9t031_stop_capture, | 493 | .stop_capture = mt9t031_stop_capture, |
494 | .set_crop = mt9t031_set_crop, | ||
473 | .set_fmt = mt9t031_set_fmt, | 495 | .set_fmt = mt9t031_set_fmt, |
474 | .try_fmt = mt9t031_try_fmt, | 496 | .try_fmt = mt9t031_try_fmt, |
475 | .set_bus_param = mt9t031_set_bus_param, | 497 | .set_bus_param = mt9t031_set_bus_param, |
diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c index 6eb4b3a818d7..3871d4a2d8ff 100644 --- a/drivers/media/video/mt9v022.c +++ b/drivers/media/video/mt9v022.c | |||
@@ -340,32 +340,11 @@ static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd) | |||
340 | width_flag; | 340 | width_flag; |
341 | } | 341 | } |
342 | 342 | ||
343 | static int mt9v022_set_fmt(struct soc_camera_device *icd, | 343 | static int mt9v022_set_crop(struct soc_camera_device *icd, |
344 | __u32 pixfmt, struct v4l2_rect *rect) | 344 | struct v4l2_rect *rect) |
345 | { | 345 | { |
346 | struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); | ||
347 | int ret; | 346 | int ret; |
348 | 347 | ||
349 | /* The caller provides a supported format, as verified per call to | ||
350 | * icd->try_fmt(), datawidth is from our supported format list */ | ||
351 | switch (pixfmt) { | ||
352 | case V4L2_PIX_FMT_GREY: | ||
353 | case V4L2_PIX_FMT_Y16: | ||
354 | if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATM) | ||
355 | return -EINVAL; | ||
356 | break; | ||
357 | case V4L2_PIX_FMT_SBGGR8: | ||
358 | case V4L2_PIX_FMT_SBGGR16: | ||
359 | if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATC) | ||
360 | return -EINVAL; | ||
361 | break; | ||
362 | case 0: | ||
363 | /* No format change, only geometry */ | ||
364 | break; | ||
365 | default: | ||
366 | return -EINVAL; | ||
367 | } | ||
368 | |||
369 | /* Like in example app. Contradicts the datasheet though */ | 348 | /* Like in example app. Contradicts the datasheet though */ |
370 | ret = reg_read(icd, MT9V022_AEC_AGC_ENABLE); | 349 | ret = reg_read(icd, MT9V022_AEC_AGC_ENABLE); |
371 | if (ret >= 0) { | 350 | if (ret >= 0) { |
@@ -403,6 +382,42 @@ static int mt9v022_set_fmt(struct soc_camera_device *icd, | |||
403 | return 0; | 382 | return 0; |
404 | } | 383 | } |
405 | 384 | ||
385 | static int mt9v022_set_fmt(struct soc_camera_device *icd, | ||
386 | struct v4l2_format *f) | ||
387 | { | ||
388 | struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); | ||
389 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
390 | struct v4l2_rect rect = { | ||
391 | .left = icd->x_current, | ||
392 | .top = icd->y_current, | ||
393 | .width = pix->width, | ||
394 | .height = pix->height, | ||
395 | }; | ||
396 | |||
397 | /* The caller provides a supported format, as verified per call to | ||
398 | * icd->try_fmt(), datawidth is from our supported format list */ | ||
399 | switch (pix->pixelformat) { | ||
400 | case V4L2_PIX_FMT_GREY: | ||
401 | case V4L2_PIX_FMT_Y16: | ||
402 | if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATM) | ||
403 | return -EINVAL; | ||
404 | break; | ||
405 | case V4L2_PIX_FMT_SBGGR8: | ||
406 | case V4L2_PIX_FMT_SBGGR16: | ||
407 | if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATC) | ||
408 | return -EINVAL; | ||
409 | break; | ||
410 | case 0: | ||
411 | /* No format change, only geometry */ | ||
412 | break; | ||
413 | default: | ||
414 | return -EINVAL; | ||
415 | } | ||
416 | |||
417 | /* No support for scaling on this camera, just crop. */ | ||
418 | return mt9v022_set_crop(icd, &rect); | ||
419 | } | ||
420 | |||
406 | static int mt9v022_try_fmt(struct soc_camera_device *icd, | 421 | static int mt9v022_try_fmt(struct soc_camera_device *icd, |
407 | struct v4l2_format *f) | 422 | struct v4l2_format *f) |
408 | { | 423 | { |
@@ -544,6 +559,7 @@ static struct soc_camera_ops mt9v022_ops = { | |||
544 | .release = mt9v022_release, | 559 | .release = mt9v022_release, |
545 | .start_capture = mt9v022_start_capture, | 560 | .start_capture = mt9v022_start_capture, |
546 | .stop_capture = mt9v022_stop_capture, | 561 | .stop_capture = mt9v022_stop_capture, |
562 | .set_crop = mt9v022_set_crop, | ||
547 | .set_fmt = mt9v022_set_fmt, | 563 | .set_fmt = mt9v022_set_fmt, |
548 | .try_fmt = mt9v022_try_fmt, | 564 | .try_fmt = mt9v022_try_fmt, |
549 | .set_bus_param = mt9v022_set_bus_param, | 565 | .set_bus_param = mt9v022_set_bus_param, |
diff --git a/drivers/media/video/mx3_camera.c b/drivers/media/video/mx3_camera.c index f525dc48f6ca..70629e172e65 100644 --- a/drivers/media/video/mx3_camera.c +++ b/drivers/media/video/mx3_camera.c | |||
@@ -544,16 +544,14 @@ static void mx3_camera_remove_device(struct soc_camera_device *icd) | |||
544 | } | 544 | } |
545 | 545 | ||
546 | static bool channel_change_requested(struct soc_camera_device *icd, | 546 | static bool channel_change_requested(struct soc_camera_device *icd, |
547 | const struct soc_camera_format_xlate *xlate, | 547 | struct v4l2_rect *rect) |
548 | __u32 pixfmt, struct v4l2_rect *rect) | ||
549 | { | 548 | { |
550 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 549 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
551 | struct mx3_camera_dev *mx3_cam = ici->priv; | 550 | struct mx3_camera_dev *mx3_cam = ici->priv; |
552 | struct idmac_channel *ichan = mx3_cam->idmac_channel[0]; | 551 | struct idmac_channel *ichan = mx3_cam->idmac_channel[0]; |
553 | 552 | ||
554 | /* So far only one configuration is supported */ | 553 | /* Do buffers have to be re-allocated or channel re-configured? */ |
555 | return pixfmt || (ichan && rect->width * rect->height > | 554 | return ichan && rect->width * rect->height > icd->width * icd->height; |
556 | icd->width * icd->height); | ||
557 | } | 555 | } |
558 | 556 | ||
559 | static int test_platform_param(struct mx3_camera_dev *mx3_cam, | 557 | static int test_platform_param(struct mx3_camera_dev *mx3_cam, |
@@ -733,61 +731,10 @@ passthrough: | |||
733 | return formats; | 731 | return formats; |
734 | } | 732 | } |
735 | 733 | ||
736 | static int mx3_camera_set_fmt(struct soc_camera_device *icd, | 734 | static void configure_geometry(struct mx3_camera_dev *mx3_cam, |
737 | __u32 pixfmt, struct v4l2_rect *rect) | 735 | struct v4l2_rect *rect) |
738 | { | 736 | { |
739 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | ||
740 | struct mx3_camera_dev *mx3_cam = ici->priv; | ||
741 | const struct soc_camera_format_xlate *xlate; | ||
742 | u32 ctrl, width_field, height_field; | 737 | u32 ctrl, width_field, height_field; |
743 | int ret; | ||
744 | |||
745 | xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); | ||
746 | if (pixfmt && !xlate) { | ||
747 | dev_warn(&ici->dev, "Format %x not found\n", pixfmt); | ||
748 | return -EINVAL; | ||
749 | } | ||
750 | |||
751 | /* | ||
752 | * We now know pixel formats and can decide upon DMA-channel(s) | ||
753 | * So far only direct camera-to-memory is supported | ||
754 | */ | ||
755 | if (channel_change_requested(icd, xlate, pixfmt, rect)) { | ||
756 | dma_cap_mask_t mask; | ||
757 | struct dma_chan *chan; | ||
758 | struct idmac_channel **ichan = &mx3_cam->idmac_channel[0]; | ||
759 | /* We have to use IDMAC_IC_7 for Bayer / generic data */ | ||
760 | struct dma_chan_request rq = {.mx3_cam = mx3_cam, | ||
761 | .id = IDMAC_IC_7}; | ||
762 | |||
763 | if (*ichan) { | ||
764 | struct videobuf_buffer *vb, *_vb; | ||
765 | dma_release_channel(&(*ichan)->dma_chan); | ||
766 | *ichan = NULL; | ||
767 | mx3_cam->active = NULL; | ||
768 | list_for_each_entry_safe(vb, _vb, &mx3_cam->capture, queue) { | ||
769 | list_del_init(&vb->queue); | ||
770 | vb->state = VIDEOBUF_ERROR; | ||
771 | wake_up(&vb->done); | ||
772 | } | ||
773 | } | ||
774 | |||
775 | dma_cap_zero(mask); | ||
776 | dma_cap_set(DMA_SLAVE, mask); | ||
777 | dma_cap_set(DMA_PRIVATE, mask); | ||
778 | chan = dma_request_channel(mask, chan_filter, &rq); | ||
779 | if (!chan) | ||
780 | return -EBUSY; | ||
781 | |||
782 | *ichan = to_idmac_chan(chan); | ||
783 | (*ichan)->client = mx3_cam; | ||
784 | } | ||
785 | |||
786 | /* | ||
787 | * Might have to perform a complete interface initialisation like in | ||
788 | * ipu_csi_init_interface() in mxc_v4l2_s_param(). Also consider | ||
789 | * mxc_v4l2_s_fmt() | ||
790 | */ | ||
791 | 738 | ||
792 | /* Setup frame size - this cannot be changed on-the-fly... */ | 739 | /* Setup frame size - this cannot be changed on-the-fly... */ |
793 | width_field = rect->width - 1; | 740 | width_field = rect->width - 1; |
@@ -808,9 +755,98 @@ static int mx3_camera_set_fmt(struct soc_camera_device *icd, | |||
808 | * No need to free resources here if we fail, we'll see if we need to | 755 | * No need to free resources here if we fail, we'll see if we need to |
809 | * do this next time we are called | 756 | * do this next time we are called |
810 | */ | 757 | */ |
758 | } | ||
759 | |||
760 | static int acquire_dma_channel(struct mx3_camera_dev *mx3_cam) | ||
761 | { | ||
762 | dma_cap_mask_t mask; | ||
763 | struct dma_chan *chan; | ||
764 | struct idmac_channel **ichan = &mx3_cam->idmac_channel[0]; | ||
765 | /* We have to use IDMAC_IC_7 for Bayer / generic data */ | ||
766 | struct dma_chan_request rq = {.mx3_cam = mx3_cam, | ||
767 | .id = IDMAC_IC_7}; | ||
768 | |||
769 | if (*ichan) { | ||
770 | struct videobuf_buffer *vb, *_vb; | ||
771 | dma_release_channel(&(*ichan)->dma_chan); | ||
772 | *ichan = NULL; | ||
773 | mx3_cam->active = NULL; | ||
774 | list_for_each_entry_safe(vb, _vb, &mx3_cam->capture, queue) { | ||
775 | list_del_init(&vb->queue); | ||
776 | vb->state = VIDEOBUF_ERROR; | ||
777 | wake_up(&vb->done); | ||
778 | } | ||
779 | } | ||
780 | |||
781 | dma_cap_zero(mask); | ||
782 | dma_cap_set(DMA_SLAVE, mask); | ||
783 | dma_cap_set(DMA_PRIVATE, mask); | ||
784 | chan = dma_request_channel(mask, chan_filter, &rq); | ||
785 | if (!chan) | ||
786 | return -EBUSY; | ||
787 | |||
788 | *ichan = to_idmac_chan(chan); | ||
789 | (*ichan)->client = mx3_cam; | ||
790 | |||
791 | return 0; | ||
792 | } | ||
793 | |||
794 | static int mx3_camera_set_crop(struct soc_camera_device *icd, | ||
795 | struct v4l2_rect *rect) | ||
796 | { | ||
797 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | ||
798 | struct mx3_camera_dev *mx3_cam = ici->priv; | ||
799 | |||
800 | /* | ||
801 | * We now know pixel formats and can decide upon DMA-channel(s) | ||
802 | * So far only direct camera-to-memory is supported | ||
803 | */ | ||
804 | if (channel_change_requested(icd, rect)) { | ||
805 | int ret = acquire_dma_channel(mx3_cam); | ||
806 | if (ret < 0) | ||
807 | return ret; | ||
808 | } | ||
809 | |||
810 | configure_geometry(mx3_cam, rect); | ||
811 | |||
812 | return icd->ops->set_crop(icd, rect); | ||
813 | } | ||
814 | |||
815 | static int mx3_camera_set_fmt(struct soc_camera_device *icd, | ||
816 | struct v4l2_format *f) | ||
817 | { | ||
818 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | ||
819 | struct mx3_camera_dev *mx3_cam = ici->priv; | ||
820 | const struct soc_camera_format_xlate *xlate; | ||
821 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
822 | struct v4l2_rect rect = { | ||
823 | .left = icd->x_current, | ||
824 | .top = icd->y_current, | ||
825 | .width = pix->width, | ||
826 | .height = pix->height, | ||
827 | }; | ||
828 | int ret; | ||
829 | |||
830 | xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); | ||
831 | if (!xlate) { | ||
832 | dev_warn(&ici->dev, "Format %x not found\n", pix->pixelformat); | ||
833 | return -EINVAL; | ||
834 | } | ||
835 | |||
836 | ret = acquire_dma_channel(mx3_cam); | ||
837 | if (ret < 0) | ||
838 | return ret; | ||
839 | |||
840 | /* | ||
841 | * Might have to perform a complete interface initialisation like in | ||
842 | * ipu_csi_init_interface() in mxc_v4l2_s_param(). Also consider | ||
843 | * mxc_v4l2_s_fmt() | ||
844 | */ | ||
845 | |||
846 | configure_geometry(mx3_cam, &rect); | ||
811 | 847 | ||
812 | ret = icd->ops->set_fmt(icd, pixfmt ? xlate->cam_fmt->fourcc : 0, rect); | 848 | ret = icd->ops->set_fmt(icd, f); |
813 | if (pixfmt && !ret) { | 849 | if (!ret) { |
814 | icd->buswidth = xlate->buswidth; | 850 | icd->buswidth = xlate->buswidth; |
815 | icd->current_fmt = xlate->host_fmt; | 851 | icd->current_fmt = xlate->host_fmt; |
816 | } | 852 | } |
@@ -1031,6 +1067,7 @@ static struct soc_camera_host_ops mx3_soc_camera_host_ops = { | |||
1031 | .suspend = mx3_camera_suspend, | 1067 | .suspend = mx3_camera_suspend, |
1032 | .resume = mx3_camera_resume, | 1068 | .resume = mx3_camera_resume, |
1033 | #endif | 1069 | #endif |
1070 | .set_crop = mx3_camera_set_crop, | ||
1034 | .set_fmt = mx3_camera_set_fmt, | 1071 | .set_fmt = mx3_camera_set_fmt, |
1035 | .try_fmt = mx3_camera_try_fmt, | 1072 | .try_fmt = mx3_camera_try_fmt, |
1036 | .get_formats = mx3_camera_get_formats, | 1073 | .get_formats = mx3_camera_get_formats, |
diff --git a/drivers/media/video/ov772x.c b/drivers/media/video/ov772x.c index 880e51f0e9fd..8dd93b36c787 100644 --- a/drivers/media/video/ov772x.c +++ b/drivers/media/video/ov772x.c | |||
@@ -781,11 +781,9 @@ ov772x_select_win(u32 width, u32 height) | |||
781 | return win; | 781 | return win; |
782 | } | 782 | } |
783 | 783 | ||
784 | static int ov772x_set_fmt(struct soc_camera_device *icd, | 784 | static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height, |
785 | __u32 pixfmt, | 785 | u32 pixfmt) |
786 | struct v4l2_rect *rect) | ||
787 | { | 786 | { |
788 | struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); | ||
789 | int ret = -EINVAL; | 787 | int ret = -EINVAL; |
790 | u8 val; | 788 | u8 val; |
791 | int i; | 789 | int i; |
@@ -806,7 +804,7 @@ static int ov772x_set_fmt(struct soc_camera_device *icd, | |||
806 | /* | 804 | /* |
807 | * select win | 805 | * select win |
808 | */ | 806 | */ |
809 | priv->win = ov772x_select_win(rect->width, rect->height); | 807 | priv->win = ov772x_select_win(width, height); |
810 | 808 | ||
811 | /* | 809 | /* |
812 | * reset hardware | 810 | * reset hardware |
@@ -870,6 +868,28 @@ ov772x_set_fmt_error: | |||
870 | return ret; | 868 | return ret; |
871 | } | 869 | } |
872 | 870 | ||
871 | static int ov772x_set_crop(struct soc_camera_device *icd, | ||
872 | struct v4l2_rect *rect) | ||
873 | { | ||
874 | struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); | ||
875 | |||
876 | if (!priv->fmt) | ||
877 | return -EINVAL; | ||
878 | |||
879 | return ov772x_set_params(priv, rect->width, rect->height, | ||
880 | priv->fmt->fourcc); | ||
881 | } | ||
882 | |||
883 | static int ov772x_set_fmt(struct soc_camera_device *icd, | ||
884 | struct v4l2_format *f) | ||
885 | { | ||
886 | struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); | ||
887 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
888 | |||
889 | return ov772x_set_params(priv, pix->width, pix->height, | ||
890 | pix->pixelformat); | ||
891 | } | ||
892 | |||
873 | static int ov772x_try_fmt(struct soc_camera_device *icd, | 893 | static int ov772x_try_fmt(struct soc_camera_device *icd, |
874 | struct v4l2_format *f) | 894 | struct v4l2_format *f) |
875 | { | 895 | { |
@@ -959,6 +979,7 @@ static struct soc_camera_ops ov772x_ops = { | |||
959 | .release = ov772x_release, | 979 | .release = ov772x_release, |
960 | .start_capture = ov772x_start_capture, | 980 | .start_capture = ov772x_start_capture, |
961 | .stop_capture = ov772x_stop_capture, | 981 | .stop_capture = ov772x_stop_capture, |
982 | .set_crop = ov772x_set_crop, | ||
962 | .set_fmt = ov772x_set_fmt, | 983 | .set_fmt = ov772x_set_fmt, |
963 | .try_fmt = ov772x_try_fmt, | 984 | .try_fmt = ov772x_try_fmt, |
964 | .set_bus_param = ov772x_set_bus_param, | 985 | .set_bus_param = ov772x_set_bus_param, |
diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c index 2cc203cfbe6c..c522616ef38f 100644 --- a/drivers/media/video/pxa_camera.c +++ b/drivers/media/video/pxa_camera.c | |||
@@ -1150,8 +1150,43 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx, | |||
1150 | return formats; | 1150 | return formats; |
1151 | } | 1151 | } |
1152 | 1152 | ||
1153 | static int pxa_camera_set_crop(struct soc_camera_device *icd, | ||
1154 | struct v4l2_rect *rect) | ||
1155 | { | ||
1156 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | ||
1157 | struct pxa_camera_dev *pcdev = ici->priv; | ||
1158 | struct soc_camera_sense sense = { | ||
1159 | .master_clock = pcdev->mclk, | ||
1160 | .pixel_clock_max = pcdev->ciclk / 4, | ||
1161 | }; | ||
1162 | int ret; | ||
1163 | |||
1164 | /* If PCLK is used to latch data from the sensor, check sense */ | ||
1165 | if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN) | ||
1166 | icd->sense = &sense; | ||
1167 | |||
1168 | ret = icd->ops->set_crop(icd, rect); | ||
1169 | |||
1170 | icd->sense = NULL; | ||
1171 | |||
1172 | if (ret < 0) { | ||
1173 | dev_warn(&ici->dev, "Failed to crop to %ux%u@%u:%u\n", | ||
1174 | rect->width, rect->height, rect->left, rect->top); | ||
1175 | } else if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) { | ||
1176 | if (sense.pixel_clock > sense.pixel_clock_max) { | ||
1177 | dev_err(&ici->dev, | ||
1178 | "pixel clock %lu set by the camera too high!", | ||
1179 | sense.pixel_clock); | ||
1180 | return -EIO; | ||
1181 | } | ||
1182 | recalculate_fifo_timeout(pcdev, sense.pixel_clock); | ||
1183 | } | ||
1184 | |||
1185 | return ret; | ||
1186 | } | ||
1187 | |||
1153 | static int pxa_camera_set_fmt(struct soc_camera_device *icd, | 1188 | static int pxa_camera_set_fmt(struct soc_camera_device *icd, |
1154 | __u32 pixfmt, struct v4l2_rect *rect) | 1189 | struct v4l2_format *f) |
1155 | { | 1190 | { |
1156 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 1191 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
1157 | struct pxa_camera_dev *pcdev = ici->priv; | 1192 | struct pxa_camera_dev *pcdev = ici->priv; |
@@ -1161,35 +1196,30 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd, | |||
1161 | .master_clock = pcdev->mclk, | 1196 | .master_clock = pcdev->mclk, |
1162 | .pixel_clock_max = pcdev->ciclk / 4, | 1197 | .pixel_clock_max = pcdev->ciclk / 4, |
1163 | }; | 1198 | }; |
1199 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
1200 | struct v4l2_format cam_f = *f; | ||
1164 | int ret; | 1201 | int ret; |
1165 | 1202 | ||
1166 | if (pixfmt) { | 1203 | xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); |
1167 | xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); | 1204 | if (!xlate) { |
1168 | if (!xlate) { | 1205 | dev_warn(&ici->dev, "Format %x not found\n", pix->pixelformat); |
1169 | dev_warn(&ici->dev, "Format %x not found\n", pixfmt); | 1206 | return -EINVAL; |
1170 | return -EINVAL; | ||
1171 | } | ||
1172 | |||
1173 | cam_fmt = xlate->cam_fmt; | ||
1174 | } | 1207 | } |
1175 | 1208 | ||
1209 | cam_fmt = xlate->cam_fmt; | ||
1210 | |||
1176 | /* If PCLK is used to latch data from the sensor, check sense */ | 1211 | /* If PCLK is used to latch data from the sensor, check sense */ |
1177 | if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN) | 1212 | if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN) |
1178 | icd->sense = &sense; | 1213 | icd->sense = &sense; |
1179 | 1214 | ||
1180 | switch (pixfmt) { | 1215 | cam_f.fmt.pix.pixelformat = cam_fmt->fourcc; |
1181 | case 0: /* Only geometry change */ | 1216 | ret = icd->ops->set_fmt(icd, &cam_f); |
1182 | ret = icd->ops->set_fmt(icd, pixfmt, rect); | ||
1183 | break; | ||
1184 | default: | ||
1185 | ret = icd->ops->set_fmt(icd, cam_fmt->fourcc, rect); | ||
1186 | } | ||
1187 | 1217 | ||
1188 | icd->sense = NULL; | 1218 | icd->sense = NULL; |
1189 | 1219 | ||
1190 | if (ret < 0) { | 1220 | if (ret < 0) { |
1191 | dev_warn(&ici->dev, "Failed to configure for format %x\n", | 1221 | dev_warn(&ici->dev, "Failed to configure for format %x\n", |
1192 | pixfmt); | 1222 | pix->pixelformat); |
1193 | } else if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) { | 1223 | } else if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) { |
1194 | if (sense.pixel_clock > sense.pixel_clock_max) { | 1224 | if (sense.pixel_clock > sense.pixel_clock_max) { |
1195 | dev_err(&ici->dev, | 1225 | dev_err(&ici->dev, |
@@ -1200,7 +1230,7 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd, | |||
1200 | recalculate_fifo_timeout(pcdev, sense.pixel_clock); | 1230 | recalculate_fifo_timeout(pcdev, sense.pixel_clock); |
1201 | } | 1231 | } |
1202 | 1232 | ||
1203 | if (pixfmt && !ret) { | 1233 | if (!ret) { |
1204 | icd->buswidth = xlate->buswidth; | 1234 | icd->buswidth = xlate->buswidth; |
1205 | icd->current_fmt = xlate->host_fmt; | 1235 | icd->current_fmt = xlate->host_fmt; |
1206 | } | 1236 | } |
@@ -1364,6 +1394,7 @@ static struct soc_camera_host_ops pxa_soc_camera_host_ops = { | |||
1364 | .remove = pxa_camera_remove_device, | 1394 | .remove = pxa_camera_remove_device, |
1365 | .suspend = pxa_camera_suspend, | 1395 | .suspend = pxa_camera_suspend, |
1366 | .resume = pxa_camera_resume, | 1396 | .resume = pxa_camera_resume, |
1397 | .set_crop = pxa_camera_set_crop, | ||
1367 | .get_formats = pxa_camera_get_formats, | 1398 | .get_formats = pxa_camera_get_formats, |
1368 | .set_fmt = pxa_camera_set_fmt, | 1399 | .set_fmt = pxa_camera_set_fmt, |
1369 | .try_fmt = pxa_camera_try_fmt, | 1400 | .try_fmt = pxa_camera_try_fmt, |
diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index ed3bfc4cf9f9..3f71cb809652 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c | |||
@@ -638,24 +638,30 @@ add_single_format: | |||
638 | return formats; | 638 | return formats; |
639 | } | 639 | } |
640 | 640 | ||
641 | static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, | ||
642 | struct v4l2_rect *rect) | ||
643 | { | ||
644 | return icd->ops->set_crop(icd, rect); | ||
645 | } | ||
646 | |||
641 | static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, | 647 | static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, |
642 | __u32 pixfmt, struct v4l2_rect *rect) | 648 | struct v4l2_format *f) |
643 | { | 649 | { |
644 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 650 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
645 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | 651 | struct sh_mobile_ceu_dev *pcdev = ici->priv; |
652 | __u32 pixfmt = f->fmt.pix.pixelformat; | ||
646 | const struct soc_camera_format_xlate *xlate; | 653 | const struct soc_camera_format_xlate *xlate; |
654 | struct v4l2_format cam_f = *f; | ||
647 | int ret; | 655 | int ret; |
648 | 656 | ||
649 | if (!pixfmt) | ||
650 | return icd->ops->set_fmt(icd, pixfmt, rect); | ||
651 | |||
652 | xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); | 657 | xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); |
653 | if (!xlate) { | 658 | if (!xlate) { |
654 | dev_warn(&ici->dev, "Format %x not found\n", pixfmt); | 659 | dev_warn(&ici->dev, "Format %x not found\n", pixfmt); |
655 | return -EINVAL; | 660 | return -EINVAL; |
656 | } | 661 | } |
657 | 662 | ||
658 | ret = icd->ops->set_fmt(icd, xlate->cam_fmt->fourcc, rect); | 663 | cam_f.fmt.pix.pixelformat = xlate->cam_fmt->fourcc; |
664 | ret = icd->ops->set_fmt(icd, &cam_f); | ||
659 | 665 | ||
660 | if (!ret) { | 666 | if (!ret) { |
661 | icd->buswidth = xlate->buswidth; | 667 | icd->buswidth = xlate->buswidth; |
@@ -787,6 +793,7 @@ static struct soc_camera_host_ops sh_mobile_ceu_host_ops = { | |||
787 | .add = sh_mobile_ceu_add_device, | 793 | .add = sh_mobile_ceu_add_device, |
788 | .remove = sh_mobile_ceu_remove_device, | 794 | .remove = sh_mobile_ceu_remove_device, |
789 | .get_formats = sh_mobile_ceu_get_formats, | 795 | .get_formats = sh_mobile_ceu_get_formats, |
796 | .set_crop = sh_mobile_ceu_set_crop, | ||
790 | .set_fmt = sh_mobile_ceu_set_fmt, | 797 | .set_fmt = sh_mobile_ceu_set_fmt, |
791 | .try_fmt = sh_mobile_ceu_try_fmt, | 798 | .try_fmt = sh_mobile_ceu_try_fmt, |
792 | .reqbufs = sh_mobile_ceu_reqbufs, | 799 | .reqbufs = sh_mobile_ceu_reqbufs, |
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index fcb05f06de8f..9939b045cb4c 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c | |||
@@ -417,9 +417,7 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv, | |||
417 | struct soc_camera_device *icd = icf->icd; | 417 | struct soc_camera_device *icd = icf->icd; |
418 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 418 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
419 | struct v4l2_pix_format *pix = &f->fmt.pix; | 419 | struct v4l2_pix_format *pix = &f->fmt.pix; |
420 | __u32 pixfmt = pix->pixelformat; | ||
421 | int ret; | 420 | int ret; |
422 | struct v4l2_rect rect; | ||
423 | 421 | ||
424 | WARN_ON(priv != file->private_data); | 422 | WARN_ON(priv != file->private_data); |
425 | 423 | ||
@@ -435,23 +433,19 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv, | |||
435 | goto unlock; | 433 | goto unlock; |
436 | } | 434 | } |
437 | 435 | ||
438 | rect.left = icd->x_current; | 436 | ret = ici->ops->set_fmt(icd, f); |
439 | rect.top = icd->y_current; | ||
440 | rect.width = pix->width; | ||
441 | rect.height = pix->height; | ||
442 | ret = ici->ops->set_fmt(icd, pix->pixelformat, &rect); | ||
443 | if (ret < 0) { | 437 | if (ret < 0) { |
444 | goto unlock; | 438 | goto unlock; |
445 | } else if (!icd->current_fmt || | 439 | } else if (!icd->current_fmt || |
446 | icd->current_fmt->fourcc != pixfmt) { | 440 | icd->current_fmt->fourcc != pix->pixelformat) { |
447 | dev_err(&ici->dev, | 441 | dev_err(&ici->dev, |
448 | "Host driver hasn't set up current format correctly!\n"); | 442 | "Host driver hasn't set up current format correctly!\n"); |
449 | ret = -EINVAL; | 443 | ret = -EINVAL; |
450 | goto unlock; | 444 | goto unlock; |
451 | } | 445 | } |
452 | 446 | ||
453 | icd->width = rect.width; | 447 | icd->width = f->fmt.pix.width; |
454 | icd->height = rect.height; | 448 | icd->height = f->fmt.pix.height; |
455 | icf->vb_vidq.field = pix->field; | 449 | icf->vb_vidq.field = pix->field; |
456 | if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 450 | if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
457 | dev_warn(&icd->dev, "Attention! Wrong buf-type %d\n", | 451 | dev_warn(&icd->dev, "Attention! Wrong buf-type %d\n", |
@@ -461,7 +455,7 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv, | |||
461 | icd->width, icd->height); | 455 | icd->width, icd->height); |
462 | 456 | ||
463 | /* set physical bus parameters */ | 457 | /* set physical bus parameters */ |
464 | ret = ici->ops->set_bus_param(icd, pixfmt); | 458 | ret = ici->ops->set_bus_param(icd, pix->pixelformat); |
465 | 459 | ||
466 | unlock: | 460 | unlock: |
467 | mutex_unlock(&icf->vb_vidq.vb_lock); | 461 | mutex_unlock(&icf->vb_vidq.vb_lock); |
@@ -685,7 +679,7 @@ static int soc_camera_s_crop(struct file *file, void *fh, | |||
685 | /* Cropping is allowed during a running capture, guard consistency */ | 679 | /* Cropping is allowed during a running capture, guard consistency */ |
686 | mutex_lock(&icf->vb_vidq.vb_lock); | 680 | mutex_lock(&icf->vb_vidq.vb_lock); |
687 | 681 | ||
688 | ret = ici->ops->set_fmt(icd, 0, &a->c); | 682 | ret = ici->ops->set_crop(icd, &a->c); |
689 | if (!ret) { | 683 | if (!ret) { |
690 | icd->width = a->c.width; | 684 | icd->width = a->c.width; |
691 | icd->height = a->c.height; | 685 | icd->height = a->c.height; |
@@ -918,6 +912,7 @@ int soc_camera_host_register(struct soc_camera_host *ici) | |||
918 | if (!ici || !ici->ops || | 912 | if (!ici || !ici->ops || |
919 | !ici->ops->try_fmt || | 913 | !ici->ops->try_fmt || |
920 | !ici->ops->set_fmt || | 914 | !ici->ops->set_fmt || |
915 | !ici->ops->set_crop || | ||
921 | !ici->ops->set_bus_param || | 916 | !ici->ops->set_bus_param || |
922 | !ici->ops->querycap || | 917 | !ici->ops->querycap || |
923 | !ici->ops->init_videobuf || | 918 | !ici->ops->init_videobuf || |
@@ -998,6 +993,7 @@ int soc_camera_device_register(struct soc_camera_device *icd) | |||
998 | !icd->ops->release || | 993 | !icd->ops->release || |
999 | !icd->ops->start_capture || | 994 | !icd->ops->start_capture || |
1000 | !icd->ops->stop_capture || | 995 | !icd->ops->stop_capture || |
996 | !icd->ops->set_crop || | ||
1001 | !icd->ops->set_fmt || | 997 | !icd->ops->set_fmt || |
1002 | !icd->ops->try_fmt || | 998 | !icd->ops->try_fmt || |
1003 | !icd->ops->query_bus_param || | 999 | !icd->ops->query_bus_param || |
diff --git a/drivers/media/video/soc_camera_platform.c b/drivers/media/video/soc_camera_platform.c index 013ab06e3180..c48676356ab7 100644 --- a/drivers/media/video/soc_camera_platform.c +++ b/drivers/media/video/soc_camera_platform.c | |||
@@ -79,8 +79,14 @@ soc_camera_platform_query_bus_param(struct soc_camera_device *icd) | |||
79 | return p->bus_param; | 79 | return p->bus_param; |
80 | } | 80 | } |
81 | 81 | ||
82 | static int soc_camera_platform_set_crop(struct soc_camera_device *icd, | ||
83 | struct v4l2_rect *rect) | ||
84 | { | ||
85 | return 0; | ||
86 | } | ||
87 | |||
82 | static int soc_camera_platform_set_fmt(struct soc_camera_device *icd, | 88 | static int soc_camera_platform_set_fmt(struct soc_camera_device *icd, |
83 | __u32 pixfmt, struct v4l2_rect *rect) | 89 | struct v4l2_format *f) |
84 | { | 90 | { |
85 | return 0; | 91 | return 0; |
86 | } | 92 | } |
@@ -125,6 +131,7 @@ static struct soc_camera_ops soc_camera_platform_ops = { | |||
125 | .release = soc_camera_platform_release, | 131 | .release = soc_camera_platform_release, |
126 | .start_capture = soc_camera_platform_start_capture, | 132 | .start_capture = soc_camera_platform_start_capture, |
127 | .stop_capture = soc_camera_platform_stop_capture, | 133 | .stop_capture = soc_camera_platform_stop_capture, |
134 | .set_crop = soc_camera_platform_set_crop, | ||
128 | .set_fmt = soc_camera_platform_set_fmt, | 135 | .set_fmt = soc_camera_platform_set_fmt, |
129 | .try_fmt = soc_camera_platform_try_fmt, | 136 | .try_fmt = soc_camera_platform_try_fmt, |
130 | .set_bus_param = soc_camera_platform_set_bus_param, | 137 | .set_bus_param = soc_camera_platform_set_bus_param, |
diff --git a/drivers/media/video/tw9910.c b/drivers/media/video/tw9910.c index 0558b22fd3fb..a39947643992 100644 --- a/drivers/media/video/tw9910.c +++ b/drivers/media/video/tw9910.c | |||
@@ -641,25 +641,12 @@ static int tw9910_set_register(struct soc_camera_device *icd, | |||
641 | } | 641 | } |
642 | #endif | 642 | #endif |
643 | 643 | ||
644 | static int tw9910_set_fmt(struct soc_camera_device *icd, __u32 pixfmt, | 644 | static int tw9910_set_crop(struct soc_camera_device *icd, |
645 | struct v4l2_rect *rect) | 645 | struct v4l2_rect *rect) |
646 | { | 646 | { |
647 | struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd); | 647 | struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd); |
648 | int ret = -EINVAL; | 648 | int ret = -EINVAL; |
649 | u8 val; | 649 | u8 val; |
650 | int i; | ||
651 | |||
652 | /* | ||
653 | * check color format | ||
654 | */ | ||
655 | for (i = 0 ; i < ARRAY_SIZE(tw9910_color_fmt) ; i++) { | ||
656 | if (pixfmt == tw9910_color_fmt[i].fourcc) { | ||
657 | ret = 0; | ||
658 | break; | ||
659 | } | ||
660 | } | ||
661 | if (ret < 0) | ||
662 | goto tw9910_set_fmt_error; | ||
663 | 650 | ||
664 | /* | 651 | /* |
665 | * select suitable norm | 652 | * select suitable norm |
@@ -746,8 +733,33 @@ tw9910_set_fmt_error: | |||
746 | return ret; | 733 | return ret; |
747 | } | 734 | } |
748 | 735 | ||
736 | static int tw9910_set_fmt(struct soc_camera_device *icd, | ||
737 | struct v4l2_format *f) | ||
738 | { | ||
739 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
740 | struct v4l2_rect rect = { | ||
741 | .left = icd->x_current, | ||
742 | .top = icd->y_current, | ||
743 | .width = pix->width, | ||
744 | .height = pix->height, | ||
745 | }; | ||
746 | int i; | ||
747 | |||
748 | /* | ||
749 | * check color format | ||
750 | */ | ||
751 | for (i = 0; i < ARRAY_SIZE(tw9910_color_fmt); i++) | ||
752 | if (pix->pixelformat == tw9910_color_fmt[i].fourcc) | ||
753 | break; | ||
754 | |||
755 | if (i == ARRAY_SIZE(tw9910_color_fmt)) | ||
756 | return -EINVAL; | ||
757 | |||
758 | return tw9910_set_crop(icd, &rect); | ||
759 | } | ||
760 | |||
749 | static int tw9910_try_fmt(struct soc_camera_device *icd, | 761 | static int tw9910_try_fmt(struct soc_camera_device *icd, |
750 | struct v4l2_format *f) | 762 | struct v4l2_format *f) |
751 | { | 763 | { |
752 | struct v4l2_pix_format *pix = &f->fmt.pix; | 764 | struct v4l2_pix_format *pix = &f->fmt.pix; |
753 | const struct tw9910_scale_ctrl *scale; | 765 | const struct tw9910_scale_ctrl *scale; |
@@ -835,6 +847,7 @@ static struct soc_camera_ops tw9910_ops = { | |||
835 | .release = tw9910_release, | 847 | .release = tw9910_release, |
836 | .start_capture = tw9910_start_capture, | 848 | .start_capture = tw9910_start_capture, |
837 | .stop_capture = tw9910_stop_capture, | 849 | .stop_capture = tw9910_stop_capture, |
850 | .set_crop = tw9910_set_crop, | ||
838 | .set_fmt = tw9910_set_fmt, | 851 | .set_fmt = tw9910_set_fmt, |
839 | .try_fmt = tw9910_try_fmt, | 852 | .try_fmt = tw9910_try_fmt, |
840 | .set_bus_param = tw9910_set_bus_param, | 853 | .set_bus_param = tw9910_set_bus_param, |