Linux-Media Archive on lore.kernel.org
 help / color / Atom feed
* [PATCH v11 00/15] TVP5150 Features and fixes
@ 2019-09-30  9:38 Marco Felsch
  2019-09-30  9:38 ` [PATCH v11 01/15] dt-bindings: connector: analog: add sdtv standards property Marco Felsch
                   ` (14 more replies)
  0 siblings, 15 replies; 22+ messages in thread
From: Marco Felsch @ 2019-09-30  9:38 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt,
	laurent.pinchart
  Cc: devicetree, kernel, linux-media

Hi,

this "last-one"+1 addresses Hans comments made on my v10 [1]. The v11
addresses all checkpatch issues and some style issues found by Hans.

Regards,
  Marco

[1] https://patchwork.linuxtv.org/cover/58504/

Javier Martinez Canillas (1):
  partial revert of "[media] tvp5150: add HW input connectors support"

Marco Felsch (13):
  dt-bindings: connector: analog: add sdtv standards property
  media: v4l: link dt-bindings and uapi
  media: v4l2-fwnode: add v4l2_fwnode_connector
  media: v4l2-fwnode: add initial connector parsing support
  media: tvp5150: add input source selection of_graph support
  media: dt-bindings: tvp5150: Add input port connectors DT bindings
  media: tvp5150: fix set_selection rectangle handling
  media: tvp5150: add FORMAT_TRY support for get/set selection handlers
  media: tvp5150: add s_power callback
  media: dt-bindings: tvp5150: cleanup bindings stlye
  media: dt-bindings: tvp5150: add optional sdtv standards documentation
  media: tvp5150: add support to limit sdtv standards
  media: tvp5150: make debug output more readable

Michael Tretter (1):
  media: tvp5150: initialize subdev before parsing device tree

 .../display/connector/analog-tv-connector.txt |   6 +
 .../devicetree/bindings/media/i2c/tvp5150.txt | 146 +++-
 drivers/media/i2c/tvp5150.c                   | 672 +++++++++++++-----
 drivers/media/v4l2-core/v4l2-fwnode.c         | 129 ++++
 include/dt-bindings/display/sdtv-standards.h  |  76 ++
 include/dt-bindings/media/tvp5150.h           |   2 -
 include/media/v4l2-fwnode.h                   |  81 +++
 include/uapi/linux/videodev2.h                |   4 +
 8 files changed, 917 insertions(+), 199 deletions(-)
 create mode 100644 include/dt-bindings/display/sdtv-standards.h

-- 
2.20.1


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH v11 01/15] dt-bindings: connector: analog: add sdtv standards property
  2019-09-30  9:38 [PATCH v11 00/15] TVP5150 Features and fixes Marco Felsch
@ 2019-09-30  9:38 ` Marco Felsch
  2019-09-30  9:38 ` [PATCH v11 02/15] media: v4l: link dt-bindings and uapi Marco Felsch
                   ` (13 subsequent siblings)
  14 siblings, 0 replies; 22+ messages in thread
From: Marco Felsch @ 2019-09-30  9:38 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt,
	laurent.pinchart
  Cc: devicetree, kernel, linux-media, Rob Herring

Some connectors no matter if in- or output supports only a limited
range of sdtv standards. It doesn't matter if the hardware behind that
connector supports more than the listed formats since the users are
restriced by a label e.g. to plug only a camera into this connector
which uses the PAL format.

This patch adds the capability to describe such limitation within the
firmware. There are no format restrictions if the property isn't
present, so it's completely backward compatible.

Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
Reviewed-by: Rob Herring <robh@kernel.org>
---
[1] https://patchwork.kernel.org/cover/10794703/

v11:
- split patch https://patchwork.linuxtv.org/patch/58491/

v10:
- fix typo s/TV_STD_*/SDTV_STD_*/

v8:
Hi Rob,

I dropped your r b tag becuase of the changes I made in this version.
Please can you have look on it again? Luckily this would be the last
time ;-)

- move definition to include/dt-bindings/display
- rename tvnorms.h to sdtv-standards.h
- TVORMS_* -> SDTV_STD_*
- add sync comments
- adapt commit message
- fix bindings documentation

v7:
I kept Robs r b tag because I only changed the example and extended
TVNORM_* macros.

- fix some style issues
- add TVNORM_NTSC, TVNORM_525_60 and TVNORM_625_50

v6:
- tvnorms.h: use tabs instead of spaces
- tvnorms.h: add TVNORM_PAL and TVNORM_SECAM
- tvnorms.h: drop rarely used TVNORM_ATSC_* norms

v2-v4:
- nothing since the patch was squashed from series [1] into this
  series.
---
 .../display/connector/analog-tv-connector.txt |  6 ++
 include/dt-bindings/display/sdtv-standards.h  | 76 +++++++++++++++++++
 2 files changed, 82 insertions(+)
 create mode 100644 include/dt-bindings/display/sdtv-standards.h

diff --git a/Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt b/Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt
index 0c0970c210ab..883bcb2604c7 100644
--- a/Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt
+++ b/Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt
@@ -6,16 +6,22 @@ Required properties:
 
 Optional properties:
 - label: a symbolic name for the connector
+- sdtv-standards: limit the supported TV standards on a connector to the given
+                  ones. If not specified all TV standards are allowed.
+                  Possible TV standards are defined in
+                  include/dt-bindings/display/sdtv-standards.h.
 
 Required nodes:
 - Video port for TV input
 
 Example
 -------
+#include <dt-bindings/display/sdtv-standards.h>
 
 tv: connector {
 	compatible = "composite-video-connector";
 	label = "tv";
+	sdtv-standards = <(SDTV_STD_PAL | SDTV_STD_NTSC)>;
 
 	port {
 		tv_connector_in: endpoint {
diff --git a/include/dt-bindings/display/sdtv-standards.h b/include/dt-bindings/display/sdtv-standards.h
new file mode 100644
index 000000000000..fbc1a3db2ea7
--- /dev/null
+++ b/include/dt-bindings/display/sdtv-standards.h
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: GPL-2.0-only or X11 */
+/*
+ * Copyright 2019 Pengutronix, Marco Felsch <kernel@pengutronix.de>
+ */
+
+#ifndef _DT_BINDINGS_DISPLAY_SDTV_STDS_H
+#define _DT_BINDINGS_DISPLAY_SDTV_STDS_H
+
+/*
+ * Attention: Keep the SDTV_STD_* bit definitions in sync with
+ * include/uapi/linux/videodev2.h V4L2_STD_* bit definitions.
+ */
+/* One bit for each standard */
+#define SDTV_STD_PAL_B		0x00000001
+#define SDTV_STD_PAL_B1		0x00000002
+#define SDTV_STD_PAL_G		0x00000004
+#define SDTV_STD_PAL_H		0x00000008
+#define SDTV_STD_PAL_I		0x00000010
+#define SDTV_STD_PAL_D		0x00000020
+#define SDTV_STD_PAL_D1		0x00000040
+#define SDTV_STD_PAL_K		0x00000080
+
+#define SDTV_STD_PAL		(SDTV_STD_PAL_B		| \
+				 SDTV_STD_PAL_B1	| \
+				 SDTV_STD_PAL_G		| \
+				 SDTV_STD_PAL_H		| \
+				 SDTV_STD_PAL_I		| \
+				 SDTV_STD_PAL_D		| \
+				 SDTV_STD_PAL_D1	| \
+				 SDTV_STD_PAL_K)
+
+#define SDTV_STD_PAL_M		0x00000100
+#define SDTV_STD_PAL_N		0x00000200
+#define SDTV_STD_PAL_Nc		0x00000400
+#define SDTV_STD_PAL_60		0x00000800
+
+#define SDTV_STD_NTSC_M		0x00001000	/* BTSC */
+#define SDTV_STD_NTSC_M_JP	0x00002000	/* EIA-J */
+#define SDTV_STD_NTSC_443	0x00004000
+#define SDTV_STD_NTSC_M_KR	0x00008000	/* FM A2 */
+
+#define SDTV_STD_NTSC		(SDTV_STD_NTSC_M	| \
+				 SDTV_STD_NTSC_M_JP	| \
+				 SDTV_STD_NTSC_M_KR)
+
+#define SDTV_STD_SECAM_B	0x00010000
+#define SDTV_STD_SECAM_D	0x00020000
+#define SDTV_STD_SECAM_G	0x00040000
+#define SDTV_STD_SECAM_H	0x00080000
+#define SDTV_STD_SECAM_K	0x00100000
+#define SDTV_STD_SECAM_K1	0x00200000
+#define SDTV_STD_SECAM_L	0x00400000
+#define SDTV_STD_SECAM_LC	0x00800000
+
+#define SDTV_STD_SECAM		(SDTV_STD_SECAM_B	| \
+				 SDTV_STD_SECAM_D	| \
+				 SDTV_STD_SECAM_G	| \
+				 SDTV_STD_SECAM_H	| \
+				 SDTV_STD_SECAM_K	| \
+				 SDTV_STD_SECAM_K1	| \
+				 SDTV_STD_SECAM_L	| \
+				 SDTV_STD_SECAM_LC)
+
+/* Standards for Countries with 60Hz Line frequency */
+#define SDTV_STD_525_60		(SDTV_STD_PAL_M		| \
+				 SDTV_STD_PAL_60	| \
+				 SDTV_STD_NTSC		| \
+				 SDTV_STD_NTSC_443)
+
+/* Standards for Countries with 50Hz Line frequency */
+#define SDTV_STD_625_50		(SDTV_STD_PAL		| \
+				 SDTV_STD_PAL_N		| \
+				 SDTV_STD_PAL_Nc	| \
+				 SDTV_STD_SECAM)
+
+#endif /* _DT_BINDINGS_DISPLAY_SDTV_STDS_H */
-- 
2.20.1


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH v11 02/15] media: v4l: link dt-bindings and uapi
  2019-09-30  9:38 [PATCH v11 00/15] TVP5150 Features and fixes Marco Felsch
  2019-09-30  9:38 ` [PATCH v11 01/15] dt-bindings: connector: analog: add sdtv standards property Marco Felsch
@ 2019-09-30  9:38 ` Marco Felsch
  2019-09-30  9:38 ` [PATCH v11 03/15] media: v4l2-fwnode: add v4l2_fwnode_connector Marco Felsch
                   ` (12 subsequent siblings)
  14 siblings, 0 replies; 22+ messages in thread
From: Marco Felsch @ 2019-09-30  9:38 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt,
	laurent.pinchart
  Cc: devicetree, kernel, linux-media

Since we expose the definition to the dt-bindings we need to keep those
definitions in sync. To address this the patch adds a simple cross
reference to the dt-bindings.

Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
---
Changelog:

v11:
- new patch since the split https://patchwork.linuxtv.org/patch/58491/

v2-v10:
- nothing
---
 include/uapi/linux/videodev2.h | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 530638dffd93..bc7acade02a0 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -1208,6 +1208,10 @@ struct v4l2_selection {
 
 typedef __u64 v4l2_std_id;
 
+/*
+ * Attention: Keep the V4L2_STD_* bit definitions in sync with
+ * include/dt-bindings/display/sdtv-standards.h SDTV_STD_* bit definitions.
+ */
 /* one bit for each */
 #define V4L2_STD_PAL_B          ((v4l2_std_id)0x00000001)
 #define V4L2_STD_PAL_B1         ((v4l2_std_id)0x00000002)
-- 
2.20.1


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH v11 03/15] media: v4l2-fwnode: add v4l2_fwnode_connector
  2019-09-30  9:38 [PATCH v11 00/15] TVP5150 Features and fixes Marco Felsch
  2019-09-30  9:38 ` [PATCH v11 01/15] dt-bindings: connector: analog: add sdtv standards property Marco Felsch
  2019-09-30  9:38 ` [PATCH v11 02/15] media: v4l: link dt-bindings and uapi Marco Felsch
@ 2019-09-30  9:38 ` Marco Felsch
  2019-09-30  9:38 ` [PATCH v11 04/15] media: v4l2-fwnode: add initial connector parsing support Marco Felsch
                   ` (11 subsequent siblings)
  14 siblings, 0 replies; 22+ messages in thread
From: Marco Felsch @ 2019-09-30  9:38 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt,
	laurent.pinchart
  Cc: devicetree, kernel, linux-media

Currently every driver needs to parse the connector endpoints by it self.
This is the initial work to make this generic. A generic connector has
common members and connector specific members. The common members are:
  - type
  - label (optional)
  - links
  - nr_of_links

The specific members are stored within a union, since only one of them
can be available at the time. Since this is the initial support the
patch adds only the analog-connector specific ones.

Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
---
[1] https://patchwork.kernel.org/cover/10794703/

v10:
- drop unused V4L2_CONN_HDMI support

v8:
- rename CON -> CONN
- supported_tvnorms_stds -> sdtv_stds and adapt description

v7:
- fix spelling issues
- constify label
- support variable label size
- replace single remote_port/id members by links member of variable
  size
- squash v4l2-connector into v4l2-fwnode

@Jacopo: I dropped your r b tag because I changed the port/id logic.

v6:
- fix some spelling and style issues
- rm unnecessary comments
- drop vga and dvi connector
- fix misspelt connector

v2-v4:
- nothing since the patch was squashed from series [1] into this
  series.
---
 include/media/v4l2-fwnode.h | 43 +++++++++++++++++++++++++++++++++++++
 1 file changed, 43 insertions(+)

diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
index f6a7bcd13197..65da646b579e 100644
--- a/include/media/v4l2-fwnode.h
+++ b/include/media/v4l2-fwnode.h
@@ -123,6 +123,49 @@ struct v4l2_fwnode_link {
 	unsigned int remote_port;
 };
 
+/**
+ * enum v4l2_connector_type - connector type
+ * @V4L2_CONN_UNKNOWN:   unknown connector type, no V4L2 connector configuration
+ * @V4L2_CONN_COMPOSITE: analog composite connector
+ * @V4L2_CONN_SVIDEO:    analog svideo connector
+ */
+enum v4l2_connector_type {
+	V4L2_CONN_UNKNOWN,
+	V4L2_CONN_COMPOSITE,
+	V4L2_CONN_SVIDEO,
+};
+
+/**
+ * struct v4l2_fwnode_connector_analog - analog connector data structure
+ * @sdtv_stds: sdtv standards this connector supports, set to V4L2_STD_ALL
+ *             if no restrictions are specified.
+ */
+struct v4l2_fwnode_connector_analog {
+	v4l2_std_id sdtv_stds;
+};
+
+/**
+ * struct v4l2_fwnode_connector - the connector data structure
+ * @label: optional connector label
+ * @type: connector type
+ * @links: list of &struct v4l2_fwnode_link links the connector is connected to
+ * @nr_of_links: total number of links
+ * @connector: connector configuration
+ * @connector.analog: analog connector configuration
+ *                    &struct v4l2_fwnode_connector_analog
+ */
+struct v4l2_fwnode_connector {
+	const char *label;
+	enum v4l2_connector_type type;
+	struct v4l2_fwnode_link *links;
+	unsigned int nr_of_links;
+
+	union {
+		struct v4l2_fwnode_connector_analog analog;
+		/* future connectors */
+	} connector;
+};
+
 /**
  * v4l2_fwnode_endpoint_parse() - parse all fwnode node properties
  * @fwnode: pointer to the endpoint's fwnode handle
-- 
2.20.1


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH v11 04/15] media: v4l2-fwnode: add initial connector parsing support
  2019-09-30  9:38 [PATCH v11 00/15] TVP5150 Features and fixes Marco Felsch
                   ` (2 preceding siblings ...)
  2019-09-30  9:38 ` [PATCH v11 03/15] media: v4l2-fwnode: add v4l2_fwnode_connector Marco Felsch
@ 2019-09-30  9:38 ` Marco Felsch
  2019-11-15 23:34   ` Sakari Ailus
  2019-09-30  9:38 ` [PATCH v11 05/15] partial revert of "[media] tvp5150: add HW input connectors support" Marco Felsch
                   ` (10 subsequent siblings)
  14 siblings, 1 reply; 22+ messages in thread
From: Marco Felsch @ 2019-09-30  9:38 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt,
	laurent.pinchart
  Cc: devicetree, kernel, linux-media

The patch adds the initial connector parsing code, so we can move from a
driver specific parsing code to a generic one. Currently only the
generic fields and the analog-connector specific fields are parsed. Parsing
the other connector specific fields can be added by a simple callbacks.

Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
---
[1] https://patchwork.kernel.org/cover/10794703/

v10:
- drop V4L2_CONN_HDMI support
- adapt pr_err msg to reflect new state (-> connector is unkown)

v9:
- Fix leading semicolon found by kbuild semicolon.cocci

v8:
- V4L2_CON_* -> V4L2_CONN_*
- tvnorms -> sdtv-standards
- adapt to new v4l2_fwnode_connector_analog member
- return error in case of V4L2_CONN_HDMI

v7:
@Jacopo: I dropped your r b tag becuase of the amount of changes I
made..

- drop unnecessary comments
- fix commet style
- s/v4l2_fwnode_connector_conv.name/v4l2_fwnode_connector_conv.compatible/
- make label size variable and drop V4L2_CONNECTOR_MAX_LABEL usage
- do not assign a default label in case of no label was specified
- remove useless /* fall through */ comments
- add support for N connector links
- rename local variables to be more meaningful
- adjust kernedoc
- add v4l2_fwnode_connector_free()
- improve error handling (use different error values)
- make use of pr_warn_once()

v6:
- use unsigned count var
- fix comment and style issues
- place '/* fall through */' to correct places
- fix error handling and cleanup by releasing fwnode
- drop vga and dvi parsing support as those connectors are rarely used
  these days

v5:
- s/strlcpy/strscpy/

v2-v4:
- nothing since the patch was squashed from series [1] into this
  series.
---
 drivers/media/v4l2-core/v4l2-fwnode.c | 129 ++++++++++++++++++++++++++
 include/media/v4l2-fwnode.h           |  38 ++++++++
 2 files changed, 167 insertions(+)

diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
index 3bd1888787eb..0bfa7cbf78df 100644
--- a/drivers/media/v4l2-core/v4l2-fwnode.c
+++ b/drivers/media/v4l2-core/v4l2-fwnode.c
@@ -595,6 +595,135 @@ void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link)
 }
 EXPORT_SYMBOL_GPL(v4l2_fwnode_put_link);
 
