All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC 0/5] V4L2 fwnode support
@ 2016-10-05  7:21 Sakari Ailus
  2016-10-05  7:21 ` [RFC 1/5] v4l: fwnode: Support generic fwnode instead of just OF Sakari Ailus
                   ` (5 more replies)
  0 siblings, 6 replies; 7+ messages in thread
From: Sakari Ailus @ 2016-10-05  7:21 UTC (permalink / raw)
  To: linux-media

Hi folks,

This patchset adds support for fwnode to V4L2. Besides OF, also ACPI based
systems can be supported this way. By using V4L2 fwnode, the individual
drivers do not need to be aware of the underlying firmware implementation.

The patchset depends on another patchset here:

<URL:http://www.spinics.net/lists/linux-acpi/msg69547.html>

And a fix for the V4L2 flash led class:

<URL:https://git.linuxtv.org/sailus/media_tree.git/commit/?h=v4l2-acpi&id=6abbf66418804aa5b82cc3231eab73c9759dcd69>

I'm sending this as RFC primarily because the other set is at RFC stage.

The intent is to eventually replace the plain OF support by the generic
fwnode support in drivers.

-- 
Kind regards,
Sakari


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

* [RFC 1/5] v4l: fwnode: Support generic fwnode instead of just OF
  2016-10-05  7:21 [RFC 0/5] V4L2 fwnode support Sakari Ailus
@ 2016-10-05  7:21 ` Sakari Ailus
  2016-10-05  7:21 ` [RFC 2/5] v4l: async: Match fwnode instead of of_node Sakari Ailus
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Sakari Ailus @ 2016-10-05  7:21 UTC (permalink / raw)
  To: linux-media

The fwnode_handle is a more generic way than OF device_node to describe
firmware nodes. This prepares for ACPI support in V4L2.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
---
 drivers/media/v4l2-core/Makefile      |   1 +
 drivers/media/v4l2-core/v4l2-fwnode.c | 338 ++++++++++++++++++++++++++++++++++
 include/media/v4l2-fwnode.h           | 104 +++++++++++
 3 files changed, 443 insertions(+)
 create mode 100644 drivers/media/v4l2-core/v4l2-fwnode.c
 create mode 100644 include/media/v4l2-fwnode.h

diff --git a/drivers/media/v4l2-core/Makefile b/drivers/media/v4l2-core/Makefile
index 795a535..a7d80da 100644
--- a/drivers/media/v4l2-core/Makefile
+++ b/drivers/media/v4l2-core/Makefile
@@ -13,6 +13,7 @@ endif
 ifeq ($(CONFIG_OF),y)
   videodev-objs += v4l2-of.o
 endif
+videodev-objs += v4l2-fwnode.o
 ifeq ($(CONFIG_TRACEPOINTS),y)
   videodev-objs += vb2-trace.o v4l2-trace.o
 endif
diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
new file mode 100644
index 0000000..78c07c5
--- /dev/null
+++ b/drivers/media/v4l2-core/v4l2-fwnode.c
@@ -0,0 +1,338 @@
+/*
+ * V4L2 fwnode binding parsing library
+ *
+ * Copyright (c) 2016 Intel Corporation.
+ * Author: Sakari Ailus <sakari.ailus@linux.intel.com>
+ *
+ * Copyright (C) 2012 - 2013 Samsung Electronics Co., Ltd.
+ * Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *
+ * Copyright (C) 2012 Renesas Electronics Corp.
+ * Author: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ */
+#include <linux/acpi.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/property.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/types.h>
+
+#include <media/v4l2-fwnode.h>
+
+static int v4l2_fwnode_endpoint_parse_csi_bus(struct fwnode_handle *fwn,
+					      struct v4l2_fwnode_endpoint *vfwn)
+{
+	struct v4l2_fwnode_bus_mipi_csi2 *bus = &vfwn->bus.mipi_csi2;
+	bool have_clk_lane = false;
+	unsigned int flags = 0;
+	unsigned int i;
+	u32 v;
+	int rval;
+
+	rval = fwnode_property_read_u32_array(fwn, "data-lanes", NULL, 0);
+	if (rval > 0) {
+		u32 array[ARRAY_SIZE(bus->data_lanes)];
+
+		bus->num_data_lanes =
+			min_t(int, ARRAY_SIZE(bus->data_lanes), rval);
+
+		fwnode_property_read_u32_array(
+			fwn, "data-lanes", array, bus->num_data_lanes);
+
+		for (i = 0; i < bus->num_data_lanes; i++)
+			bus->data_lanes[i] = array[i];
+	}
+
+	rval = fwnode_property_read_u32_array(fwn, "lane-polarities", NULL, 0);
+	if (rval > 0) {
+		u32 array[ARRAY_SIZE(bus->lane_polarities)];
+
+		if (rval < 1 + bus->num_data_lanes /* clock + data */) {
+			pr_warn("too few lane-polarities entries (need %u, got %u)\n",
+				1 + bus->num_data_lanes, rval);
+			return -EINVAL;
+		}
+
+		fwnode_property_read_u32_array(
+			fwn, "lane-polarities", array, 1 + bus->num_data_lanes);
+
+		for (i = 0; i < 1 + bus->num_data_lanes; i++)
+			bus->lane_polarities[i] = array[i];
+	}
+
+	if (!fwnode_property_read_u32(fwn, "clock-lanes", &v)) {
+		bus->clock_lane = v;
+		have_clk_lane = true;
+	}
+
+	if (fwnode_property_present(fwn, "clock-noncontinuous"))
+		flags |= V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK;
+	else if (have_clk_lane || bus->num_data_lanes > 0)
+		flags |= V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
+
+	bus->flags = flags;
+	vfwn->bus_type = V4L2_MBUS_CSI2;
+
+	return 0;
+}
+
+static void v4l2_fwnode_endpoint_parse_parallel_bus(
+	struct fwnode_handle *fwn, struct v4l2_fwnode_endpoint *vfwn)
+{
+	struct v4l2_fwnode_bus_parallel *bus = &vfwn->bus.parallel;
+	unsigned int flags = 0;
+	u32 v;
+
+	if (!fwnode_property_read_u32(fwn, "hsync-active", &v))
+		flags |= v ? V4L2_MBUS_HSYNC_ACTIVE_HIGH :
+			V4L2_MBUS_HSYNC_ACTIVE_LOW;
+
+	if (!fwnode_property_read_u32(fwn, "vsync-active", &v))
+		flags |= v ? V4L2_MBUS_VSYNC_ACTIVE_HIGH :
+			V4L2_MBUS_VSYNC_ACTIVE_LOW;
+
+	if (!fwnode_property_read_u32(fwn, "field-even-active", &v))
+		flags |= v ? V4L2_MBUS_FIELD_EVEN_HIGH :
+			V4L2_MBUS_FIELD_EVEN_LOW;
+	if (flags)
+		vfwn->bus_type = V4L2_MBUS_PARALLEL;
+	else
+		vfwn->bus_type = V4L2_MBUS_BT656;
+
+	if (!fwnode_property_read_u32(fwn, "pclk-sample", &v))
+		flags |= v ? V4L2_MBUS_PCLK_SAMPLE_RISING :
+			V4L2_MBUS_PCLK_SAMPLE_FALLING;
+
+	if (!fwnode_property_read_u32(fwn, "data-active", &v))
+		flags |= v ? V4L2_MBUS_DATA_ACTIVE_HIGH :
+			V4L2_MBUS_DATA_ACTIVE_LOW;
+
+	if (fwnode_property_present(fwn, "slave-mode"))
+		flags |= V4L2_MBUS_SLAVE;
+	else
+		flags |= V4L2_MBUS_MASTER;
+
+	if (!fwnode_property_read_u32(fwn, "bus-width", &v))
+		bus->bus_width = v;
+
+	if (!fwnode_property_read_u32(fwn, "data-shift", &v))
+		bus->data_shift = v;
+
+	if (!fwnode_property_read_u32(fwn, "sync-on-green-active", &v))
+		flags |= v ? V4L2_MBUS_VIDEO_SOG_ACTIVE_HIGH :
+			V4L2_MBUS_VIDEO_SOG_ACTIVE_LOW;
+
+	bus->flags = flags;
+
+}
+
+/**
+ * v4l2_fwnode_endpoint_parse() - parse all fwnode node properties
+ * @fwn: pointer to fwnode_handle
+ * @vfwn: pointer to the V4L2 fwnode data structure
+ *
+ * All properties are optional. If none are found, we don't set any flags.
+ * This means the port has a static configuration and no properties have
+ * to be specified explicitly.
+ * If any properties that identify the bus as parallel are found and
+ * slave-mode isn't set, we set V4L2_MBUS_MASTER. Similarly, if we recognise
+ * the bus as serial CSI-2 and clock-noncontinuous isn't set, we set the
+ * V4L2_MBUS_CSI2_CONTINUOUS_CLOCK flag.
+ * The caller should hold a reference to @node.
+ *
+ * NOTE: This function does not parse properties the size of which is
+ * variable without a low fixed limit. Please use
+ * v4l2_fwnode_endpoint_alloc_parse() in new drivers instead.
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwn,
+			       struct v4l2_fwnode_endpoint *vfwn)
+{
+	int rval;
+
+	fwnode_graph_parse_endpoint(fwn, &vfwn->base);
+
+	/* Zero fields from bus_type to until the end */
+	memset(&vfwn->bus_type, 0, sizeof(*vfwn) -
+	       offsetof(typeof(*vfwn), bus_type));
+
+	rval = v4l2_fwnode_endpoint_parse_csi_bus(fwn, vfwn);
+	if (rval)
+		return rval;
+	/*
+	 * Parse the parallel video bus properties only if none
+	 * of the MIPI CSI-2 specific properties were found.
+	 */
+	if (vfwn->bus.mipi_csi2.flags == 0)
+		v4l2_fwnode_endpoint_parse_parallel_bus(fwn, vfwn);
+
+	return 0;
+}
+EXPORT_SYMBOL(v4l2_fwnode_endpoint_parse);
+
+/*
+ * v4l2_fwnode_endpoint_free() - free the V4L2 fwnode acquired by
+ * v4l2_fwnode_endpoint_alloc_parse()
+ * @fwn - the V4L2 fwnode the resources of which are to be released
+ *
+ * It is safe to call this function with NULL argument or on an
+ * V4L2 fwnode the parsing of which failed.
+ */
+void v4l2_fwnode_endpoint_free(struct v4l2_fwnode_endpoint *vfwn)
+{
+	if (IS_ERR_OR_NULL(vfwn))
+		return;
+
+	kfree(vfwn->link_frequencies);
+	kfree(vfwn);
+}
+EXPORT_SYMBOL(v4l2_fwnode_endpoint_free);
+
+/**
+ * v4l2_fwnode_endpoint_alloc_parse() - parse all fwnode node properties
+ * @node: pointer to fwnode_handle
+ *
+ * All properties are optional. If none are found, we don't set any flags.
+ * This means the port has a static configuration and no properties have
+ * to be specified explicitly.
+ * If any properties that identify the bus as parallel are found and
+ * slave-mode isn't set, we set V4L2_MBUS_MASTER. Similarly, if we recognise
+ * the bus as serial CSI-2 and clock-noncontinuous isn't set, we set the
+ * V4L2_MBUS_CSI2_CONTINUOUS_CLOCK flag.
+ * The caller should hold a reference to @node.
+ *
+ * v4l2_fwnode_endpoint_alloc_parse() has two important differences to
+ * v4l2_fwnode_endpoint_parse():
+ *
+ * 1. It also parses variable size data and
+ *
+ * 2. The memory it has allocated to store the variable size data must
+ *    be freed using v4l2_fwnode_endpoint_free() when no longer needed.
+ *
+ * Return: Pointer to v4l2_fwnode_endpoint if successful, on error a
+ * negative error code.
+ */
+struct v4l2_fwnode_endpoint *v4l2_fwnode_endpoint_alloc_parse(
+	struct fwnode_handle *fwn)
+{
+	struct v4l2_fwnode_endpoint *vfwn;
+	int rval;
+
+	vfwn = kzalloc(sizeof(*vfwn), GFP_KERNEL);
+	if (!vfwn)
+		return ERR_PTR(-ENOMEM);
+
+	rval = v4l2_fwnode_endpoint_parse(fwn, vfwn);
+	if (rval < 0)
+		goto out_err;
+
+	rval = fwnode_property_read_u64_array(fwn, "link-frequencies",
+					      NULL, 0);
+
+	if (rval < 0)
+		goto out_err;
+
+	vfwn->link_frequencies =
+		kmalloc_array(rval, sizeof(*vfwn->link_frequencies),
+			      GFP_KERNEL);
+	if (!vfwn->link_frequencies) {
+		rval = -ENOMEM;
+		goto out_err;
+	}
+
+	vfwn->nr_of_link_frequencies = rval;
+
+	rval = fwnode_property_read_u64_array(
+		fwn, "link-frequencies", vfwn->link_frequencies,
+		vfwn->nr_of_link_frequencies);
+	if (rval < 0)
+		goto out_err;
+
+	return vfwn;
+
+out_err:
+	v4l2_fwnode_endpoint_free(vfwn);
+	return ERR_PTR(rval);
+}
+EXPORT_SYMBOL(v4l2_fwnode_endpoint_alloc_parse);
+
+/**
+ * v4l2_fwnode_endpoint_parse_link() - parse a link between two endpoints
+ * @node: pointer to the fwnode at the local end of the link
+ * @link: pointer to the V4L2 fwnode link data structure
+ *
+ * Fill the link structure with the local and remote nodes and port numbers.
+ * The local_node and remote_node fields are set to point to the local and
+ * remote port's parent nodes respectively (the port parent node being the
+ * parent node of the port node if that node isn't a 'ports' node, or the
+ * grand-parent node of the port node otherwise).
+ *
+ * A reference is taken to both the local and remote nodes, the caller
+ * must use v4l2_fwnode_endpoint_put_link() to drop the references
+ * when done with the link.
+ *
+ * Return: 0 on success, or -ENOLINK if the remote fwnode can't be found.
+ */
+int v4l2_fwnode_parse_link(struct fwnode_handle *__fwn,
+			   struct v4l2_fwnode_link *link)
+{
+	struct fwnode_handle *fwn;
+	const char *port_prop = is_of_node(__fwn) ? "reg" : "port";
+
+	memset(link, 0, sizeof(*link));
+
+	fwn = fwnode_get_parent(__fwn);
+	fwnode_property_read_u32(fwn, port_prop, &link->local_port);
+	fwn = fwnode_get_next_parent(fwn);
+	if (is_of_node(fwn)) {
+		if (of_node_cmp(to_of_node(fwn)->name, "ports") == 0)
+			fwn = fwnode_get_next_parent(fwn);
+	} else {
+		/* The "ports" node is always there in ACPI. */
+		fwn = fwnode_get_next_parent(fwn);
+	}
+	link->local_node = fwn;
+
+	fwn = fwnode_graph_get_remote_endpoint(fwn);
+	if (!fwn) {
+		fwnode_handle_put(fwn);
+		return -ENOLINK;
+	}
+
+	fwn = fwnode_get_parent(fwn);
+	fwnode_property_read_u32(fwn, port_prop, &link->remote_port);
+	fwn = fwnode_get_next_parent(fwn);
+	if (is_of_node(fwn)) {
+		if (of_node_cmp(to_of_node(fwn)->name, "ports") == 0)
+			fwn = fwnode_get_next_parent(fwn);
+	} else {
+		/* The "ports" node is always there in ACPI. */
+		fwn = fwnode_get_next_parent(fwn);
+	}
+	link->remote_node = fwn;
+
+	return 0;
+}
+EXPORT_SYMBOL(v4l2_fwnode_parse_link);
+
+/**
+ * v4l2_fwnode_put_link() - drop references to nodes in a link
+ * @link: pointer to the V4L2 fwnode link data structure
+ *
+ * Drop references to the local and remote nodes in the link. This
+ * function must be called on every link parsed with
+ * v4l2_fwnode_parse_link().
+ */
+void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link)
+{
+	fwnode_handle_put(link->local_node);
+	fwnode_handle_put(link->remote_node);
+}
+EXPORT_SYMBOL(v4l2_fwnode_put_link);
diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
new file mode 100644
index 0000000..a675d8a
--- /dev/null
+++ b/include/media/v4l2-fwnode.h
@@ -0,0 +1,104 @@
+/*
+ * V4L2 fwnode binding parsing library
+ *
+ * Copyright (c) 2016 Intel Corporation.
+ * Author: Sakari Ailus <sakari.ailus@linux.intel.com>
+ *
+ * Copyright (C) 2012 - 2013 Samsung Electronics Co., Ltd.
+ * Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *
+ * Copyright (C) 2012 Renesas Electronics Corp.
+ * Author: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ */
+#ifndef _V4L2_FWNODE_H
+#define _V4L2_FWNODE_H
+
+#include <linux/list.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/of_graph.h>
+
+#include <media/v4l2-mediabus.h>
+
+struct fwnode_handle;
+
+/**
+ * struct v4l2_fwnode_bus_mipi_csi2 - MIPI CSI-2 bus data structure
+ * @flags: media bus (V4L2_MBUS_*) flags
+ * @data_lanes: an array of physical data lane indexes
+ * @clock_lane: physical lane index of the clock lane
+ * @num_data_lanes: number of data lanes
+ * @lane_polarities: polarity of the lanes. The order is the same of
+ *		   the physical lanes.
+ */
+struct v4l2_fwnode_bus_mipi_csi2 {
+	unsigned int flags;
+	unsigned char data_lanes[4];
+	unsigned char clock_lane;
+	unsigned short num_data_lanes;
+	bool lane_polarities[5];
+};
+
+/**
+ * struct v4l2_fwnode_bus_parallel - parallel data bus data structure
+ * @flags: media bus (V4L2_MBUS_*) flags
+ * @bus_width: bus width in bits
+ * @data_shift: data shift in bits
+ */
+struct v4l2_fwnode_bus_parallel {
+	unsigned int flags;
+	unsigned char bus_width;
+	unsigned char data_shift;
+};
+
+/**
+ * struct v4l2_fwnode_endpoint - the endpoint data structure
+ * @base: fwnode endpoint of the v4l2_fwnode
+ * @bus_type: bus type
+ * @bus: bus configuration data structure
+ * @link_frequencies: array of supported link frequencies
+ * @nr_of_link_frequencies: number of elements in link_frequenccies array
+ */
+struct v4l2_fwnode_endpoint {
+	struct fwnode_endpoint base;
+	/*
+	 * Fields below this line will be zeroed by
+	 * v4l2_fwnode_parse_endpoint()
+	 */
+	enum v4l2_mbus_type bus_type;
+	union {
+		struct v4l2_fwnode_bus_parallel parallel;
+		struct v4l2_fwnode_bus_mipi_csi2 mipi_csi2;
+	} bus;
+	u64 *link_frequencies;
+	unsigned int nr_of_link_frequencies;
+};
+
+/**
+ * struct v4l2_fwnode_link - a link between two endpoints
+ * @local_node: pointer to device_node of this endpoint
+ * @local_port: identifier of the port this endpoint belongs to
+ * @remote_node: pointer to device_node of the remote endpoint
+ * @remote_port: identifier of the port the remote endpoint belongs to
+ */
+struct v4l2_fwnode_link {
+	struct fwnode_handle *local_node;
+	unsigned int local_port;
+	struct fwnode_handle *remote_node;
+	unsigned int remote_port;
+};
+
+int v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwn,
+			       struct v4l2_fwnode_endpoint *vfwn);
+struct v4l2_fwnode_endpoint *v4l2_fwnode_endpoint_alloc_parse(
+	struct fwnode_handle *fwn);
+void v4l2_fwnode_endpoint_free(struct v4l2_fwnode_endpoint *vfwn);
+int v4l2_fwnode_parse_link(struct fwnode_handle *fwn,
+			   struct v4l2_fwnode_link *link);
+void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link);
+
+#endif /* _V4L2_FWNODE_H */
-- 
2.7.4


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

