diff options
author | Guennadi Liakhovetski <g.liakhovetski@gmx.de> | 2013-08-28 09:28:28 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <m.chehab@samsung.com> | 2013-10-31 02:36:48 -0400 |
commit | fc5d0f8a8878319f6cb87045fd704360b2bb4e52 (patch) | |
tree | e0dbd0795a100088ad47f4df0f0c335e484f112a | |
parent | 774cc4c289152bfb77806ccae722a9ae2d29dd02 (diff) |
[media] V4L2: em28xx: register a V4L2 clock source
Camera sensors usually require a master clock for data sampling. This patch
registers such a clock source for em28xx cameras. This fixes the currently
broken em28xx ov2640 camera support and can also be used by other camera
sensors.
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
-rw-r--r-- | drivers/media/usb/em28xx/em28xx-camera.c | 41 | ||||
-rw-r--r-- | drivers/media/usb/em28xx/em28xx-cards.c | 3 | ||||
-rw-r--r-- | drivers/media/usb/em28xx/em28xx.h | 1 |
3 files changed, 35 insertions, 10 deletions
diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c index 73cc50afa5e1..2f451e40edaf 100644 --- a/drivers/media/usb/em28xx/em28xx-camera.c +++ b/drivers/media/usb/em28xx/em28xx-camera.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/i2c.h> | 22 | #include <linux/i2c.h> |
23 | #include <media/soc_camera.h> | 23 | #include <media/soc_camera.h> |
24 | #include <media/mt9v011.h> | 24 | #include <media/mt9v011.h> |
25 | #include <media/v4l2-clk.h> | ||
25 | #include <media/v4l2-common.h> | 26 | #include <media/v4l2-common.h> |
26 | 27 | ||
27 | #include "em28xx.h" | 28 | #include "em28xx.h" |
@@ -325,13 +326,24 @@ int em28xx_detect_sensor(struct em28xx *dev) | |||
325 | 326 | ||
326 | int em28xx_init_camera(struct em28xx *dev) | 327 | int em28xx_init_camera(struct em28xx *dev) |
327 | { | 328 | { |
329 | char clk_name[V4L2_SUBDEV_NAME_SIZE]; | ||
330 | struct i2c_client *client = &dev->i2c_client[dev->def_i2c_bus]; | ||
331 | struct i2c_adapter *adap = &dev->i2c_adap[dev->def_i2c_bus]; | ||
332 | int ret = 0; | ||
333 | |||
334 | v4l2_clk_name_i2c(clk_name, sizeof(clk_name), | ||
335 | i2c_adapter_id(adap), client->addr); | ||
336 | dev->clk = v4l2_clk_register_fixed(clk_name, "mclk", -EINVAL); | ||
337 | if (IS_ERR(dev->clk)) | ||
338 | return PTR_ERR(dev->clk); | ||
339 | |||
328 | switch (dev->em28xx_sensor) { | 340 | switch (dev->em28xx_sensor) { |
329 | case EM28XX_MT9V011: | 341 | case EM28XX_MT9V011: |
330 | { | 342 | { |
331 | struct mt9v011_platform_data pdata; | 343 | struct mt9v011_platform_data pdata; |
332 | struct i2c_board_info mt9v011_info = { | 344 | struct i2c_board_info mt9v011_info = { |
333 | .type = "mt9v011", | 345 | .type = "mt9v011", |
334 | .addr = dev->i2c_client[dev->def_i2c_bus].addr, | 346 | .addr = client->addr, |
335 | .platform_data = &pdata, | 347 | .platform_data = &pdata, |
336 | }; | 348 | }; |
337 | 349 | ||
@@ -352,10 +364,11 @@ int em28xx_init_camera(struct em28xx *dev) | |||
352 | dev->sensor_xtal = 4300000; | 364 | dev->sensor_xtal = 4300000; |
353 | pdata.xtal = dev->sensor_xtal; | 365 | pdata.xtal = dev->sensor_xtal; |
354 | if (NULL == | 366 | if (NULL == |
355 | v4l2_i2c_new_subdev_board(&dev->v4l2_dev, | 367 | v4l2_i2c_new_subdev_board(&dev->v4l2_dev, adap, |
356 | &dev->i2c_adap[dev->def_i2c_bus], | 368 | &mt9v011_info, NULL)) { |
357 | &mt9v011_info, NULL)) | 369 | ret = -ENODEV; |
358 | return -ENODEV; | 370 | break; |
371 | } | ||
359 | /* probably means GRGB 16 bit bayer */ | 372 | /* probably means GRGB 16 bit bayer */ |
360 | dev->vinmode = 0x0d; | 373 | dev->vinmode = 0x0d; |
361 | dev->vinctl = 0x00; | 374 | dev->vinctl = 0x00; |
@@ -391,7 +404,7 @@ int em28xx_init_camera(struct em28xx *dev) | |||
391 | struct i2c_board_info ov2640_info = { | 404 | struct i2c_board_info ov2640_info = { |
392 | .type = "ov2640", | 405 | .type = "ov2640", |
393 | .flags = I2C_CLIENT_SCCB, | 406 | .flags = I2C_CLIENT_SCCB, |
394 | .addr = dev->i2c_client[dev->def_i2c_bus].addr, | 407 | .addr = client->addr, |
395 | .platform_data = &camlink, | 408 | .platform_data = &camlink, |
396 | }; | 409 | }; |
397 | struct v4l2_mbus_framefmt fmt; | 410 | struct v4l2_mbus_framefmt fmt; |
@@ -408,9 +421,12 @@ int em28xx_init_camera(struct em28xx *dev) | |||
408 | dev->sensor_yres = 480; | 421 | dev->sensor_yres = 480; |
409 | 422 | ||
410 | subdev = | 423 | subdev = |
411 | v4l2_i2c_new_subdev_board(&dev->v4l2_dev, | 424 | v4l2_i2c_new_subdev_board(&dev->v4l2_dev, adap, |
412 | &dev->i2c_adap[dev->def_i2c_bus], | ||
413 | &ov2640_info, NULL); | 425 | &ov2640_info, NULL); |
426 | if (NULL == subdev) { | ||
427 | ret = -ENODEV; | ||
428 | break; | ||
429 | } | ||
414 | 430 | ||
415 | fmt.code = V4L2_MBUS_FMT_YUYV8_2X8; | 431 | fmt.code = V4L2_MBUS_FMT_YUYV8_2X8; |
416 | fmt.width = 640; | 432 | fmt.width = 640; |
@@ -427,8 +443,13 @@ int em28xx_init_camera(struct em28xx *dev) | |||
427 | } | 443 | } |
428 | case EM28XX_NOSENSOR: | 444 | case EM28XX_NOSENSOR: |
429 | default: | 445 | default: |
430 | return -EINVAL; | 446 | ret = -EINVAL; |
431 | } | 447 | } |
432 | 448 | ||
433 | return 0; | 449 | if (ret < 0) { |
450 | v4l2_clk_unregister_fixed(dev->clk); | ||
451 | dev->clk = NULL; | ||
452 | } | ||
453 | |||
454 | return ret; | ||
434 | } | 455 | } |
diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 3765670f742a..464cec060fa4 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include <media/tvaudio.h> | 36 | #include <media/tvaudio.h> |
37 | #include <media/i2c-addr.h> | 37 | #include <media/i2c-addr.h> |
38 | #include <media/tveeprom.h> | 38 | #include <media/tveeprom.h> |
39 | #include <media/v4l2-clk.h> | ||
39 | #include <media/v4l2-common.h> | 40 | #include <media/v4l2-common.h> |
40 | 41 | ||
41 | #include "em28xx.h" | 42 | #include "em28xx.h" |
@@ -2857,6 +2858,8 @@ void em28xx_release_resources(struct em28xx *dev) | |||
2857 | if (dev->def_i2c_bus) | 2858 | if (dev->def_i2c_bus) |
2858 | em28xx_i2c_unregister(dev, 1); | 2859 | em28xx_i2c_unregister(dev, 1); |
2859 | em28xx_i2c_unregister(dev, 0); | 2860 | em28xx_i2c_unregister(dev, 0); |
2861 | if (dev->clk) | ||
2862 | v4l2_clk_unregister_fixed(dev->clk); | ||
2860 | 2863 | ||
2861 | v4l2_ctrl_handler_free(&dev->ctrl_handler); | 2864 | v4l2_ctrl_handler_free(&dev->ctrl_handler); |
2862 | 2865 | ||
diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index 205e9038b1c0..c9ebe19d064c 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h | |||
@@ -492,6 +492,7 @@ struct em28xx { | |||
492 | 492 | ||
493 | struct v4l2_device v4l2_dev; | 493 | struct v4l2_device v4l2_dev; |
494 | struct v4l2_ctrl_handler ctrl_handler; | 494 | struct v4l2_ctrl_handler ctrl_handler; |
495 | struct v4l2_clk *clk; | ||
495 | struct em28xx_board board; | 496 | struct em28xx_board board; |
496 | 497 | ||
497 | /* Webcam specific fields */ | 498 | /* Webcam specific fields */ |