diff mbox series

[RFC,04/12] staging: media: max96712: change DT parsing routine

Message ID 20250131163408.2019144-5-laurentiu.palcu@oss.nxp.com (mailing list archive)
State New
Headers show
Series staging: media: max96712: Add support for streams and multiple sensors | expand

Commit Message

Laurentiu Palcu Jan. 31, 2025, 4:33 p.m. UTC
Currently, the driver supports only one source media pad. In order to be
able to use the driver with other serializers we need sink media pads as
well. This patch adds support for parsing the source endpoints and
create the corresponding sink pads associated with the endpoints in DT.

The driver functionality is not changed at this point: only sink and
source pads are created. However, since the first source pad index is 4,
the user needs to make sure to link the source pad correctly to the next
downstream node.

Signed-off-by: Laurentiu Palcu <laurentiu.palcu@oss.nxp.com>
---
 drivers/staging/media/max96712/max96712.c | 122 +++++++++++++++++++---
 1 file changed, 106 insertions(+), 16 deletions(-)

Comments

Dan Carpenter Feb. 1, 2025, 10:30 a.m. UTC | #1
On Fri, Jan 31, 2025 at 06:33:58PM +0200, Laurentiu Palcu wrote:
> -static int max96712_parse_dt(struct max96712_priv *priv)
> +static int max96712_parse_rx_ports(struct max96712_priv *priv, struct device_node *node,
> +				   struct of_endpoint *ep)
> +{
> +	struct device *dev = &priv->client->dev;
> +	struct max96712_rx_port *source;
> +	struct fwnode_handle *remote_port_parent;
> +
> +	if (priv->rx_ports[ep->port].fwnode) {
> +		dev_info(dev, "Multiple port endpoints are not supported: %d", ep->port);
> +		return 0;
> +	}
> +
> +	source = &priv->rx_ports[ep->port];
> +	source->fwnode = fwnode_graph_get_remote_endpoint(of_fwnode_handle(node));
> +	if (!source->fwnode) {
> +		dev_info(dev, "Endpoint %pOF has no remote endpoint connection\n", ep->local_node);
> +		return 0;
> +	}
> +
> +	remote_port_parent = fwnode_graph_get_remote_port_parent(of_fwnode_handle(node));
> +
> +	if (!fwnode_device_is_available(remote_port_parent)) {
> +		dev_dbg(dev, "Skipping port %d as remote port parent is disabled.\n",
> +			ep->port);
> +		source->fwnode = NULL;

I don't understand the refcounting in this function.  Should we call
fwnode_handle_put(source->fwnode); before setting this to NULL?

> +		goto fwnode_put;
> +	}
> +
> +	priv->rx_port_mask |= BIT(ep->port);
> +	priv->n_rx_ports++;
> +
> +fwnode_put:
> +	fwnode_handle_put(remote_port_parent);
> +	fwnode_handle_put(source->fwnode);
> +	return 0;

I don't understand why we save source->fwnode but drop the refcount on
the success path.  My instinct says that it should be a source_fwnode
local stack variable instead.  (But again, I've only glanced at this
code so I could be wrong).


> +}
> +

regards,
dan carpenter
diff mbox series

Patch

diff --git a/drivers/staging/media/max96712/max96712.c b/drivers/staging/media/max96712/max96712.c
index cf39f5243cd6d..9c255979932d6 100644
--- a/drivers/staging/media/max96712/max96712.c
+++ b/drivers/staging/media/max96712/max96712.c
@@ -130,6 +130,13 @@ 
 #define MAX96712_VRX_PATGEN_CHKR_RPT_B			CCI_REG8(0x1075)
 #define MAX96712_VRX_PATGEN_CHKR_ALT			CCI_REG8(0x1076)
 
