diff options
Diffstat (limited to 'drivers/media/video/mt9m111.c')
-rw-r--r-- | drivers/media/video/mt9m111.c | 524 |
1 files changed, 271 insertions, 253 deletions
diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c index fc5e2de03766..90da699601ea 100644 --- a/drivers/media/video/mt9m111.c +++ b/drivers/media/video/mt9m111.c | |||
@@ -148,12 +148,12 @@ enum mt9m111_context { | |||
148 | }; | 148 | }; |
149 | 149 | ||
150 | struct mt9m111 { | 150 | struct mt9m111 { |
151 | struct i2c_client *client; | 151 | struct v4l2_subdev subdev; |
152 | struct soc_camera_device icd; | ||
153 | int model; /* V4L2_IDENT_MT9M11x* codes from v4l2-chip-ident.h */ | 152 | int model; /* V4L2_IDENT_MT9M11x* codes from v4l2-chip-ident.h */ |
154 | enum mt9m111_context context; | 153 | enum mt9m111_context context; |
155 | struct v4l2_rect rect; | 154 | struct v4l2_rect rect; |
156 | u32 pixfmt; | 155 | u32 pixfmt; |
156 | unsigned int gain; | ||
157 | unsigned char autoexposure; | 157 | unsigned char autoexposure; |
158 | unsigned char datawidth; | 158 | unsigned char datawidth; |
159 | unsigned int powered:1; | 159 | unsigned int powered:1; |
@@ -166,6 +166,11 @@ struct mt9m111 { | |||
166 | unsigned int autowhitebalance:1; | 166 | unsigned int autowhitebalance:1; |
167 | }; | 167 | }; |
168 | 168 | ||
169 | static struct mt9m111 *to_mt9m111(const struct i2c_client *client) | ||
170 | { | ||
171 | return container_of(i2c_get_clientdata(client), struct mt9m111, subdev); | ||
172 | } | ||
173 | |||
169 | static int reg_page_map_set(struct i2c_client *client, const u16 reg) | 174 | static int reg_page_map_set(struct i2c_client *client, const u16 reg) |
170 | { | 175 | { |
171 | int ret; | 176 | int ret; |
@@ -190,7 +195,7 @@ static int mt9m111_reg_read(struct i2c_client *client, const u16 reg) | |||
190 | 195 | ||
191 | ret = reg_page_map_set(client, reg); | 196 | ret = reg_page_map_set(client, reg); |
192 | if (!ret) | 197 | if (!ret) |
193 | ret = swab16(i2c_smbus_read_word_data(client, (reg & 0xff))); | 198 | ret = swab16(i2c_smbus_read_word_data(client, reg & 0xff)); |
194 | 199 | ||
195 | dev_dbg(&client->dev, "read reg.%03x -> %04x\n", reg, ret); | 200 | dev_dbg(&client->dev, "read reg.%03x -> %04x\n", reg, ret); |
196 | return ret; | 201 | return ret; |
@@ -203,7 +208,7 @@ static int mt9m111_reg_write(struct i2c_client *client, const u16 reg, | |||
203 | 208 | ||
204 | ret = reg_page_map_set(client, reg); | 209 | ret = reg_page_map_set(client, reg); |
205 | if (!ret) | 210 | if (!ret) |
206 | ret = i2c_smbus_write_word_data(client, (reg & 0xff), | 211 | ret = i2c_smbus_write_word_data(client, reg & 0xff, |
207 | swab16(data)); | 212 | swab16(data)); |
208 | dev_dbg(&client->dev, "write reg.%03x = %04x -> %d\n", reg, data, ret); | 213 | dev_dbg(&client->dev, "write reg.%03x = %04x -> %d\n", reg, data, ret); |
209 | return ret; | 214 | return ret; |
@@ -229,10 +234,9 @@ static int mt9m111_reg_clear(struct i2c_client *client, const u16 reg, | |||
229 | return mt9m111_reg_write(client, reg, ret & ~data); | 234 | return mt9m111_reg_write(client, reg, ret & ~data); |
230 | } | 235 | } |
231 | 236 | ||
232 | static int mt9m111_set_context(struct soc_camera_device *icd, | 237 | static int mt9m111_set_context(struct i2c_client *client, |
233 | enum mt9m111_context ctxt) | 238 | enum mt9m111_context ctxt) |
234 | { | 239 | { |
235 | struct i2c_client *client = to_i2c_client(icd->control); | ||
236 | int valB = MT9M111_CTXT_CTRL_RESTART | MT9M111_CTXT_CTRL_DEFECTCOR_B | 240 | int valB = MT9M111_CTXT_CTRL_RESTART | MT9M111_CTXT_CTRL_DEFECTCOR_B |
237 | | MT9M111_CTXT_CTRL_RESIZE_B | MT9M111_CTXT_CTRL_CTRL2_B | 241 | | MT9M111_CTXT_CTRL_RESIZE_B | MT9M111_CTXT_CTRL_CTRL2_B |
238 | | MT9M111_CTXT_CTRL_GAMMA_B | MT9M111_CTXT_CTRL_READ_MODE_B | 242 | | MT9M111_CTXT_CTRL_GAMMA_B | MT9M111_CTXT_CTRL_READ_MODE_B |
@@ -246,17 +250,16 @@ static int mt9m111_set_context(struct soc_camera_device *icd, | |||
246 | return reg_write(CONTEXT_CONTROL, valA); | 250 | return reg_write(CONTEXT_CONTROL, valA); |
247 | } | 251 | } |
248 | 252 | ||
249 | static int mt9m111_setup_rect(struct soc_camera_device *icd, | 253 | static int mt9m111_setup_rect(struct i2c_client *client, |
250 | struct v4l2_rect *rect) | 254 | struct v4l2_rect *rect) |
251 | { | 255 | { |
252 | struct i2c_client *client = to_i2c_client(icd->control); | 256 | struct mt9m111 *mt9m111 = to_mt9m111(client); |
253 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | ||
254 | int ret, is_raw_format; | 257 | int ret, is_raw_format; |
255 | int width = rect->width; | 258 | int width = rect->width; |
256 | int height = rect->height; | 259 | int height = rect->height; |
257 | 260 | ||
258 | if ((mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR8) | 261 | if (mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR8 || |
259 | || (mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR16)) | 262 | mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR16) |
260 | is_raw_format = 1; | 263 | is_raw_format = 1; |
261 | else | 264 | else |
262 | is_raw_format = 0; | 265 | is_raw_format = 0; |
@@ -292,9 +295,8 @@ static int mt9m111_setup_rect(struct soc_camera_device *icd, | |||
292 | return ret; | 295 | return ret; |
293 | } | 296 | } |
294 | 297 | ||
295 | static int mt9m111_setup_pixfmt(struct soc_camera_device *icd, u16 outfmt) | 298 | static int mt9m111_setup_pixfmt(struct i2c_client *client, u16 outfmt) |
296 | { | 299 | { |
297 | struct i2c_client *client = to_i2c_client(icd->control); | ||
298 | int ret; | 300 | int ret; |
299 | 301 | ||
300 | ret = reg_write(OUTPUT_FORMAT_CTRL2_A, outfmt); | 302 | ret = reg_write(OUTPUT_FORMAT_CTRL2_A, outfmt); |
@@ -303,19 +305,19 @@ static int mt9m111_setup_pixfmt(struct soc_camera_device *icd, u16 outfmt) | |||
303 | return ret; | 305 | return ret; |
304 | } | 306 | } |
305 | 307 | ||
306 | static int mt9m111_setfmt_bayer8(struct soc_camera_device *icd) | 308 | static int mt9m111_setfmt_bayer8(struct i2c_client *client) |
307 | { | 309 | { |
308 | return mt9m111_setup_pixfmt(icd, MT9M111_OUTFMT_PROCESSED_BAYER); | 310 | return mt9m111_setup_pixfmt(client, MT9M111_OUTFMT_PROCESSED_BAYER); |
309 | } | 311 | } |
310 | 312 | ||
311 | static int mt9m111_setfmt_bayer10(struct soc_camera_device *icd) | 313 | static int mt9m111_setfmt_bayer10(struct i2c_client *client) |
312 | { | 314 | { |
313 | return mt9m111_setup_pixfmt(icd, MT9M111_OUTFMT_BYPASS_IFP); | 315 | return mt9m111_setup_pixfmt(client, MT9M111_OUTFMT_BYPASS_IFP); |
314 | } | 316 | } |
315 | 317 | ||
316 | static int mt9m111_setfmt_rgb565(struct soc_camera_device *icd) | 318 | static int mt9m111_setfmt_rgb565(struct i2c_client *client) |
317 | { | 319 | { |
318 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | 320 | struct mt9m111 *mt9m111 = to_mt9m111(client); |
319 | int val = 0; | 321 | int val = 0; |
320 | 322 | ||
321 | if (mt9m111->swap_rgb_red_blue) | 323 | if (mt9m111->swap_rgb_red_blue) |
@@ -324,12 +326,12 @@ static int mt9m111_setfmt_rgb565(struct soc_camera_device *icd) | |||
324 | val |= MT9M111_OUTFMT_SWAP_RGB_EVEN; | 326 | val |= MT9M111_OUTFMT_SWAP_RGB_EVEN; |
325 | val |= MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565; | 327 | val |= MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565; |
326 | 328 | ||
327 | return mt9m111_setup_pixfmt(icd, val); | 329 | return mt9m111_setup_pixfmt(client, val); |
328 | } | 330 | } |
329 | 331 | ||
330 | static int mt9m111_setfmt_rgb555(struct soc_camera_device *icd) | 332 | static int mt9m111_setfmt_rgb555(struct i2c_client *client) |
331 | { | 333 | { |
332 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | 334 | struct mt9m111 *mt9m111 = to_mt9m111(client); |
333 | int val = 0; | 335 | int val = 0; |
334 | 336 | ||
335 | if (mt9m111->swap_rgb_red_blue) | 337 | if (mt9m111->swap_rgb_red_blue) |
@@ -338,12 +340,12 @@ static int mt9m111_setfmt_rgb555(struct soc_camera_device *icd) | |||
338 | val |= MT9M111_OUTFMT_SWAP_RGB_EVEN; | 340 | val |= MT9M111_OUTFMT_SWAP_RGB_EVEN; |
339 | val |= MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB555; | 341 | val |= MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB555; |
340 | 342 | ||
341 | return mt9m111_setup_pixfmt(icd, val); | 343 | return mt9m111_setup_pixfmt(client, val); |
342 | } | 344 | } |
343 | 345 | ||
344 | static int mt9m111_setfmt_yuv(struct soc_camera_device *icd) | 346 | static int mt9m111_setfmt_yuv(struct i2c_client *client) |
345 | { | 347 | { |
346 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | 348 | struct mt9m111 *mt9m111 = to_mt9m111(client); |
347 | int val = 0; | 349 | int val = 0; |
348 | 350 | ||
349 | if (mt9m111->swap_yuv_cb_cr) | 351 | if (mt9m111->swap_yuv_cb_cr) |
@@ -351,52 +353,22 @@ static int mt9m111_setfmt_yuv(struct soc_camera_device *icd) | |||
351 | if (mt9m111->swap_yuv_y_chromas) | 353 | if (mt9m111->swap_yuv_y_chromas) |
352 | val |= MT9M111_OUTFMT_SWAP_YCbCr_C_Y; | 354 | val |= MT9M111_OUTFMT_SWAP_YCbCr_C_Y; |
353 | 355 | ||
354 | return mt9m111_setup_pixfmt(icd, val); | 356 | return mt9m111_setup_pixfmt(client, val); |
355 | } | 357 | } |
356 | 358 | ||
357 | static int mt9m111_enable(struct soc_camera_device *icd) | 359 | static int mt9m111_enable(struct i2c_client *client) |
358 | { | 360 | { |
359 | struct i2c_client *client = to_i2c_client(icd->control); | 361 | struct mt9m111 *mt9m111 = to_mt9m111(client); |
360 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | ||
361 | struct soc_camera_link *icl = client->dev.platform_data; | ||
362 | int ret; | 362 | int ret; |
363 | 363 | ||
364 | if (icl->power) { | ||
365 | ret = icl->power(&client->dev, 1); | ||
366 | if (ret < 0) { | ||
367 | dev_err(icd->vdev->parent, | ||
368 | "Platform failed to power-on the camera.\n"); | ||
369 | return ret; | ||
370 | } | ||
371 | } | ||
372 | |||
373 | ret = reg_set(RESET, MT9M111_RESET_CHIP_ENABLE); | 364 | ret = reg_set(RESET, MT9M111_RESET_CHIP_ENABLE); |
374 | if (!ret) | 365 | if (!ret) |
375 | mt9m111->powered = 1; | 366 | mt9m111->powered = 1; |
376 | return ret; | 367 | return ret; |
377 | } | 368 | } |
378 | 369 | ||
379 | static int mt9m111_disable(struct soc_camera_device *icd) | 370 | static int mt9m111_reset(struct i2c_client *client) |
380 | { | ||
381 | struct i2c_client *client = to_i2c_client(icd->control); | ||
382 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | ||
383 | struct soc_camera_link *icl = client->dev.platform_data; | ||
384 | int ret; | ||
385 | |||
386 | ret = reg_clear(RESET, MT9M111_RESET_CHIP_ENABLE); | ||
387 | if (!ret) | ||
388 | mt9m111->powered = 0; | ||
389 | |||
390 | if (icl->power) | ||
391 | icl->power(&client->dev, 0); | ||
392 | |||
393 | return ret; | ||
394 | } | ||
395 | |||
396 | static int mt9m111_reset(struct soc_camera_device *icd) | ||
397 | { | 371 | { |
398 | struct i2c_client *client = to_i2c_client(icd->control); | ||
399 | struct soc_camera_link *icl = client->dev.platform_data; | ||
400 | int ret; | 372 | int ret; |
401 | 373 | ||
402 | ret = reg_set(RESET, MT9M111_RESET_RESET_MODE); | 374 | ret = reg_set(RESET, MT9M111_RESET_RESET_MODE); |
@@ -406,26 +378,12 @@ static int mt9m111_reset(struct soc_camera_device *icd) | |||
406 | ret = reg_clear(RESET, MT9M111_RESET_RESET_MODE | 378 | ret = reg_clear(RESET, MT9M111_RESET_RESET_MODE |
407 | | MT9M111_RESET_RESET_SOC); | 379 | | MT9M111_RESET_RESET_SOC); |
408 | 380 | ||
409 | if (icl->reset) | ||
410 | icl->reset(&client->dev); | ||
411 | |||
412 | return ret; | 381 | return ret; |
413 | } | 382 | } |
414 | 383 | ||
415 | static int mt9m111_start_capture(struct soc_camera_device *icd) | ||
416 | { | ||
417 | return 0; | ||
418 | } | ||
419 | |||
420 | static int mt9m111_stop_capture(struct soc_camera_device *icd) | ||
421 | { | ||
422 | return 0; | ||
423 | } | ||
424 | |||
425 | static unsigned long mt9m111_query_bus_param(struct soc_camera_device *icd) | 384 | static unsigned long mt9m111_query_bus_param(struct soc_camera_device *icd) |
426 | { | 385 | { |
427 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | 386 | struct soc_camera_link *icl = to_soc_camera_link(icd); |
428 | struct soc_camera_link *icl = mt9m111->client->dev.platform_data; | ||
429 | unsigned long flags = SOCAM_MASTER | SOCAM_PCLK_SAMPLE_RISING | | 387 | unsigned long flags = SOCAM_MASTER | SOCAM_PCLK_SAMPLE_RISING | |
430 | SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH | | 388 | SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH | |
431 | SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8; | 389 | SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8; |
@@ -438,62 +396,126 @@ static int mt9m111_set_bus_param(struct soc_camera_device *icd, unsigned long f) | |||
438 | return 0; | 396 | return 0; |
439 | } | 397 | } |
440 | 398 | ||
441 | static int mt9m111_set_crop(struct soc_camera_device *icd, | 399 | static int mt9m111_make_rect(struct i2c_client *client, |
442 | struct v4l2_rect *rect) | 400 | struct v4l2_rect *rect) |
443 | { | 401 | { |
444 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | 402 | struct mt9m111 *mt9m111 = to_mt9m111(client); |
403 | |||
404 | if (mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR8 || | ||
405 | mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR16) { | ||
406 | /* Bayer format - even size lengths */ | ||
407 | rect->width = ALIGN(rect->width, 2); | ||
408 | rect->height = ALIGN(rect->height, 2); | ||
409 | /* Let the user play with the starting pixel */ | ||
410 | } | ||
411 | |||
412 | /* FIXME: the datasheet doesn't specify minimum sizes */ | ||
413 | soc_camera_limit_side(&rect->left, &rect->width, | ||
414 | MT9M111_MIN_DARK_COLS, 2, MT9M111_MAX_WIDTH); | ||
415 | |||
416 | soc_camera_limit_side(&rect->top, &rect->height, | ||
417 | MT9M111_MIN_DARK_ROWS, 2, MT9M111_MAX_HEIGHT); | ||
418 | |||
419 | return mt9m111_setup_rect(client, rect); | ||
420 | } | ||
421 | |||
422 | static int mt9m111_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | ||
423 | { | ||
424 | struct v4l2_rect rect = a->c; | ||
425 | struct i2c_client *client = sd->priv; | ||
426 | struct mt9m111 *mt9m111 = to_mt9m111(client); | ||
445 | int ret; | 427 | int ret; |
446 | 428 | ||
447 | dev_dbg(&icd->dev, "%s left=%d, top=%d, width=%d, height=%d\n", | 429 | dev_dbg(&client->dev, "%s left=%d, top=%d, width=%d, height=%d\n", |
448 | __func__, rect->left, rect->top, rect->width, | 430 | __func__, rect.left, rect.top, rect.width, rect.height); |
449 | rect->height); | ||
450 | 431 | ||
451 | ret = mt9m111_setup_rect(icd, rect); | 432 | ret = mt9m111_make_rect(client, &rect); |
452 | if (!ret) | 433 | if (!ret) |
453 | mt9m111->rect = *rect; | 434 | mt9m111->rect = rect; |
454 | return ret; | 435 | return ret; |
455 | } | 436 | } |
456 | 437 | ||
457 | static int mt9m111_set_pixfmt(struct soc_camera_device *icd, u32 pixfmt) | 438 | static int mt9m111_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) |
458 | { | 439 | { |
459 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | 440 | struct i2c_client *client = sd->priv; |
441 | struct mt9m111 *mt9m111 = to_mt9m111(client); | ||
442 | |||
443 | a->c = mt9m111->rect; | ||
444 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
445 | |||
446 | return 0; | ||
447 | } | ||
448 | |||
449 | static int mt9m111_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) | ||
450 | { | ||
451 | a->bounds.left = MT9M111_MIN_DARK_COLS; | ||
452 | a->bounds.top = MT9M111_MIN_DARK_ROWS; | ||
453 | a->bounds.width = MT9M111_MAX_WIDTH; | ||
454 | a->bounds.height = MT9M111_MAX_HEIGHT; | ||
455 | a->defrect = a->bounds; | ||
456 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
457 | a->pixelaspect.numerator = 1; | ||
458 | a->pixelaspect.denominator = 1; | ||
459 | |||
460 | return 0; | ||
461 | } | ||
462 | |||
463 | static int mt9m111_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | ||
464 | { | ||
465 | struct i2c_client *client = sd->priv; | ||
466 | struct mt9m111 *mt9m111 = to_mt9m111(client); | ||
467 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
468 | |||
469 | pix->width = mt9m111->rect.width; | ||
470 | pix->height = mt9m111->rect.height; | ||
471 | pix->pixelformat = mt9m111->pixfmt; | ||
472 | pix->field = V4L2_FIELD_NONE; | ||
473 | pix->colorspace = V4L2_COLORSPACE_SRGB; | ||
474 | |||
475 | return 0; | ||
476 | } | ||
477 | |||
478 | static int mt9m111_set_pixfmt(struct i2c_client *client, u32 pixfmt) | ||
479 | { | ||
480 | struct mt9m111 *mt9m111 = to_mt9m111(client); | ||
460 | int ret; | 481 | int ret; |
461 | 482 | ||
462 | switch (pixfmt) { | 483 | switch (pixfmt) { |
463 | case V4L2_PIX_FMT_SBGGR8: | 484 | case V4L2_PIX_FMT_SBGGR8: |
464 | ret = mt9m111_setfmt_bayer8(icd); | 485 | ret = mt9m111_setfmt_bayer8(client); |
465 | break; | 486 | break; |
466 | case V4L2_PIX_FMT_SBGGR16: | 487 | case V4L2_PIX_FMT_SBGGR16: |
467 | ret = mt9m111_setfmt_bayer10(icd); | 488 | ret = mt9m111_setfmt_bayer10(client); |
468 | break; | 489 | break; |
469 | case V4L2_PIX_FMT_RGB555: | 490 | case V4L2_PIX_FMT_RGB555: |
470 | ret = mt9m111_setfmt_rgb555(icd); | 491 | ret = mt9m111_setfmt_rgb555(client); |
471 | break; | 492 | break; |
472 | case V4L2_PIX_FMT_RGB565: | 493 | case V4L2_PIX_FMT_RGB565: |
473 | ret = mt9m111_setfmt_rgb565(icd); | 494 | ret = mt9m111_setfmt_rgb565(client); |
474 | break; | 495 | break; |
475 | case V4L2_PIX_FMT_UYVY: | 496 | case V4L2_PIX_FMT_UYVY: |
476 | mt9m111->swap_yuv_y_chromas = 0; | 497 | mt9m111->swap_yuv_y_chromas = 0; |
477 | mt9m111->swap_yuv_cb_cr = 0; | 498 | mt9m111->swap_yuv_cb_cr = 0; |
478 | ret = mt9m111_setfmt_yuv(icd); | 499 | ret = mt9m111_setfmt_yuv(client); |
479 | break; | 500 | break; |
480 | case V4L2_PIX_FMT_VYUY: | 501 | case V4L2_PIX_FMT_VYUY: |
481 | mt9m111->swap_yuv_y_chromas = 0; | 502 | mt9m111->swap_yuv_y_chromas = 0; |
482 | mt9m111->swap_yuv_cb_cr = 1; | 503 | mt9m111->swap_yuv_cb_cr = 1; |
483 | ret = mt9m111_setfmt_yuv(icd); | 504 | ret = mt9m111_setfmt_yuv(client); |
484 | break; | 505 | break; |
485 | case V4L2_PIX_FMT_YUYV: | 506 | case V4L2_PIX_FMT_YUYV: |
486 | mt9m111->swap_yuv_y_chromas = 1; | 507 | mt9m111->swap_yuv_y_chromas = 1; |
487 | mt9m111->swap_yuv_cb_cr = 0; | 508 | mt9m111->swap_yuv_cb_cr = 0; |
488 | ret = mt9m111_setfmt_yuv(icd); | 509 | ret = mt9m111_setfmt_yuv(client); |
489 | break; | 510 | break; |
490 | case V4L2_PIX_FMT_YVYU: | 511 | case V4L2_PIX_FMT_YVYU: |
491 | mt9m111->swap_yuv_y_chromas = 1; | 512 | mt9m111->swap_yuv_y_chromas = 1; |
492 | mt9m111->swap_yuv_cb_cr = 1; | 513 | mt9m111->swap_yuv_cb_cr = 1; |
493 | ret = mt9m111_setfmt_yuv(icd); | 514 | ret = mt9m111_setfmt_yuv(client); |
494 | break; | 515 | break; |
495 | default: | 516 | default: |
496 | dev_err(&icd->dev, "Pixel format not handled : %x\n", pixfmt); | 517 | dev_err(&client->dev, "Pixel format not handled : %x\n", |
518 | pixfmt); | ||
497 | ret = -EINVAL; | 519 | ret = -EINVAL; |
498 | } | 520 | } |
499 | 521 | ||
@@ -503,10 +525,10 @@ static int mt9m111_set_pixfmt(struct soc_camera_device *icd, u32 pixfmt) | |||
503 | return ret; | 525 | return ret; |
504 | } | 526 | } |
505 | 527 | ||
506 | static int mt9m111_set_fmt(struct soc_camera_device *icd, | 528 | static int mt9m111_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) |
507 | struct v4l2_format *f) | ||
508 | { | 529 | { |
509 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | 530 | struct i2c_client *client = sd->priv; |
531 | struct mt9m111 *mt9m111 = to_mt9m111(client); | ||
510 | struct v4l2_pix_format *pix = &f->fmt.pix; | 532 | struct v4l2_pix_format *pix = &f->fmt.pix; |
511 | struct v4l2_rect rect = { | 533 | struct v4l2_rect rect = { |
512 | .left = mt9m111->rect.left, | 534 | .left = mt9m111->rect.left, |
@@ -516,40 +538,56 @@ static int mt9m111_set_fmt(struct soc_camera_device *icd, | |||
516 | }; | 538 | }; |
517 | int ret; | 539 | int ret; |
518 | 540 | ||
519 | dev_dbg(&icd->dev, "%s fmt=%x left=%d, top=%d, width=%d, height=%d\n", | 541 | dev_dbg(&client->dev, |
520 | __func__, pix->pixelformat, rect.left, rect.top, rect.width, | 542 | "%s fmt=%x left=%d, top=%d, width=%d, height=%d\n", __func__, |
521 | rect.height); | 543 | pix->pixelformat, rect.left, rect.top, rect.width, rect.height); |
522 | 544 | ||
523 | ret = mt9m111_setup_rect(icd, &rect); | 545 | ret = mt9m111_make_rect(client, &rect); |
524 | if (!ret) | 546 | if (!ret) |
525 | ret = mt9m111_set_pixfmt(icd, pix->pixelformat); | 547 | ret = mt9m111_set_pixfmt(client, pix->pixelformat); |
526 | if (!ret) | 548 | if (!ret) |
527 | mt9m111->rect = rect; | 549 | mt9m111->rect = rect; |
528 | return ret; | 550 | return ret; |
529 | } | 551 | } |
530 | 552 | ||
531 | static int mt9m111_try_fmt(struct soc_camera_device *icd, | 553 | static int mt9m111_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) |
532 | struct v4l2_format *f) | ||
533 | { | 554 | { |
534 | struct v4l2_pix_format *pix = &f->fmt.pix; | 555 | struct v4l2_pix_format *pix = &f->fmt.pix; |
556 | bool bayer = pix->pixelformat == V4L2_PIX_FMT_SBGGR8 || | ||
557 | pix->pixelformat == V4L2_PIX_FMT_SBGGR16; | ||
558 | |||
559 | /* | ||
560 | * With Bayer format enforce even side lengths, but let the user play | ||
561 | * with the starting pixel | ||
562 | */ | ||
535 | 563 | ||
536 | if (pix->height > MT9M111_MAX_HEIGHT) | 564 | if (pix->height > MT9M111_MAX_HEIGHT) |
537 | pix->height = MT9M111_MAX_HEIGHT; | 565 | pix->height = MT9M111_MAX_HEIGHT; |
566 | else if (pix->height < 2) | ||
567 | pix->height = 2; | ||
568 | else if (bayer) | ||
569 | pix->height = ALIGN(pix->height, 2); | ||
570 | |||
538 | if (pix->width > MT9M111_MAX_WIDTH) | 571 | if (pix->width > MT9M111_MAX_WIDTH) |
539 | pix->width = MT9M111_MAX_WIDTH; | 572 | pix->width = MT9M111_MAX_WIDTH; |
573 | else if (pix->width < 2) | ||
574 | pix->width = 2; | ||
575 | else if (bayer) | ||
576 | pix->width = ALIGN(pix->width, 2); | ||
540 | 577 | ||
541 | return 0; | 578 | return 0; |
542 | } | 579 | } |
543 | 580 | ||
544 | static int mt9m111_get_chip_id(struct soc_camera_device *icd, | 581 | static int mt9m111_g_chip_ident(struct v4l2_subdev *sd, |
545 | struct v4l2_dbg_chip_ident *id) | 582 | struct v4l2_dbg_chip_ident *id) |
546 | { | 583 | { |
547 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | 584 | struct i2c_client *client = sd->priv; |
585 | struct mt9m111 *mt9m111 = to_mt9m111(client); | ||
548 | 586 | ||
549 | if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR) | 587 | if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR) |
550 | return -EINVAL; | 588 | return -EINVAL; |
551 | 589 | ||
552 | if (id->match.addr != mt9m111->client->addr) | 590 | if (id->match.addr != client->addr) |
553 | return -ENODEV; | 591 | return -ENODEV; |
554 | 592 | ||
555 | id->ident = mt9m111->model; | 593 | id->ident = mt9m111->model; |
@@ -559,11 +597,11 @@ static int mt9m111_get_chip_id(struct soc_camera_device *icd, | |||
559 | } | 597 | } |
560 | 598 | ||
561 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 599 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
562 | static int mt9m111_get_register(struct soc_camera_device *icd, | 600 | static int mt9m111_g_register(struct v4l2_subdev *sd, |
563 | struct v4l2_dbg_register *reg) | 601 | struct v4l2_dbg_register *reg) |
564 | { | 602 | { |
603 | struct i2c_client *client = sd->priv; | ||
565 | int val; | 604 | int val; |
566 | struct i2c_client *client = to_i2c_client(icd->control); | ||
567 | 605 | ||
568 | if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff) | 606 | if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff) |
569 | return -EINVAL; | 607 | return -EINVAL; |
@@ -580,10 +618,10 @@ static int mt9m111_get_register(struct soc_camera_device *icd, | |||
580 | return 0; | 618 | return 0; |
581 | } | 619 | } |
582 | 620 | ||
583 | static int mt9m111_set_register(struct soc_camera_device *icd, | 621 | static int mt9m111_s_register(struct v4l2_subdev *sd, |
584 | struct v4l2_dbg_register *reg) | 622 | struct v4l2_dbg_register *reg) |
585 | { | 623 | { |
586 | struct i2c_client *client = to_i2c_client(icd->control); | 624 | struct i2c_client *client = sd->priv; |
587 | 625 | ||
588 | if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff) | 626 | if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff) |
589 | return -EINVAL; | 627 | return -EINVAL; |
@@ -635,45 +673,21 @@ static const struct v4l2_queryctrl mt9m111_controls[] = { | |||
635 | } | 673 | } |
636 | }; | 674 | }; |
637 | 675 | ||
638 | static int mt9m111_video_probe(struct soc_camera_device *); | ||
639 | static void mt9m111_video_remove(struct soc_camera_device *); | ||
640 | static int mt9m111_get_control(struct soc_camera_device *, | ||
641 | struct v4l2_control *); | ||
642 | static int mt9m111_set_control(struct soc_camera_device *, | ||
643 | struct v4l2_control *); | ||
644 | static int mt9m111_resume(struct soc_camera_device *icd); | 676 | static int mt9m111_resume(struct soc_camera_device *icd); |
645 | static int mt9m111_init(struct soc_camera_device *icd); | 677 | static int mt9m111_suspend(struct soc_camera_device *icd, pm_message_t state); |
646 | static int mt9m111_release(struct soc_camera_device *icd); | ||
647 | 678 | ||
648 | static struct soc_camera_ops mt9m111_ops = { | 679 | static struct soc_camera_ops mt9m111_ops = { |
649 | .owner = THIS_MODULE, | 680 | .suspend = mt9m111_suspend, |
650 | .probe = mt9m111_video_probe, | ||
651 | .remove = mt9m111_video_remove, | ||
652 | .init = mt9m111_init, | ||
653 | .resume = mt9m111_resume, | 681 | .resume = mt9m111_resume, |
654 | .release = mt9m111_release, | ||
655 | .start_capture = mt9m111_start_capture, | ||
656 | .stop_capture = mt9m111_stop_capture, | ||
657 | .set_crop = mt9m111_set_crop, | ||
658 | .set_fmt = mt9m111_set_fmt, | ||
659 | .try_fmt = mt9m111_try_fmt, | ||
660 | .query_bus_param = mt9m111_query_bus_param, | 682 | .query_bus_param = mt9m111_query_bus_param, |
661 | .set_bus_param = mt9m111_set_bus_param, | 683 | .set_bus_param = mt9m111_set_bus_param, |
662 | .controls = mt9m111_controls, | 684 | .controls = mt9m111_controls, |
663 | .num_controls = ARRAY_SIZE(mt9m111_controls), | 685 | .num_controls = ARRAY_SIZE(mt9m111_controls), |
664 | .get_control = mt9m111_get_control, | ||
665 | .set_control = mt9m111_set_control, | ||
666 | .get_chip_id = mt9m111_get_chip_id, | ||
667 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
668 | .get_register = mt9m111_get_register, | ||
669 | .set_register = mt9m111_set_register, | ||
670 | #endif | ||
671 | }; | 686 | }; |
672 | 687 | ||
673 | static int mt9m111_set_flip(struct soc_camera_device *icd, int flip, int mask) | 688 | static int mt9m111_set_flip(struct i2c_client *client, int flip, int mask) |
674 | { | 689 | { |
675 | struct i2c_client *client = to_i2c_client(icd->control); | 690 | struct mt9m111 *mt9m111 = to_mt9m111(client); |
676 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | ||
677 | int ret; | 691 | int ret; |
678 | 692 | ||
679 | if (mt9m111->context == HIGHPOWER) { | 693 | if (mt9m111->context == HIGHPOWER) { |
@@ -691,9 +705,8 @@ static int mt9m111_set_flip(struct soc_camera_device *icd, int flip, int mask) | |||
691 | return ret; | 705 | return ret; |
692 | } | 706 | } |
693 | 707 | ||
694 | static int mt9m111_get_global_gain(struct soc_camera_device *icd) | 708 | static int mt9m111_get_global_gain(struct i2c_client *client) |
695 | { | 709 | { |
696 | struct i2c_client *client = to_i2c_client(icd->control); | ||
697 | int data; | 710 | int data; |
698 | 711 | ||
699 | data = reg_read(GLOBAL_GAIN); | 712 | data = reg_read(GLOBAL_GAIN); |
@@ -703,15 +716,15 @@ static int mt9m111_get_global_gain(struct soc_camera_device *icd) | |||
703 | return data; | 716 | return data; |
704 | } | 717 | } |
705 | 718 | ||
706 | static int mt9m111_set_global_gain(struct soc_camera_device *icd, int gain) | 719 | static int mt9m111_set_global_gain(struct i2c_client *client, int gain) |
707 | { | 720 | { |
708 | struct i2c_client *client = to_i2c_client(icd->control); | 721 | struct mt9m111 *mt9m111 = to_mt9m111(client); |
709 | u16 val; | 722 | u16 val; |
710 | 723 | ||
711 | if (gain > 63 * 2 * 2) | 724 | if (gain > 63 * 2 * 2) |
712 | return -EINVAL; | 725 | return -EINVAL; |
713 | 726 | ||
714 | icd->gain = gain; | 727 | mt9m111->gain = gain; |
715 | if ((gain >= 64 * 2) && (gain < 63 * 2 * 2)) | 728 | if ((gain >= 64 * 2) && (gain < 63 * 2 * 2)) |
716 | val = (1 << 10) | (1 << 9) | (gain / 4); | 729 | val = (1 << 10) | (1 << 9) | (gain / 4); |
717 | else if ((gain >= 64) && (gain < 64 * 2)) | 730 | else if ((gain >= 64) && (gain < 64 * 2)) |
@@ -722,10 +735,9 @@ static int mt9m111_set_global_gain(struct soc_camera_device *icd, int gain) | |||
722 | return reg_write(GLOBAL_GAIN, val); | 735 | return reg_write(GLOBAL_GAIN, val); |
723 | } | 736 | } |
724 | 737 | ||
725 | static int mt9m111_set_autoexposure(struct soc_camera_device *icd, int on) | 738 | static int mt9m111_set_autoexposure(struct i2c_client *client, int on) |
726 | { | 739 | { |
727 | struct i2c_client *client = to_i2c_client(icd->control); | 740 | struct mt9m111 *mt9m111 = to_mt9m111(client); |
728 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | ||
729 | int ret; | 741 | int ret; |
730 | 742 | ||
731 | if (on) | 743 | if (on) |
@@ -739,10 +751,9 @@ static int mt9m111_set_autoexposure(struct soc_camera_device *icd, int on) | |||
739 | return ret; | 751 | return ret; |
740 | } | 752 | } |
741 | 753 | ||
742 | static int mt9m111_set_autowhitebalance(struct soc_camera_device *icd, int on) | 754 | static int mt9m111_set_autowhitebalance(struct i2c_client *client, int on) |
743 | { | 755 | { |
744 | struct i2c_client *client = to_i2c_client(icd->control); | 756 | struct mt9m111 *mt9m111 = to_mt9m111(client); |
745 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | ||
746 | int ret; | 757 | int ret; |
747 | 758 | ||
748 | if (on) | 759 | if (on) |
@@ -756,11 +767,10 @@ static int mt9m111_set_autowhitebalance(struct soc_camera_device *icd, int on) | |||
756 | return ret; | 767 | return ret; |
757 | } | 768 | } |
758 | 769 | ||
759 | static int mt9m111_get_control(struct soc_camera_device *icd, | 770 | static int mt9m111_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) |
760 | struct v4l2_control *ctrl) | ||
761 | { | 771 | { |
762 | struct i2c_client *client = to_i2c_client(icd->control); | 772 | struct i2c_client *client = sd->priv; |
763 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | 773 | struct mt9m111 *mt9m111 = to_mt9m111(client); |
764 | int data; | 774 | int data; |
765 | 775 | ||
766 | switch (ctrl->id) { | 776 | switch (ctrl->id) { |
@@ -785,7 +795,7 @@ static int mt9m111_get_control(struct soc_camera_device *icd, | |||
785 | ctrl->value = !!(data & MT9M111_RMB_MIRROR_COLS); | 795 | ctrl->value = !!(data & MT9M111_RMB_MIRROR_COLS); |
786 | break; | 796 | break; |
787 | case V4L2_CID_GAIN: | 797 | case V4L2_CID_GAIN: |
788 | data = mt9m111_get_global_gain(icd); | 798 | data = mt9m111_get_global_gain(client); |
789 | if (data < 0) | 799 | if (data < 0) |
790 | return data; | 800 | return data; |
791 | ctrl->value = data; | 801 | ctrl->value = data; |
@@ -800,37 +810,36 @@ static int mt9m111_get_control(struct soc_camera_device *icd, | |||
800 | return 0; | 810 | return 0; |
801 | } | 811 | } |
802 | 812 | ||
803 | static int mt9m111_set_control(struct soc_camera_device *icd, | 813 | static int mt9m111_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) |
804 | struct v4l2_control *ctrl) | ||
805 | { | 814 | { |
806 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | 815 | struct i2c_client *client = sd->priv; |
816 | struct mt9m111 *mt9m111 = to_mt9m111(client); | ||
807 | const struct v4l2_queryctrl *qctrl; | 817 | const struct v4l2_queryctrl *qctrl; |
808 | int ret; | 818 | int ret; |
809 | 819 | ||
810 | qctrl = soc_camera_find_qctrl(&mt9m111_ops, ctrl->id); | 820 | qctrl = soc_camera_find_qctrl(&mt9m111_ops, ctrl->id); |
811 | |||
812 | if (!qctrl) | 821 | if (!qctrl) |
813 | return -EINVAL; | 822 | return -EINVAL; |
814 | 823 | ||
815 | switch (ctrl->id) { | 824 | switch (ctrl->id) { |
816 | case V4L2_CID_VFLIP: | 825 | case V4L2_CID_VFLIP: |
817 | mt9m111->vflip = ctrl->value; | 826 | mt9m111->vflip = ctrl->value; |
818 | ret = mt9m111_set_flip(icd, ctrl->value, | 827 | ret = mt9m111_set_flip(client, ctrl->value, |
819 | MT9M111_RMB_MIRROR_ROWS); | 828 | MT9M111_RMB_MIRROR_ROWS); |
820 | break; | 829 | break; |
821 | case V4L2_CID_HFLIP: | 830 | case V4L2_CID_HFLIP: |
822 | mt9m111->hflip = ctrl->value; | 831 | mt9m111->hflip = ctrl->value; |
823 | ret = mt9m111_set_flip(icd, ctrl->value, | 832 | ret = mt9m111_set_flip(client, ctrl->value, |
824 | MT9M111_RMB_MIRROR_COLS); | 833 | MT9M111_RMB_MIRROR_COLS); |
825 | break; | 834 | break; |
826 | case V4L2_CID_GAIN: | 835 | case V4L2_CID_GAIN: |
827 | ret = mt9m111_set_global_gain(icd, ctrl->value); | 836 | ret = mt9m111_set_global_gain(client, ctrl->value); |
828 | break; | 837 | break; |
829 | case V4L2_CID_EXPOSURE_AUTO: | 838 | case V4L2_CID_EXPOSURE_AUTO: |
830 | ret = mt9m111_set_autoexposure(icd, ctrl->value); | 839 | ret = mt9m111_set_autoexposure(client, ctrl->value); |
831 | break; | 840 | break; |
832 | case V4L2_CID_AUTO_WHITE_BALANCE: | 841 | case V4L2_CID_AUTO_WHITE_BALANCE: |
833 | ret = mt9m111_set_autowhitebalance(icd, ctrl->value); | 842 | ret = mt9m111_set_autowhitebalance(client, ctrl->value); |
834 | break; | 843 | break; |
835 | default: | 844 | default: |
836 | ret = -EINVAL; | 845 | ret = -EINVAL; |
@@ -839,62 +848,62 @@ static int mt9m111_set_control(struct soc_camera_device *icd, | |||
839 | return ret; | 848 | return ret; |
840 | } | 849 | } |
841 | 850 | ||
842 | static int mt9m111_restore_state(struct soc_camera_device *icd) | 851 | static int mt9m111_suspend(struct soc_camera_device *icd, pm_message_t state) |
843 | { | 852 | { |
844 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | 853 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); |
845 | 854 | struct mt9m111 *mt9m111 = to_mt9m111(client); | |
846 | mt9m111_set_context(icd, mt9m111->context); | 855 | |
847 | mt9m111_set_pixfmt(icd, mt9m111->pixfmt); | 856 | mt9m111->gain = mt9m111_get_global_gain(client); |
848 | mt9m111_setup_rect(icd, &mt9m111->rect); | 857 | |
849 | mt9m111_set_flip(icd, mt9m111->hflip, MT9M111_RMB_MIRROR_COLS); | 858 | return 0; |
850 | mt9m111_set_flip(icd, mt9m111->vflip, MT9M111_RMB_MIRROR_ROWS); | 859 | } |
851 | mt9m111_set_global_gain(icd, icd->gain); | 860 | |
852 | mt9m111_set_autoexposure(icd, mt9m111->autoexposure); | 861 | static int mt9m111_restore_state(struct i2c_client *client) |
853 | mt9m111_set_autowhitebalance(icd, mt9m111->autowhitebalance); | 862 | { |
863 | struct mt9m111 *mt9m111 = to_mt9m111(client); | ||
864 | |||
865 | mt9m111_set_context(client, mt9m111->context); | ||
866 | mt9m111_set_pixfmt(client, mt9m111->pixfmt); | ||
867 | mt9m111_setup_rect(client, &mt9m111->rect); | ||
868 | mt9m111_set_flip(client, mt9m111->hflip, MT9M111_RMB_MIRROR_COLS); | ||
869 | mt9m111_set_flip(client, mt9m111->vflip, MT9M111_RMB_MIRROR_ROWS); | ||
870 | mt9m111_set_global_gain(client, mt9m111->gain); | ||
871 | mt9m111_set_autoexposure(client, mt9m111->autoexposure); | ||
872 | mt9m111_set_autowhitebalance(client, mt9m111->autowhitebalance); | ||
854 | return 0; | 873 | return 0; |
855 | } | 874 | } |
856 | 875 | ||
857 | static int mt9m111_resume(struct soc_camera_device *icd) | 876 | static int mt9m111_resume(struct soc_camera_device *icd) |
858 | { | 877 | { |
859 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | 878 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); |
879 | struct mt9m111 *mt9m111 = to_mt9m111(client); | ||
860 | int ret = 0; | 880 | int ret = 0; |
861 | 881 | ||
862 | if (mt9m111->powered) { | 882 | if (mt9m111->powered) { |
863 | ret = mt9m111_enable(icd); | 883 | ret = mt9m111_enable(client); |
864 | if (!ret) | 884 | if (!ret) |
865 | ret = mt9m111_reset(icd); | 885 | ret = mt9m111_reset(client); |
866 | if (!ret) | 886 | if (!ret) |
867 | ret = mt9m111_restore_state(icd); | 887 | ret = mt9m111_restore_state(client); |
868 | } | 888 | } |
869 | return ret; | 889 | return ret; |
870 | } | 890 | } |
871 | 891 | ||
872 | static int mt9m111_init(struct soc_camera_device *icd) | 892 | static int mt9m111_init(struct i2c_client *client) |
873 | { | 893 | { |
874 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | 894 | struct mt9m111 *mt9m111 = to_mt9m111(client); |
875 | int ret; | 895 | int ret; |
876 | 896 | ||
877 | mt9m111->context = HIGHPOWER; | 897 | mt9m111->context = HIGHPOWER; |
878 | ret = mt9m111_enable(icd); | 898 | ret = mt9m111_enable(client); |
879 | if (!ret) | 899 | if (!ret) |
880 | ret = mt9m111_reset(icd); | 900 | ret = mt9m111_reset(client); |
881 | if (!ret) | 901 | if (!ret) |
882 | ret = mt9m111_set_context(icd, mt9m111->context); | 902 | ret = mt9m111_set_context(client, mt9m111->context); |
883 | if (!ret) | 903 | if (!ret) |
884 | ret = mt9m111_set_autoexposure(icd, mt9m111->autoexposure); | 904 | ret = mt9m111_set_autoexposure(client, mt9m111->autoexposure); |
885 | if (ret) | 905 | if (ret) |
886 | dev_err(&icd->dev, "mt9m11x init failed: %d\n", ret); | 906 | dev_err(&client->dev, "mt9m11x init failed: %d\n", ret); |
887 | return ret; | ||
888 | } | ||
889 | |||
890 | static int mt9m111_release(struct soc_camera_device *icd) | ||
891 | { | ||
892 | int ret; | ||
893 | |||
894 | ret = mt9m111_disable(icd); | ||
895 | if (ret < 0) | ||
896 | dev_err(&icd->dev, "mt9m11x release failed: %d\n", ret); | ||
897 | |||
898 | return ret; | 907 | return ret; |
899 | } | 908 | } |
900 | 909 | ||
@@ -902,10 +911,10 @@ static int mt9m111_release(struct soc_camera_device *icd) | |||
902 | * Interface active, can use i2c. If it fails, it can indeed mean, that | 911 | * Interface active, can use i2c. If it fails, it can indeed mean, that |
903 | * this wasn't our capture interface, so, we wait for the right one | 912 | * this wasn't our capture interface, so, we wait for the right one |
904 | */ | 913 | */ |
905 | static int mt9m111_video_probe(struct soc_camera_device *icd) | 914 | static int mt9m111_video_probe(struct soc_camera_device *icd, |
915 | struct i2c_client *client) | ||
906 | { | 916 | { |
907 | struct i2c_client *client = to_i2c_client(icd->control); | 917 | struct mt9m111 *mt9m111 = to_mt9m111(client); |
908 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | ||
909 | s32 data; | 918 | s32 data; |
910 | int ret; | 919 | int ret; |
911 | 920 | ||
@@ -917,10 +926,13 @@ static int mt9m111_video_probe(struct soc_camera_device *icd) | |||
917 | to_soc_camera_host(icd->dev.parent)->nr != icd->iface) | 926 | to_soc_camera_host(icd->dev.parent)->nr != icd->iface) |
918 | return -ENODEV; | 927 | return -ENODEV; |
919 | 928 | ||
920 | ret = mt9m111_enable(icd); | 929 | mt9m111->autoexposure = 1; |
921 | if (ret) | 930 | mt9m111->autowhitebalance = 1; |
922 | goto ei2c; | 931 | |
923 | ret = mt9m111_reset(icd); | 932 | mt9m111->swap_rgb_even_odd = 1; |
933 | mt9m111->swap_rgb_red_blue = 1; | ||
934 | |||
935 | ret = mt9m111_init(client); | ||
924 | if (ret) | 936 | if (ret) |
925 | goto ei2c; | 937 | goto ei2c; |
926 | 938 | ||
@@ -935,7 +947,7 @@ static int mt9m111_video_probe(struct soc_camera_device *icd) | |||
935 | break; | 947 | break; |
936 | default: | 948 | default: |
937 | ret = -ENODEV; | 949 | ret = -ENODEV; |
938 | dev_err(&icd->dev, | 950 | dev_err(&client->dev, |
939 | "No MT9M11x chip detected, register read %x\n", data); | 951 | "No MT9M11x chip detected, register read %x\n", data); |
940 | goto ei2c; | 952 | goto ei2c; |
941 | } | 953 | } |
@@ -943,42 +955,51 @@ static int mt9m111_video_probe(struct soc_camera_device *icd) | |||
943 | icd->formats = mt9m111_colour_formats; | 955 | icd->formats = mt9m111_colour_formats; |
944 | icd->num_formats = ARRAY_SIZE(mt9m111_colour_formats); | 956 | icd->num_formats = ARRAY_SIZE(mt9m111_colour_formats); |
945 | 957 | ||
946 | dev_info(&icd->dev, "Detected a MT9M11x chip ID %x\n", data); | 958 | dev_info(&client->dev, "Detected a MT9M11x chip ID %x\n", data); |
947 | 959 | ||
948 | ret = soc_camera_video_start(icd); | ||
949 | if (ret) | ||
950 | goto eisis; | ||
951 | |||
952 | mt9m111->autoexposure = 1; | ||
953 | mt9m111->autowhitebalance = 1; | ||
954 | |||
955 | mt9m111->swap_rgb_even_odd = 1; | ||
956 | mt9m111->swap_rgb_red_blue = 1; | ||
957 | |||
958 | return 0; | ||
959 | eisis: | ||
960 | ei2c: | 960 | ei2c: |
961 | return ret; | 961 | return ret; |
962 | } | 962 | } |
963 | 963 | ||
964 | static void mt9m111_video_remove(struct soc_camera_device *icd) | 964 | static struct v4l2_subdev_core_ops mt9m111_subdev_core_ops = { |
965 | { | 965 | .g_ctrl = mt9m111_g_ctrl, |
966 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | 966 | .s_ctrl = mt9m111_s_ctrl, |
967 | .g_chip_ident = mt9m111_g_chip_ident, | ||
968 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
969 | .g_register = mt9m111_g_register, | ||
970 | .s_register = mt9m111_s_register, | ||
971 | #endif | ||
972 | }; | ||
967 | 973 | ||
968 | dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9m111->client->addr, | 974 | static struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = { |
969 | mt9m111->icd.dev.parent, mt9m111->icd.vdev); | 975 | .s_fmt = mt9m111_s_fmt, |
970 | soc_camera_video_stop(&mt9m111->icd); | 976 | .g_fmt = mt9m111_g_fmt, |
971 | } | 977 | .try_fmt = mt9m111_try_fmt, |
978 | .s_crop = mt9m111_s_crop, | ||
979 | .g_crop = mt9m111_g_crop, | ||
980 | .cropcap = mt9m111_cropcap, | ||
981 | }; | ||
982 | |||
983 | static struct v4l2_subdev_ops mt9m111_subdev_ops = { | ||
984 | .core = &mt9m111_subdev_core_ops, | ||
985 | .video = &mt9m111_subdev_video_ops, | ||
986 | }; | ||
972 | 987 | ||
973 | static int mt9m111_probe(struct i2c_client *client, | 988 | static int mt9m111_probe(struct i2c_client *client, |
974 | const struct i2c_device_id *did) | 989 | const struct i2c_device_id *did) |
975 | { | 990 | { |
976 | struct mt9m111 *mt9m111; | 991 | struct mt9m111 *mt9m111; |
977 | struct soc_camera_device *icd; | 992 | struct soc_camera_device *icd = client->dev.platform_data; |
978 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 993 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); |
979 | struct soc_camera_link *icl = client->dev.platform_data; | 994 | struct soc_camera_link *icl; |
980 | int ret; | 995 | int ret; |
981 | 996 | ||
997 | if (!icd) { | ||
998 | dev_err(&client->dev, "MT9M11x: missing soc-camera data!\n"); | ||
999 | return -EINVAL; | ||
1000 | } | ||
1001 | |||
1002 | icl = to_soc_camera_link(icd); | ||
982 | if (!icl) { | 1003 | if (!icl) { |
983 | dev_err(&client->dev, "MT9M11x driver needs platform data\n"); | 1004 | dev_err(&client->dev, "MT9M11x driver needs platform data\n"); |
984 | return -EINVAL; | 1005 | return -EINVAL; |
@@ -994,38 +1015,35 @@ static int mt9m111_probe(struct i2c_client *client, | |||
994 | if (!mt9m111) | 1015 | if (!mt9m111) |
995 | return -ENOMEM; | 1016 | return -ENOMEM; |
996 | 1017 | ||
997 | mt9m111->client = client; | 1018 | v4l2_i2c_subdev_init(&mt9m111->subdev, client, &mt9m111_subdev_ops); |
998 | i2c_set_clientdata(client, mt9m111); | ||
999 | 1019 | ||
1000 | /* Second stage probe - when a capture adapter is there */ | 1020 | /* Second stage probe - when a capture adapter is there */ |
1001 | icd = &mt9m111->icd; | 1021 | icd->ops = &mt9m111_ops; |
1002 | icd->ops = &mt9m111_ops; | 1022 | icd->y_skip_top = 0; |
1003 | icd->control = &client->dev; | 1023 | |
1004 | icd->x_min = MT9M111_MIN_DARK_COLS; | 1024 | mt9m111->rect.left = MT9M111_MIN_DARK_COLS; |
1005 | icd->y_min = MT9M111_MIN_DARK_ROWS; | 1025 | mt9m111->rect.top = MT9M111_MIN_DARK_ROWS; |
1006 | icd->x_current = icd->x_min; | 1026 | mt9m111->rect.width = MT9M111_MAX_WIDTH; |
1007 | icd->y_current = icd->y_min; | 1027 | mt9m111->rect.height = MT9M111_MAX_HEIGHT; |
1008 | icd->width_min = MT9M111_MIN_DARK_ROWS; | 1028 | |
1009 | icd->width_max = MT9M111_MAX_WIDTH; | 1029 | ret = mt9m111_video_probe(icd, client); |
1010 | icd->height_min = MT9M111_MIN_DARK_COLS; | 1030 | if (ret) { |
1011 | icd->height_max = MT9M111_MAX_HEIGHT; | 1031 | icd->ops = NULL; |
1012 | icd->y_skip_top = 0; | 1032 | i2c_set_clientdata(client, NULL); |
1013 | icd->iface = icl->bus_id; | 1033 | kfree(mt9m111); |
1014 | 1034 | } | |
1015 | ret = soc_camera_device_register(icd); | ||
1016 | if (ret) | ||
1017 | goto eisdr; | ||
1018 | return 0; | ||
1019 | 1035 | ||
1020 | eisdr: | ||
1021 | kfree(mt9m111); | ||
1022 | return ret; | 1036 | return ret; |
1023 | } | 1037 | } |
1024 | 1038 | ||
1025 | static int mt9m111_remove(struct i2c_client *client) | 1039 | static int mt9m111_remove(struct i2c_client *client) |
1026 | { | 1040 | { |
1027 | struct mt9m111 *mt9m111 = i2c_get_clientdata(client); | 1041 | struct mt9m111 *mt9m111 = to_mt9m111(client); |
1028 | soc_camera_device_unregister(&mt9m111->icd); | 1042 | struct soc_camera_device *icd = client->dev.platform_data; |
1043 | |||
1044 | icd->ops = NULL; | ||
1045 | i2c_set_clientdata(client, NULL); | ||
1046 | client->driver = NULL; | ||
1029 | kfree(mt9m111); | 1047 | kfree(mt9m111); |
1030 | 1048 | ||
1031 | return 0; | 1049 | return 0; |