+static const struct v4l2_fwnode_connector_conv {
+	enum v4l2_connector_type type;
+	const char *compatible;
+} connectors[] = {
+	{
+		.type = V4L2_CONN_COMPOSITE,
+		.compatible = "composite-video-connector",
+	}, {
+		.type = V4L2_CONN_SVIDEO,
+		.compatible = "svideo-connector",
+	},
+};
+
+static enum v4l2_connector_type
+v4l2_fwnode_string_to_connector_type(const char *con_str)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(connectors); i++)
+		if (!strcmp(con_str, connectors[i].compatible))
+			return connectors[i].type;
+
+	return V4L2_CONN_UNKNOWN;
+}
+
+static int
+v4l2_fwnode_connector_parse_analog(struct fwnode_handle *fwnode,
+				   struct v4l2_fwnode_connector *vc)
+{
+	u32 stds;
+	int ret;
+
+	ret = fwnode_property_read_u32(fwnode, "sdtv-standards", &stds);
+
+	/* The property is optional. */
+	vc->connector.analog.sdtv_stds = ret ? V4L2_STD_ALL : stds;
+
+	return 0;
+}
+
+void v4l2_fwnode_connector_free(struct v4l2_fwnode_connector *connector)
+{
+	unsigned int i;
+
+	if (IS_ERR_OR_NULL(connector))
+		return;
+
+	for (i = 0; i < connector->nr_of_links; i++)
+		v4l2_fwnode_put_link(&connector->links[i]);
+	kfree(connector->links);
+}
+EXPORT_SYMBOL_GPL(v4l2_fwnode_connector_free);
+
+int v4l2_fwnode_connector_alloc_parse(struct fwnode_handle *fwnode,
+				      struct v4l2_fwnode_connector *connector)
+{
+	struct fwnode_handle *remote_pp, *remote_ep;
+	const char *type_name;
+	unsigned int i = 0, ep_num = 0;
+	int err;
+
+	memset(connector, 0, sizeof(*connector));
+
+	remote_pp = fwnode_graph_get_remote_port_parent(fwnode);
+	if (!remote_pp)
+		return -ENOLINK;
+
+	/* Parse all common properties first. */
+	fwnode_graph_for_each_endpoint(remote_pp, remote_ep)
+		ep_num++;
+
+	connector->nr_of_links = ep_num;
+	connector->links = kmalloc_array(ep_num, sizeof(*connector->links),
+					 GFP_KERNEL);
+	if (!connector->links) {
+		err = -ENOMEM;
+		goto err_put_fwnode;
+	}
+
+	fwnode_graph_for_each_endpoint(remote_pp, remote_ep) {
+		err = v4l2_fwnode_parse_link(remote_ep, &connector->links[i]);
+		if (err) {
+			fwnode_handle_put(remote_ep);
+			goto err_free_links;
+		}
+		i++;
+	}
+
+	/*
+	 * Links reference counting guarantees access -> no duplication needed
+	 */
+	fwnode_property_read_string(remote_pp, "label", &connector->label);
+
+	/* The connector-type is stored within the compatible string. */
+	err = fwnode_property_read_string(remote_pp, "compatible", &type_name);
+	if (err) {
+		err = -EINVAL;
+		goto err_free_links;
+	}
+	connector->type = v4l2_fwnode_string_to_connector_type(type_name);
+
+	/* Now parse the connector specific properties. */
+	switch (connector->type) {
+	case V4L2_CONN_COMPOSITE:
+	case V4L2_CONN_SVIDEO:
+		err = v4l2_fwnode_connector_parse_analog(remote_pp, connector);
+		break;
+	case V4L2_CONN_UNKNOWN:
+	default:
+		pr_err("Unknown connector type\n");
+		err = -EINVAL;
+		goto err_free_links;
+	}
+
+	fwnode_handle_put(remote_pp);
+
+	return err;
+
+err_free_links:
+	for (i = 0; i < ep_num; i++)
+		v4l2_fwnode_put_link(&connector->links[i]);
+	kfree(connector->links);
+err_put_fwnode:
+	fwnode_handle_put(remote_pp);
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(v4l2_fwnode_connector_alloc_parse);
+
 static int
 v4l2_async_notifier_fwnode_parse_endpoint(struct device *dev,
 					  struct v4l2_async_notifier *notifier,
diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
index 65da646b579e..800302aa84d8 100644
--- a/include/media/v4l2-fwnode.h
+++ b/include/media/v4l2-fwnode.h
@@ -276,6 +276,44 @@ int v4l2_fwnode_parse_link(struct fwnode_handle *fwnode,
  */
 void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link);
 
+/**
+ * v4l2_fwnode_connector_free() - free the V4L2 connector acquired by
+ * v4l2_fwnode_parse_connector()
+ * @connector: the V4L2 connector the resources of which are to be released
+ *
+ * Drop references to the connection link partners and free the memory allocated
+ * by v4l2_fwnode_parse_connector() call.
+ *
+ * It is safe to call this function with NULL argument or on a V4L2 connector
+ * the parsing of which failed.
+ */
+void v4l2_fwnode_connector_free(struct v4l2_fwnode_connector *connector);
+
+/**
+ * v4l2_fwnode_parse_connector() - parse the connector on endpoint
+ * @fwnode: pointer to the endpoint's fwnode handle where the connector is
+ *          connected to
+ * @connector: pointer to the V4L2 fwnode connector data structure
+ *
+ * Fill the connector data structure with the connector type, label, all found
+ * links between the host and the connector as well as connector specific data.
+ * Since the label is optional it can be %NULL if no one was found.
+ *
+ * A reference is taken to both the connector and the connector destination
+ * where the connector belongs to. This must be dropped when no longer needed.
+ * Also the memory it has allocated to store the variable size data must be
+ * freed. Both dropping the references and freeing the memory is done by
+ * v4l2_fwnode_connector_free().
+ *
+ * Return:
+ * * %0 on success or a negative error code on failure:
+ * * %-ENOMEM if memory allocation failed
+ * * %-ENOLINK if the connector can't be found
+ * * %-EINVAL on parsing failure
+ */
+int v4l2_fwnode_connector_alloc_parse(struct fwnode_handle *fwnode,
+				      struct v4l2_fwnode_connector *connector);
+
 /**
  * typedef parse_endpoint_func - Driver's callback function to be called on
  *	each V4L2 fwnode endpoint.
-- 
2.20.1


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH v11 05/15] partial revert of "[media] tvp5150: add HW input connectors support"
  2019-09-30  9:38 [PATCH v11 00/15] TVP5150 Features and fixes Marco Felsch
                   ` (3 preceding siblings ...)
  2019-09-30  9:38 ` [PATCH v11 04/15] media: v4l2-fwnode: add initial connector parsing support Marco Felsch
@ 2019-09-30  9:38 ` Marco Felsch
  2019-09-30  9:38 ` [PATCH v11 06/15] media: tvp5150: add input source selection of_graph support Marco Felsch
                   ` (9 subsequent siblings)
  14 siblings, 0 replies; 22+ messages in thread
From: Marco Felsch @ 2019-09-30  9:38 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt,
	laurent.pinchart
  Cc: devicetree, kernel, linux-media, Javier Martinez Canillas,
	Mauro Carvalho Chehab, Rob Herring

From: Javier Martinez Canillas <javierm@redhat.com>

Commit f7b4b54e6364 ("[media] tvp5150: add HW input connectors support")
added input signals support for the tvp5150, but the approach was found
to be incorrect so the corresponding DT binding commit 82c2ffeb217a
("[media] tvp5150: document input connectors DT bindings") was reverted.

This left the driver with an undocumented (and wrong) DT parsing logic,
so lets get rid of this code as well until the input connectors support
is implemented properly.

It's a partial revert due other patches added on top of mentioned commit
not allowing the commit to be reverted cleanly anymore. But all the code
related to the DT parsing logic and input entities creation are removed.

Suggested-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
[m.felsch@pengutronix.de: rm TVP5150_INPUT_NUM define]
Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
Acked-by: Rob Herring <robh@kernel.org>
---
 drivers/media/i2c/tvp5150.c         | 145 ----------------------------
 include/dt-bindings/media/tvp5150.h |   2 -
 2 files changed, 147 deletions(-)

diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
index edad49cebcdf..11a5fd7e2f58 100644
--- a/drivers/media/i2c/tvp5150.c
+++ b/drivers/media/i2c/tvp5150.c
@@ -53,8 +53,6 @@ struct tvp5150 {
 	struct v4l2_subdev sd;
 #ifdef CONFIG_MEDIA_CONTROLLER
 	struct media_pad pads[TVP5150_NUM_PADS];
-	struct media_entity input_ent[TVP5150_INPUT_NUM];
-	struct media_pad input_pad[TVP5150_INPUT_NUM];
 #endif
 	struct v4l2_ctrl_handler hdl;
 	struct v4l2_rect rect;
@@ -1169,40 +1167,6 @@ static int tvp5150_enum_frame_size(struct v4l2_subdev *sd,
 	return 0;
 }
 
-/****************************************************************************
-			Media entity ops
- ****************************************************************************/
-
-#ifdef CONFIG_MEDIA_CONTROLLER
-static int tvp5150_link_setup(struct media_entity *entity,
-			      const struct media_pad *local,
-			      const struct media_pad *remote, u32 flags)
-{
-	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
-	struct tvp5150 *decoder = to_tvp5150(sd);
-	int i;
-
-	for (i = 0; i < TVP5150_INPUT_NUM; i++) {
-		if (remote->entity == &decoder->input_ent[i])
-			break;
-	}
-
-	/* Do nothing for entities that are not input connectors */
-	if (i == TVP5150_INPUT_NUM)
-		return 0;
-
-	decoder->input = i;
-
-	tvp5150_selmux(sd);
-
-	return 0;
-}
-
-static const struct media_entity_operations tvp5150_sd_media_ops = {
-	.link_setup = tvp5150_link_setup,
-};
-#endif
-
 /****************************************************************************
 			I2C Command
  ****************************************************************************/
@@ -1350,42 +1314,6 @@ static int tvp5150_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
 	return 0;
 }
 
-static int tvp5150_registered(struct v4l2_subdev *sd)
-{
-#ifdef CONFIG_MEDIA_CONTROLLER
-	struct tvp5150 *decoder = to_tvp5150(sd);
-	int ret = 0;
-	int i;
-
-	for (i = 0; i < TVP5150_INPUT_NUM; i++) {
-		struct media_entity *input = &decoder->input_ent[i];
-		struct media_pad *pad = &decoder->input_pad[i];
-
-		if (!input->name)
-			continue;
-
-		decoder->input_pad[i].flags = MEDIA_PAD_FL_SOURCE;
-
-		ret = media_entity_pads_init(input, 1, pad);
-		if (ret < 0)
-			return ret;
-
-		ret = media_device_register_entity(sd->v4l2_dev->mdev, input);
-		if (ret < 0)
-			return ret;
-
-		ret = media_create_pad_link(input, 0, &sd->entity,
-					    TVP5150_PAD_IF_INPUT, 0);
-		if (ret < 0) {
-			media_device_unregister_entity(input);
-			return ret;
-		}
-	}
-#endif
-
-	return 0;
-}
-
 /* ----------------------------------------------------------------------- */
 
 static const struct v4l2_ctrl_ops tvp5150_ctrl_ops = {
@@ -1439,10 +1367,6 @@ static const struct v4l2_subdev_ops tvp5150_ops = {
 	.pad = &tvp5150_pad_ops,
 };
 
-static const struct v4l2_subdev_internal_ops tvp5150_internal_ops = {
-	.registered = tvp5150_registered,
-};
-
 /****************************************************************************
 			I2C Client & Driver
  ****************************************************************************/
@@ -1595,12 +1519,6 @@ static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np)
 {
 	struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = 0 };
 	struct device_node *ep;
-#ifdef CONFIG_MEDIA_CONTROLLER
-	struct device_node *connectors, *child;
-	struct media_entity *input;
-	const char *name;
-	u32 input_type;
-#endif
 	unsigned int flags;
 	int ret = 0;
 
@@ -1624,67 +1542,6 @@ static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np)
 
 	decoder->mbus_type = bus_cfg.bus_type;
 
-#ifdef CONFIG_MEDIA_CONTROLLER
-	connectors = of_get_child_by_name(np, "connectors");
-
-	if (!connectors)
-		goto err;
-
-	for_each_available_child_of_node(connectors, child) {
-		ret = of_property_read_u32(child, "input", &input_type);
-		if (ret) {
-			dev_err(decoder->sd.dev,
-				 "missing type property in node %pOFn\n",
-				 child);
-			of_node_put(child);
-			goto err_connector;
-		}
-
-		if (input_type >= TVP5150_INPUT_NUM) {
-			ret = -EINVAL;
-			of_node_put(child);
-			goto err_connector;
-		}
-
-		input = &decoder->input_ent[input_type];
-
-		/* Each input connector can only be defined once */
-		if (input->name) {
-			dev_err(decoder->sd.dev,
-				 "input %s with same type already exists\n",
-				 input->name);
-			of_node_put(child);
-			ret = -EINVAL;
-			goto err_connector;
-		}
-
-		switch (input_type) {
-		case TVP5150_COMPOSITE0:
-		case TVP5150_COMPOSITE1:
-			input->function = MEDIA_ENT_F_CONN_COMPOSITE;
-			break;
-		case TVP5150_SVIDEO:
-			input->function = MEDIA_ENT_F_CONN_SVIDEO;
-			break;
-		}
-
-		input->flags = MEDIA_ENT_FL_CONNECTOR;
-
-		ret = of_property_read_string(child, "label", &name);
-		if (ret < 0) {
-			dev_err(decoder->sd.dev,
-				 "missing label property in node %pOFn\n",
-				 child);
-			of_node_put(child);
-			goto err_connector;
-		}
-
-		input->name = name;
-	}
-
-err_connector:
-	of_node_put(connectors);
-#endif
 err:
 	of_node_put(ep);
 	return ret;
@@ -1735,7 +1592,6 @@ static int tvp5150_probe(struct i2c_client *c)
 	}
 
 	v4l2_i2c_subdev_init(sd, c, &tvp5150_ops);
-	sd->internal_ops = &tvp5150_internal_ops;
 	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
 
 #if defined(CONFIG_MEDIA_CONTROLLER)
@@ -1750,7 +1606,6 @@ static int tvp5150_probe(struct i2c_client *c)
 	if (res < 0)
 		return res;
 
-	sd->entity.ops = &tvp5150_sd_media_ops;
 #endif
 
 	res = tvp5150_detect_version(core);
diff --git a/include/dt-bindings/media/tvp5150.h b/include/dt-bindings/media/tvp5150.h
index 01eedf4985b8..dda00c038530 100644
--- a/include/dt-bindings/media/tvp5150.h
+++ b/include/dt-bindings/media/tvp5150.h
@@ -14,8 +14,6 @@
 #define TVP5150_COMPOSITE1 1
 #define TVP5150_SVIDEO     2
 
-#define TVP5150_INPUT_NUM  3
-
 /* TVP5150 HW outputs */
 #define TVP5150_NORMAL       0
 #define TVP5150_BLACK_SCREEN 1
-- 
2.20.1


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH v11 06/15] media: tvp5150: add input source selection of_graph support
  2019-09-30  9:38 [PATCH v11 00/15] TVP5150 Features and fixes Marco Felsch
                   ` (4 preceding siblings ...)
  2019-09-30  9:38 ` [PATCH v11 05/15] partial revert of "[media] tvp5150: add HW input connectors support" Marco Felsch