* [RFC 2/5] v4l: async: Match fwnode instead of of_node
  2016-10-05  7:21 [RFC 0/5] V4L2 fwnode support Sakari Ailus
  2016-10-05  7:21 ` [RFC 1/5] v4l: fwnode: Support generic fwnode instead of just OF Sakari Ailus
@ 2016-10-05  7:21 ` Sakari Ailus
  2016-10-05  7:21 ` [RFC 3/5] omap3isp: Switch to fwnode API Sakari Ailus
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Sakari Ailus @ 2016-10-05  7:21 UTC (permalink / raw)
  To: linux-media

Match more generic fwnode instead of OF specific of_node. This will allows
ACPI support.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
---
 drivers/media/v4l2-core/v4l2-async.c | 12 ++++++++++++
 include/media/v4l2-async.h           |  5 +++++
 include/media/v4l2-subdev.h          |  3 +++
 3 files changed, 20 insertions(+)

diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index 5bada20..0dd5e85 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -45,6 +45,11 @@ static bool match_of(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
 	return sd->of_node == asd->match.of.node;
 }
 
+static bool match_fwnode(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
+{
+	return sd->fwnode == asd->match.fwnode.fwn;
+}
+
 static bool match_custom(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
 {
 	if (!asd->match.custom.match)
@@ -79,6 +84,9 @@ static struct v4l2_async_subdev *v4l2_async_belongs(struct v4l2_async_notifier *
 		case V4L2_ASYNC_MATCH_OF:
 			match = match_of;
 			break;
+		case V4L2_ASYNC_MATCH_FWNODE:
+			match = match_fwnode;
+			break;
 		default:
 			/* Cannot happen, unless someone breaks us */
 			WARN_ON(true);
@@ -156,6 +164,7 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
 		case V4L2_ASYNC_MATCH_DEVNAME:
 		case V4L2_ASYNC_MATCH_I2C:
 		case V4L2_ASYNC_MATCH_OF:
+		case V4L2_ASYNC_MATCH_FWNODE:
 			break;
 		default:
 			dev_err(notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL,
@@ -280,6 +289,9 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
 	 */
 	if (!sd->of_node && sd->dev)
 		sd->of_node = sd->dev->of_node;
+	if (!sd->fwnode && sd->dev)
+		sd->fwnode = sd->dev->of_node ?
+			&sd->dev->of_node->fwnode : sd->dev->fwnode;
 
 	mutex_lock(&list_lock);
 
diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
index 8e2a236..d6768ab 100644
--- a/include/media/v4l2-async.h
+++ b/include/media/v4l2-async.h
@@ -32,6 +32,7 @@ struct v4l2_async_notifier;
  * @V4L2_ASYNC_MATCH_DEVNAME: Match will use the device name
  * @V4L2_ASYNC_MATCH_I2C: Match will check for I2C adapter ID and address
  * @V4L2_ASYNC_MATCH_OF: Match will use OF node
+ * @V4L2_ASYNC_MATCH_FWNODE: Match will use firmware node
  *
  * This enum is used by the asyncrhronous sub-device logic to define the
  * algorithm that will be used to match an asynchronous device.
@@ -41,6 +42,7 @@ enum v4l2_async_match_type {
 	V4L2_ASYNC_MATCH_DEVNAME,
 	V4L2_ASYNC_MATCH_I2C,
 	V4L2_ASYNC_MATCH_OF,
+	V4L2_ASYNC_MATCH_FWNODE,
 };
 
 /**
@@ -58,6 +60,9 @@ struct v4l2_async_subdev {
 			const struct device_node *node;
 		} of;
 		struct {
+			const struct fwnode_handle *fwn;
+		} fwnode;
+		struct {
 			const char *name;
 		} device_name;
 		struct {
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index cf778c5..bb8ef1d 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -788,6 +788,8 @@ struct v4l2_subdev_platform_data {
  * @devnode: subdev device node
  * @dev: pointer to the physical device, if any
  * @of_node: The device_node of the subdev, usually the same as dev->of_node.
+ * @fwnode: The fwnode_handle of the subdev, usually the same as
+ *	    either dev->of_node->fwnode or dev->fwnode (whichever is non-NULL).
  * @async_list: Links this subdev to a global subdev_list or @notifier->done
  *	list.
  * @asd: Pointer to respective &struct v4l2_async_subdev.
@@ -819,6 +821,7 @@ struct v4l2_subdev {
 	struct video_device *devnode;
 	struct device *dev;
 	struct device_node *of_node;
+	struct fwnode_handle *fwnode;
 	struct list_head async_list;
 	struct v4l2_async_subdev *asd;
 	struct v4l2_async_notifier *notifier;
-- 
2.7.4


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

* [RFC 3/5] omap3isp: Switch to fwnode API
  2016-10-05  7:21 [RFC 0/5] V4L2 fwnode support Sakari Ailus
  2016-10-05  7:21 ` [RFC 1/5] v4l: fwnode: Support generic fwnode instead of just OF Sakari Ailus
  2016-10-05  7:21 ` [RFC 2/5] v4l: async: Match fwnode instead of of_node Sakari Ailus
@ 2016-10-05  7:21 ` Sakari Ailus
  2016-10-05  7:21 ` [RFC 4/5] smiapp: Support ACPI power control Sakari Ailus
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Sakari Ailus @ 2016-10-05  7:21 UTC (permalink / raw)
  To: linux-media

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
---
 drivers/media/platform/omap3isp/isp.c | 75 ++++++++++++++++++-----------------
 1 file changed, 38 insertions(+), 37 deletions(-)

diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c
index 0321d84..f999629 100644
--- a/drivers/media/platform/omap3isp/isp.c
+++ b/drivers/media/platform/omap3isp/isp.c
@@ -55,6 +55,7 @@
 #include <linux/module.h>
 #include <linux/omap-iommu.h>
 #include <linux/platform_device.h>
+#include <linux/property.h>
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
 #include <linux/sched.h>
@@ -63,9 +64,9 @@
 #include <asm/dma-iommu.h>
 
 #include <media/v4l2-common.h>
+#include <media/v4l2-fwnode.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-mc.h>
-#include <media/v4l2-of.h>
 
 #include "isp.h"
 #include "ispreg.h"
@@ -2024,43 +2025,42 @@ enum isp_of_phy {
 	ISP_OF_PHY_CSIPHY2,
 };
 
-static int isp_of_parse_node(struct device *dev, struct device_node *node,
-			     struct isp_async_subdev *isd)
+static int isp_fwnode_parse(struct device *dev, struct fwnode_handle *fwn,
+			    struct isp_async_subdev *isd)
 {
 	struct isp_bus_cfg *buscfg = &isd->bus;
-	struct v4l2_of_endpoint vep;
+	struct v4l2_fwnode_endpoint vfwn;
 	unsigned int i;
 	int ret;
 
-	ret = v4l2_of_parse_endpoint(node, &vep);
+	ret = v4l2_fwnode_endpoint_parse(fwn, &vfwn);
 	if (ret)
 		return ret;
 
-	dev_dbg(dev, "parsing endpoint %s, interface %u\n", node->full_name,
-		vep.base.port);
+	dev_dbg(dev, "interface %u\n", vfwn.base.port);
 
-	switch (vep.base.port) {
+	switch (vfwn.base.port) {
 	case ISP_OF_PHY_PARALLEL:
 		buscfg->interface = ISP_INTERFACE_PARALLEL;
 		buscfg->bus.parallel.data_lane_shift =
-			vep.bus.parallel.data_shift;
+			vfwn.bus.parallel.data_shift;
 		buscfg->bus.parallel.clk_pol =
-			!!(vep.bus.parallel.flags
+			!!(vfwn.bus.parallel.flags
 			   & V4L2_MBUS_PCLK_SAMPLE_FALLING);
 		buscfg->bus.parallel.hs_pol =
-			!!(vep.bus.parallel.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW);
+			!!(vfwn.bus.parallel.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW);
 		buscfg->bus.parallel.vs_pol =
-			!!(vep.bus.parallel.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW);
+			!!(vfwn.bus.parallel.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW);
 		buscfg->bus.parallel.fld_pol =
-			!!(vep.bus.parallel.flags & V4L2_MBUS_FIELD_EVEN_LOW);
+			!!(vfwn.bus.parallel.flags & V4L2_MBUS_FIELD_EVEN_LOW);
 		buscfg->bus.parallel.data_pol =
-			!!(vep.bus.parallel.flags & V4L2_MBUS_DATA_ACTIVE_LOW);
+			!!(vfwn.bus.parallel.flags & V4L2_MBUS_DATA_ACTIVE_LOW);
 		break;
 
 	case ISP_OF_PHY_CSIPHY1:
 	case ISP_OF_PHY_CSIPHY2:
 		/* FIXME: always assume CSI-2 for now. */
-		switch (vep.base.port) {
+		switch (vfwn.base.port) {
 		case ISP_OF_PHY_CSIPHY1:
 			buscfg->interface = ISP_INTERFACE_CSI2C_PHY1;
 			break;
@@ -2068,18 +2068,18 @@ static int isp_of_parse_node(struct device *dev, struct device_node *node,
 			buscfg->interface = ISP_INTERFACE_CSI2A_PHY2;
 			break;
 		}
-		buscfg->bus.csi2.lanecfg.clk.pos = vep.bus.mipi_csi2.clock_lane;
+		buscfg->bus.csi2.lanecfg.clk.pos = vfwn.bus.mipi_csi2.clock_lane;
 		buscfg->bus.csi2.lanecfg.clk.pol =
-			vep.bus.mipi_csi2.lane_polarities[0];
+			vfwn.bus.mipi_csi2.lane_polarities[0];
 		dev_dbg(dev, "clock lane polarity %u, pos %u\n",
 			buscfg->bus.csi2.lanecfg.clk.pol,
 			buscfg->bus.csi2.lanecfg.clk.pos);
 
 		for (i = 0; i < ISP_CSIPHY2_NUM_DATA_LANES; i++) {
 			buscfg->bus.csi2.lanecfg.data[i].pos =
-				vep.bus.mipi_csi2.data_lanes[i];
+				vfwn.bus.mipi_csi2.data_lanes[i];
 			buscfg->bus.csi2.lanecfg.data[i].pol =
-				vep.bus.mipi_csi2.lane_polarities[i + 1];
+				vfwn.bus.mipi_csi2.lane_polarities[i + 1];
 			dev_dbg(dev, "data lane %u polarity %u, pos %u\n", i,
 				buscfg->bus.csi2.lanecfg.data[i].pol,
 				buscfg->bus.csi2.lanecfg.data[i].pos);
@@ -2094,18 +2094,17 @@ static int isp_of_parse_node(struct device *dev, struct device_node *node,
 		break;
 
 	default:
-		dev_warn(dev, "%s: invalid interface %u\n", node->full_name,
-			 vep.base.port);
+		dev_warn(dev, "invalid interface %u\n", vfwn.base.port);
 		break;
 	}
 
 	return 0;
 }
 
-static int isp_of_parse_nodes(struct device *dev,
-			      struct v4l2_async_notifier *notifier)
+static int isp_fwnodes_parse(struct device *dev,
+			     struct v4l2_async_notifier *notifier)
 {
-	struct device_node *node = NULL;
+	struct fwnode_handle *fwn = NULL;
 
 	notifier->subdevs = devm_kcalloc(
 		dev, ISP_MAX_SUBDEVS, sizeof(*notifier->subdevs), GFP_KERNEL);
@@ -2113,30 +2112,32 @@ static int isp_of_parse_nodes(struct device *dev,
 		return -ENOMEM;
 
 	while (notifier->num_subdevs < ISP_MAX_SUBDEVS &&
-	       (node = of_graph_get_next_endpoint(dev->of_node, node))) {
+	       (fwn = fwnode_graph_get_next_endpoint(device_fwnode_handle(dev),
+						     fwn))) {
 		struct isp_async_subdev *isd;
 
 		isd = devm_kzalloc(dev, sizeof(*isd), GFP_KERNEL);
 		if (!isd) {
-			of_node_put(node);
+			fwnode_handle_put(fwn);
 			return -ENOMEM;
 		}
 
 		notifier->subdevs[notifier->num_subdevs] = &isd->asd;
 
-		if (isp_of_parse_node(dev, node, isd)) {
-			of_node_put(node);
+		if (isp_fwnode_parse(dev, fwn, isd)) {
+			fwnode_handle_put(fwn);
 			return -EINVAL;
 		}
 
-		isd->asd.match.of.node = of_graph_get_remote_port_parent(node);
-		of_node_put(node);
-		if (!isd->asd.match.of.node) {
+		isd->asd.match.fwnode.fwn =
+			fwnode_graph_get_remote_port_parent(fwn);
+		fwnode_handle_put(fwn);
+		if (!isd->asd.match.fwnode.fwn) {
 			dev_warn(dev, "bad remote port parent\n");
 			return -EINVAL;
 		}
 
-		isd->asd.match_type = V4L2_ASYNC_MATCH_OF;
+		isd->asd.match_type = V4L2_ASYNC_MATCH_FWNODE;
 		notifier->num_subdevs++;
 	}
 
@@ -2210,8 +2211,8 @@ static int isp_probe(struct platform_device *pdev)
 		return -ENOMEM;
 	}
 
-	ret = of_property_read_u32(pdev->dev.of_node, "ti,phy-type",
-				   &isp->phy_type);
+	ret = fwnode_property_read_u32(device_fwnode_handle(&pdev->dev),
+				       "ti,phy-type", &isp->phy_type);
 	if (ret)
 		return ret;
 
@@ -2220,12 +2221,12 @@ static int isp_probe(struct platform_device *pdev)
 	if (IS_ERR(isp->syscon))
 		return PTR_ERR(isp->syscon);
 
-	ret = of_property_read_u32_index(pdev->dev.of_node, "syscon", 1,
-					 &isp->syscon_offset);
+	ret = of_property_read_u32_index(pdev->dev.of_node,
+					 "syscon", 1, &isp->syscon_offset);
 	if (ret)
 		return ret;
 
-	ret = isp_of_parse_nodes(&pdev->dev, &isp->notifier);
+	ret = isp_fwnodes_parse(&pdev->dev, &isp->notifier);
 	if (ret < 0)
 		return ret;
 
-- 
2.7.4


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

* [RFC 4/5] smiapp: Support ACPI power control
  2016-10-05  7:21 [RFC 0/5] V4L2 fwnode support Sakari Ailus
                   ` (2 preceding siblings ...)
  2016-10-05  7:21 ` [RFC 3/5] omap3isp: Switch to fwnode API Sakari Ailus
@ 2016-10-05  7:21 ` Sakari Ailus
  2016-10-05  7:21 ` [RFC 5/5] smiapp: Switch to fwnode API Sakari Ailus
  2016-10-05  8:32 ` [RFC 6/6] v4l2: async: Provide interoperability between OF and fwnode matching Sakari Ailus
  5 siblings, 0 replies; 7+ messages in thread
