mirror of https://gitee.com/openkylin/linux.git
[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>
This commit is contained in:
parent
774cc4c289
commit
fc5d0f8a88
|
@ -22,6 +22,7 @@
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <media/soc_camera.h>
|
#include <media/soc_camera.h>
|
||||||
#include <media/mt9v011.h>
|
#include <media/mt9v011.h>
|
||||||
|
#include <media/v4l2-clk.h>
|
||||||
#include <media/v4l2-common.h>
|
#include <media/v4l2-common.h>
|
||||||
|
|
||||||
#include "em28xx.h"
|
#include "em28xx.h"
|
||||||
|
@ -325,13 +326,24 @@ int em28xx_detect_sensor(struct em28xx *dev)
|
||||||
|
|
||||||
int em28xx_init_camera(struct em28xx *dev)
|
int em28xx_init_camera(struct em28xx *dev)
|
||||||
{
|
{
|
||||||
|
char clk_name[V4L2_SUBDEV_NAME_SIZE];
|
||||||
|
struct i2c_client *client = &dev->i2c_client[dev->def_i2c_bus];
|
||||||
|
struct i2c_adapter *adap = &dev->i2c_adap[dev->def_i2c_bus];
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
v4l2_clk_name_i2c(clk_name, sizeof(clk_name),
|
||||||
|
i2c_adapter_id(adap), client->addr);
|
||||||
|
dev->clk = v4l2_clk_register_fixed(clk_name, "mclk", -EINVAL);
|
||||||
|
if (IS_ERR(dev->clk))
|
||||||
|
return PTR_ERR(dev->clk);
|
||||||
|
|
||||||
switch (dev->em28xx_sensor) {
|
switch (dev->em28xx_sensor) {
|
||||||
case EM28XX_MT9V011:
|
case EM28XX_MT9V011:
|
||||||
{
|
{
|
||||||
struct mt9v011_platform_data pdata;
|
struct mt9v011_platform_data pdata;
|
||||||
struct i2c_board_info mt9v011_info = {
|
struct i2c_board_info mt9v011_info = {
|
||||||
.type = "mt9v011",
|
.type = "mt9v011",
|
||||||
.addr = dev->i2c_client[dev->def_i2c_bus].addr,
|
.addr = client->addr,
|
||||||
.platform_data = &pdata,
|
.platform_data = &pdata,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -352,10 +364,11 @@ int em28xx_init_camera(struct em28xx *dev)
|
||||||
dev->sensor_xtal = 4300000;
|
dev->sensor_xtal = 4300000;
|
||||||
pdata.xtal = dev->sensor_xtal;
|
pdata.xtal = dev->sensor_xtal;
|
||||||
if (NULL ==
|
if (NULL ==
|
||||||
v4l2_i2c_new_subdev_board(&dev->v4l2_dev,
|
v4l2_i2c_new_subdev_board(&dev->v4l2_dev, adap,
|
||||||
&dev->i2c_adap[dev->def_i2c_bus],
|
&mt9v011_info, NULL)) {
|
||||||
&mt9v011_info, NULL))
|
ret = -ENODEV;
|
||||||
return -ENODEV;
|
break;
|
||||||
|
}
|
||||||
/* probably means GRGB 16 bit bayer */
|
/* probably means GRGB 16 bit bayer */
|
||||||
dev->vinmode = 0x0d;
|
dev->vinmode = 0x0d;
|
||||||
dev->vinctl = 0x00;
|
dev->vinctl = 0x00;
|
||||||
|
@ -391,7 +404,7 @@ int em28xx_init_camera(struct em28xx *dev)
|
||||||
struct i2c_board_info ov2640_info = {
|
struct i2c_board_info ov2640_info = {
|
||||||
.type = "ov2640",
|
.type = "ov2640",
|
||||||
.flags = I2C_CLIENT_SCCB,
|
.flags = I2C_CLIENT_SCCB,
|
||||||
.addr = dev->i2c_client[dev->def_i2c_bus].addr,
|
.addr = client->addr,
|
||||||
.platform_data = &camlink,
|
.platform_data = &camlink,
|
||||||
};
|
};
|
||||||
struct v4l2_mbus_framefmt fmt;
|
struct v4l2_mbus_framefmt fmt;
|
||||||
|
@ -408,9 +421,12 @@ int em28xx_init_camera(struct em28xx *dev)
|
||||||
dev->sensor_yres = 480;
|
dev->sensor_yres = 480;
|
||||||
|
|
||||||
subdev =
|
subdev =
|
||||||
v4l2_i2c_new_subdev_board(&dev->v4l2_dev,
|
v4l2_i2c_new_subdev_board(&dev->v4l2_dev, adap,
|
||||||
&dev->i2c_adap[dev->def_i2c_bus],
|
|
||||||
&ov2640_info, NULL);
|
&ov2640_info, NULL);
|
||||||
|
if (NULL == subdev) {
|
||||||
|
ret = -ENODEV;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
fmt.code = V4L2_MBUS_FMT_YUYV8_2X8;
|
fmt.code = V4L2_MBUS_FMT_YUYV8_2X8;
|
||||||
fmt.width = 640;
|
fmt.width = 640;
|
||||||
|
@ -427,8 +443,13 @@ int em28xx_init_camera(struct em28xx *dev)
|
||||||
}
|
}
|
||||||
case EM28XX_NOSENSOR:
|
case EM28XX_NOSENSOR:
|
||||||
default:
|
default:
|
||||||
return -EINVAL;
|
ret = -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
if (ret < 0) {
|
||||||
|
v4l2_clk_unregister_fixed(dev->clk);
|
||||||
|
dev->clk = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
#include <media/tvaudio.h>
|
#include <media/tvaudio.h>
|
||||||
#include <media/i2c-addr.h>
|
#include <media/i2c-addr.h>
|
||||||
#include <media/tveeprom.h>
|
#include <media/tveeprom.h>
|
||||||
|
#include <media/v4l2-clk.h>
|
||||||
#include <media/v4l2-common.h>
|
#include <media/v4l2-common.h>
|
||||||
|
|
||||||
#include "em28xx.h"
|
#include "em28xx.h"
|
||||||
|
@ -2857,6 +2858,8 @@ void em28xx_release_resources(struct em28xx *dev)
|
||||||
if (dev->def_i2c_bus)
|
if (dev->def_i2c_bus)
|
||||||
em28xx_i2c_unregister(dev, 1);
|
em28xx_i2c_unregister(dev, 1);
|
||||||
em28xx_i2c_unregister(dev, 0);
|
em28xx_i2c_unregister(dev, 0);
|
||||||
|
if (dev->clk)
|
||||||
|
v4l2_clk_unregister_fixed(dev->clk);
|
||||||
|
|
||||||
v4l2_ctrl_handler_free(&dev->ctrl_handler);
|
v4l2_ctrl_handler_free(&dev->ctrl_handler);
|
||||||
|
|
||||||
|
|
|
@ -492,6 +492,7 @@ struct em28xx {
|
||||||
|
|
||||||
struct v4l2_device v4l2_dev;
|
struct v4l2_device v4l2_dev;
|
||||||
struct v4l2_ctrl_handler ctrl_handler;
|
struct v4l2_ctrl_handler ctrl_handler;
|
||||||
|
struct v4l2_clk *clk;
|
||||||
struct em28xx_board board;
|
struct em28xx_board board;
|
||||||
|
|
||||||
/* Webcam specific fields */
|
/* Webcam specific fields */
|
||||||
|
|
Loading…
Reference in New Issue