@ 2019-09-30  9:38 ` Marco Felsch
  2019-09-30  9:38 ` [PATCH v11 07/15] media: dt-bindings: tvp5150: Add input port connectors DT bindings Marco Felsch
                   ` (8 subsequent siblings)
  14 siblings, 0 replies; 22+ messages in thread
From: Marco Felsch @ 2019-09-30  9:38 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt,
	laurent.pinchart
  Cc: devicetree, kernel, linux-media

This patch adds the of_graph support to describe the tvp input connections.
Physical the TVP5150 has three ports: AIP1A, AIP1B and YOUT. As result
of discussion [1],[2] the device-tree maps these ports 1:1. Look at the
Documentation for more information. Since the TVP5150 is a converter/bridge
the device-tree must contain at least 1-input and 1-output port. The
mc-connectors and mc-links are only created if the device-tree contains the
corresponding connector nodes. If more than one connector is available the
media_entity_operations.link_setup() callback ensures that only one
connector is active.

[1] https://www.spinics.net/lists/linux-media/msg138545.html
[2] https://www.spinics.net/lists/linux-media/msg138546.html

Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>

---
Changelog:

[1] https://patchwork.kernel.org/cover/10794703/
[2] https://patchwork.kernel.org/cover/10786553/

v11:
- add local struct v4l2_fwnode_connector *v4lc to address 'over 80
  characters' warning
- fix casting style issue

v8:
- fix rebasing issue
- fix error handling during tvp5150_registered()
- adapt to new v4l2_connector_type enum

v7:
- don't init enum tvp5150_pads with TVP5150_COMPOSITE0 functionality
- break some 80 character limitation to improve readability
- fix comment style -> always start with capital letters and end with dot
- fix some minor style issues
- fix tvp5150_registered error handling
- simplify tvp5150_mc_init
- make connectors static
  -> since now only three connectors are possible (as described in DT)
  -> drop tvp5150.endpoints storage
  -> squash tvp5150_parse_dt and tvp5150_add_of_connectors
- improve tvp5150_parse_dt:
  -> make parsing stricter and fix not detected missconfigured dt-data
  -> svideo must be connected now to port@[0,1]/endpoint@1

v6:
- fix misspelled comments
- use 'unsigned int' where it's possible
- cleanup ifdef part-2:
  * tvp5150_mc_init, tvp5150_add_of_connectors: add surrounding
    CONFIG_MEDIA_CONTROLLER if def and stubs to improve quality
- tvp5150_mc_init: uniform interface, use 'struct tvp5150' since all
  internal function do this.
- tvp5150_add_of_connectors: call within probe() to make it cleaner
- tvp5150_parse_dt: move local loop vars within the loop.

v5:
- Fixing build deps:
  - tvp5150_mc_init: fix CONFIG_MEDIA_CONTROLLER deps
  - struct tvp5150: drop CONFIG_MEDIA_CONTROLLER conditional property
    includes. This leads into to complex deps for futher development.
  - tvp5150_dt_cleanup: enable function only if CONFIG_OF is enabled
  - tvp5150_parse_dt: enable function only if CONFIG_OF is enabled
  - tvp5150_probe: call tvp5150_dt_cleanup only if CONFIG_OF is enabled

- Simplify link_setup routine:
  - use generic connector parsing since both series [1,2] are squashed into
    one
  - struct tvp5150: drop pads_state and modify_second_link property
    due to link_setup() rework.
  - tvp5150_link_setup: add more comments
  - tvp5150_link_setup: simply the link setup routine a lot. Edit the 2nd
    link directly within the driver instead of a recursive media-framework
    call (__media_entity_setup_link). This improves the readability and
    shrinks the driver code.
  - tvp5150_link_setup: disable all active links in case user switches
    connectors without disable it first.
  - tvp5150_registered: simplify default link enable path due to link_setup()
    rework.

- General cleanups
  - tvp5150_parse_dt: drop unecessary test
  - tvp5150_parse_dt: add err message due to misconfiguration
  - tvp5150_parse_dt: make use of V4L2_MBUS_UNKNOWN definition
  - s/dev_dbg/dev_dbg_lvl

v4:
 - rebase on top of media_tree/master, fix merge conflict due to commit
   60359a28d592 ("media: v4l: fwnode: Initialise the V4L2 fwnode endpoints
   to zero")

v3:
- probe(): s/err/err_free_v4l2_ctrls
- drop MC dependency for tvp5150_pads

v2:
- adapt commit message
- unify ifdef switches
- rename tvp5150_valid_input -> tvp5150_of_valid_input, to be more precise
- mc: use 2-input and 1-output pad
- mc: link svideo connector to both input pads
- mc: enable/disable svideo links in one go
- mc: change link_setup() behaviour, switch the input src don't require a
      explicite disable before.
- mc: rename 'local' media_pad param to tvp5150_pad to avoid confusion
- mc: enable link to the first available connector and set the
      corresponding tvp5150 input src per default during registered()
- mc/of: factor out oftree connector allocation
- of: drop svideo dt port
- of: move svideo connector to port@0/endpoint@1
- of: require at least 1-in and 1-out endpoint
---
 drivers/media/i2c/tvp5150.c | 382 +++++++++++++++++++++++++++++++++---
 1 file changed, 352 insertions(+), 30 deletions(-)

diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
index 11a5fd7e2f58..d8325b6dbaee 100644
--- a/drivers/media/i2c/tvp5150.c
+++ b/drivers/media/i2c/tvp5150.c
@@ -32,6 +32,8 @@
 #define TVP5150_FIELD		V4L2_FIELD_ALTERNATE
 #define TVP5150_COLORSPACE	V4L2_COLORSPACE_SMPTE170M
 
+#define TVP5150_MAX_CONNECTORS	3 /* Check dt-bindings for more information */
+
 MODULE_DESCRIPTION("Texas Instruments TVP5150A/TVP5150AM1/TVP5151 video decoder driver");
 MODULE_AUTHOR("Mauro Carvalho Chehab");
 MODULE_LICENSE("GPL v2");
@@ -44,16 +46,25 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)");
 #define dprintk0(__dev, __arg...) dev_dbg_lvl(__dev, 0, 0, __arg)
 
 enum tvp5150_pads {
-	TVP5150_PAD_IF_INPUT,
+	TVP5150_PAD_AIP1A,
+	TVP5150_PAD_AIP1B,
 	TVP5150_PAD_VID_OUT,
 	TVP5150_NUM_PADS
 };
 
+struct tvp5150_connector {
+	struct v4l2_fwnode_connector base;
+	struct media_entity ent;
+	struct media_pad pad;
+};
+
 struct tvp5150 {
 	struct v4l2_subdev sd;
-#ifdef CONFIG_MEDIA_CONTROLLER
+
 	struct media_pad pads[TVP5150_NUM_PADS];
-#endif
+	struct tvp5150_connector connectors[TVP5150_MAX_CONNECTORS];
+	unsigned int connectors_num;
+
 	struct v4l2_ctrl_handler hdl;
 	struct v4l2_rect rect;
 	struct regmap *regmap;
@@ -1167,6 +1178,132 @@ static int tvp5150_enum_frame_size(struct v4l2_subdev *sd,
 	return 0;
 }
 
+/****************************************************************************
+ *			Media entity ops
+ ****************************************************************************/
+#if defined(CONFIG_MEDIA_CONTROLLER)
+static int tvp5150_set_link(struct media_pad *connector_pad,
+			    struct media_pad *tvp5150_pad, u32 flags)
+{
+	struct media_link *link;
+
+	link = media_entity_find_link(connector_pad, tvp5150_pad);
+	if (!link)
+		return -EINVAL;
+
+	link->flags = flags;
+	link->reverse->flags = link->flags;
+
+	return 0;
+}
+
+static int tvp5150_disable_all_input_links(struct tvp5150 *decoder)
+{
+	struct media_pad *connector_pad;
+	unsigned int i;
+	int err;
+
+	for (i = 0; i < TVP5150_NUM_PADS - 1; i++) {
+		connector_pad = media_entity_remote_pad(&decoder->pads[i]);
+		if (!connector_pad)
+			continue;
+
+		err = tvp5150_set_link(connector_pad, &decoder->pads[i], 0);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+static int tvp5150_s_routing(struct v4l2_subdev *sd, u32 input, u32 output,
+			     u32 config);
+
+static int tvp5150_link_setup(struct media_entity *entity,
+			      const struct media_pad *tvp5150_pad,
+			      const struct media_pad *remote, u32 flags)
+{
+	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+	struct tvp5150 *decoder = to_tvp5150(sd);
+	struct media_pad *other_tvp5150_pad =
+		&decoder->pads[tvp5150_pad->index ^ 1];
+	struct v4l2_fwnode_connector *v4lc;
+	bool is_svideo = false;
+	unsigned int i;
+	int err;
+
+	/*
+	 * The TVP5150 state is determined by the enabled sink pad link(s).
+	 * Enabling or disabling the source pad link has no effect.
+	 */
+	if (tvp5150_pad->flags & MEDIA_PAD_FL_SOURCE)
+		return 0;
+
+	/* Check if the svideo connector should be enabled */
+	for (i = 0; i < decoder->connectors_num; i++) {
+		if (remote->entity == &decoder->connectors[i].ent) {
+			v4lc = &decoder->connectors[i].base;
+			is_svideo = v4lc->type == V4L2_CONN_SVIDEO;
+			break;
+		}
+	}
+
+	dev_dbg_lvl(sd->dev, 1, debug, "link setup '%s':%d->'%s':%d[%d]",
+		    remote->entity->name, remote->index,
+		    tvp5150_pad->entity->name, tvp5150_pad->index,
+		    flags & MEDIA_LNK_FL_ENABLED);
+	if (is_svideo)
+		dev_dbg_lvl(sd->dev, 1, debug,
+			    "link setup '%s':%d->'%s':%d[%d]",
+			    remote->entity->name, remote->index,
+			    other_tvp5150_pad->entity->name,
+			    other_tvp5150_pad->index,
+			    flags & MEDIA_LNK_FL_ENABLED);
+
+	/*
+	 * The TVP5150 has an internal mux which allows the following setup:
+	 *
+	 * comp-connector1  --\
+	 *		       |---> AIP1A
+	 *		      /
+	 * svideo-connector -|
+	 *		      \
+	 *		       |---> AIP1B
+	 * comp-connector2  --/
+	 *
+	 * We can't rely on user space that the current connector gets disabled
+	 * first before enabling the new connector. Disable all active
+	 * connector links to be on the safe side.
+	 */
+	err = tvp5150_disable_all_input_links(decoder);
+	if (err)
+		return err;
+
+	tvp5150_s_routing(sd, is_svideo ? TVP5150_SVIDEO : tvp5150_pad->index,
+			  flags & MEDIA_LNK_FL_ENABLED ? TVP5150_NORMAL :
+			  TVP5150_BLACK_SCREEN, 0);
+
+	if (flags & MEDIA_LNK_FL_ENABLED) {
+		/*
+		 * S-Video connector is conneted to both ports AIP1A and AIP1B.
+		 * Both links must be enabled in one-shot regardless which link
+		 * the user requests.
+		 */
+		if (is_svideo) {
+			err = tvp5150_set_link((struct media_pad *)remote,
+					       other_tvp5150_pad, flags);
+			if (err)
+				return err;
+		}
+	}
+
+	return 0;
+}
+
+static const struct media_entity_operations tvp5150_sd_media_ops = {
+	.link_setup = tvp5150_link_setup,
+};
+#endif
 /****************************************************************************
 			I2C Command
  ****************************************************************************/
@@ -1314,6 +1451,73 @@ static int tvp5150_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
 	return 0;
 }
 
+static int tvp5150_registered(struct v4l2_subdev *sd)
+{
+#if defined(CONFIG_MEDIA_CONTROLLER)
+	struct tvp5150 *decoder = to_tvp5150(sd);
+	unsigned int i;
+	int ret;
+
+	/*
+	 * Setup connector pads and links. Enable the link to the first
+	 * available connector per default.
+	 */
+	for (i = 0; i < decoder->connectors_num; i++) {
+		struct media_entity *con = &decoder->connectors[i].ent;
+		struct media_pad *pad = &decoder->connectors[i].pad;
+		struct v4l2_fwnode_connector *v4lc =
+			&decoder->connectors[i].base;
+		unsigned int port = v4lc->links[0].remote_port;
+		unsigned int flags = i ? 0 : MEDIA_LNK_FL_ENABLED;
+		bool is_svideo = v4lc->type == V4L2_CONN_SVIDEO;
+
+		pad->flags = MEDIA_PAD_FL_SOURCE;
+		ret = media_entity_pads_init(con, 1, pad);
+		if (ret < 0)
+			goto err;
+
+		ret = media_device_register_entity(sd->v4l2_dev->mdev, con);
+		if (ret < 0)
+			goto err;
+
+		ret = media_create_pad_link(con, 0, &sd->entity, port, flags);
+		if (ret < 0)
+			goto err;
+
+		if (is_svideo) {
+			/*
+			 * Check tvp5150_link_setup() comments for more
+			 * information.
+			 */
+			port = decoder->connectors[i].base.links[1].remote_port;
+			ret = media_create_pad_link(con, 0, &sd->entity, port,
+						    flags);
+			if (ret < 0)
+				goto err;
+		}
+
+		/* Enable default input. */
+		if (flags == MEDIA_LNK_FL_ENABLED) {
+			decoder->input =
+				is_svideo ? TVP5150_SVIDEO :
+				port == 0 ? TVP5150_COMPOSITE0 :
+				TVP5150_COMPOSITE1;
+
+			tvp5150_selmux(sd);
+		}
+	}
+
+	return 0;
+
+err:
+	for (i = 0; i < decoder->connectors_num; i++)
+		media_device_unregister_entity(&decoder->connectors[i].ent);
+	return ret;
+#endif
+
+	return 0;
+}
+
 /* ----------------------------------------------------------------------- */
 
 static const struct v4l2_ctrl_ops tvp5150_ctrl_ops = {
@@ -1367,6 +1571,10 @@ static const struct v4l2_subdev_ops tvp5150_ops = {
 	.pad = &tvp5150_pad_ops,
 };
 
+static const struct v4l2_subdev_internal_ops tvp5150_internal_ops = {
+	.registered = tvp5150_registered,
+};
+
 /****************************************************************************
 			I2C Client & Driver
  ****************************************************************************/
@@ -1515,36 +1723,159 @@ static int tvp5150_init(struct i2c_client *c)
 	return 0;
 }
 
-static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np)
+#if defined(CONFIG_MEDIA_CONTROLLER)
+static int tvp5150_mc_init(struct tvp5150 *decoder)
 {
-	struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = 0 };
-	struct device_node *ep;
-	unsigned int flags;
-	int ret = 0;
+	struct v4l2_subdev *sd = &decoder->sd;
+	unsigned int i;
 
-	ep = of_graph_get_next_endpoint(np, NULL);
-	if (!ep)
-		return -EINVAL;
+	sd->entity.ops = &tvp5150_sd_media_ops;
+	sd->entity.function = MEDIA_ENT_F_ATV_DECODER;
+
+	for (i = 0; i < TVP5150_NUM_PADS - 1; i++) {
+		decoder->pads[i].flags = MEDIA_PAD_FL_SINK;
+		decoder->pads[i].sig_type = PAD_SIGNAL_ANALOG;
+	}
+
+	decoder->pads[i].flags = MEDIA_PAD_FL_SOURCE;
+	decoder->pads[i].sig_type = PAD_SIGNAL_DV;
 
-	ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &bus_cfg);
+	return media_entity_pads_init(&sd->entity, TVP5150_NUM_PADS,
+				      decoder->pads);
+}
+
+#else /* !defined(CONFIG_MEDIA_CONTROLLER) */
+
+static inline int tvp5150_mc_init(struct tvp5150 *decoder)
+{
+	return 0;
+}
+#endif /* defined(CONFIG_MEDIA_CONTROLLER) */
+
+static int
+tvp5150_add_connector(struct tvp5150 *decoder, struct device_node *np,
+		      unsigned int portn, unsigned int epn, unsigned int svideo)
+{
+	struct device *dev = decoder->sd.dev;
+	struct device_node *ep_np, *remote_np;
+	struct v4l2_fwnode_connector *vc;
+	struct tvp5150_connector *c;
+	unsigned int next_connector = decoder->connectors_num;
+	int ret;
+
+	/* Get free connector entry. */
+	if (next_connector >= TVP5150_MAX_CONNECTORS)
+		return 0;
+
+	c = &decoder->connectors[next_connector];
+	vc = &c->base;
+	ep_np = of_graph_get_endpoint_by_regs(np, portn, epn);
+	remote_np = of_graph_get_remote_port_parent(ep_np);
+
+	ret = v4l2_fwnode_connector_alloc_parse(of_fwnode_handle(ep_np), vc);
 	if (ret)
 		goto err;
 
-	flags = bus_cfg.bus.parallel.flags;
+	if ((!svideo && vc->type != V4L2_CONN_COMPOSITE) ||
+	    (svideo && vc->type != V4L2_CONN_SVIDEO)) {
+		dev_err(dev, "Invalid connector type for port@%u/endpoint@%u\n",
+			portn, epn);
+		ret = -EINVAL;
+		goto err;
+	}
 
+	if (svideo &&
+	    (vc->nr_of_links != 2 ||
+	     vc->links[0].remote_port == vc->links[1].remote_port)) {
+		dev_err(dev, "Invalid Svideo connector configuration\n");
+		ret = -EINVAL;
+		goto err;
+	}
+
+	c->ent.flags = MEDIA_ENT_FL_CONNECTOR;
+	c->ent.name = vc->label;
+	c->ent.name = kasprintf(GFP_KERNEL, "%s %s", remote_np->name,
+				vc->label ? vc->label : "");
+	c->ent.function = vc->type == V4L2_CONN_SVIDEO ?
+		MEDIA_ENT_F_CONN_SVIDEO : MEDIA_ENT_F_CONN_COMPOSITE;
+
+	decoder->connectors_num++;
+
+	of_node_put(remote_np);
+	of_node_put(ep_np);
+	return 0;
+
+err:
+	of_node_put(remote_np);
+	of_node_put(ep_np);
+	v4l2_fwnode_connector_free(vc);
+	return ret;
+}
+
+static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np)
+{
+	struct device *dev = decoder->sd.dev;
+	struct device_node *ep_np;
+	struct v4l2_fwnode_endpoint bus_cfg = {
+		.bus_type = V4L2_MBUS_UNKNOWN
+	};
+	unsigned int flags, ep_num;
+	int ret;
+
+	/* At least 1 output and 1 input. */
+	ep_num = of_graph_get_endpoint_count(np);
+	if (ep_num < 2 || ep_num > 5) {
+		dev_err(dev, "At least 1 input and 1 output must be connected to the device.\n");
+		return -EINVAL;
+	}
+
+	/* Layout if all connectors are used
+	 *
+	 * tvp-5150 port@0 (AIP1A)
+	 *	endpoint@0 -----------> Comp0-Con  port
+	 *	endpoint@1 --------+--> Svideo-Con port
+	 * tvp-5150 port@1 (AIP1B) |
+	 *	endpoint@1 --------+
+	 *	endpoint@0 -----------> Comp1-Con  port
+	 * tvp-5150 port@2
+	 *	endpoint (video bitstream output at YOUT[0-7] parallel bus)
+	 */
+	for_each_endpoint_of_node(np, ep_np) {
+		struct of_endpoint ep;
+
+		of_graph_parse_endpoint(ep_np, &ep);
+		if (ep.port > 1)
+			continue;
+
+		ret = tvp5150_add_connector(decoder, np, ep.port, ep.id,
+					    ep.id ? 1 : 0);
+		if (ret) {
+			of_node_put(ep_np);
+			return ret;
+		}
+	}
+
+	ep_np = of_graph_get_endpoint_by_regs(np, TVP5150_PAD_VID_OUT, 0);
+	if (!ep_np) {
+		dev_err(dev, "Error no output endpoint available\n");
+		return -EINVAL;
+	}
+	ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep_np), &bus_cfg);
+	of_node_put(ep_np);
+	if (ret)
+		return ret;
+
+	flags = bus_cfg.bus.parallel.flags;
 	if (bus_cfg.bus_type == V4L2_MBUS_PARALLEL &&
 	    !(flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH &&
 	      flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH &&
 	      flags & V4L2_MBUS_FIELD_EVEN_LOW)) {
-		ret = -EINVAL;
-		goto err;
+		return -EINVAL;
 	}
 
 	decoder->mbus_type = bus_cfg.bus_type;
 
-err:
-	of_node_put(ep);
-	return ret;
+	return decoder->connectors_num ? 0 : -ENODEV;
 }
 
 static const char * const tvp5150_test_patterns[2] = {
@@ -1592,22 +1923,13 @@ static int tvp5150_probe(struct i2c_client *c)
 	}
 
 	v4l2_i2c_subdev_init(sd, c, &tvp5150_ops);
+	sd->internal_ops = &tvp5150_internal_ops;
 	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
 
-#if defined(CONFIG_MEDIA_CONTROLLER)
-	core->pads[TVP5150_PAD_IF_INPUT].flags = MEDIA_PAD_FL_SINK;
-	core->pads[TVP5150_PAD_IF_INPUT].sig_type = PAD_SIGNAL_ANALOG;
-	core->pads[TVP5150_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE;
-	core->pads[TVP5150_PAD_VID_OUT].sig_type = PAD_SIGNAL_DV;
-
-	sd->entity.function = MEDIA_ENT_F_ATV_DECODER;
-
-	res = media_entity_pads_init(&sd->entity, TVP5150_NUM_PADS, core->pads);
-	if (res < 0)
+	res = tvp5150_mc_init(core);
+	if (res)
 		return res;
 
-#endif
-
 	res = tvp5150_detect_version(core);
 	if (res < 0)
 		return res;
-- 
2.20.1


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH v11 07/15] media: dt-bindings: tvp5150: Add input port connectors DT bindings
  2019-09-30  9:38 [PATCH v11 00/15] TVP5150 Features and fixes Marco Felsch
                   ` (5 preceding siblings ...)
  2019-09-30  9:38 ` [PATCH v11 06/15] media: tvp5150: add input source selection of_graph support Marco Felsch
@ 2019-09-30  9:38 ` Marco Felsch
  2019-09-30  9:38 ` [PATCH v11 08/15] media: tvp5150: fix set_selection rectangle handling Marco Felsch
                   ` (7 subsequent siblings)
  14 siblings, 0 replies; 22+ messages in thread
