Hi All,
This patch series adds support for BT656 mode in the ov772x sensor
and also enables color bar test pattern control.
Cheers,
Prabhakar
Changes for v2:
* Updated DT bindings
* Driver defaults to parallel mode
* Fixed return type when endpoint parsing fails
Lad Prabhakar (3):
dt-bindings: media: ov772x: Document endpoint properties
media: i2c: ov772x: Add support for BT656 mode
media: i2c: ov772x: Add test pattern control
.../devicetree/bindings/media/i2c/ov772x.txt | 16 +++++
drivers/media/i2c/ov772x.c | 65 ++++++++++++++++++-
include/media/i2c/ov772x.h | 1 +
3 files changed, 81 insertions(+), 1 deletion(-)
--
2.17.1
Add support to read the bus-type and enable BT656 mode if needed.
The driver defaults to parallel mode if bus-type is not specified in DT.
Signed-off-by: Lad Prabhakar <[email protected]>
Reviewed-by: Biju Das <[email protected]>
---
drivers/media/i2c/ov772x.c | 40 ++++++++++++++++++++++++++++++++++++++
1 file changed, 40 insertions(+)
diff --git a/drivers/media/i2c/ov772x.c b/drivers/media/i2c/ov772x.c
index 2cc6a678069a..2de9248e3689 100644
--- a/drivers/media/i2c/ov772x.c
+++ b/drivers/media/i2c/ov772x.c
@@ -31,6 +31,7 @@
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-event.h>
+#include <media/v4l2-fwnode.h>
#include <media/v4l2-image-sizes.h>
#include <media/v4l2-subdev.h>
@@ -434,6 +435,7 @@ struct ov772x_priv {
#ifdef CONFIG_MEDIA_CONTROLLER
struct media_pad pad;
#endif
+ struct v4l2_fwnode_endpoint ep;
};
/*
@@ -574,6 +576,7 @@ static int ov772x_s_stream(struct v4l2_subdev *sd, int enable)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct ov772x_priv *priv = to_ov772x(sd);
+ unsigned int val;
int ret = 0;
mutex_lock(&priv->lock);
@@ -581,6 +584,22 @@ static int ov772x_s_stream(struct v4l2_subdev *sd, int enable)
if (priv->streaming == enable)
goto done;
+ if (priv->ep.bus_type == V4L2_MBUS_BT656 && enable) {
+ ret = regmap_read(priv->regmap, COM7, &val);
+ if (ret)
+ goto done;
+ val |= ITU656_ON_OFF;
+ ret = regmap_write(priv->regmap, COM7, val);
+ } else if (priv->ep.bus_type == V4L2_MBUS_BT656 && !enable) {
+ ret = regmap_read(priv->regmap, COM7, &val);
+ if (ret)
+ goto done;
+ val &= ~ITU656_ON_OFF;
+ ret = regmap_write(priv->regmap, COM7, val);
+ }
+ if (ret)
+ goto done;
+
ret = regmap_update_bits(priv->regmap, COM2, SOFT_SLEEP_MODE,
enable ? 0 : SOFT_SLEEP_MODE);
if (ret)
@@ -1354,6 +1373,7 @@ static const struct v4l2_subdev_ops ov772x_subdev_ops = {
static int ov772x_probe(struct i2c_client *client)
{
+ struct fwnode_handle *endpoint;
struct ov772x_priv *priv;
int ret;
static const struct regmap_config ov772x_regmap_config = {
@@ -1415,6 +1435,26 @@ static int ov772x_probe(struct i2c_client *client)
goto error_clk_put;
}
+ endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev),
+ NULL);
+ if (!endpoint) {
+ dev_err(&client->dev, "endpoint node not found\n");
+ ret = -EINVAL;
+ goto error_clk_put;
+ }
+
+ ret = v4l2_fwnode_endpoint_parse(endpoint, &priv->ep);
+ fwnode_handle_put(endpoint);
+ if (ret) {
+ dev_err(&client->dev, "Could not parse endpoint\n");
+ goto error_clk_put;
+ }
+
+ /* fallback to parallel mode */
+ if (priv->ep.bus_type != V4L2_MBUS_PARALLEL &&
+ priv->ep.bus_type != V4L2_MBUS_BT656)
+ priv->ep.bus_type = V4L2_MBUS_PARALLEL;
+
ret = ov772x_video_probe(priv);
if (ret < 0)
goto error_gpio_put;
--
2.17.1
Add support for test pattern control supported by the sensor.
Signed-off-by: Lad Prabhakar <[email protected]>
Reviewed-by: Biju Das <[email protected]>
---
drivers/media/i2c/ov772x.c | 25 ++++++++++++++++++++++++-
include/media/i2c/ov772x.h | 1 +
2 files changed, 25 insertions(+), 1 deletion(-)
diff --git a/drivers/media/i2c/ov772x.c b/drivers/media/i2c/ov772x.c
index 2de9248e3689..457887ec548d 100644
--- a/drivers/media/i2c/ov772x.c
+++ b/drivers/media/i2c/ov772x.c
@@ -227,7 +227,7 @@
/* COM3 */
#define SWAP_MASK (SWAP_RGB | SWAP_YUV | SWAP_ML)
-#define IMG_MASK (VFLIP_IMG | HFLIP_IMG)
+#define IMG_MASK (VFLIP_IMG | HFLIP_IMG | SCOLOR_TEST)
#define VFLIP_IMG 0x80 /* Vertical flip image ON/OFF selection */
#define HFLIP_IMG 0x40 /* Horizontal mirror image ON/OFF selection */
@@ -425,6 +425,7 @@ struct ov772x_priv {
const struct ov772x_win_size *win;
struct v4l2_ctrl *vflip_ctrl;
struct v4l2_ctrl *hflip_ctrl;
+ unsigned int test_pattern;
/* band_filter = COM8[5] ? 256 - BDBASE : 0 */
struct v4l2_ctrl *band_filter_ctrl;
unsigned int fps;
@@ -540,6 +541,11 @@ static const struct ov772x_win_size ov772x_win_sizes[] = {
},
};
+static const char * const ov772x_test_pattern_menu[] = {
+ "Disabled",
+ "Vertical Color Bar Type 1",
+};
+
/*
* frame rate settings lists
*/
@@ -772,6 +778,13 @@ static int ov772x_s_frame_interval(struct v4l2_subdev *sd,
return ret;
}
+static int ov772x_enable_test_pattern(struct ov772x_priv *priv, u32 pattern)
+{
+ priv->test_pattern = pattern;
+ return regmap_update_bits(priv->regmap, COM3, SCOLOR_TEST,
+ pattern ? SCOLOR_TEST : 0x00);
+}
+
static int ov772x_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct ov772x_priv *priv = container_of(ctrl->handler,
@@ -819,6 +832,8 @@ static int ov772x_s_ctrl(struct v4l2_ctrl *ctrl)
}
return ret;
+ case V4L2_CID_TEST_PATTERN:
+ return ov772x_enable_test_pattern(priv, ctrl->val);
}
return -EINVAL;
@@ -1113,10 +1128,14 @@ static int ov772x_set_params(struct ov772x_priv *priv,
val |= VFLIP_IMG;
if (priv->info && (priv->info->flags & OV772X_FLAG_HFLIP))
val |= HFLIP_IMG;
+ if (priv->info && (priv->info->flags & OV772X_FLAG_TEST_PATTERN))
+ val |= SCOLOR_TEST;
if (priv->vflip_ctrl->val)
val ^= VFLIP_IMG;
if (priv->hflip_ctrl->val)
val ^= HFLIP_IMG;
+ if (priv->test_pattern)
+ val ^= SCOLOR_TEST;
ret = regmap_update_bits(priv->regmap, COM3, SWAP_MASK | IMG_MASK, val);
if (ret < 0)
@@ -1414,6 +1433,10 @@ static int ov772x_probe(struct i2c_client *client)
priv->band_filter_ctrl = v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops,
V4L2_CID_BAND_STOP_FILTER,
0, 256, 1, 0);
+ v4l2_ctrl_new_std_menu_items(&priv->hdl, &ov772x_ctrl_ops,
+ V4L2_CID_TEST_PATTERN,
+ ARRAY_SIZE(ov772x_test_pattern_menu) - 1,
+ 0, 0, ov772x_test_pattern_menu);
priv->subdev.ctrl_handler = &priv->hdl;
if (priv->hdl.error) {
ret = priv->hdl.error;
diff --git a/include/media/i2c/ov772x.h b/include/media/i2c/ov772x.h
index a1702d420087..65e6f8d2f4bb 100644
--- a/include/media/i2c/ov772x.h
+++ b/include/media/i2c/ov772x.h
@@ -12,6 +12,7 @@
/* for flags */
#define OV772X_FLAG_VFLIP (1 << 0) /* Vertical flip image */
#define OV772X_FLAG_HFLIP (1 << 1) /* Horizontal flip image */
+#define OV772X_FLAG_TEST_PATTERN (1 << 2) /* Test pattern */
/*
* for Edge ctrl
--
2.17.1
On Mon, Aug 03, 2020 at 12:39:12PM +0100, Lad Prabhakar wrote:
> Add support to read the bus-type and enable BT656 mode if needed.
>
> The driver defaults to parallel mode if bus-type is not specified in DT.
>
> Signed-off-by: Lad Prabhakar <[email protected]>
> Reviewed-by: Biju Das <[email protected]>
> ---
> drivers/media/i2c/ov772x.c | 40 ++++++++++++++++++++++++++++++++++++++
> 1 file changed, 40 insertions(+)
>
> diff --git a/drivers/media/i2c/ov772x.c b/drivers/media/i2c/ov772x.c
> index 2cc6a678069a..2de9248e3689 100644
> --- a/drivers/media/i2c/ov772x.c
> +++ b/drivers/media/i2c/ov772x.c
> @@ -31,6 +31,7 @@
> #include <media/v4l2-ctrls.h>
> #include <media/v4l2-device.h>
> #include <media/v4l2-event.h>
> +#include <media/v4l2-fwnode.h>
> #include <media/v4l2-image-sizes.h>
> #include <media/v4l2-subdev.h>
>
> @@ -434,6 +435,7 @@ struct ov772x_priv {
> #ifdef CONFIG_MEDIA_CONTROLLER
> struct media_pad pad;
> #endif
> + struct v4l2_fwnode_endpoint ep;
> };
>
> /*
> @@ -574,6 +576,7 @@ static int ov772x_s_stream(struct v4l2_subdev *sd, int enable)
> {
> struct i2c_client *client = v4l2_get_subdevdata(sd);
> struct ov772x_priv *priv = to_ov772x(sd);
> + unsigned int val;
> int ret = 0;
>
> mutex_lock(&priv->lock);
> @@ -581,6 +584,22 @@ static int ov772x_s_stream(struct v4l2_subdev *sd, int enable)
> if (priv->streaming == enable)
> goto done;
>
> + if (priv->ep.bus_type == V4L2_MBUS_BT656 && enable) {
> + ret = regmap_read(priv->regmap, COM7, &val);
> + if (ret)
> + goto done;
> + val |= ITU656_ON_OFF;
> + ret = regmap_write(priv->regmap, COM7, val);
> + } else if (priv->ep.bus_type == V4L2_MBUS_BT656 && !enable) {
is the !enable intentional ? (sorry I don't have access to the sensor
manual). If not, see below:
> + ret = regmap_read(priv->regmap, COM7, &val);
> + if (ret)
> + goto done;
> + val &= ~ITU656_ON_OFF;
> + ret = regmap_write(priv->regmap, COM7, val);
> + }
> + if (ret)
> + goto done;
Could you write this as:
static int ov772x_s_stream(struct v4l2_subdev *sd, int enable)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct ov772x_priv *priv = to_ov772x(sd);
int ret = 0;
mutex_lock(&priv->lock);
if (priv->streaming == enable)
goto done;
if (enable) {
ret = regmap_read(priv->regmap, COM7, &val);
if (ret)
goto done;
if (priv->ep.bus_type == V4L2_MBUS_BT656)
val |= ITU656_ON_OFF;
else /* if you accept my suggestion to consider othe
bus types as errors */
val &= ~ITU656_ON_OFF;
ret = regmap_write(priv->regmap, COM7, val);
if (ret)
goto done;
dev_dbg(&client->dev, "format %d, win %s\n",
priv->cfmt->code, priv->win->name);
}
ret = regmap_update_bits(priv->regmap, COM2, SOFT_SLEEP_MODE,
enable ? 0 : SOFT_SLEEP_MODE);
if (ret)
goto done;
priv->streaming = enable;
done:
mutex_unlock(&priv->lock);
return ret;
}
> ret = regmap_update_bits(priv->regmap, COM2, SOFT_SLEEP_MODE,
> enable ? 0 : SOFT_SLEEP_MODE);
> if (ret)
> @@ -1354,6 +1373,7 @@ static const struct v4l2_subdev_ops ov772x_subdev_ops = {
>
> static int ov772x_probe(struct i2c_client *client)
> {
> + struct fwnode_handle *endpoint;
> struct ov772x_priv *priv;
> int ret;
> static const struct regmap_config ov772x_regmap_config = {
> @@ -1415,6 +1435,26 @@ static int ov772x_probe(struct i2c_client *client)
> goto error_clk_put;
> }
>
> + endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev),
> + NULL);
> + if (!endpoint) {
> + dev_err(&client->dev, "endpoint node not found\n");
> + ret = -EINVAL;
> + goto error_clk_put;
> + }
> +
> + ret = v4l2_fwnode_endpoint_parse(endpoint, &priv->ep);
> + fwnode_handle_put(endpoint);
> + if (ret) {
> + dev_err(&client->dev, "Could not parse endpoint\n");
> + goto error_clk_put;
> + }
> +
> + /* fallback to parallel mode */
> + if (priv->ep.bus_type != V4L2_MBUS_PARALLEL &&
> + priv->ep.bus_type != V4L2_MBUS_BT656)
> + priv->ep.bus_type = V4L2_MBUS_PARALLEL;
shouldn't this be an error ? It's either the bus type has not been
specified on DT (which is fine, otherwise old DTB without that
properties will fail) and the bus identification routine implemented
in v4l2_fwnode_endpoint_parse() detected a bus type which is not
supported, hence the DT properties are wrong, and this should be an
error. If you plan to expand the parsing routine to support, say
bus-width and pclk polarity please break this out to a new function.
Thanks
j
> +
> ret = ov772x_video_probe(priv);
> if (ret < 0)
> goto error_gpio_put;
> --
> 2.17.1
>
Hi Jacopo,
Thank you for the review.
On Thu, Aug 6, 2020 at 3:41 PM Jacopo Mondi <[email protected]> wrote:
>
> On Mon, Aug 03, 2020 at 12:39:12PM +0100, Lad Prabhakar wrote:
> > Add support to read the bus-type and enable BT656 mode if needed.
> >
> > The driver defaults to parallel mode if bus-type is not specified in DT.
> >
> > Signed-off-by: Lad Prabhakar <[email protected]>
> > Reviewed-by: Biju Das <[email protected]>
> > ---
> > drivers/media/i2c/ov772x.c | 40 ++++++++++++++++++++++++++++++++++++++
> > 1 file changed, 40 insertions(+)
> >
> > diff --git a/drivers/media/i2c/ov772x.c b/drivers/media/i2c/ov772x.c
> > index 2cc6a678069a..2de9248e3689 100644
> > --- a/drivers/media/i2c/ov772x.c
> > +++ b/drivers/media/i2c/ov772x.c
> > @@ -31,6 +31,7 @@
> > #include <media/v4l2-ctrls.h>
> > #include <media/v4l2-device.h>
> > #include <media/v4l2-event.h>
> > +#include <media/v4l2-fwnode.h>
> > #include <media/v4l2-image-sizes.h>
> > #include <media/v4l2-subdev.h>
> >
> > @@ -434,6 +435,7 @@ struct ov772x_priv {
> > #ifdef CONFIG_MEDIA_CONTROLLER
> > struct media_pad pad;
> > #endif
> > + struct v4l2_fwnode_endpoint ep;
> > };
> >
> > /*
> > @@ -574,6 +576,7 @@ static int ov772x_s_stream(struct v4l2_subdev *sd, int enable)
> > {
> > struct i2c_client *client = v4l2_get_subdevdata(sd);
> > struct ov772x_priv *priv = to_ov772x(sd);
> > + unsigned int val;
> > int ret = 0;
> >
> > mutex_lock(&priv->lock);
> > @@ -581,6 +584,22 @@ static int ov772x_s_stream(struct v4l2_subdev *sd, int enable)
> > if (priv->streaming == enable)
> > goto done;
> >
> > + if (priv->ep.bus_type == V4L2_MBUS_BT656 && enable) {
> > + ret = regmap_read(priv->regmap, COM7, &val);
> > + if (ret)
> > + goto done;
> > + val |= ITU656_ON_OFF;
> > + ret = regmap_write(priv->regmap, COM7, val);
> > + } else if (priv->ep.bus_type == V4L2_MBUS_BT656 && !enable) {
>
> is the !enable intentional ? (sorry I don't have access to the sensor
> manual). If not, see below:
>
> > + ret = regmap_read(priv->regmap, COM7, &val);
> > + if (ret)
> > + goto done;
> > + val &= ~ITU656_ON_OFF;
> > + ret = regmap_write(priv->regmap, COM7, val);
> > + }
> > + if (ret)
> > + goto done;
>
> Could you write this as:
>
Agreed will do.
> static int ov772x_s_stream(struct v4l2_subdev *sd, int enable)
> {
> struct i2c_client *client = v4l2_get_subdevdata(sd);
> struct ov772x_priv *priv = to_ov772x(sd);
> int ret = 0;
>
> mutex_lock(&priv->lock);
>
> if (priv->streaming == enable)
> goto done;
>
> if (enable) {
> ret = regmap_read(priv->regmap, COM7, &val);
> if (ret)
> goto done;
>
> if (priv->ep.bus_type == V4L2_MBUS_BT656)
> val |= ITU656_ON_OFF;
> else /* if you accept my suggestion to consider othe
> bus types as errors */
> val &= ~ITU656_ON_OFF;
>
> ret = regmap_write(priv->regmap, COM7, val);
> if (ret)
> goto done;
>
> dev_dbg(&client->dev, "format %d, win %s\n",
> priv->cfmt->code, priv->win->name);
> }
>
> ret = regmap_update_bits(priv->regmap, COM2, SOFT_SLEEP_MODE,
> enable ? 0 : SOFT_SLEEP_MODE);
> if (ret)
> goto done;
> priv->streaming = enable;
>
> done:
> mutex_unlock(&priv->lock);
>
> return ret;
> }
>
>
> > ret = regmap_update_bits(priv->regmap, COM2, SOFT_SLEEP_MODE,
> > enable ? 0 : SOFT_SLEEP_MODE);
> > if (ret)
> > @@ -1354,6 +1373,7 @@ static const struct v4l2_subdev_ops ov772x_subdev_ops = {
> >
> > static int ov772x_probe(struct i2c_client *client)
> > {
> > + struct fwnode_handle *endpoint;
> > struct ov772x_priv *priv;
> > int ret;
> > static const struct regmap_config ov772x_regmap_config = {
> > @@ -1415,6 +1435,26 @@ static int ov772x_probe(struct i2c_client *client)
> > goto error_clk_put;
> > }
> >
> > + endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev),
> > + NULL);
> > + if (!endpoint) {
> > + dev_err(&client->dev, "endpoint node not found\n");
> > + ret = -EINVAL;
> > + goto error_clk_put;
> > + }
> > +
> > + ret = v4l2_fwnode_endpoint_parse(endpoint, &priv->ep);
> > + fwnode_handle_put(endpoint);
> > + if (ret) {
> > + dev_err(&client->dev, "Could not parse endpoint\n");
> > + goto error_clk_put;
> > + }
> > +
> > + /* fallback to parallel mode */
> > + if (priv->ep.bus_type != V4L2_MBUS_PARALLEL &&
> > + priv->ep.bus_type != V4L2_MBUS_BT656)
> > + priv->ep.bus_type = V4L2_MBUS_PARALLEL;
>
> shouldn't this be an error ? It's either the bus type has not been
> specified on DT (which is fine, otherwise old DTB without that
> properties will fail) and the bus identification routine implemented
> in v4l2_fwnode_endpoint_parse() detected a bus type which is not
> supported, hence the DT properties are wrong, and this should be an
> error. If you plan to expand the parsing routine to support, say
> bus-width and pclk polarity please break this out to a new function.
>
Agreed.
Cheers,
Prabhakar
> Thanks
> j
>
> > +
> > ret = ov772x_video_probe(priv);
> > if (ret < 0)
> > goto error_gpio_put;
> > --
> > 2.17.1
> >