mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-24 01:41:39 +00:00
media: v4l2: i2c: ov7670: Implement OF mbus configuration
ov7670 driver supports two optional properties supplied through platform data, but currently does not support any standard video interface property. Add support through OF parsing for 2 generic properties (vsync and hsync polarities) and for one custom property already supported through platform data to suppress pixel clock output during horizontal blanking. While at there, check return value of register writes in set_fmt function and rationalize spacings. Signal polarities and pixel clock blanking verified through scope and image capture. Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
This commit is contained in:
parent
622b2d10fc
commit
01b8444828
2 changed files with 85 additions and 14 deletions
|
@ -692,6 +692,7 @@ config VIDEO_OV7670
|
||||||
tristate "OmniVision OV7670 sensor support"
|
tristate "OmniVision OV7670 sensor support"
|
||||||
depends on I2C && VIDEO_V4L2
|
depends on I2C && VIDEO_V4L2
|
||||||
depends on MEDIA_CAMERA_SUPPORT
|
depends on MEDIA_CAMERA_SUPPORT
|
||||||
|
select V4L2_FWNODE
|
||||||
---help---
|
---help---
|
||||||
This is a Video4Linux2 sensor-level driver for the OmniVision
|
This is a Video4Linux2 sensor-level driver for the OmniVision
|
||||||
OV7670 VGA camera. It currently only works with the M88ALP01
|
OV7670 VGA camera. It currently only works with the M88ALP01
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include <linux/gpio/consumer.h>
|
#include <linux/gpio/consumer.h>
|
||||||
#include <media/v4l2-device.h>
|
#include <media/v4l2-device.h>
|
||||||
#include <media/v4l2-ctrls.h>
|
#include <media/v4l2-ctrls.h>
|
||||||
|
#include <media/v4l2-fwnode.h>
|
||||||
#include <media/v4l2-mediabus.h>
|
#include <media/v4l2-mediabus.h>
|
||||||
#include <media/v4l2-image-sizes.h>
|
#include <media/v4l2-image-sizes.h>
|
||||||
#include <media/i2c/ov7670.h>
|
#include <media/i2c/ov7670.h>
|
||||||
|
@ -242,6 +243,7 @@ struct ov7670_info {
|
||||||
struct clk *clk;
|
struct clk *clk;
|
||||||
struct gpio_desc *resetb_gpio;
|
struct gpio_desc *resetb_gpio;
|
||||||
struct gpio_desc *pwdn_gpio;
|
struct gpio_desc *pwdn_gpio;
|
||||||
|
unsigned int mbus_config; /* Media bus configuration flags */
|
||||||
int min_width; /* Filter out smaller sizes */
|
int min_width; /* Filter out smaller sizes */
|
||||||
int min_height; /* Filter out smaller sizes */
|
int min_height; /* Filter out smaller sizes */
|
||||||
int clock_speed; /* External clock speed (MHz) */
|
int clock_speed; /* External clock speed (MHz) */
|
||||||
|
@ -1014,7 +1016,7 @@ static int ov7670_set_fmt(struct v4l2_subdev *sd,
|
||||||
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
|
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
|
||||||
struct v4l2_mbus_framefmt *mbus_fmt;
|
struct v4l2_mbus_framefmt *mbus_fmt;
|
||||||
#endif
|
#endif
|
||||||
unsigned char com7;
|
unsigned char com7, com10 = 0;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (format->pad)
|
if (format->pad)
|
||||||
|
@ -1034,7 +1036,6 @@ static int ov7670_set_fmt(struct v4l2_subdev *sd,
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = ov7670_try_fmt_internal(sd, &format->format, &ovfmt, &wsize);
|
ret = ov7670_try_fmt_internal(sd, &format->format, &ovfmt, &wsize);
|
||||||
|
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
/*
|
/*
|
||||||
|
@ -1045,16 +1046,41 @@ static int ov7670_set_fmt(struct v4l2_subdev *sd,
|
||||||
*/
|
*/
|
||||||
com7 = ovfmt->regs[0].value;
|
com7 = ovfmt->regs[0].value;
|
||||||
com7 |= wsize->com7_bit;
|
com7 |= wsize->com7_bit;
|
||||||
ov7670_write(sd, REG_COM7, com7);
|
ret = ov7670_write(sd, REG_COM7, com7);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Configure the media bus through COM10 register
|
||||||
|
*/
|
||||||
|
if (info->mbus_config & V4L2_MBUS_VSYNC_ACTIVE_LOW)
|
||||||
|
com10 |= COM10_VS_NEG;
|
||||||
|
if (info->mbus_config & V4L2_MBUS_HSYNC_ACTIVE_LOW)
|
||||||
|
com10 |= COM10_HREF_REV;
|
||||||
|
if (info->pclk_hb_disable)
|
||||||
|
com10 |= COM10_PCLK_HB;
|
||||||
|
ret = ov7670_write(sd, REG_COM10, com10);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now write the rest of the array. Also store start/stops
|
* Now write the rest of the array. Also store start/stops
|
||||||
*/
|
*/
|
||||||
ov7670_write_array(sd, ovfmt->regs + 1);
|
ret = ov7670_write_array(sd, ovfmt->regs + 1);
|
||||||
ov7670_set_hw(sd, wsize->hstart, wsize->hstop, wsize->vstart,
|
if (ret)
|
||||||
wsize->vstop);
|
return ret;
|
||||||
ret = 0;
|
|
||||||
if (wsize->regs)
|
ret = ov7670_set_hw(sd, wsize->hstart, wsize->hstop, wsize->vstart,
|
||||||
|
wsize->vstop);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (wsize->regs) {
|
||||||
ret = ov7670_write_array(sd, wsize->regs);
|
ret = ov7670_write_array(sd, wsize->regs);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
info->fmt = ovfmt;
|
info->fmt = ovfmt;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1067,8 +1093,10 @@ static int ov7670_set_fmt(struct v4l2_subdev *sd,
|
||||||
* to write it unconditionally, and that will make the frame
|
* to write it unconditionally, and that will make the frame
|
||||||
* rate persistent too.
|
* rate persistent too.
|
||||||
*/
|
*/
|
||||||
if (ret == 0)
|
ret = ov7670_write(sd, REG_CLKRC, info->clkrc);
|
||||||
ret = ov7670_write(sd, REG_CLKRC, info->clkrc);
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1692,6 +1720,45 @@ static int ov7670_init_gpio(struct i2c_client *client, struct ov7670_info *info)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ov7670_parse_dt() - Parse device tree to collect mbus configuration
|
||||||
|
* properties
|
||||||
|
*/
|
||||||
|
static int ov7670_parse_dt(struct device *dev,
|
||||||
|
struct ov7670_info *info)
|
||||||
|
{
|
||||||
|
struct fwnode_handle *fwnode = dev_fwnode(dev);
|
||||||
|
struct v4l2_fwnode_endpoint bus_cfg;
|
||||||
|
struct fwnode_handle *ep;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!fwnode)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
info->pclk_hb_disable = false;
|
||||||
|
if (fwnode_property_present(fwnode, "ov7670,pclk-hb-disable"))
|
||||||
|
info->pclk_hb_disable = true;
|
||||||
|
|
||||||
|
ep = fwnode_graph_get_next_endpoint(fwnode, NULL);
|
||||||
|
if (!ep)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
ret = v4l2_fwnode_endpoint_parse(ep, &bus_cfg);
|
||||||
|
if (ret) {
|
||||||
|
fwnode_handle_put(ep);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bus_cfg.bus_type != V4L2_MBUS_PARALLEL) {
|
||||||
|
dev_err(dev, "Unsupported media bus type\n");
|
||||||
|
fwnode_handle_put(ep);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
info->mbus_config = bus_cfg.bus.parallel.flags;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int ov7670_probe(struct i2c_client *client,
|
static int ov7670_probe(struct i2c_client *client,
|
||||||
const struct i2c_device_id *id)
|
const struct i2c_device_id *id)
|
||||||
{
|
{
|
||||||
|
@ -1712,7 +1779,13 @@ static int ov7670_probe(struct i2c_client *client,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
info->clock_speed = 30; /* default: a guess */
|
info->clock_speed = 30; /* default: a guess */
|
||||||
if (client->dev.platform_data) {
|
|
||||||
|
if (dev_fwnode(&client->dev)) {
|
||||||
|
ret = ov7670_parse_dt(&client->dev, info);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
} else if (client->dev.platform_data) {
|
||||||
struct ov7670_config *config = client->dev.platform_data;
|
struct ov7670_config *config = client->dev.platform_data;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1779,9 +1852,6 @@ static int ov7670_probe(struct i2c_client *client,
|
||||||
tpf.denominator = 30;
|
tpf.denominator = 30;
|
||||||
info->devtype->set_framerate(sd, &tpf);
|
info->devtype->set_framerate(sd, &tpf);
|
||||||
|
|
||||||
if (info->pclk_hb_disable)
|
|
||||||
ov7670_write(sd, REG_COM10, COM10_PCLK_HB);
|
|
||||||
|
|
||||||
v4l2_ctrl_handler_init(&info->hdl, 10);
|
v4l2_ctrl_handler_init(&info->hdl, 10);
|
||||||
v4l2_ctrl_new_std(&info->hdl, &ov7670_ctrl_ops,
|
v4l2_ctrl_new_std(&info->hdl, &ov7670_ctrl_ops,
|
||||||
V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
|
V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
|
||||||
|
|
Loading…
Reference in a new issue