From: Marco Felsch @ 2019-09-30  9:38 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt,
	laurent.pinchart
  Cc: devicetree, kernel, linux-media, Rob Herring

The TVP5150/1 decoders support different video input sources to their
AIP1A/B pins.

Possible configurations are as follows:
  - Analog Composite signal connected to AIP1A.
  - Analog Composite signal connected to AIP1B.
  - Analog S-Video Y (luminance) and C (chrominance)
    signals connected to AIP1A and AIP1B respectively.

This patch extends the device tree bindings documentation to describe
how the input connectors for these devices should be defined in a DT.

Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
Reviewed-by: Rob Herring <robh@kernel.org>
---
Changelog:

v7:
Hi Rob,
I droped your r b tag because I changed the bindings in this
patch version. Please can you have a look on it again?

- fix missing AIP1B svideo connection (description and examples)

v3:
- remove examples for one and two inputs
- replace space by tabs

v2:
- adapt port layout in accordance with
  https://www.spinics.net/lists/linux-media/msg138546.html with the
  svideo-connector deviation (use only one endpoint)
---
 .../devicetree/bindings/media/i2c/tvp5150.txt | 112 ++++++++++++++++--
 1 file changed, 105 insertions(+), 7 deletions(-)

diff --git a/Documentation/devicetree/bindings/media/i2c/tvp5150.txt b/Documentation/devicetree/bindings/media/i2c/tvp5150.txt
index 8c0fc1a26bf0..28b64ad149ef 100644
--- a/Documentation/devicetree/bindings/media/i2c/tvp5150.txt
+++ b/Documentation/devicetree/bindings/media/i2c/tvp5150.txt
@@ -12,11 +12,32 @@ Optional Properties:
 - pdn-gpios: phandle for the GPIO connected to the PDN pin, if any.
 - reset-gpios: phandle for the GPIO connected to the RESETB pin, if any.
 
-The device node must contain one 'port' child node for its digital output
-video port, in accordance with the video interface bindings defined in
-Documentation/devicetree/bindings/media/video-interfaces.txt.
+The device node must contain one 'port' child node per device physical input
+and output port, in accordance with the video interface bindings defined in
+Documentation/devicetree/bindings/media/video-interfaces.txt. The port nodes
+are numbered as follows
 
-Required Endpoint Properties for parallel synchronization:
+	  Name		Type		Port
+	--------------------------------------
+	  AIP1A		sink		0
+	  AIP1B		sink		1
+	  Y-OUT		src		2
+
+The device node must contain at least one sink port and the src port. Each input
+port must be linked to an endpoint defined in
+Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt. The
+port/connector layout is as follows
+
+tvp-5150 port@0 (AIP1A)
+	endpoint@0 -----------> Comp0-Con  port
+	endpoint@1 ------+----> Svideo-Con port
+tvp-5150 port@1 (AIP1B)  |
+	endpoint@1 ------+
+	endpoint@0 -----------> Comp1-Con  port
+tvp-5150 port@2
+	endpoint (video bitstream output at YOUT[0-7] parallel bus)
+
+Required Endpoint Properties for parallel synchronization on output port:
 
 - hsync-active: active state of the HSYNC signal. Must be <1> (HIGH).
 - vsync-active: active state of the VSYNC signal. Must be <1> (HIGH).
@@ -26,17 +47,94 @@ Required Endpoint Properties for parallel synchronization:
 If none of hsync-active, vsync-active and field-even-active is specified,
 the endpoint is assumed to use embedded BT.656 synchronization.
 
-Example:
+Example - three input sources:
+
+comp_connector_0 {
+	compatible = "composite-video-connector";
+	label = "Composite0";
+
+	port {
+		composite0_to_tvp5150: endpoint {
+			remote-endpoint = <&tvp5150_to_composite0>;
+		};
+	};
+};
+
+comp_connector_1 {
+	compatible = "composite-video-connector";
+	label = "Composite1";
+
+	port {
+		composite1_to_tvp5150: endpoint {
+			remote-endpoint = <&tvp5150_to_composite1>;
+		};
+	};
+};
+
+svideo_connector {
+	compatible = "svideo-connector";
+	label = "S-Video";
+
+	port {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		svideo_luma_to_tvp5150: endpoint@0 {
+			reg = <0>;
+			remote-endpoint = <&tvp5150_to_svideo_luma>;
+		};
+
+		svideo_chroma_to_tvp5150: endpoint@1 {
+			reg = <1>;
+			remote-endpoint = <&tvp5150_to_svideo_chroma>;
+		};
+	};
+};
 
 &i2c2 {
-	...
 	tvp5150@5c {
 		compatible = "ti,tvp5150";
 		reg = <0x5c>;
 		pdn-gpios = <&gpio4 30 GPIO_ACTIVE_LOW>;
 		reset-gpios = <&gpio6 7 GPIO_ACTIVE_LOW>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		port@0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+
+			tvp5150_to_composite0: endpoint@0 {
+				reg = <0>;
+				remote-endpoint = <&composite0_to_tvp5150>;
+			};
+
+			tvp5150_to_svideo_luma: endpoint@1 {
+				reg = <1>;
+				remote-endpoint = <&svideo_luma_to_tvp5150>;
+			};
+		};
+
+		port@1 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <1>;
+
+			tvp5150_to_composite1: endpoint@0 {
+				reg = <0>;
+                                remote-endpoint = <&composite1_to_tvp5150>;
+			};
+
+			tvp5150_to_svideo_chroma: endpoint@1 {
+				reg = <1>;
+				remote-endpoint = <&svideo_chroma_to_tvp5150>;
+			};
+		};
+
+		port@2 {
+			reg = <2>;
 
-		port {
 			tvp5150_1: endpoint {
 				remote-endpoint = <&ccdc_ep>;
 			};
-- 
2.20.1


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH v11 08/15] media: tvp5150: fix set_selection rectangle handling
  2019-09-30  9:38 [PATCH v11 00/15] TVP5150 Features and fixes Marco Felsch
                   ` (6 preceding siblings ...)
  2019-09-30  9:38 ` [PATCH v11 07/15] media: dt-bindings: tvp5150: Add input port connectors DT bindings Marco Felsch
@ 2019-09-30  9:38 ` Marco Felsch
  2019-09-30  9:38 ` [PATCH v11 09/15] media: tvp5150: add FORMAT_TRY support for get/set selection handlers Marco Felsch
                   ` (6 subsequent siblings)
  14 siblings, 0 replies; 22+ messages in thread
From: Marco Felsch @ 2019-09-30  9:38 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt,
	laurent.pinchart
  Cc: devicetree, kernel, linux-media

Currently a local copy of sel->r is made and adapted to the hardware
constraints. After the adaption the value is applied to the hardware but
the driver forgot to reflect the adapted value to the user space.

Drop the local copy and work directly on the requested rectangle
instead to fix this.

Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
---

v10:
- new patch
---
 drivers/media/i2c/tvp5150.c | 32 ++++++++++++++++----------------
 1 file changed, 16 insertions(+), 16 deletions(-)

diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
index d8325b6dbaee..3de935036a4e 100644
--- a/drivers/media/i2c/tvp5150.c
+++ b/drivers/media/i2c/tvp5150.c
@@ -1024,7 +1024,7 @@ static int tvp5150_set_selection(struct v4l2_subdev *sd,
 				 struct v4l2_subdev_selection *sel)
 {
 	struct tvp5150 *decoder = to_tvp5150(sd);
-	struct v4l2_rect rect = sel->r;
+	struct v4l2_rect *rect = &sel->r;
 	v4l2_std_id std;
 	int hmax;
 
@@ -1033,11 +1033,11 @@ static int tvp5150_set_selection(struct v4l2_subdev *sd,
 		return -EINVAL;
 
 	dev_dbg_lvl(sd->dev, 1, debug, "%s left=%d, top=%d, width=%d, height=%d\n",
-		__func__, rect.left, rect.top, rect.width, rect.height);
+		__func__, rect->left, rect->top, rect->width, rect->height);
 
 	/* tvp5150 has some special limits */
-	rect.left = clamp(rect.left, 0, TVP5150_MAX_CROP_LEFT);
-	rect.top = clamp(rect.top, 0, TVP5150_MAX_CROP_TOP);
+	rect->left = clamp(rect->left, 0, TVP5150_MAX_CROP_LEFT);
+	rect->top = clamp(rect->top, 0, TVP5150_MAX_CROP_TOP);
 
 	/* Calculate height based on current standard */
 	if (decoder->norm == V4L2_STD_ALL)
@@ -1055,26 +1055,26 @@ static int tvp5150_set_selection(struct v4l2_subdev *sd,
 	 *  - width = 2 due to UYVY colorspace
 	 *  - height, image = no special alignment
 	 */
-	v4l_bound_align_image(&rect.width,
-			      TVP5150_H_MAX - TVP5150_MAX_CROP_LEFT - rect.left,
-			      TVP5150_H_MAX - rect.left, 1, &rect.height,
-			      hmax - TVP5150_MAX_CROP_TOP - rect.top,
-			      hmax - rect.top, 0, 0);
+	v4l_bound_align_image(&rect->width,
+			      TVP5150_H_MAX - TVP5150_MAX_CROP_LEFT - rect->left,
+			      TVP5150_H_MAX - rect->left, 1, &rect->height,
+			      hmax - TVP5150_MAX_CROP_TOP - rect->top,
+			      hmax - rect->top, 0, 0);
 
-	regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_START, rect.top);
+	regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_START, rect->top);
 	regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_STOP,
-		     rect.top + rect.height - hmax);
+		     rect->top + rect->height - hmax);
 	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_ST_MSB,
-		     rect.left >> TVP5150_CROP_SHIFT);
+		     rect->left >> TVP5150_CROP_SHIFT);
 	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_ST_LSB,
-		     rect.left | (1 << TVP5150_CROP_SHIFT));
+		     rect->left | (1 << TVP5150_CROP_SHIFT));
 	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_STP_MSB,
-		     (rect.left + rect.width - TVP5150_MAX_CROP_LEFT) >>
+		     (rect->left + rect->width - TVP5150_MAX_CROP_LEFT) >>
 		     TVP5150_CROP_SHIFT);
 	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_STP_LSB,
-		     rect.left + rect.width - TVP5150_MAX_CROP_LEFT);
+		     rect->left + rect->width - TVP5150_MAX_CROP_LEFT);
 
-	decoder->rect = rect;
+	decoder->rect = *rect;
 
 	return 0;
 }
-- 
2.20.1


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH v11 09/15] media: tvp5150: add FORMAT_TRY support for get/set selection handlers
  2019-09-30  9:38 [PATCH v11 00/15] TVP5150 Features and fixes Marco Felsch
                   ` (7 preceding siblings ...)
  2019-09-30  9:38 ` [PATCH v11 08/15] media: tvp5150: fix set_selection rectangle handling Marco Felsch
@ 2019-09-30  9:38 ` Marco Felsch
  2019-09-30  9:38 ` [PATCH v11 10/15] media: tvp5150: initialize subdev before parsing device tree Marco Felsch
                   ` (5 subsequent siblings)
  14 siblings, 0 replies; 22+ messages in thread
From: Marco Felsch @ 2019-09-30  9:38 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt,
	laurent.pinchart
  Cc: devicetree, kernel, linux-media

Since commit 10d5509c8d50 ("[media] v4l2: remove g/s_crop from video ops")
the 'which' field for set/get_selection must be FORMAT_ACTIVE. There is
no way to try different selections. The patch adds a helper function to
select the correct selection memory space (sub-device file handle or
driver state) which will be set/returned.

The selection rectangle is updated if the format is FORMAT_ACTIVE and
the rectangle position and/or size differs from the current set
rectangle.

Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
---
Changelog:
v11:
- s/__tvp5150_get_pad_crop/tvp5150_get_pad_crop/
- s/__tvp5150_set_selection/tvp5150_set_hw_selection/
- drop inline for tvp5150_set_hw_selection
- fix allignment issue

v10:
- __tvp5150_get_pad_crop: drop confusing fall-through
- set_selection: fix FORMAT_TRY handling if CONFIG_VIDEO_V4L2_SUBDEV_API
                 is disabled. Adapt sel->r and return 0.
v8:
- adapt commit message
- remove wrong FORMAT_TRY handling for tvp5150_fill_fmt() handling
- return 0 during set_selection if FORMAT_TRY was requested and
  CONFIG_VIDEO_V4L2_SUBDEV_API is disabled
- return -EINVAL during get_selection if FORMAT_TRY was requested and
  CONFIG_VIDEO_V4L2_SUBDEV_API is disabled
v7:
- __tvp5150_get_pad_crop(): return error on default case
- simplify __tvp5150_get_pad_crop() error handling
- tvp5150_set_selection() squash __tvp5150_set_selection() execution
  conditions
v6:
nothing
v5:
 - handle stub for v4l2_subdev_get_try_crop() internal since commit
   ("media: v4l2-subdev: add stubs for v4l2_subdev_get_try_*")
   isn't anymore part of this series.
 - add error handling of __tvp5150_get_pad_crop()
v4:
 - fix merge conflict due to rebase on top of media-tree/master
 - __tvp5150_get_pad_crop(): cosmetic alignment fixes
---
 drivers/media/i2c/tvp5150.c | 113 ++++++++++++++++++++++++++----------
 1 file changed, 81 insertions(+), 32 deletions(-)

diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
index 3de935036a4e..69697c00dbd7 100644
--- a/drivers/media/i2c/tvp5150.c
+++ b/drivers/media/i2c/tvp5150.c
@@ -19,6 +19,7 @@
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-fwnode.h>
 #include <media/v4l2-mc.h>
+#include <media/v4l2-rect.h>
 
 #include "tvp5150_reg.h"
 
@@ -995,6 +996,25 @@ static void tvp5150_set_default(v4l2_std_id std, struct v4l2_rect *crop)
 		crop->height = TVP5150_V_MAX_OTHERS;
 }
 
+static struct v4l2_rect *
+tvp5150_get_pad_crop(struct tvp5150 *decoder,
+		     struct v4l2_subdev_pad_config *cfg, unsigned int pad,
+		     enum v4l2_subdev_format_whence which)
+{
+	switch (which) {
+	case V4L2_SUBDEV_FORMAT_ACTIVE:
+		return &decoder->rect;
+	case V4L2_SUBDEV_FORMAT_TRY:
+#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
+		return v4l2_subdev_get_try_crop(&decoder->sd, cfg, pad);
+#else
+		return ERR_PTR(-EINVAL);
+#endif
+	default:
+		return ERR_PTR(-EINVAL);
+	}
+}
+
 static int tvp5150_fill_fmt(struct v4l2_subdev *sd,
 			    struct v4l2_subdev_pad_config *cfg,
 			    struct v4l2_subdev_format *format)
@@ -1019,17 +1039,51 @@ static int tvp5150_fill_fmt(struct v4l2_subdev *sd,
 	return 0;
 }
 
+unsigned int tvp5150_get_hmax(struct v4l2_subdev *sd)
+{
+	struct tvp5150 *decoder = to_tvp5150(sd);
+	v4l2_std_id std;
+
+	/* Calculate height based on current standard */
+	if (decoder->norm == V4L2_STD_ALL)
+		std = tvp5150_read_std(sd);
+	else
+		std = decoder->norm;
+
+	return (std & V4L2_STD_525_60) ?
+		TVP5150_V_MAX_525_60 : TVP5150_V_MAX_OTHERS;
+}
+
+static void tvp5150_set_hw_selection(struct v4l2_subdev *sd,
+				     struct v4l2_rect *rect)
+{
+	struct tvp5150 *decoder = to_tvp5150(sd);
+	unsigned int hmax = tvp5150_get_hmax(sd);
+
+	regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_START, rect->top);
+	regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_STOP,
+		     rect->top + rect->height - hmax);
+	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_ST_MSB,
+		     rect->left >> TVP5150_CROP_SHIFT);
+	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_ST_LSB,
+		     rect->left | (1 << TVP5150_CROP_SHIFT));
+	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_STP_MSB,
+		     (rect->left + rect->width - TVP5150_MAX_CROP_LEFT) >>
+		     TVP5150_CROP_SHIFT);
+	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_STP_LSB,
+		     rect->left + rect->width - TVP5150_MAX_CROP_LEFT);
+}
+
 static int tvp5150_set_selection(struct v4l2_subdev *sd,
 				 struct v4l2_subdev_pad_config *cfg,
 				 struct v4l2_subdev_selection *sel)
 {
 	struct tvp5150 *decoder = to_tvp5150(sd);
 	struct v4l2_rect *rect = &sel->r;
-	v4l2_std_id std;
-	int hmax;
+	struct v4l2_rect *crop;
+	unsigned int hmax;
 
-	if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE ||
-	    sel->target != V4L2_SEL_TGT_CROP)
+	if (sel->target != V4L2_SEL_TGT_CROP)
 		return -EINVAL;
 
 	dev_dbg_lvl(sd->dev, 1, debug, "%s left=%d, top=%d, width=%d, height=%d\n",
@@ -1038,17 +1092,7 @@ static int tvp5150_set_selection(struct v4l2_subdev *sd,
 	/* tvp5150 has some special limits */
 	rect->left = clamp(rect->left, 0, TVP5150_MAX_CROP_LEFT);
 	rect->top = clamp(rect->top, 0, TVP5150_MAX_CROP_TOP);
-
-	/* Calculate height based on current standard */
-	if (decoder->norm == V4L2_STD_ALL)
-		std = tvp5150_read_std(sd);
-	else
-		std = decoder->norm;
-
-	if (std & V4L2_STD_525_60)
-		hmax = TVP5150_V_MAX_525_60;
-	else
-		hmax = TVP5150_V_MAX_OTHERS;
+	hmax = tvp5150_get_hmax(sd);
 
 	/*
 	 * alignments:
@@ -1061,20 +1105,23 @@ static int tvp5150_set_selection(struct v4l2_subdev *sd,
 			      hmax - TVP5150_MAX_CROP_TOP - rect->top,
 			      hmax - rect->top, 0, 0);
 
-	regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_START, rect->top);
-	regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_STOP,
-		     rect->top + rect->height - hmax);
-	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_ST_MSB,
-		     rect->left >> TVP5150_CROP_SHIFT);
-	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_ST_LSB,
-		     rect->left | (1 << TVP5150_CROP_SHIFT));
-	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_STP_MSB,
-		     (rect->left + rect->width - TVP5150_MAX_CROP_LEFT) >>
-		     TVP5150_CROP_SHIFT);
-	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_STP_LSB,
-		     rect->left + rect->width - TVP5150_MAX_CROP_LEFT);
+	if (!IS_ENABLED(CONFIG_VIDEO_V4L2_SUBDEV_API) &&
+	    sel->which == V4L2_SUBDEV_FORMAT_TRY)
+		return 0;
+
+	crop = tvp5150_get_pad_crop(decoder, cfg, sel->pad, sel->which);
+	if (IS_ERR(crop))
+		return PTR_ERR(crop);
+
+	/*
+	 * Update output image size if the selection (crop) rectangle size or
+	 * position has been modified.
+	 */
+	if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE &&
+	    !v4l2_rect_equal(rect, crop))
+		tvp5150_set_hw_selection(sd, rect);
 
-	decoder->rect = *rect;
+	*crop = *rect;
 
 	return 0;
 }