+#define MAX96712_MAX_RX_PORTS				4
+#define MAX96712_MAX_TX_PORTS				2
+#define MAX96712_MAX_VPG_PORTS				1
+#define MAX96712_MAX_PORTS				(MAX96712_MAX_RX_PORTS + \
+							 MAX96712_MAX_TX_PORTS + \
+							 MAX96712_MAX_VPG_PORTS)
+
 enum max96712_pattern {
 	MAX96712_PATTERN_CHECKERBOARD = 0,
 	MAX96712_PATTERN_GRADIENT,
@@ -139,6 +146,11 @@  struct max96712_info {
 	unsigned int dpllfreq;
 };
 
+struct max96712_rx_port {
+	struct v4l2_subdev *sd;
+	struct fwnode_handle *fwnode;
+};
+
 struct max96712_priv {
 	struct i2c_client *client;
 	struct regmap *regmap;
@@ -151,7 +163,11 @@  struct max96712_priv {
 
 	struct v4l2_subdev sd;
 	struct v4l2_ctrl_handler ctrl_handler;
-	struct media_pad pads[1];
+	struct media_pad pads[MAX96712_MAX_PORTS];
+
+	struct max96712_rx_port rx_ports[MAX96712_MAX_RX_PORTS];
+	unsigned int rx_port_mask;
+	unsigned int n_rx_ports;
 
 	enum max96712_pattern pattern;
 };
@@ -343,9 +359,12 @@  static int max96712_init_state(struct v4l2_subdev *sd,
 		.xfer_func      = V4L2_XFER_FUNC_DEFAULT,
 	};
 	struct v4l2_mbus_framefmt *fmt;
+	int i;
 
-	fmt = v4l2_subdev_state_get_format(state, 0);
-	*fmt = default_fmt;
+	for (i = 0; i < MAX96712_MAX_PORTS; i++) {
+		fmt = v4l2_subdev_state_get_format(state, i);
+		*fmt = default_fmt;
+	}
 
 	return 0;
 }
@@ -392,6 +411,7 @@  static int max96712_v4l2_register(struct max96712_priv *priv)
 {
 	long pixel_rate;
 	int ret;
+	int i;
 
 	priv->sd.internal_ops = &max96712_internal_ops;
 	v4l2_i2c_subdev_init(&priv->sd, priv->client, &max96712_subdev_ops);
@@ -418,8 +438,14 @@  static int max96712_v4l2_register(struct max96712_priv *priv)
 	if (ret)
 		goto error;
 
-	priv->pads[0].flags = MEDIA_PAD_FL_SOURCE;
-	ret = media_entity_pads_init(&priv->sd.entity, 1, priv->pads);
+	for (i = 0; i < MAX96712_MAX_RX_PORTS + MAX96712_MAX_TX_PORTS; i++)
+		priv->pads[i].flags = i < MAX96712_MAX_RX_PORTS ?
+				      MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE;
+
+	/* The last pad is the VPG pad. */
+	priv->pads[i].flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_INTERNAL;
+
+	ret = media_entity_pads_init(&priv->sd.entity, MAX96712_MAX_PORTS, priv->pads);
 	if (ret)
 		goto error;
 
@@ -443,24 +469,53 @@  static int max96712_v4l2_register(struct max96712_priv *priv)
 	return ret;
 }
 
-static int max96712_parse_dt(struct max96712_priv *priv)
+static int max96712_parse_rx_ports(struct max96712_priv *priv, struct device_node *node,
+				   struct of_endpoint *ep)
+{
+	struct device *dev = &priv->client->dev;
+	struct max96712_rx_port *source;
+	struct fwnode_handle *remote_port_parent;
+
+	if (priv->rx_ports[ep->port].fwnode) {
+		dev_info(dev, "Multiple port endpoints are not supported: %d", ep->port);
+		return 0;
+	}
+
+	source = &priv->rx_ports[ep->port];
+	source->fwnode = fwnode_graph_get_remote_endpoint(of_fwnode_handle(node));
+	if (!source->fwnode) {
+		dev_info(dev, "Endpoint %pOF has no remote endpoint connection\n", ep->local_node);
+		return 0;
+	}
+
+	remote_port_parent = fwnode_graph_get_remote_port_parent(of_fwnode_handle(node));
+
+	if (!fwnode_device_is_available(remote_port_parent)) {
+		dev_dbg(dev, "Skipping port %d as remote port parent is disabled.\n",
+			ep->port);
+		source->fwnode = NULL;
+		goto fwnode_put;
+	}
+
+	priv->rx_port_mask |= BIT(ep->port);
+	priv->n_rx_ports++;
+
+fwnode_put:
+	fwnode_handle_put(remote_port_parent);
+	fwnode_handle_put(source->fwnode);
+	return 0;
+}
+
+static int max96712_parse_tx_ports(struct max96712_priv *priv, struct device_node *node,
+				   struct of_endpoint *ep)
 {
-	struct fwnode_handle *ep;
 	struct v4l2_fwnode_endpoint v4l2_ep = {
 		.bus_type = V4L2_MBUS_UNKNOWN,
 	};
 	unsigned int supported_lanes;
 	int ret;
 
-	ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(&priv->client->dev), 4,
-					     0, 0);
-	if (!ep) {
-		dev_err(&priv->client->dev, "Not connected to subdevice\n");
-		return -EINVAL;
-	}
-
-	ret = v4l2_fwnode_endpoint_parse(ep, &v4l2_ep);
-	fwnode_handle_put(ep);
+	ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(node), &v4l2_ep);
 	if (ret) {
 		dev_err(&priv->client->dev, "Could not parse v4l2 endpoint\n");
 		return -EINVAL;
@@ -492,6 +547,41 @@  static int max96712_parse_dt(struct max96712_priv *priv)
 	return 0;
 }
 
+static int max96712_parse_dt(struct max96712_priv *priv)
+{
+	struct device *dev = &priv->client->dev;
+	struct device_node *node = NULL;
+	int ret = 0;
+
+	for_each_endpoint_of_node(dev->of_node, node) {
+		struct of_endpoint ep;
+
+		of_graph_parse_endpoint(node, &ep);
+
+		if (ep.port >= MAX96712_MAX_PORTS) {
+			dev_err(dev, "Invalid endpoint %s on port %d",
+				of_node_full_name(ep.local_node), ep.port);
+			continue;
+		}
+
+		if (ep.port >= MAX96712_MAX_RX_PORTS) {
+			ret = max96712_parse_tx_ports(priv, node, &ep);
+			if (ret)
+				goto exit;
+
+			continue;
+		}
+
+		ret = max96712_parse_rx_ports(priv, node, &ep);
+		if (ret)
+			goto exit;
+	}
+
+exit:
+	of_node_put(node);
+	return ret;
+}
+
 static const struct regmap_config max96712_i2c_regmap = {
 	.reg_bits = 16,
 	.val_bits = 8,