From: Sakari Ailus @ 2016-10-05  7:21 UTC (permalink / raw)
  To: linux-media

On ACPI systems the ACPI will control at least regulators to the sensor. On
such systems the sensor driver does not explicitly need to control them,
thus make them optional.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
---
 drivers/media/i2c/smiapp/smiapp-core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c
index 59872b3..e0d7586 100644
--- a/drivers/media/i2c/smiapp/smiapp-core.c
+++ b/drivers/media/i2c/smiapp/smiapp-core.c
@@ -2887,7 +2887,7 @@ static int smiapp_probe(struct i2c_client *client,
 	v4l2_i2c_subdev_init(&sensor->src->sd, client, &smiapp_ops);
 	sensor->src->sd.internal_ops = &smiapp_internal_src_ops;
 
-	sensor->vana = devm_regulator_get(&client->dev, "vana");
+	sensor->vana = devm_regulator_get_optional(&client->dev, "vana");
 	if (IS_ERR(sensor->vana)) {
 		dev_err(&client->dev, "could not get regulator for vana\n");
 		return PTR_ERR(sensor->vana);
-- 
2.7.4


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

* [RFC 5/5] smiapp: Switch to fwnode API
  2016-10-05  7:21 [RFC 0/5] V4L2 fwnode support Sakari Ailus
                   ` (3 preceding siblings ...)
  2016-10-05  7:21 ` [RFC 4/5] smiapp: Support ACPI power control Sakari Ailus
@ 2016-10-05  7:21 ` Sakari Ailus
  2016-10-05  8:32 ` [RFC 6/6] v4l2: async: Provide interoperability between OF and fwnode matching Sakari Ailus
  5 siblings, 0 replies; 7+ messages in thread
From: Sakari Ailus @ 2016-10-05  7:21 UTC (permalink / raw)
  To: linux-media

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
---
 drivers/media/i2c/smiapp/smiapp-core.c | 29 +++++++++++++++--------------
 1 file changed, 15 insertions(+), 14 deletions(-)

diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c
index e0d7586..e07d38e 100644
--- a/drivers/media/i2c/smiapp/smiapp-core.c
+++ b/drivers/media/i2c/smiapp/smiapp-core.c
@@ -27,12 +27,13 @@
 #include <linux/gpio/consumer.h>
 #include <linux/module.h>
 #include <linux/pm_runtime.h>
+#include <linux/property.h>
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
 #include <linux/smiapp.h>
 #include <linux/v4l2-mediabus.h>
+#include <media/v4l2-fwnode.h>
 #include <media/v4l2-device.h>
-#include <media/v4l2-of.h>
 
 #include "smiapp.h"
 
@@ -2793,19 +2794,20 @@ static int smiapp_resume(struct device *dev)
 static struct smiapp_hwconfig *smiapp_get_hwconfig(struct device *dev)
 {
 	struct smiapp_hwconfig *hwcfg;
-	struct v4l2_of_endpoint *bus_cfg;
-	struct device_node *ep;
+	struct v4l2_fwnode_endpoint *bus_cfg;
+	struct fwnode_handle *ep;
+	struct fwnode_handle *fwn = device_fwnode_handle(dev);
 	int i;
 	int rval;
 
-	if (!dev->of_node)
+	if (!fwn)
 		return dev->platform_data;
 
-	ep = of_graph_get_next_endpoint(dev->of_node, NULL);
+	ep = fwnode_graph_get_next_endpoint(fwn, NULL);
 	if (!ep)
 		return NULL;
 
-	bus_cfg = v4l2_of_alloc_parse_endpoint(ep);
+	bus_cfg = v4l2_fwnode_endpoint_alloc_parse(ep);
 	if (IS_ERR(bus_cfg))
 		goto out_err;
 
@@ -2826,11 +2828,10 @@ static struct smiapp_hwconfig *smiapp_get_hwconfig(struct device *dev)
 	dev_dbg(dev, "lanes %u\n", hwcfg->lanes);
 
 	/* NVM size is not mandatory */
-	of_property_read_u32(dev->of_node, "nokia,nvm-size",
-				    &hwcfg->nvm_size);
+	fwnode_property_read_u32(fwn, "nokia,nvm-size", &hwcfg->nvm_size);
 
-	rval = of_property_read_u32(dev->of_node, "clock-frequency",
-				    &hwcfg->ext_clk);
+	rval = fwnode_property_read_u32(fwn, "clock-frequency",
+					&hwcfg->ext_clk);
 	if (rval) {
 		dev_warn(dev, "can't get clock-frequency\n");
 		goto out_err;
@@ -2855,13 +2856,13 @@ static struct smiapp_hwconfig *smiapp_get_hwconfig(struct device *dev)
 		dev_dbg(dev, "freq %d: %lld\n", i, hwcfg->op_sys_clock[i]);
 	}
 
-	v4l2_of_free_endpoint(bus_cfg);
-	of_node_put(ep);
+	v4l2_fwnode_endpoint_free(bus_cfg);
+	fwnode_handle_put(ep);
 	return hwcfg;
 
 out_err:
-	v4l2_of_free_endpoint(bus_cfg);
-	of_node_put(ep);
+	v4l2_fwnode_endpoint_free(bus_cfg);
+	fwnode_handle_put(ep);
 	return NULL;
 }
 
-- 
2.7.4


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

* [RFC 6/6] v4l2: async: Provide interoperability between OF and fwnode matching
  2016-10-05  7:21 [RFC 0/5] V4L2 fwnode support Sakari Ailus
                   ` (4 preceding siblings ...)
  2016-10-05  7:21 ` [RFC 5/5] smiapp: Switch to fwnode API Sakari Ailus
@ 2016-10-05  8:32 ` Sakari Ailus
  5 siblings, 0 replies; 7+ messages in thread
From: Sakari Ailus @ 2016-10-05  8:32 UTC (permalink / raw)
  To: linux-media

Of and fwnode support are separated in V4L2 and individual drivers may
implement one of them. Sub-devices do not match with a notifier
expecting sub-devices with fwnodes, nor the other way around.

Fix this by checking for sub-device's of_node field in fwnode match and
fwnode field in OF match.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
---
 drivers/media/v4l2-core/v4l2-async.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index 0dd5e85..984e6fa 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -42,12 +42,16 @@ static bool match_devname(struct v4l2_subdev *sd,
 
 static bool match_of(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
 {
-	return sd->of_node == asd->match.of.node;
+	return sd->of_node == asd->match.of.node ||
+		(sd->fwnode && is_of_node(sd->fwnode) &&
+		 sd->fwnode == of_fwnode_handle(asd->match.of.node));
 }
 
 static bool match_fwnode(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
 {
-	return sd->fwnode == asd->match.fwnode.fwn;
+	return sd->fwnode == asd->match.fwnode.fwn ||
+		(sd->of_node &&
+		 of_fwnode_handle(sd->of_node) == asd->match.fwnode.fwn);
 }
 
 static bool match_custom(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
-- 
2.7.4


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

end of thread, other threads:[~2016-10-05  8:34 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-10-05  7:21 [RFC 0/5] V4L2 fwnode support Sakari Ailus
2016-10-05  7:21 ` [RFC 1/5] v4l: fwnode: Support generic fwnode instead of just OF Sakari Ailus
2016-10-05  7:21 ` [RFC 2/5] v4l: async: Match fwnode instead of of_node Sakari Ailus
2016-10-05  7:21 ` [RFC 3/5] omap3isp: Switch to fwnode API Sakari Ailus
2016-10-05  7:21 ` [RFC 4/5] smiapp: Support ACPI power control Sakari Ailus
2016-10-05  7:21 ` [RFC 5/5] smiapp: Switch to fwnode API Sakari Ailus
2016-10-05  8:32 ` [RFC 6/6] v4l2: async: Provide interoperability between OF and fwnode matching Sakari Ailus

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.