@@ -1084,11 +1131,9 @@ static int tvp5150_get_selection(struct v4l2_subdev *sd,
 				 struct v4l2_subdev_selection *sel)
 {
 	struct tvp5150 *decoder = container_of(sd, struct tvp5150, sd);
+	struct v4l2_rect *crop;
 	v4l2_std_id std;
 
-	if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
-		return -EINVAL;
-
 	switch (sel->target) {
 	case V4L2_SEL_TGT_CROP_BOUNDS:
 		sel->r.left = 0;
@@ -1106,7 +1151,11 @@ static int tvp5150_get_selection(struct v4l2_subdev *sd,
 			sel->r.height = TVP5150_V_MAX_OTHERS;
 		return 0;
 	case V4L2_SEL_TGT_CROP:
-		sel->r = decoder->rect;
+		crop = tvp5150_get_pad_crop(decoder, cfg, sel->pad,
+					    sel->which);
+		if (IS_ERR(crop))
+			return PTR_ERR(crop);
+		sel->r = *crop;
 		return 0;
 	default:
 		return -EINVAL;
-- 
2.20.1


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH v11 10/15] media: tvp5150: initialize subdev before parsing device tree
  2019-09-30  9:38 [PATCH v11 00/15] TVP5150 Features and fixes Marco Felsch
                   ` (8 preceding siblings ...)
  2019-09-30  9:38 ` [PATCH v11 09/15] media: tvp5150: add FORMAT_TRY support for get/set selection handlers Marco Felsch
@ 2019-09-30  9:38 ` Marco Felsch
  2019-09-30  9:38 ` [PATCH v11 11/15] media: tvp5150: add s_power callback Marco Felsch
                   ` (4 subsequent siblings)
  14 siblings, 0 replies; 22+ messages in thread
From: Marco Felsch @ 2019-09-30  9:38 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt,
	laurent.pinchart
  Cc: devicetree, kernel, linux-media, Michael Tretter

From: Michael Tretter <m.tretter@pengutronix.de>

There are several debug prints in the tvp5150_parse_dt() function, which
do not print the prefix, because the v4l2_subdev is not initialized, yet.

Initialize the v4l2_subdev before parsing the device tree to fix the
debug messages.

Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
---
 drivers/media/i2c/tvp5150.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
index 69697c00dbd7..dda9f0a2995f 100644
--- a/drivers/media/i2c/tvp5150.c
+++ b/drivers/media/i2c/tvp5150.c
@@ -1959,6 +1959,9 @@ static int tvp5150_probe(struct i2c_client *c)
 
 	core->regmap = map;
 	sd = &core->sd;
+	v4l2_i2c_subdev_init(sd, c, &tvp5150_ops);
+	sd->internal_ops = &tvp5150_internal_ops;
+	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
 
 	if (IS_ENABLED(CONFIG_OF) && np) {
 		res = tvp5150_parse_dt(core, np);
@@ -1971,10 +1974,6 @@ static int tvp5150_probe(struct i2c_client *c)
 		core->mbus_type = V4L2_MBUS_BT656;
 	}
 
-	v4l2_i2c_subdev_init(sd, c, &tvp5150_ops);
-	sd->internal_ops = &tvp5150_internal_ops;
-	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-
 	res = tvp5150_mc_init(core);
 	if (res)
 		return res;
-- 
2.20.1


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH v11 11/15] media: tvp5150: add s_power callback
  2019-09-30  9:38 [PATCH v11 00/15] TVP5150 Features and fixes Marco Felsch
                   ` (9 preceding siblings ...)
  2019-09-30  9:38 ` [PATCH v11 10/15] media: tvp5150: initialize subdev before parsing device tree Marco Felsch
@ 2019-09-30  9:38 ` Marco Felsch
  2019-10-24 11:59   ` Sakari Ailus
  2019-09-30  9:38 ` [PATCH v11 12/15] media: dt-bindings: tvp5150: cleanup bindings stlye Marco Felsch
                   ` (3 subsequent siblings)
  14 siblings, 1 reply; 22+ messages in thread
From: Marco Felsch @ 2019-09-30  9:38 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt,
	laurent.pinchart
  Cc: devicetree, kernel, linux-media

Don't en-/disable the interrupts during s_stream because someone can
disable the stream but wants to get informed if the stream is locked
again. So keep the interrupts enabled the whole time the pipeline is
opened.

Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
---
 drivers/media/i2c/tvp5150.c | 23 +++++++++++++++++------
 1 file changed, 17 insertions(+), 6 deletions(-)

diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
index dda9f0a2995f..4afe2093b950 100644
--- a/drivers/media/i2c/tvp5150.c
+++ b/drivers/media/i2c/tvp5150.c
@@ -1356,11 +1356,26 @@ static const struct media_entity_operations tvp5150_sd_media_ops = {
 /****************************************************************************
 			I2C Command
  ****************************************************************************/
+static int tvp5150_s_power(struct  v4l2_subdev *sd, int on)
+{
+	struct tvp5150 *decoder = to_tvp5150(sd);
+	unsigned int val = 0;
+
+	if (on)
+		val = TVP5150_INT_A_LOCK;
+
+	if (decoder->irq)
+		/* Enable / Disable lock interrupt */
+		regmap_update_bits(decoder->regmap, TVP5150_INT_ENABLE_REG_A,
+				   TVP5150_INT_A_LOCK, val);
+
+	return 0;
+}
 
 static int tvp5150_s_stream(struct v4l2_subdev *sd, int enable)
 {
 	struct tvp5150 *decoder = to_tvp5150(sd);
-	unsigned int mask, val = 0, int_val = 0;
+	unsigned int mask, val = 0;
 
 	mask = TVP5150_MISC_CTL_YCBCR_OE | TVP5150_MISC_CTL_SYNC_OE |
 	       TVP5150_MISC_CTL_CLOCK_OE;
@@ -1373,15 +1388,10 @@ static int tvp5150_s_stream(struct v4l2_subdev *sd, int enable)
 			val = decoder->lock ? decoder->oe : 0;
 		else
 			val = decoder->oe;
-		int_val = TVP5150_INT_A_LOCK;
 		v4l2_subdev_notify_event(&decoder->sd, &tvp5150_ev_fmt);
 	}
 
 	regmap_update_bits(decoder->regmap, TVP5150_MISC_CTL, mask, val);
-	if (decoder->irq)
-		/* Enable / Disable lock interrupt */
-		regmap_update_bits(decoder->regmap, TVP5150_INT_ENABLE_REG_A,
-				   TVP5150_INT_A_LOCK, int_val);
 
 	return 0;
 }
@@ -1580,6 +1590,7 @@ static const struct v4l2_subdev_core_ops tvp5150_core_ops = {
 	.g_register = tvp5150_g_register,
 	.s_register = tvp5150_s_register,
 #endif
+	.s_power = tvp5150_s_power,
 };
 
 static const struct v4l2_subdev_tuner_ops tvp5150_tuner_ops = {
-- 
2.20.1


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH v11 12/15] media: dt-bindings: tvp5150: cleanup bindings stlye
  2019-09-30  9:38 [PATCH v11 00/15] TVP5150 Features and fixes Marco Felsch
                   ` (10 preceding siblings ...)
  2019-09-30  9:38 ` [PATCH v11 11/15] media: tvp5150: add s_power callback Marco Felsch
@ 2019-09-30  9:38 ` Marco Felsch
  2019-09-30  9:38 ` [PATCH v11 13/15] media: dt-bindings: tvp5150: add optional sdtv standards documentation Marco Felsch
                   ` (2 subsequent siblings)
  14 siblings, 0 replies; 22+ messages in thread
From: Marco Felsch @ 2019-09-30  9:38 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt,
	laurent.pinchart
  Cc: devicetree, kernel, linux-media, Rob Herring

Use underlines to highlight optional and required properties. This is
quite common for all bindings. Align descriptions and start sentence
with uppercase letter. Also reword the usage of the required
endpoint properties for the output port in case BT.656 should be used.

Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
Reviewed-by: Rob Herring <robh@kernel.org>
---
 .../devicetree/bindings/media/i2c/tvp5150.txt | 30 +++++++++++--------
 1 file changed, 17 insertions(+), 13 deletions(-)

diff --git a/Documentation/devicetree/bindings/media/i2c/tvp5150.txt b/Documentation/devicetree/bindings/media/i2c/tvp5150.txt
index 28b64ad149ef..cc98b38c7e73 100644
--- a/Documentation/devicetree/bindings/media/i2c/tvp5150.txt
+++ b/Documentation/devicetree/bindings/media/i2c/tvp5150.txt
@@ -5,12 +5,14 @@ The TVP5150 and TVP5151 are video decoders that convert baseband NTSC and PAL
 with discrete syncs or 8-bit ITU-R BT.656 with embedded syncs output formats.
 
 Required Properties:
-- compatible: value must be "ti,tvp5150"
-- reg: I2C slave address
+====================
+- compatible:	Value must be "ti,tvp5150".
+- reg:		I2C slave address.
 
 Optional Properties:
-- pdn-gpios: phandle for the GPIO connected to the PDN pin, if any.
-- reset-gpios: phandle for the GPIO connected to the RESETB pin, if any.
+====================
+- pdn-gpios:	Phandle for the GPIO connected to the PDN pin, if any.
+- reset-gpios:	Phandle for the GPIO connected to the RESETB pin, if any.
 
 The device node must contain one 'port' child node per device physical input
 and output port, in accordance with the video interface bindings defined in
@@ -24,9 +26,8 @@ are numbered as follows
 	  Y-OUT		src		2
 
 The device node must contain at least one sink port and the src port. Each input
-port must be linked to an endpoint defined in
-Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt. The
-port/connector layout is as follows
+port must be linked to an endpoint defined in [1]. The port/connector layout is
+as follows
 
 tvp-5150 port@0 (AIP1A)
 	endpoint@0 -----------> Comp0-Con  port
@@ -38,14 +39,17 @@ tvp-5150 port@2
 	endpoint (video bitstream output at YOUT[0-7] parallel bus)
 
 Required Endpoint Properties for parallel synchronization on output port:
+=========================================================================
 
-- hsync-active: active state of the HSYNC signal. Must be <1> (HIGH).
-- vsync-active: active state of the VSYNC signal. Must be <1> (HIGH).
-- field-even-active: field signal level during the even field data
-  transmission. Must be <0>.
+- hsync-active:		Active state of the HSYNC signal. Must be <1> (HIGH).
+- vsync-active:		Active state of the VSYNC signal. Must be <1> (HIGH).
+- field-even-active:	Field signal level during the even field data
+			transmission. Must be <0>.
 
-If none of hsync-active, vsync-active and field-even-active is specified,
-the endpoint is assumed to use embedded BT.656 synchronization.
+Note: Do not specify any of these properties if you want to use the embedded
+      BT.656 synchronization.
+
+[1] Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt.
 
 Example - three input sources:
 
-- 
2.20.1


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH v11 13/15] media: dt-bindings: tvp5150: add optional sdtv standards documentation
  2019-09-30  9:38 [PATCH v11 00/15] TVP5150 Features and fixes Marco Felsch
                   ` (11 preceding siblings ...)
  2019-09-30  9:38 ` [PATCH v11 12/15] media: dt-bindings: tvp5150: cleanup bindings stlye Marco Felsch
@ 2019-09-30  9:38 ` Marco Felsch
  2019-09-30  9:38 ` [PATCH v11 14/15] media: tvp5150: add support to limit sdtv standards Marco Felsch
  2019-09-30  9:39 ` [PATCH v11 15/15] media: tvp5150: make debug output more readable Marco Felsch
  14 siblings, 0 replies; 22+ messages in thread
From: Marco Felsch @ 2019-09-30  9:38 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt,
	laurent.pinchart
  Cc: devicetree, kernel, linux-media, Rob Herring

Document the optional binding to limit the possible sdtv standards on the
input connectors.

Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
Reviewed-by: Rob Herring <robh@kernel.org>

v8:
- adapt to new sdtv-standards
- adapt commit message
- fix missing include within example code
---
 .../devicetree/bindings/media/i2c/tvp5150.txt          | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/Documentation/devicetree/bindings/media/i2c/tvp5150.txt b/Documentation/devicetree/bindings/media/i2c/tvp5150.txt
index cc98b38c7e73..f876b79c335f 100644
--- a/Documentation/devicetree/bindings/media/i2c/tvp5150.txt
+++ b/Documentation/devicetree/bindings/media/i2c/tvp5150.txt
@@ -49,13 +49,22 @@ Required Endpoint Properties for parallel synchronization on output port:
 Note: Do not specify any of these properties if you want to use the embedded
       BT.656 synchronization.
 
+Optional Connector Properties:
+==============================
+
+- sdtv-standards: Set the possible signals to which the hardware tries to lock
+                  instead of using the autodetection mechnism. Please look at
+                  [1] for more information.
+
 [1] Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt.
 
 Example - three input sources:
+#include <dt-bindings/display/sdtv-standards.h>
 
 comp_connector_0 {
 	compatible = "composite-video-connector";
 	label = "Composite0";
+	sdtv-standards = <TVNORM_PAL_M>; /* limit to pal-m signals */
 
 	port {
 		composite0_to_tvp5150: endpoint {
@@ -67,6 +76,7 @@ comp_connector_0 {
 comp_connector_1 {
 	compatible = "composite-video-connector";
 	label = "Composite1";
+	sdtv-standards = <TVNORM_NTSC_M>; /* limit to ntsc-m signals */
 
 	port {
 		composite1_to_tvp5150: endpoint {
-- 
2.20.1


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH v11 14/15] media: tvp5150: add support to limit sdtv standards
  2019-09-30  9:38 [PATCH v11 00/15] TVP5150 Features and fixes Marco Felsch
                   ` (12 preceding siblings ...)
  2019-09-30  9:38 ` [PATCH v11 13/15] media: dt-bindings: tvp5150: add optional sdtv standards documentation Marco Felsch
@ 2019-09-30  9:38 ` Marco Felsch
  2019-09-30  9:39 ` [PATCH v11 15/15] media: tvp5150: make debug output more readable Marco Felsch
  14 siblings, 0 replies; 22+ messages in thread
From: Marco Felsch @ 2019-09-30  9:38 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt,
	laurent.pinchart
  Cc: devicetree, kernel, linux-media

The tvp5150 accepts NTSC(M,J,4.43), PAL (B,D,G,H,I,M,N) and SECAM video
data and is able to auto-detect the input signal. The auto-detection
does not work if the connector does not receive an input signal and the
tvp5150 might not be configured correctly. This misconfiguration leads
into wrong decoded video streams if the tvp5150 gets powered on before
the video signal is present.

Limit the supported sdtv standards according to the actual selected
connector to avoid a misconfiguration.

Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
---
[1] https://patchwork.kernel.org/cover/10794703/

v11:
- address 80 character warnings by:
  - use struct v4l2_fwnode_connector *v4lc
  - add truct v4l2_fwnode_connector_analog *v4lca

v8:
- adapt commit message
- fix rebasing issue
- apdapt to new v4l2_fwnode_connector_analog naming
- fix cur_connector update during tvp5150_link_setup()
  -> Only update if we have of-connectors.
- fix supported_stds detection during tvp5150_s_std()
  -> use connectors_num to detect of-connectors presence

v5:
- probe() initialize supported tv-norms according the given connectors
  if they are available.
- check if media-controller is used. Don't limit the norm if it isn't
  used.
- add more logic to be smarter during connector changing so it is
  intuitiver for the user space.

v2-v4:
- nothing since the patch was squashed from series [1] into this
  series.
---
 drivers/media/i2c/tvp5150.c | 77 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 75 insertions(+), 2 deletions(-)

diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
index 4afe2093b950..94eabfadf9fa 100644
--- a/drivers/media/i2c/tvp5150.c
+++ b/drivers/media/i2c/tvp5150.c
@@ -32,6 +32,13 @@
 #define TVP5150_MBUS_FMT	MEDIA_BUS_FMT_UYVY8_2X8
 #define TVP5150_FIELD		V4L2_FIELD_ALTERNATE
 #define TVP5150_COLORSPACE	V4L2_COLORSPACE_SMPTE170M
+#define TVP5150_STD_MASK	(V4L2_STD_NTSC     | \
+				 V4L2_STD_NTSC_443 | \
+				 V4L2_STD_PAL      | \
+				 V4L2_STD_PAL_M    | \
+				 V4L2_STD_PAL_N    | \
+				 V4L2_STD_PAL_Nc   | \
+				 V4L2_STD_SECAM)
 
 #define TVP5150_MAX_CONNECTORS	3 /* Check dt-bindings for more information */
 
@@ -64,6 +71,7 @@ struct tvp5150 {
 
 	struct media_pad pads[TVP5150_NUM_PADS];
 	struct tvp5150_connector connectors[TVP5150_MAX_CONNECTORS];
+	struct tvp5150_connector *cur_connector;
 	unsigned int connectors_num;
 
 	struct v4l2_ctrl_handler hdl;
@@ -783,17 +791,33 @@ static int tvp5150_g_std(struct v4l2_subdev *sd, v4l2_std_id *std)
 static int tvp5150_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
 {
 	struct tvp5150 *decoder = to_tvp5150(sd);
+	struct tvp5150_connector *cur_con = decoder->cur_connector;
+	v4l2_std_id supported_stds;
 
 	if (decoder->norm == std)
 		return 0;
 
+	/* In case of no of-connectors are available no limitations are made */
+	if (!decoder->connectors_num)
+		supported_stds = V4L2_STD_ALL;
+	else
+		supported_stds = cur_con->base.connector.analog.sdtv_stds;
+
+	/*
+	 * Check if requested std or group of std's is/are supported by the
+	 * connector.
+	 */
+	if ((supported_stds & std) == 0)
+		return -EINVAL;
+
 	/* Change cropping height limits */
 	if (std & V4L2_STD_525_60)
 		decoder->rect.height = TVP5150_V_MAX_525_60;
 	else
 		decoder->rect.height = TVP5150_V_MAX_OTHERS;
 
-	decoder->norm = std;
+	/* Set only the specific supported std in case of group of std's. */
+	decoder->norm = supported_stds & std;
 
 	return tvp5150_set_std(sd, std);
 }
@@ -1333,6 +1357,10 @@ static int tvp5150_link_setup(struct media_entity *entity,
 			  TVP5150_BLACK_SCREEN, 0);
 
 	if (flags & MEDIA_LNK_FL_ENABLED) {
+		u32 new_norm;
+		struct v4l2_fwnode_connector_analog *v4lca =
+			&decoder->cur_connector->base.connector.analog;
+
 		/*
 		 * S-Video connector is conneted to both ports AIP1A and AIP1B.
 		 * Both links must be enabled in one-shot regardless which link
@@ -1344,6 +1372,27 @@ static int tvp5150_link_setup(struct media_entity *entity,
 			if (err)
 				return err;
 		}
+
+		if (!decoder->connectors_num)
+			return 0;
+
+		/* Update the current connector */
+		decoder->cur_connector =
+			container_of(remote, struct tvp5150_connector, pad);
+
+		/*
+		 * Do nothing if the new connector supports the same tv-norms as
+		 * the old one.
+		 */
+		new_norm = decoder->norm & v4lca->sdtv_stds;
+		if (decoder->norm == new_norm)
+			return 0;
+
+		/*
+		 * Fallback to the new connector tv-norms if we can't find any
+		 * common between the current tv-norm and the new one.
+		 */
+		tvp5150_s_std(sd, new_norm ? new_norm : v4lca->sdtv_stds);
 	}
 
 	return 0;
@@ -1563,6 +1612,8 @@ static int tvp5150_registered(struct v4l2_subdev *sd)
 				TVP5150_COMPOSITE1;
 
 			tvp5150_selmux(sd);
+			decoder->cur_connector = &decoder->connectors[i];
+			tvp5150_s_std(sd, v4lc->connector.analog.sdtv_stds);
 		}
 	}
 
@@ -1852,6 +1903,13 @@ tvp5150_add_connector(struct tvp5150 *decoder, struct device_node *np,
 		goto err;
 	}
 
+	if (!(vc->connector.analog.sdtv_stds & TVP5150_STD_MASK)) {
+		dev_err(dev, "Unsupported tv-norm on connector %s\n",
+			remote_np->name);
+		ret = -EINVAL;
+		goto err;
+	}
+
 	c->ent.flags = MEDIA_ENT_FL_CONNECTOR;
 	c->ent.name = vc->label;
 	c->ent.name = kasprintf(GFP_KERNEL, "%s %s", remote_np->name,
@@ -1949,6 +2007,7 @@ static int tvp5150_probe(struct i2c_client *c)
 	struct v4l2_subdev *sd;
 	struct device_node *np = c->dev.of_node;
 	struct regmap *map;
+	unsigned int i;
 	int res;
 
 	/* Check if the adapter supports the needed features */
@@ -1993,7 +2052,21 @@ static int tvp5150_probe(struct i2c_client *c)
 	if (res < 0)
 		return res;
 
-	core->norm = V4L2_STD_ALL;	/* Default is autodetect */
+	/*
+	 * Iterate over all available connectors in case they are supported and
+	 * successfully parsed. Fallback to default autodetect in case they
+	 * aren't supported.
+	 */
+	for (i = 0; i < core->connectors_num; i++) {
+		struct v4l2_fwnode_connector *vc;
+
+		vc = &core->connectors[i].base;
+		core->norm |= vc->connector.analog.sdtv_stds;
+	}
+
+	if (!core->connectors_num)
+		core->norm = V4L2_STD_ALL;
+
 	core->detected_norm = V4L2_STD_UNKNOWN;
 	core->input = TVP5150_COMPOSITE1;
 	core->enable = true;
-- 
2.20.1


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH v11 15/15] media: tvp5150: make debug output more readable
  2019-09-30  9:38 [PATCH v11 00/15] TVP5150 Features and fixes Marco Felsch
                   ` (13 preceding siblings ...)
  2019-09-30  9:38 ` [PATCH v11 14/15] media: tvp5150: add support to limit sdtv standards Marco Felsch
@ 2019-09-30  9:39 ` Marco Felsch
  14 siblings, 0 replies; 22+ messages in thread
From: Marco Felsch @ 2019-09-30  9:39 UTC (permalink / raw)
  To: mchehab, sakari.ailus, hans.verkuil, jacopo+renesas, robh+dt,
	laurent.pinchart
  Cc: devicetree, kernel, linux-media, Jacopo Mondi

The debug output for tvp5150_selmux() isn't really intuitive. Register
values are printed decimal formatted and the input/output driver states
are printed as enum. Even more the "normal" output enum mapps to zero so
a active output will printing output=0 and a inactive output=1.

Change this by brinting the register values hex formatted and the states
as more readable string.

Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
---
 drivers/media/i2c/tvp5150.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
index 94eabfadf9fa..60c23f5b1ffd 100644
--- a/drivers/media/i2c/tvp5150.c
+++ b/drivers/media/i2c/tvp5150.c
@@ -300,9 +300,12 @@ static void tvp5150_selmux(struct v4l2_subdev *sd)
 		break;
 	}
 
