aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/mt9v022.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/mt9v022.c')
-rw-r--r--drivers/media/video/mt9v022.c131
1 files changed, 104 insertions, 27 deletions
diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c
index ab1965425289..35ea0ddd0715 100644
--- a/drivers/media/video/mt9v022.c
+++ b/drivers/media/video/mt9v022.c
@@ -55,6 +55,13 @@ MODULE_PARM_DESC(sensor_type, "Sensor type: \"colour\" or \"monochrome\"");
55/* Progressive scan, master, defaults */ 55/* Progressive scan, master, defaults */
56#define MT9V022_CHIP_CONTROL_DEFAULT 0x188 56#define MT9V022_CHIP_CONTROL_DEFAULT 0x188
57 57
58#define MT9V022_MAX_WIDTH 752
59#define MT9V022_MAX_HEIGHT 480
60#define MT9V022_MIN_WIDTH 48
61#define MT9V022_MIN_HEIGHT 32
62#define MT9V022_COLUMN_SKIP 1
63#define MT9V022_ROW_SKIP 4
64
58static const struct soc_camera_data_format mt9v022_colour_formats[] = { 65static const struct soc_camera_data_format mt9v022_colour_formats[] = {
59 /* Order important: first natively supported, 66 /* Order important: first natively supported,
60 * second supported with a GPIO extender */ 67 * second supported with a GPIO extender */
@@ -86,6 +93,8 @@ static const struct soc_camera_data_format mt9v022_monochrome_formats[] = {
86 93
87struct mt9v022 { 94struct mt9v022 {
88 struct v4l2_subdev subdev; 95 struct v4l2_subdev subdev;
96 struct v4l2_rect rect; /* Sensor window */
97 __u32 fourcc;
89 int model; /* V4L2_IDENT_MT9V022* codes from v4l2-chip-ident.h */ 98 int model; /* V4L2_IDENT_MT9V022* codes from v4l2-chip-ident.h */
90 u16 chip_control; 99 u16 chip_control;
91}; 100};
@@ -250,44 +259,101 @@ static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd)
250 259
251static int mt9v022_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) 260static int mt9v022_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
252{ 261{
253 struct v4l2_rect *rect = &a->c;
254 struct i2c_client *client = sd->priv; 262 struct i2c_client *client = sd->priv;
263 struct mt9v022 *mt9v022 = to_mt9v022(client);
264 struct v4l2_rect rect = a->c;
255 struct soc_camera_device *icd = client->dev.platform_data; 265 struct soc_camera_device *icd = client->dev.platform_data;
256 int ret; 266 int ret;
257 267
268 /* Bayer format - even size lengths */
269 if (mt9v022->fourcc == V4L2_PIX_FMT_SBGGR8 ||
270 mt9v022->fourcc == V4L2_PIX_FMT_SBGGR16) {
271 rect.width = ALIGN(rect.width, 2);
272 rect.height = ALIGN(rect.height, 2);
273 /* Let the user play with the starting pixel */
274 }
275
276 soc_camera_limit_side(&rect.left, &rect.width,
277 MT9V022_COLUMN_SKIP, MT9V022_MIN_WIDTH, MT9V022_MAX_WIDTH);
278
279 soc_camera_limit_side(&rect.top, &rect.height,
280 MT9V022_ROW_SKIP, MT9V022_MIN_HEIGHT, MT9V022_MAX_HEIGHT);
281
258 /* Like in example app. Contradicts the datasheet though */ 282 /* Like in example app. Contradicts the datasheet though */
259 ret = reg_read(client, MT9V022_AEC_AGC_ENABLE); 283 ret = reg_read(client, MT9V022_AEC_AGC_ENABLE);
260 if (ret >= 0) { 284 if (ret >= 0) {
261 if (ret & 1) /* Autoexposure */ 285 if (ret & 1) /* Autoexposure */
262 ret = reg_write(client, MT9V022_MAX_TOTAL_SHUTTER_WIDTH, 286 ret = reg_write(client, MT9V022_MAX_TOTAL_SHUTTER_WIDTH,
263 rect->height + icd->y_skip_top + 43); 287 rect.height + icd->y_skip_top + 43);
264 else 288 else
265 ret = reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, 289 ret = reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH,
266 rect->height + icd->y_skip_top + 43); 290 rect.height + icd->y_skip_top + 43);
267 } 291 }
268 /* Setup frame format: defaults apart from width and height */ 292 /* Setup frame format: defaults apart from width and height */
269 if (!ret) 293 if (!ret)
270 ret = reg_write(client, MT9V022_COLUMN_START, rect->left); 294 ret = reg_write(client, MT9V022_COLUMN_START, rect.left);
271 if (!ret) 295 if (!ret)
272 ret = reg_write(client, MT9V022_ROW_START, rect->top); 296 ret = reg_write(client, MT9V022_ROW_START, rect.top);
273 if (!ret) 297 if (!ret)
274 /* Default 94, Phytec driver says: 298 /* Default 94, Phytec driver says:
275 * "width + horizontal blank >= 660" */ 299 * "width + horizontal blank >= 660" */
276 ret = reg_write(client, MT9V022_HORIZONTAL_BLANKING, 300 ret = reg_write(client, MT9V022_HORIZONTAL_BLANKING,
277 rect->width > 660 - 43 ? 43 : 301 rect.width > 660 - 43 ? 43 :
278 660 - rect->width); 302 660 - rect.width);
279 if (!ret) 303 if (!ret)
280 ret = reg_write(client, MT9V022_VERTICAL_BLANKING, 45); 304 ret = reg_write(client, MT9V022_VERTICAL_BLANKING, 45);
281 if (!ret) 305 if (!ret)
282 ret = reg_write(client, MT9V022_WINDOW_WIDTH, rect->width); 306 ret = reg_write(client, MT9V022_WINDOW_WIDTH, rect.width);
283 if (!ret) 307 if (!ret)
284 ret = reg_write(client, MT9V022_WINDOW_HEIGHT, 308 ret = reg_write(client, MT9V022_WINDOW_HEIGHT,
285 rect->height + icd->y_skip_top); 309 rect.height + icd->y_skip_top);
286 310
287 if (ret < 0) 311 if (ret < 0)
288 return ret; 312 return ret;
289 313
290 dev_dbg(&client->dev, "Frame %ux%u pixel\n", rect->width, rect->height); 314 dev_dbg(&client->dev, "Frame %ux%u pixel\n", rect.width, rect.height);
315
316 mt9v022->rect = rect;
317
318 return 0;
319}
320
321static int mt9v022_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
322{
323 struct i2c_client *client = sd->priv;
324 struct mt9v022 *mt9v022 = to_mt9v022(client);
325
326 a->c = mt9v022->rect;
327 a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
328
329 return 0;
330}
331
332static int mt9v022_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
333{
334 a->bounds.left = MT9V022_COLUMN_SKIP;
335 a->bounds.top = MT9V022_ROW_SKIP;
336 a->bounds.width = MT9V022_MAX_WIDTH;
337 a->bounds.height = MT9V022_MAX_HEIGHT;
338 a->defrect = a->bounds;
339 a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
340 a->pixelaspect.numerator = 1;
341 a->pixelaspect.denominator = 1;
342
343 return 0;
344}
345
346static int mt9v022_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
347{
348 struct i2c_client *client = sd->priv;
349 struct mt9v022 *mt9v022 = to_mt9v022(client);
350 struct v4l2_pix_format *pix = &f->fmt.pix;
351
352 pix->width = mt9v022->rect.width;
353 pix->height = mt9v022->rect.height;
354 pix->pixelformat = mt9v022->fourcc;
355 pix->field = V4L2_FIELD_NONE;
356 pix->colorspace = V4L2_COLORSPACE_SRGB;
291 357
292 return 0; 358 return 0;
293} 359}
@@ -296,16 +362,16 @@ static int mt9v022_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
296{ 362{
297 struct i2c_client *client = sd->priv; 363 struct i2c_client *client = sd->priv;
298 struct mt9v022 *mt9v022 = to_mt9v022(client); 364 struct mt9v022 *mt9v022 = to_mt9v022(client);
299 struct soc_camera_device *icd = client->dev.platform_data;
300 struct v4l2_pix_format *pix = &f->fmt.pix; 365 struct v4l2_pix_format *pix = &f->fmt.pix;
301 struct v4l2_crop a = { 366 struct v4l2_crop a = {
302 .c = { 367 .c = {
303 .left = icd->rect_current.left, 368 .left = mt9v022->rect.left,
304 .top = icd->rect_current.top, 369 .top = mt9v022->rect.top,
305 .width = pix->width, 370 .width = pix->width,
306 .height = pix->height, 371 .height = pix->height,
307 }, 372 },
308 }; 373 };
374 int ret;
309 375
310 /* The caller provides a supported format, as verified per call to 376 /* The caller provides a supported format, as verified per call to
311 * icd->try_fmt(), datawidth is from our supported format list */ 377 * icd->try_fmt(), datawidth is from our supported format list */
@@ -328,7 +394,14 @@ static int mt9v022_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
328 } 394 }
329 395
330 /* No support for scaling on this camera, just crop. */ 396 /* No support for scaling on this camera, just crop. */
331 return mt9v022_s_crop(sd, &a); 397 ret = mt9v022_s_crop(sd, &a);
398 if (!ret) {
399 pix->width = mt9v022->rect.width;
400 pix->height = mt9v022->rect.height;
401 mt9v022->fourcc = pix->pixelformat;
402 }
403
404 return ret;
332} 405}
333 406
334static int mt9v022_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) 407static int mt9v022_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
@@ -336,10 +409,13 @@ static int mt9v022_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
336 struct i2c_client *client = sd->priv; 409 struct i2c_client *client = sd->priv;
337 struct soc_camera_device *icd = client->dev.platform_data; 410 struct soc_camera_device *icd = client->dev.platform_data;
338 struct v4l2_pix_format *pix = &f->fmt.pix; 411 struct v4l2_pix_format *pix = &f->fmt.pix;
412 int align = pix->pixelformat == V4L2_PIX_FMT_SBGGR8 ||
413 pix->pixelformat == V4L2_PIX_FMT_SBGGR16;
339 414
340 v4l_bound_align_image(&pix->width, 48, 752, 2 /* ? */, 415 v4l_bound_align_image(&pix->width, MT9V022_MIN_WIDTH,
341 &pix->height, 32 + icd->y_skip_top, 416 MT9V022_MAX_WIDTH, align,
342 480 + icd->y_skip_top, 0, 0); 417 &pix->height, MT9V022_MIN_HEIGHT + icd->y_skip_top,
418 MT9V022_MAX_HEIGHT + icd->y_skip_top, align, 0);
343 419
344 return 0; 420 return 0;
345} 421}
@@ -669,6 +745,8 @@ static int mt9v022_video_probe(struct soc_camera_device *icd,
669 if (flags & SOCAM_DATAWIDTH_8) 745 if (flags & SOCAM_DATAWIDTH_8)
670 icd->num_formats++; 746 icd->num_formats++;
671 747
748 mt9v022->fourcc = icd->formats->fourcc;
749
672 dev_info(&client->dev, "Detected a MT9V022 chip ID %x, %s sensor\n", 750 dev_info(&client->dev, "Detected a MT9V022 chip ID %x, %s sensor\n",
673 data, mt9v022->model == V4L2_IDENT_MT9V022IX7ATM ? 751 data, mt9v022->model == V4L2_IDENT_MT9V022IX7ATM ?
674 "monochrome" : "colour"); 752 "monochrome" : "colour");
@@ -679,10 +757,9 @@ ei2c:
679 757
680static void mt9v022_video_remove(struct soc_camera_device *icd) 758static void mt9v022_video_remove(struct soc_camera_device *icd)
681{ 759{
682 struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
683 struct soc_camera_link *icl = to_soc_camera_link(icd); 760 struct soc_camera_link *icl = to_soc_camera_link(icd);
684 761
685 dev_dbg(&client->dev, "Video %x removed: %p, %p\n", client->addr, 762 dev_dbg(&icd->dev, "Video removed: %p, %p\n",
686 icd->dev.parent, icd->vdev); 763 icd->dev.parent, icd->vdev);
687 if (icl->free_bus) 764 if (icl->free_bus)
688 icl->free_bus(icl); 765 icl->free_bus(icl);
@@ -701,8 +778,11 @@ static struct v4l2_subdev_core_ops mt9v022_subdev_core_ops = {
701static struct v4l2_subdev_video_ops mt9v022_subdev_video_ops = { 778static struct v4l2_subdev_video_ops mt9v022_subdev_video_ops = {
702 .s_stream = mt9v022_s_stream, 779 .s_stream = mt9v022_s_stream,
703 .s_fmt = mt9v022_s_fmt, 780 .s_fmt = mt9v022_s_fmt,
781 .g_fmt = mt9v022_g_fmt,
704 .try_fmt = mt9v022_try_fmt, 782 .try_fmt = mt9v022_try_fmt,
705 .s_crop = mt9v022_s_crop, 783 .s_crop = mt9v022_s_crop,
784 .g_crop = mt9v022_g_crop,
785 .cropcap = mt9v022_cropcap,
706}; 786};
707 787
708static struct v4l2_subdev_ops mt9v022_subdev_ops = { 788static struct v4l2_subdev_ops mt9v022_subdev_ops = {
@@ -745,16 +825,13 @@ static int mt9v022_probe(struct i2c_client *client,
745 mt9v022->chip_control = MT9V022_CHIP_CONTROL_DEFAULT; 825 mt9v022->chip_control = MT9V022_CHIP_CONTROL_DEFAULT;
746 826
747 icd->ops = &mt9v022_ops; 827 icd->ops = &mt9v022_ops;
748 icd->rect_max.left = 1;
749 icd->rect_max.top = 4;
750 icd->rect_max.width = 752;
751 icd->rect_max.height = 480;
752 icd->rect_current.left = 1;
753 icd->rect_current.top = 4;
754 icd->width_min = 48;
755 icd->height_min = 32;
756 icd->y_skip_top = 1; 828 icd->y_skip_top = 1;
757 829
830 mt9v022->rect.left = MT9V022_COLUMN_SKIP;
831 mt9v022->rect.top = MT9V022_ROW_SKIP;
832 mt9v022->rect.width = MT9V022_MAX_WIDTH;
833 mt9v022->rect.height = MT9V022_MAX_HEIGHT;
834
758 ret = mt9v022_video_probe(icd, client); 835 ret = mt9v022_video_probe(icd, client);
759 if (ret) { 836 if (ret) {
760 icd->ops = NULL; 837 icd->ops = NULL;