-	dev_dbg_lvl(sd->dev, 1, debug, "Selecting video route: route input=%i, output=%i => tvp5150 input=%i, opmode=%i\n",
-			decoder->input, decoder->output,
-			input, opmode);
+	dev_dbg_lvl(sd->dev, 1, debug,
+		    "Selecting video route: route input=%s, output=%s => tvp5150 input=0x%02x, opmode=0x%02x\n",
+		    decoder->input == 0 ? "aip1a" :
+		    decoder->input == 2 ? "aip1b" : "svideo",
+		    decoder->output == 0 ? "normal" : "black-frame-gen",
+		    input, opmode);
 
 	regmap_write(decoder->regmap, TVP5150_OP_MODE_CTL, opmode);
 	regmap_write(decoder->regmap, TVP5150_VD_IN_SRC_SEL_1, input);
-- 
2.20.1


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v11 11/15] media: tvp5150: add s_power callback
  2019-09-30  9:38 ` [PATCH v11 11/15] media: tvp5150: add s_power callback Marco Felsch
@ 2019-10-24 11:59   ` Sakari Ailus
  2019-11-08 10:25     ` Marco Felsch
  0 siblings, 1 reply; 22+ messages in thread
From: Sakari Ailus @ 2019-10-24 11:59 UTC (permalink / raw)
  To: Marco Felsch
  Cc: mchehab, hans.verkuil, jacopo+renesas, robh+dt, laurent.pinchart,
	devicetree, kernel, linux-media

Hi Marco,

On Mon, Sep 30, 2019 at 11:38:56AM +0200, Marco Felsch wrote:
> Don't en-/disable the interrupts during s_stream because someone can
> disable the stream but wants to get informed if the stream is locked
> again. So keep the interrupts enabled the whole time the pipeline is
> opened.
> 
> Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> ---
>  drivers/media/i2c/tvp5150.c | 23 +++++++++++++++++------
>  1 file changed, 17 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
> index dda9f0a2995f..4afe2093b950 100644
> --- a/drivers/media/i2c/tvp5150.c
> +++ b/drivers/media/i2c/tvp5150.c
> @@ -1356,11 +1356,26 @@ static const struct media_entity_operations tvp5150_sd_media_ops = {
>  /****************************************************************************
>  			I2C Command
>   ****************************************************************************/
> +static int tvp5150_s_power(struct  v4l2_subdev *sd, int on)
> +{
> +	struct tvp5150 *decoder = to_tvp5150(sd);
> +	unsigned int val = 0;
> +
> +	if (on)
> +		val = TVP5150_INT_A_LOCK;
> +
> +	if (decoder->irq)
> +		/* Enable / Disable lock interrupt */
> +		regmap_update_bits(decoder->regmap, TVP5150_INT_ENABLE_REG_A,
> +				   TVP5150_INT_A_LOCK, val);

Could you use runtime PM to do this instead?

> +
> +	return 0;
> +}
>  
>  static int tvp5150_s_stream(struct v4l2_subdev *sd, int enable)
>  {
>  	struct tvp5150 *decoder = to_tvp5150(sd);
> -	unsigned int mask, val = 0, int_val = 0;
> +	unsigned int mask, val = 0;
>  
>  	mask = TVP5150_MISC_CTL_YCBCR_OE | TVP5150_MISC_CTL_SYNC_OE |
>  	       TVP5150_MISC_CTL_CLOCK_OE;
> @@ -1373,15 +1388,10 @@ static int tvp5150_s_stream(struct v4l2_subdev *sd, int enable)
>  			val = decoder->lock ? decoder->oe : 0;
>  		else
>  			val = decoder->oe;
> -		int_val = TVP5150_INT_A_LOCK;
>  		v4l2_subdev_notify_event(&decoder->sd, &tvp5150_ev_fmt);
>  	}
>  
>  	regmap_update_bits(decoder->regmap, TVP5150_MISC_CTL, mask, val);
> -	if (decoder->irq)
> -		/* Enable / Disable lock interrupt */
> -		regmap_update_bits(decoder->regmap, TVP5150_INT_ENABLE_REG_A,
> -				   TVP5150_INT_A_LOCK, int_val);
>  
>  	return 0;
>  }
> @@ -1580,6 +1590,7 @@ static const struct v4l2_subdev_core_ops tvp5150_core_ops = {
>  	.g_register = tvp5150_g_register,
>  	.s_register = tvp5150_s_register,
>  #endif
> +	.s_power = tvp5150_s_power,
>  };
>  
>  static const struct v4l2_subdev_tuner_ops tvp5150_tuner_ops = {
> -- 
> 2.20.1
> 

-- 
Sakari Ailus
sakari.ailus@linux.intel.com

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v11 11/15] media: tvp5150: add s_power callback
  2019-10-24 11:59   ` Sakari Ailus
@ 2019-11-08 10:25     ` Marco Felsch
  2019-11-08 10:38       ` Sakari Ailus
  0 siblings, 1 reply; 22+ messages in thread
From: Marco Felsch @ 2019-11-08 10:25 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: mchehab, hans.verkuil, jacopo+renesas, robh+dt, laurent.pinchart,
	devicetree, kernel, linux-media

Hi Sakari,

On 19-10-24 14:59, Sakari Ailus wrote:
> Hi Marco,
> 
> On Mon, Sep 30, 2019 at 11:38:56AM +0200, Marco Felsch wrote:
> > Don't en-/disable the interrupts during s_stream because someone can
> > disable the stream but wants to get informed if the stream is locked
> > again. So keep the interrupts enabled the whole time the pipeline is
> > opened.
> > 
> > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > ---
> >  drivers/media/i2c/tvp5150.c | 23 +++++++++++++++++------
> >  1 file changed, 17 insertions(+), 6 deletions(-)
> > 
> > diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
> > index dda9f0a2995f..4afe2093b950 100644
> > --- a/drivers/media/i2c/tvp5150.c
> > +++ b/drivers/media/i2c/tvp5150.c
> > @@ -1356,11 +1356,26 @@ static const struct media_entity_operations tvp5150_sd_media_ops = {
> >  /****************************************************************************
> >  			I2C Command
> >   ****************************************************************************/
> > +static int tvp5150_s_power(struct  v4l2_subdev *sd, int on)
> > +{
> > +	struct tvp5150 *decoder = to_tvp5150(sd);
> > +	unsigned int val = 0;
> > +
> > +	if (on)
> > +		val = TVP5150_INT_A_LOCK;
> > +
> > +	if (decoder->irq)
> > +		/* Enable / Disable lock interrupt */
> > +		regmap_update_bits(decoder->regmap, TVP5150_INT_ENABLE_REG_A,
> > +				   TVP5150_INT_A_LOCK, val);
> 
> Could you use runtime PM to do this instead?

You mean I should add a simple runtime_resume/suspend() which is called
during v4l2_subdev_internal_ops.open/close()? Of course I can do that
but why?

Regards,
  Marco

> > +
> > +	return 0;
> > +}
> >  
> >  static int tvp5150_s_stream(struct v4l2_subdev *sd, int enable)
> >  {
> >  	struct tvp5150 *decoder = to_tvp5150(sd);
> > -	unsigned int mask, val = 0, int_val = 0;
> > +	unsigned int mask, val = 0;
> >  
> >  	mask = TVP5150_MISC_CTL_YCBCR_OE | TVP5150_MISC_CTL_SYNC_OE |
> >  	       TVP5150_MISC_CTL_CLOCK_OE;
> > @@ -1373,15 +1388,10 @@ static int tvp5150_s_stream(struct v4l2_subdev *sd, int enable)
> >  			val = decoder->lock ? decoder->oe : 0;
> >  		else
> >  			val = decoder->oe;
> > -		int_val = TVP5150_INT_A_LOCK;
> >  		v4l2_subdev_notify_event(&decoder->sd, &tvp5150_ev_fmt);
> >  	}
> >  
> >  	regmap_update_bits(decoder->regmap, TVP5150_MISC_CTL, mask, val);
> > -	if (decoder->irq)
> > -		/* Enable / Disable lock interrupt */
> > -		regmap_update_bits(decoder->regmap, TVP5150_INT_ENABLE_REG_A,
> > -				   TVP5150_INT_A_LOCK, int_val);
> >  
> >  	return 0;
> >  }
> > @@ -1580,6 +1590,7 @@ static const struct v4l2_subdev_core_ops tvp5150_core_ops = {
> >  	.g_register = tvp5150_g_register,
> >  	.s_register = tvp5150_s_register,
> >  #endif
> > +	.s_power = tvp5150_s_power,
> >  };
> >  
> >  static const struct v4l2_subdev_tuner_ops tvp5150_tuner_ops = {
> > -- 
> > 2.20.1
> > 
> 
> -- 
> Sakari Ailus
> sakari.ailus@linux.intel.com
> 

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v11 11/15] media: tvp5150: add s_power callback
  2019-11-08 10:25     ` Marco Felsch
@ 2019-11-08 10:38       ` Sakari Ailus
  0 siblings, 0 replies; 22+ messages in thread
From: Sakari Ailus @ 2019-11-08 10:38 UTC (permalink / raw)
  To: Marco Felsch
  Cc: mchehab, hans.verkuil, jacopo+renesas, robh+dt, laurent.pinchart,
	devicetree, kernel, linux-media

Hi Marco,

On Fri, Nov 08, 2019 at 11:25:02AM +0100, Marco Felsch wrote:
> Hi Sakari,
> 
> On 19-10-24 14:59, Sakari Ailus wrote:
> > Hi Marco,
> > 
> > On Mon, Sep 30, 2019 at 11:38:56AM +0200, Marco Felsch wrote:
> > > Don't en-/disable the interrupts during s_stream because someone can
> > > disable the stream but wants to get informed if the stream is locked
> > > again. So keep the interrupts enabled the whole time the pipeline is
> > > opened.
> > > 
> > > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > > ---
> > >  drivers/media/i2c/tvp5150.c | 23 +++++++++++++++++------
> > >  1 file changed, 17 insertions(+), 6 deletions(-)
> > > 
> > > diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
> > > index dda9f0a2995f..4afe2093b950 100644
> > > --- a/drivers/media/i2c/tvp5150.c
> > > +++ b/drivers/media/i2c/tvp5150.c
> > > @@ -1356,11 +1356,26 @@ static const struct media_entity_operations tvp5150_sd_media_ops = {
> > >  /****************************************************************************
> > >  			I2C Command
> > >   ****************************************************************************/
> > > +static int tvp5150_s_power(struct  v4l2_subdev *sd, int on)
> > > +{
> > > +	struct tvp5150 *decoder = to_tvp5150(sd);
> > > +	unsigned int val = 0;
> > > +
> > > +	if (on)
> > > +		val = TVP5150_INT_A_LOCK;
> > > +
> > > +	if (decoder->irq)
> > > +		/* Enable / Disable lock interrupt */
> > > +		regmap_update_bits(decoder->regmap, TVP5150_INT_ENABLE_REG_A,
> > > +				   TVP5150_INT_A_LOCK, val);
> > 
> > Could you use runtime PM to do this instead?
> 
> You mean I should add a simple runtime_resume/suspend() which is called
> during v4l2_subdev_internal_ops.open/close()? Of course I can do that
> but why?

There's no reason to use generic mechanisms that have been around for ten
or so years. Eventually the s_power() op will be dropped.

-- 
Sakari Ailus

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v11 04/15] media: v4l2-fwnode: add initial connector parsing support
  2019-09-30  9:38 ` [PATCH v11 04/15] media: v4l2-fwnode: add initial connector parsing support Marco Felsch
@ 2019-11-15 23:34   ` Sakari Ailus
  2019-11-19 11:37     ` Marco Felsch
  0 siblings, 1 reply; 22+ messages in thread
From: Sakari Ailus @ 2019-11-15 23:34 UTC (permalink / raw)
  To: Marco Felsch
  Cc: mchehab, hans.verkuil, jacopo+renesas, robh+dt, laurent.pinchart,
	devicetree, kernel, linux-media

Hi Marco,

On Mon, Sep 30, 2019 at 11:38:49AM +0200, Marco Felsch wrote:
> The patch adds the initial connector parsing code, so we can move from a
> driver specific parsing code to a generic one. Currently only the
> generic fields and the analog-connector specific fields are parsed. Parsing
> the other connector specific fields can be added by a simple callbacks.
> 
> Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> ---
> [1] https://patchwork.kernel.org/cover/10794703/
> 
> v10:
> - drop V4L2_CONN_HDMI support
> - adapt pr_err msg to reflect new state (-> connector is unkown)
> 
> v9:
> - Fix leading semicolon found by kbuild semicolon.cocci
> 
> v8:
> - V4L2_CON_* -> V4L2_CONN_*
> - tvnorms -> sdtv-standards
> - adapt to new v4l2_fwnode_connector_analog member
> - return error in case of V4L2_CONN_HDMI
> 
> v7:
> @Jacopo: I dropped your r b tag becuase of the amount of changes I
> made..
> 
> - drop unnecessary comments
> - fix commet style
> - s/v4l2_fwnode_connector_conv.name/v4l2_fwnode_connector_conv.compatible/
> - make label size variable and drop V4L2_CONNECTOR_MAX_LABEL usage
> - do not assign a default label in case of no label was specified
> - remove useless /* fall through */ comments
> - add support for N connector links
> - rename local variables to be more meaningful
> - adjust kernedoc
> - add v4l2_fwnode_connector_free()
> - improve error handling (use different error values)
> - make use of pr_warn_once()
> 
> v6:
> - use unsigned count var
> - fix comment and style issues
> - place '/* fall through */' to correct places
> - fix error handling and cleanup by releasing fwnode
> - drop vga and dvi parsing support as those connectors are rarely used
>   these days
> 
> v5:
> - s/strlcpy/strscpy/
> 
> v2-v4:
> - nothing since the patch was squashed from series [1] into this
>   series.
> ---
>  drivers/media/v4l2-core/v4l2-fwnode.c | 129 ++++++++++++++++++++++++++
>  include/media/v4l2-fwnode.h           |  38 ++++++++
>  2 files changed, 167 insertions(+)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
> index 3bd1888787eb..0bfa7cbf78df 100644
> --- a/drivers/media/v4l2-core/v4l2-fwnode.c
> +++ b/drivers/media/v4l2-core/v4l2-fwnode.c
> @@ -595,6 +595,135 @@ void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link)
>  }
>  EXPORT_SYMBOL_GPL(v4l2_fwnode_put_link);
>  
> +static const struct v4l2_fwnode_connector_conv {
> +	enum v4l2_connector_type type;
> +	const char *compatible;
> +} connectors[] = {
> +	{
> +		.type = V4L2_CONN_COMPOSITE,
> +		.compatible = "composite-video-connector",
> +	}, {
> +		.type = V4L2_CONN_SVIDEO,
> +		.compatible = "svideo-connector",
> +	},
> +};
> +
> +static enum v4l2_connector_type
> +v4l2_fwnode_string_to_connector_type(const char *con_str)
> +{
> +	unsigned int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(connectors); i++)
> +		if (!strcmp(con_str, connectors[i].compatible))
> +			return connectors[i].type;
> +
> +	return V4L2_CONN_UNKNOWN;
> +}
> +
> +static int
> +v4l2_fwnode_connector_parse_analog(struct fwnode_handle *fwnode,
> +				   struct v4l2_fwnode_connector *vc)
> +{
> +	u32 stds;
> +	int ret;
> +
> +	ret = fwnode_property_read_u32(fwnode, "sdtv-standards", &stds);
> +
> +	/* The property is optional. */
> +	vc->connector.analog.sdtv_stds = ret ? V4L2_STD_ALL : stds;
> +
> +	return 0;
> +}
> +
> +void v4l2_fwnode_connector_free(struct v4l2_fwnode_connector *connector)
> +{
> +	unsigned int i;
> +
> +	if (IS_ERR_OR_NULL(connector))
> +		return;
> +
> +	for (i = 0; i < connector->nr_of_links; i++)
> +		v4l2_fwnode_put_link(&connector->links[i]);
> +	kfree(connector->links);

Please do set connector->links NULL here. That avoids accidentally double
kfree on the pointer.

> +}
> +EXPORT_SYMBOL_GPL(v4l2_fwnode_connector_free);
> +
> +int v4l2_fwnode_connector_alloc_parse(struct fwnode_handle *fwnode,
> +				      struct v4l2_fwnode_connector *connector)
> +{
> +	struct fwnode_handle *remote_pp, *remote_ep;
> +	const char *type_name;
> +	unsigned int i = 0, ep_num = 0;
> +	int err;
> +
> +	memset(connector, 0, sizeof(*connector));
> +
> +	remote_pp = fwnode_graph_get_remote_port_parent(fwnode);
> +	if (!remote_pp)
> +		return -ENOLINK;
> +
> +	/* Parse all common properties first. */
> +	fwnode_graph_for_each_endpoint(remote_pp, remote_ep)
> +		ep_num++;

If there are no endpoints, ep_num will be zero and kmalloc_array() will
return NULL? There should be a way there are no endpoints, rather than
returning -ENOMEM.

> +
> +	connector->nr_of_links = ep_num;
> +	connector->links = kmalloc_array(ep_num, sizeof(*connector->links),
> +					 GFP_KERNEL);
> +	if (!connector->links) {
> +		err = -ENOMEM;
> +		goto err_put_fwnode;
> +	}
> +
> +	fwnode_graph_for_each_endpoint(remote_pp, remote_ep) {
> +		err = v4l2_fwnode_parse_link(remote_ep, &connector->links[i]);

If you start parsing a connector starting from another device connected to
it, nothing seems to prevent parsing the same links twice, in case the
connector is connected to more than one sub-device.

Or do I miss something crucial here?

> +		if (err) {
> +			fwnode_handle_put(remote_ep);
> +			goto err_free_links;
> +		}
> +		i++;
> +	}
> +
> +	/*
> +	 * Links reference counting guarantees access -> no duplication needed
> +	 */
> +	fwnode_property_read_string(remote_pp, "label", &connector->label);
> +
> +	/* The connector-type is stored within the compatible string. */
> +	err = fwnode_property_read_string(remote_pp, "compatible", &type_name);
> +	if (err) {
> +		err = -EINVAL;
> +		goto err_free_links;
> +	}
> +	connector->type = v4l2_fwnode_string_to_connector_type(type_name);
> +
> +	/* Now parse the connector specific properties. */
> +	switch (connector->type) {
> +	case V4L2_CONN_COMPOSITE:
> +	case V4L2_CONN_SVIDEO:
> +		err = v4l2_fwnode_connector_parse_analog(remote_pp, connector);
> +		break;
> +	case V4L2_CONN_UNKNOWN:
> +	default:
> +		pr_err("Unknown connector type\n");
> +		err = -EINVAL;
> +		goto err_free_links;
> +	}
> +
> +	fwnode_handle_put(remote_pp);
> +
> +	return err;
> +
> +err_free_links:
> +	for (i = 0; i < ep_num; i++)
> +		v4l2_fwnode_put_link(&connector->links[i]);
> +	kfree(connector->links);
> +err_put_fwnode:
> +	fwnode_handle_put(remote_pp);
> +
> +	return err;
> +}
> +EXPORT_SYMBOL_GPL(v4l2_fwnode_connector_alloc_parse);
> +
>  static int
>  v4l2_async_notifier_fwnode_parse_endpoint(struct device *dev,
>  					  struct v4l2_async_notifier *notifier,
> diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
> index 65da646b579e..800302aa84d8 100644
> --- a/include/media/v4l2-fwnode.h
> +++ b/include/media/v4l2-fwnode.h
> @@ -276,6 +276,44 @@ int v4l2_fwnode_parse_link(struct fwnode_handle *fwnode,
>   */
>  void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link);
>  
> +/**
> + * v4l2_fwnode_connector_free() - free the V4L2 connector acquired by
> + * v4l2_fwnode_parse_connector()

This would be nicer aligned with the text after the dash.

> + * @connector: the V4L2 connector the resources of which are to be released
> + *
> + * Drop references to the connection link partners and free the memory allocated
> + * by v4l2_fwnode_parse_connector() call.
> + *
> + * It is safe to call this function with NULL argument or on a V4L2 connector
> + * the parsing of which failed.
> + */
> +void v4l2_fwnode_connector_free(struct v4l2_fwnode_connector *connector);
> +
> +/**
> + * v4l2_fwnode_parse_connector() - parse the connector on endpoint

The name is different from the actual function.

> + * @fwnode: pointer to the endpoint's fwnode handle where the connector is
> + *          connected to
> + * @connector: pointer to the V4L2 fwnode connector data structure
> + *
> + * Fill the connector data structure with the connector type, label, all found
> + * links between the host and the connector as well as connector specific data.
> + * Since the label is optional it can be %NULL if no one was found.
> + *
> + * A reference is taken to both the connector and the connector destination
> + * where the connector belongs to. This must be dropped when no longer needed.
> + * Also the memory it has allocated to store the variable size data must be
> + * freed. Both dropping the references and freeing the memory is done by
> + * v4l2_fwnode_connector_free().
> + *
> + * Return:
> + * * %0 on success or a negative error code on failure:
> + * * %-ENOMEM if memory allocation failed
> + * * %-ENOLINK if the connector can't be found
> + * * %-EINVAL on parsing failure

Could this error code tell the endpoint is not connected to a connector?

I think the perfectly suitable error code for this would be -ENOTCONN. :-D

> + */
> +int v4l2_fwnode_connector_alloc_parse(struct fwnode_handle *fwnode,
> +				      struct v4l2_fwnode_connector *connector);
> +
>  /**
>   * typedef parse_endpoint_func - Driver's callback function to be called on
>   *	each V4L2 fwnode endpoint.
> 

-- 
Regards,

Sakari Ailus
sakari.ailus@linux.intel.com

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v11 04/15] media: v4l2-fwnode: add initial connector parsing support
  2019-11-15 23:34   ` Sakari Ailus
@ 2019-11-19 11:37     ` Marco Felsch
  2019-11-27  8:17       ` Marco Felsch
  0 siblings, 1 reply; 22+ messages in thread
From: Marco Felsch @ 2019-11-19 11:37 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: mchehab, hans.verkuil, jacopo+renesas, robh+dt, laurent.pinchart,
	devicetree, kernel, linux-media

Hi Sakari,

On 19-11-16 01:34, Sakari Ailus wrote:
> Hi Marco,
> 
> On Mon, Sep 30, 2019 at 11:38:49AM +0200, Marco Felsch wrote:
> > The patch adds the initial connector parsing code, so we can move from a
> > driver specific parsing code to a generic one. Currently only the
> > generic fields and the analog-connector specific fields are parsed. Parsing
> > the other connector specific fields can be added by a simple callbacks.
> > 
> > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > ---
> > [1] https://patchwork.kernel.org/cover/10794703/
> > 
> > v10:
> > - drop V4L2_CONN_HDMI support
> > - adapt pr_err msg to reflect new state (-> connector is unkown)
> > 
> > v9:
> > - Fix leading semicolon found by kbuild semicolon.cocci
> > 
> > v8:
> > - V4L2_CON_* -> V4L2_CONN_*
> > - tvnorms -> sdtv-standards
> > - adapt to new v4l2_fwnode_connector_analog member
> > - return error in case of V4L2_CONN_HDMI
> > 
> > v7:
> > @Jacopo: I dropped your r b tag becuase of the amount of changes I
> > made..
> > 
> > - drop unnecessary comments
> > - fix commet style
> > - s/v4l2_fwnode_connector_conv.name/v4l2_fwnode_connector_conv.compatible/
> > - make label size variable and drop V4L2_CONNECTOR_MAX_LABEL usage
> > - do not assign a default label in case of no label was specified
> > - remove useless /* fall through */ comments
> > - add support for N connector links
> > - rename local variables to be more meaningful
> > - adjust kernedoc
> > - add v4l2_fwnode_connector_free()
> > - improve error handling (use different error values)
> > - make use of pr_warn_once()
> > 
> > v6:
> > - use unsigned count var
> > - fix comment and style issues
> > - place '/* fall through */' to correct places
> > - fix error handling and cleanup by releasing fwnode
> > - drop vga and dvi parsing support as those connectors are rarely used
> >   these days
> > 
> > v5:
> > - s/strlcpy/strscpy/
> > 
> > v2-v4:
> > - nothing since the patch was squashed from series [1] into this
> >   series.
> > ---
> >  drivers/media/v4l2-core/v4l2-fwnode.c | 129 ++++++++++++++++++++++++++
> >  include/media/v4l2-fwnode.h           |  38 ++++++++
> >  2 files changed, 167 insertions(+)
> > 
> > diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
> > index 3bd1888787eb..0bfa7cbf78df 100644
> > --- a/drivers/media/v4l2-core/v4l2-fwnode.c
> > +++ b/drivers/media/v4l2-core/v4l2-fwnode.c
> > @@ -595,6 +595,135 @@ void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link)
> >  }
> >  EXPORT_SYMBOL_GPL(v4l2_fwnode_put_link);
> >  
> > +static const struct v4l2_fwnode_connector_conv {
> > +	enum v4l2_connector_type type;
> > +	const char *compatible;
> > +} connectors[] = {
> > +	{
> > +		.type = V4L2_CONN_COMPOSITE,
> > +		.compatible = "composite-video-connector",
> > +	}, {
> > +		.type = V4L2_CONN_SVIDEO,
> > +		.compatible = "svideo-connector",
> > +	},
> > +};
> > +
> > +static enum v4l2_connector_type
> > +v4l2_fwnode_string_to_connector_type(const char *con_str)
> > +{
> > +	unsigned int i;
> > +
> > +	for (i = 0; i < ARRAY_SIZE(connectors); i++)
> > +		if (!strcmp(con_str, connectors[i].compatible))
> > +			return connectors[i].type;
> > +
> > +	return V4L2_CONN_UNKNOWN;
> > +}
> > +
> > +static int
> > +v4l2_fwnode_connector_parse_analog(struct fwnode_handle *fwnode,
> > +				   struct v4l2_fwnode_connector *vc)
> > +{
> > +	u32 stds;
> > +	int ret;
> > +
> > +	ret = fwnode_property_read_u32(fwnode, "sdtv-standards", &stds);
> > +
> > +	/* The property is optional. */
> > +	vc->connector.analog.sdtv_stds = ret ? V4L2_STD_ALL : stds;
> > +
> > +	return 0;
> > +}
> > +
> > +void v4l2_fwnode_connector_free(struct v4l2_fwnode_connector *connector)
> > +{
> > +	unsigned int i;
> > +
> > +	if (IS_ERR_OR_NULL(connector))
> > +		return;
> > +
> > +	for (i = 0; i < connector->nr_of_links; i++)
> > +		v4l2_fwnode_put_link(&connector->links[i]);
> > +	kfree(connector->links);
> 
> Please do set connector->links NULL here. That avoids accidentally double
> kfree on the pointer.

Okay, I will do that.

> > +}
> > +EXPORT_SYMBOL_GPL(v4l2_fwnode_connector_free);
> > +
> > +int v4l2_fwnode_connector_alloc_parse(struct fwnode_handle *fwnode,
> > +				      struct v4l2_fwnode_connector *connector)
> > +{
> > +	struct fwnode_handle *remote_pp, *remote_ep;
> > +	const char *type_name;
> > +	unsigned int i = 0, ep_num = 0;
> > +	int err;
> > +
> > +	memset(connector, 0, sizeof(*connector));
> > +
> > +	remote_pp = fwnode_graph_get_remote_port_parent(fwnode);
> > +	if (!remote_pp)
> > +		return -ENOLINK;

Should I drop this logic here and force the caller to pass the connector
endpoint?

> > +
> > +	/* Parse all common properties first. */
> > +	fwnode_graph_for_each_endpoint(remote_pp, remote_ep)
> > +		ep_num++;
> 
> If there are no endpoints, ep_num will be zero and kmalloc_array() will
> return NULL? There should be a way there are no endpoints, rather than
> returning -ENOMEM.

Hm.. using the current implementation (please see my above comment)
ensures that there is always one link but if I change that I need to
check this, good point.

> > +
> > +	connector->nr_of_links = ep_num;
> > +	connector->links = kmalloc_array(ep_num, sizeof(*connector->links),
> > +					 GFP_KERNEL);
> > +	if (!connector->links) {
> > +		err = -ENOMEM;
> > +		goto err_put_fwnode;
> > +	}
> > +
> > +	fwnode_graph_for_each_endpoint(remote_pp, remote_ep) {
> > +		err = v4l2_fwnode_parse_link(remote_ep, &connector->links[i]);
> 
> If you start parsing a connector starting from another device connected to
> it, nothing seems to prevent parsing the same links twice, in case the
> connector is connected to more than one sub-device.
> 
> Or do I miss something crucial here?

That is true because currently each sub-device implements their own
connector parsing/handling stuff.. What i wanted to address with this
code is that one sub-device can have multiple links to one connector
e.g. s-video connectors (1xluma 1xchroma). I don't know how to handle
this without a simple connector device.

Regards,
  Marco

> > +		if (err) {
> > +			fwnode_handle_put(remote_ep);
> > +			goto err_free_links;
> > +		}
> > +		i++;
> > +	}
> > +
> > +	/*
> > +	 * Links reference counting guarantees access -> no duplication needed
> > +	 */
> > +	fwnode_property_read_string(remote_pp, "label", &connector->label);
> > +
> > +	/* The connector-type is stored within the compatible string. */
> > +	err = fwnode_property_read_string(remote_pp, "compatible", &type_name);
> > +	if (err) {
> > +		err = -EINVAL;
> > +		goto err_free_links;
> > +	}
> > +	connector->type = v4l2_fwnode_string_to_connector_type(type_name);
> > +
> > +	/* Now parse the connector specific properties. */
> > +	switch (connector->type) {
> > +	case V4L2_CONN_COMPOSITE:
> > +	case V4L2_CONN_SVIDEO:
> > +		err = v4l2_fwnode_connector_parse_analog(remote_pp, connector);
> > +		break;
> > +	case V4L2_CONN_UNKNOWN:
> > +	default:
> > +		pr_err("Unknown connector type\n");
> > +		err = -EINVAL;
> > +		goto err_free_links;
> > +	}
> > +
> > +	fwnode_handle_put(remote_pp);
> > +
> > +	return err;
> > +
> > +err_free_links:
> > +	for (i = 0; i < ep_num; i++)
> > +		v4l2_fwnode_put_link(&connector->links[i]);
> > +	kfree(connector->links);
> > +err_put_fwnode:
> > +	fwnode_handle_put(remote_pp);
> > +
> > +	return err;
> > +}
> > +EXPORT_SYMBOL_GPL(v4l2_fwnode_connector_alloc_parse);
> > +
> >  static int
> >  v4l2_async_notifier_fwnode_parse_endpoint(struct device *dev,
> >  					  struct v4l2_async_notifier *notifier,
> > diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
> > index 65da646b579e..800302aa84d8 100644
> > --- a/include/media/v4l2-fwnode.h
> > +++ b/include/media/v4l2-fwnode.h
> > @@ -276,6 +276,44 @@ int v4l2_fwnode_parse_link(struct fwnode_handle *fwnode,
> >   */
> >  void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link);
> >  
> > +/**
> > + * v4l2_fwnode_connector_free() - free the V4L2 connector acquired by
> > + * v4l2_fwnode_parse_connector()
> 
> This would be nicer aligned with the text after the dash.
> 
> > + * @connector: the V4L2 connector the resources of which are to be released
> > + *
> > + * Drop references to the connection link partners and free the memory allocated
> > + * by v4l2_fwnode_parse_connector() call.
> > + *
> > + * It is safe to call this function with NULL argument or on a V4L2 connector
> > + * the parsing of which failed.
> > + */
> > +void v4l2_fwnode_connector_free(struct v4l2_fwnode_connector *connector);
> > +
> > +/**
> > + * v4l2_fwnode_parse_connector() - parse the connector on endpoint
> 
> The name is different from the actual function.
> 
> > + * @fwnode: pointer to the endpoint's fwnode handle where the connector is
> > + *          connected to
> > + * @connector: pointer to the V4L2 fwnode connector data structure
> > + *
> > + * Fill the connector data structure with the connector type, label, all found
> > + * links between the host and the connector as well as connector specific data.
> > + * Since the label is optional it can be %NULL if no one was found.
> > + *
> > + * A reference is taken to both the connector and the connector destination
> > + * where the connector belongs to. This must be dropped when no longer needed.
> > + * Also the memory it has allocated to store the variable size data must be
> > + * freed. Both dropping the references and freeing the memory is done by
> > + * v4l2_fwnode_connector_free().
> > + *
> > + * Return:
> > + * * %0 on success or a negative error code on failure:
> > + * * %-ENOMEM if memory allocation failed
> > + * * %-ENOLINK if the connector can't be found
> > + * * %-EINVAL on parsing failure
> 
> Could this error code tell the endpoint is not connected to a connector?
> 
> I think the perfectly suitable error code for this would be -ENOTCONN. :-D
> 
> > + */
> > +int v4l2_fwnode_connector_alloc_parse(struct fwnode_handle *fwnode,
> > +				      struct v4l2_fwnode_connector *connector);
> > +
> >  /**
> >   * typedef parse_endpoint_func - Driver's callback function to be called on
> >   *	each V4L2 fwnode endpoint.
> > 
> 
> -- 
> Regards,
> 
> Sakari Ailus
> sakari.ailus@linux.intel.com
> 

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v11 04/15] media: v4l2-fwnode: add initial connector parsing support
  2019-11-19 11:37     ` Marco Felsch
@ 2019-11-27  8:17       ` Marco Felsch
  0 siblings, 0 replies; 22+ messages in thread
From: Marco Felsch @ 2019-11-27  8:17 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: devicetree, robh+dt, jacopo+renesas, laurent.pinchart, kernel,
	hans.verkuil, mchehab, linux-media

Hi Sakari,

gentle ping.

Regards,
  Marco

On 19-11-19 12:37, Marco Felsch wrote:
> Hi Sakari,
> 
> On 19-11-16 01:34, Sakari Ailus wrote:
> > Hi Marco,
> > 
> > On Mon, Sep 30, 2019 at 11:38:49AM +0200, Marco Felsch wrote:
> > > The patch adds the initial connector parsing code, so we can move from a
> > > driver specific parsing code to a generic one. Currently only the
> > > generic fields and the analog-connector specific fields are parsed. Parsing
> > > the other connector specific fields can be added by a simple callbacks.
> > > 
> > > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > > ---
> > > [1] https://patchwork.kernel.org/cover/10794703/
> > > 
> > > v10:
> > > - drop V4L2_CONN_HDMI support
> > > - adapt pr_err msg to reflect new state (-> connector is unkown)
> > > 
> > > v9:
> > > - Fix leading semicolon found by kbuild semicolon.cocci
> > > 
> > > v8:
> > > - V4L2_CON_* -> V4L2_CONN_*
> > > - tvnorms -> sdtv-standards
> > > - adapt to new v4l2_fwnode_connector_analog member
> > > - return error in case of V4L2_CONN_HDMI
> > > 
> > > v7:
> > > @Jacopo: I dropped your r b tag becuase of the amount of changes I
> > > made..
> > > 
> > > - drop unnecessary comments
> > > - fix commet style
> > > - s/v4l2_fwnode_connector_conv.name/v4l2_fwnode_connector_conv.compatible/
> > > - make label size variable and drop V4L2_CONNECTOR_MAX_LABEL usage
> > > - do not assign a default label in case of no label was specified
> > > - remove useless /* fall through */ comments
> > > - add support for N connector links
> > > - rename local variables to be more meaningful
> > > - adjust kernedoc
> > > - add v4l2_fwnode_connector_free()
> > > - improve error handling (use different error values)
> > > - make use of pr_warn_once()
> > > 
> > > v6:
> > > - use unsigned count var
> > > - fix comment and style issues
> > > - place '/* fall through */' to correct places
> > > - fix error handling and cleanup by releasing fwnode
> > > - drop vga and dvi parsing support as those connectors are rarely used
> > >   these days
> > > 
> > > v5:
> > > - s/strlcpy/strscpy/
> > > 
> > > v2-v4:
> > > - nothing since the patch was squashed from series [1] into this
> > >   series.
> > > ---
> > >  drivers/media/v4l2-core/v4l2-fwnode.c | 129 ++++++++++++++++++++++++++
> > >  include/media/v4l2-fwnode.h           |  38 ++++++++
> > >  2 files changed, 167 insertions(+)
> > > 
> > > diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
> > > index 3bd1888787eb..0bfa7cbf78df 100644
> > > --- a/drivers/media/v4l2-core/v4l2-fwnode.c
> > > +++ b/drivers/media/v4l2-core/v4l2-fwnode.c
> > > @@ -595,6 +595,135 @@ void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link)
> > >  }
> > >  EXPORT_SYMBOL_GPL(v4l2_fwnode_put_link);
> > >  
> > > +static const struct v4l2_fwnode_connector_conv {
> > > +	enum v4l2_connector_type type;
> > > +	const char *compatible;
> > > +} connectors[] = {
> > > +	{
> > > +		.type = V4L2_CONN_COMPOSITE,
> > > +		.compatible = "composite-video-connector",
> > > +	}, {
> > > +		.type = V4L2_CONN_SVIDEO,
> > > +		.compatible = "svideo-connector",
> > > +	},
> > > +};
> > > +
> > > +static enum v4l2_connector_type
> > > +v4l2_fwnode_string_to_connector_type(const char *con_str)
> > > +{
> > > +	unsigned int i;
> > > +
> > > +	for (i = 0; i < ARRAY_SIZE(connectors); i++)
> > > +		if (!strcmp(con_str, connectors[i].compatible))
> > > +			return connectors[i].type;
> > > +
> > > +	return V4L2_CONN_UNKNOWN;
> > > +}
> > > +
> > > +static int
> > > +v4l2_fwnode_connector_parse_analog(struct fwnode_handle *fwnode,
> > > +				   struct v4l2_fwnode_connector *vc)
> > > +{
> > > +	u32 stds;
> > > +	int ret;
> > > +
> > > +	ret = fwnode_property_read_u32(fwnode, "sdtv-standards", &stds);
> > > +
> > > +	/* The property is optional. */
> > > +	vc->connector.analog.sdtv_stds = ret ? V4L2_STD_ALL : stds;
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +void v4l2_fwnode_connector_free(struct v4l2_fwnode_connector *connector)
> > > +{
> > > +	unsigned int i;
> > > +
> > > +	if (IS_ERR_OR_NULL(connector))
> > > +		return;
> > > +
> > > +	for (i = 0; i < connector->nr_of_links; i++)
> > > +		v4l2_fwnode_put_link(&connector->links[i]);
> > > +	kfree(connector->links);
> > 
> > Please do set connector->links NULL here. That avoids accidentally double
> > kfree on the pointer.
> 
> Okay, I will do that.
> 
> > > +}
> > > +EXPORT_SYMBOL_GPL(v4l2_fwnode_connector_free);
> > > +
> > > +int v4l2_fwnode_connector_alloc_parse(struct fwnode_handle *fwnode,
> > > +				      struct v4l2_fwnode_connector *connector)
> > > +{
> > > +	struct fwnode_handle *remote_pp, *remote_ep;
> > > +	const char *type_name;
> > > +	unsigned int i = 0, ep_num = 0;
> > > +	int err;
> > > +
> > > +	memset(connector, 0, sizeof(*connector));
> > > +
> > > +	remote_pp = fwnode_graph_get_remote_port_parent(fwnode);
> > > +	if (!remote_pp)
> > > +		return -ENOLINK;
> 
> Should I drop this logic here and force the caller to pass the connector
> endpoint?
> 
> > > +
> > > +	/* Parse all common properties first. */
> > > +	fwnode_graph_for_each_endpoint(remote_pp, remote_ep)
> > > +		ep_num++;
> > 
> > If there are no endpoints, ep_num will be zero and kmalloc_array() will
> > return NULL? There should be a way there are no endpoints, rather than
> > returning -ENOMEM.
> 
> Hm.. using the current implementation (please see my above comment)
> ensures that there is always one link but if I change that I need to
> check this, good point.
> 
> > > +
> > > +	connector->nr_of_links = ep_num;
> > > +	connector->links = kmalloc_array(ep_num, sizeof(*connector->links),
> > > +					 GFP_KERNEL);
> > > +	if (!connector->links) {
> > > +		err = -ENOMEM;
> > > +		goto err_put_fwnode;
> > > +	}
> > > +
> > > +	fwnode_graph_for_each_endpoint(remote_pp, remote_ep) {
> > > +		err = v4l2_fwnode_parse_link(remote_ep, &connector->links[i]);
> > 
> > If you start parsing a connector starting from another device connected to
> > it, nothing seems to prevent parsing the same links twice, in case the
> > connector is connected to more than one sub-device.
> > 
> > Or do I miss something crucial here?
> 
> That is true because currently each sub-device implements their own
> connector parsing/handling stuff.. What i wanted to address with this
> code is that one sub-device can have multiple links to one connector
> e.g. s-video connectors (1xluma 1xchroma). I don't know how to handle
> this without a simple connector device.
> 
> Regards,
>   Marco
> 
> > > +		if (err) {
> > > +			fwnode_handle_put(remote_ep);
> > > +			goto err_free_links;
> > > +		}
> > > +		i++;
> > > +	}
> > > +
> > > +	/*
> > > +	 * Links reference counting guarantees access -> no duplication needed
> > > +	 */
> > > +	fwnode_property_read_string(remote_pp, "label", &connector->label);
> > > +
> > > +	/* The connector-type is stored within the compatible string. */
> > > +	err = fwnode_property_read_string(remote_pp, "compatible", &type_name);
> > > +	if (err) {
> > > +		err = -EINVAL;
> > > +		goto err_free_links;
> > > +	}
> > > +	connector->type = v4l2_fwnode_string_to_connector_type(type_name);
> > > +
> > > +	/* Now parse the connector specific properties. */
> > > +	switch (connector->type) {
> > > +	case V4L2_CONN_COMPOSITE:
> > > +	case V4L2_CONN_SVIDEO:
> > > +		err = v4l2_fwnode_connector_parse_analog(remote_pp, connector);
> > > +		break;
> > > +	case V4L2_CONN_UNKNOWN:
> > > +	default:
> > > +		pr_err("Unknown connector type\n");
> > > +		err = -EINVAL;
> > > +		goto err_free_links;
> > > +	}
> > > +
> > > +	fwnode_handle_put(remote_pp);
> > > +
> > > +	return err;
> > > +
> > > +err_free_links:
> > > +	for (i = 0; i < ep_num; i++)
> > > +		v4l2_fwnode_put_link(&connector->links[i]);
> > > +	kfree(connector->links);
> > > +err_put_fwnode:
> > > +	fwnode_handle_put(remote_pp);
> > > +
> > > +	return err;
> > > +}
> > > +EXPORT_SYMBOL_GPL(v4l2_fwnode_connector_alloc_parse);
> > > +
> > >  static int
> > >  v4l2_async_notifier_fwnode_parse_endpoint(struct device *dev,
> > >  					  struct v4l2_async_notifier *notifier,
> > > diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
> > > index 65da646b579e..800302aa84d8 100644
> > > --- a/include/media/v4l2-fwnode.h
> > > +++ b/include/media/v4l2-fwnode.h
> > > @@ -276,6 +276,44 @@ int v4l2_fwnode_parse_link(struct fwnode_handle *fwnode,
> > >   */
> > >  void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link);
> > >  
> > > +/**
> > > + * v4l2_fwnode_connector_free() - free the V4L2 connector acquired by
> > > + * v4l2_fwnode_parse_connector()
> > 
> > This would be nicer aligned with the text after the dash.
> > 
> > > + * @connector: the V4L2 connector the resources of which are to be released
> > > + *
> > > + * Drop references to the connection link partners and free the memory allocated
> > > + * by v4l2_fwnode_parse_connector() call.
> > > + *
> > > + * It is safe to call this function with NULL argument or on a V4L2 connector
> > > + * the parsing of which failed.
> > > + */
> > > +void v4l2_fwnode_connector_free(struct v4l2_fwnode_connector *connector);
> > > +
> > > +/**
> > > + * v4l2_fwnode_parse_connector() - parse the connector on endpoint
> > 
> > The name is different from the actual function.
> > 
> > > + * @fwnode: pointer to the endpoint's fwnode handle where the connector is
> > > + *          connected to
> > > + * @connector: pointer to the V4L2 fwnode connector data structure
> > > + *
> > > + * Fill the connector data structure with the connector type, label, all found
> > > + * links between the host and the connector as well as connector specific data.
> > > + * Since the label is optional it can be %NULL if no one was found.
> > > + *
> > > + * A reference is taken to both the connector and the connector destination
> > > + * where the connector belongs to. This must be dropped when no longer needed.
> > > + * Also the memory it has allocated to store the variable size data must be
> > > + * freed. Both dropping the references and freeing the memory is done by
> > > + * v4l2_fwnode_connector_free().
> > > + *
> > > + * Return:
> > > + * * %0 on success or a negative error code on failure:
> > > + * * %-ENOMEM if memory allocation failed
> > > + * * %-ENOLINK if the connector can't be found
> > > + * * %-EINVAL on parsing failure
> > 
> > Could this error code tell the endpoint is not connected to a connector?
> > 
> > I think the perfectly suitable error code for this would be -ENOTCONN. :-D
> > 
> > > + */
> > > +int v4l2_fwnode_connector_alloc_parse(struct fwnode_handle *fwnode,
> > > +				      struct v4l2_fwnode_connector *connector);
> > > +
> > >  /**
> > >   * typedef parse_endpoint_func - Driver's callback function to be called on
> > >   *	each V4L2 fwnode endpoint.
> > > 
> > 
> > -- 
> > Regards,
> > 
> > Sakari Ailus
> > sakari.ailus@linux.intel.com
> > 
> 
> -- 
> Pengutronix e.K.                           |                             |
> Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
> 31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
> Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
> 
> 

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply	[flat|nested] 22+ messages in thread

end of thread, back to index

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-09-30  9:38 [PATCH v11 00/15] TVP5150 Features and fixes Marco Felsch
2019-09-30  9:38 ` [PATCH v11 01/15] dt-bindings: connector: analog: add sdtv standards property Marco Felsch
2019-09-30  9:38 ` [PATCH v11 02/15] media: v4l: link dt-bindings and uapi Marco Felsch
2019-09-30  9:38 ` [PATCH v11 03/15] media: v4l2-fwnode: add v4l2_fwnode_connector Marco Felsch
2019-09-30  9:38 ` [PATCH v11 04/15] media: v4l2-fwnode: add initial connector parsing support Marco Felsch
2019-11-15 23:34   ` Sakari Ailus
2019-11-19 11:37     ` Marco Felsch
2019-11-27  8:17       ` Marco Felsch
2019-09-30  9:38 ` [PATCH v11 05/15] partial revert of "[media] tvp5150: add HW input connectors support" Marco Felsch
2019-09-30  9:38 ` [PATCH v11 06/15] media: tvp5150: add input source selection of_graph support Marco Felsch
2019-09-30  9:38 ` [PATCH v11 07/15] media: dt-bindings: tvp5150: Add input port connectors DT bindings Marco Felsch
2019-09-30  9:38 ` [PATCH v11 08/15] media: tvp5150: fix set_selection rectangle handling Marco Felsch
2019-09-30  9:38 ` [PATCH v11 09/15] media: tvp5150: add FORMAT_TRY support for get/set selection handlers Marco Felsch
2019-09-30  9:38 ` [PATCH v11 10/15] media: tvp5150: initialize subdev before parsing device tree Marco Felsch
2019-09-30  9:38 ` [PATCH v11 11/15] media: tvp5150: add s_power callback Marco Felsch
2019-10-24 11:59   ` Sakari Ailus
2019-11-08 10:25     ` Marco Felsch
2019-11-08 10:38       ` Sakari Ailus
2019-09-30  9:38 ` [PATCH v11 12/15] media: dt-bindings: tvp5150: cleanup bindings stlye Marco Felsch
2019-09-30  9:38 ` [PATCH v11 13/15] media: dt-bindings: tvp5150: add optional sdtv standards documentation Marco Felsch
2019-09-30  9:38 ` [PATCH v11 14/15] media: tvp5150: add support to limit sdtv standards Marco Felsch
2019-09-30  9:39 ` [PATCH v11 15/15] media: tvp5150: make debug output more readable Marco Felsch

Linux-Media Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/linux-media/0 linux-media/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 linux-media linux-media/ https://lore.kernel.org/linux-media \
		linux-media@vger.kernel.org
	public-inbox-index linux-media

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.linux-media


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git