// SPDX-License-Identifier: GPL-2.0-only /* * V4L2 fwnode binding parsing library * * The origins of the V4L2 fwnode library are in V4L2 OF library that * formerly was located in v4l2-of.c. * * Copyright (c) 2016 Intel Corporation. * Author: Sakari Ailus <[email protected]> * * Copyright (C) 2012 - 2013 Samsung Electronics Co., Ltd. * Author: Sylwester Nawrocki <[email protected]> * * Copyright (C) 2012 Renesas Electronics Corp. * Author: Guennadi Liakhovetski <[email protected]> */ #include <linux/acpi.h> #include <linux/kernel.h> #include <linux/mm.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-async.h> #include <media/v4l2-fwnode.h> #include <media/v4l2-subdev.h> #include "v4l2-subdev-priv.h" static const struct v4l2_fwnode_bus_conv { … } buses[] = …; static const struct v4l2_fwnode_bus_conv * get_v4l2_fwnode_bus_conv_by_fwnode_bus(enum v4l2_fwnode_bus_type type) { … } static enum v4l2_mbus_type v4l2_fwnode_bus_type_to_mbus(enum v4l2_fwnode_bus_type type) { … } static const char * v4l2_fwnode_bus_type_to_string(enum v4l2_fwnode_bus_type type) { … } static const struct v4l2_fwnode_bus_conv * get_v4l2_fwnode_bus_conv_by_mbus(enum v4l2_mbus_type type) { … } static const char * v4l2_fwnode_mbus_type_to_string(enum v4l2_mbus_type type) { … } static int v4l2_fwnode_endpoint_parse_csi2_bus(struct fwnode_handle *fwnode, struct v4l2_fwnode_endpoint *vep, enum v4l2_mbus_type bus_type) { … } #define PARALLEL_MBUS_FLAGS … static void v4l2_fwnode_endpoint_parse_parallel_bus(struct fwnode_handle *fwnode, struct v4l2_fwnode_endpoint *vep, enum v4l2_mbus_type bus_type) { … } static void v4l2_fwnode_endpoint_parse_csi1_bus(struct fwnode_handle *fwnode, struct v4l2_fwnode_endpoint *vep, enum v4l2_mbus_type bus_type) { … } static int __v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwnode, struct v4l2_fwnode_endpoint *vep) { … } int v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwnode, struct v4l2_fwnode_endpoint *vep) { … } EXPORT_SYMBOL_GPL(…); void v4l2_fwnode_endpoint_free(struct v4l2_fwnode_endpoint *vep) { … } EXPORT_SYMBOL_GPL(…); int v4l2_fwnode_endpoint_alloc_parse(struct fwnode_handle *fwnode, struct v4l2_fwnode_endpoint *vep) { … } EXPORT_SYMBOL_GPL(…); int v4l2_fwnode_parse_link(struct fwnode_handle *fwnode, struct v4l2_fwnode_link *link) { … } EXPORT_SYMBOL_GPL(…); void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link) { … } EXPORT_SYMBOL_GPL(…); static const struct v4l2_fwnode_connector_conv { … } connectors[] = …; static enum v4l2_connector_type v4l2_fwnode_string_to_connector_type(const char *con_str) { … } static void v4l2_fwnode_connector_parse_analog(struct fwnode_handle *fwnode, struct v4l2_fwnode_connector *vc) { … } void v4l2_fwnode_connector_free(struct v4l2_fwnode_connector *connector) { … } EXPORT_SYMBOL_GPL(…); static enum v4l2_connector_type v4l2_fwnode_get_connector_type(struct fwnode_handle *fwnode) { … } int v4l2_fwnode_connector_parse(struct fwnode_handle *fwnode, struct v4l2_fwnode_connector *connector) { … } EXPORT_SYMBOL_GPL(…); int v4l2_fwnode_connector_add_link(struct fwnode_handle *fwnode, struct v4l2_fwnode_connector *connector) { … } EXPORT_SYMBOL_GPL(…); int v4l2_fwnode_device_parse(struct device *dev, struct v4l2_fwnode_device_properties *props) { … } EXPORT_SYMBOL_GPL(…); /* * v4l2_fwnode_reference_parse - parse references for async sub-devices * @dev: the device node the properties of which are parsed for references * @notifier: the async notifier where the async subdevs will be added * @prop: the name of the property * * Return: 0 on success * -ENOENT if no entries were found * -ENOMEM if memory allocation failed * -EINVAL if property parsing failed */ static int v4l2_fwnode_reference_parse(struct device *dev, struct v4l2_async_notifier *notifier, const char *prop) { … } /* * v4l2_fwnode_reference_get_int_prop - parse a reference with integer * arguments * @fwnode: fwnode to read @prop from * @notifier: notifier for @dev * @prop: the name of the property * @index: the index of the reference to get * @props: the array of integer property names * @nprops: the number of integer property names in @nprops * * First find an fwnode referred to by the reference at @index in @prop. * * Then under that fwnode, @nprops times, for each property in @props, * iteratively follow child nodes starting from fwnode such that they have the * property in @props array at the index of the child node distance from the * root node and the value of that property matching with the integer argument * of the reference, at the same index. * * The child fwnode reached at the end of the iteration is then returned to the * caller. * * The core reason for this is that you cannot refer to just any node in ACPI. * So to refer to an endpoint (easy in DT) you need to refer to a device, then * provide a list of (property name, property value) tuples where each tuple * uniquely identifies a child node. The first tuple identifies a child directly * underneath the device fwnode, the next tuple identifies a child node * underneath the fwnode identified by the previous tuple, etc. until you * reached the fwnode you need. * * THIS EXAMPLE EXISTS MERELY TO DOCUMENT THIS FUNCTION. DO NOT USE IT AS A * REFERENCE IN HOW ACPI TABLES SHOULD BE WRITTEN!! See documentation under * Documentation/firmware-guide/acpi/dsd/ instead and especially graph.txt, * data-node-references.txt and leds.txt . * * Scope (\_SB.PCI0.I2C2) * { * Device (CAM0) * { * Name (_DSD, Package () { * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), * Package () { * Package () { * "compatible", * Package () { "nokia,smia" } * }, * }, * ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"), * Package () { * Package () { "port0", "PRT0" }, * } * }) * Name (PRT0, Package() { * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), * Package () { * Package () { "port", 0 }, * }, * ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"), * Package () { * Package () { "endpoint0", "EP00" }, * } * }) * Name (EP00, Package() { * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), * Package () { * Package () { "endpoint", 0 }, * Package () { * "remote-endpoint", * Package() { * \_SB.PCI0.ISP, 4, 0 * } * }, * } * }) * } * } * * Scope (\_SB.PCI0) * { * Device (ISP) * { * Name (_DSD, Package () { * ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"), * Package () { * Package () { "port4", "PRT4" }, * } * }) * * Name (PRT4, Package() { * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), * Package () { * Package () { "port", 4 }, * }, * ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"), * Package () { * Package () { "endpoint0", "EP40" }, * } * }) * * Name (EP40, Package() { * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), * Package () { * Package () { "endpoint", 0 }, * Package () { * "remote-endpoint", * Package () { * \_SB.PCI0.I2C2.CAM0, * 0, 0 * } * }, * } * }) * } * } * * From the EP40 node under ISP device, you could parse the graph remote * endpoint using v4l2_fwnode_reference_get_int_prop with these arguments: * * @fwnode: fwnode referring to EP40 under ISP. * @prop: "remote-endpoint" * @index: 0 * @props: "port", "endpoint" * @nprops: 2 * * And you'd get back fwnode referring to EP00 under CAM0. * * The same works the other way around: if you use EP00 under CAM0 as the * fwnode, you'll get fwnode referring to EP40 under ISP. * * The same example in DT syntax would look like this: * * cam: cam0 { * compatible = "nokia,smia"; * * port { * port = <0>; * endpoint { * endpoint = <0>; * remote-endpoint = <&isp 4 0>; * }; * }; * }; * * isp: isp { * ports { * port@4 { * port = <4>; * endpoint { * endpoint = <0>; * remote-endpoint = <&cam 0 0>; * }; * }; * }; * }; * * Return: 0 on success * -ENOENT if no entries (or the property itself) were found * -EINVAL if property parsing otherwise failed * -ENOMEM if memory allocation failed */ static struct fwnode_handle * v4l2_fwnode_reference_get_int_prop(struct fwnode_handle *fwnode, const char *prop, unsigned int index, const char * const *props, unsigned int nprops) { … } struct v4l2_fwnode_int_props { … }; /* * v4l2_fwnode_reference_parse_int_props - parse references for async * sub-devices * @dev: struct device pointer * @notifier: notifier for @dev * @prop: the name of the property * @props: the array of integer property names * @nprops: the number of integer properties * * Use v4l2_fwnode_reference_get_int_prop to find fwnodes through reference in * property @prop with integer arguments with child nodes matching in properties * @props. Then, set up V4L2 async sub-devices for those fwnodes in the notifier * accordingly. * * While it is technically possible to use this function on DT, it is only * meaningful on ACPI. On Device tree you can refer to any node in the tree but * on ACPI the references are limited to devices. * * Return: 0 on success * -ENOENT if no entries (or the property itself) were found * -EINVAL if property parsing otherwisefailed * -ENOMEM if memory allocation failed */ static int v4l2_fwnode_reference_parse_int_props(struct device *dev, struct v4l2_async_notifier *notifier, const struct v4l2_fwnode_int_props *p) { … } /** * v4l2_async_nf_parse_fwnode_sensor - parse common references on * sensors for async sub-devices * @dev: the device node the properties of which are parsed for references * @notifier: the async notifier where the async subdevs will be added * * Parse common sensor properties for remote devices related to the * sensor and set up async sub-devices for them. * * Any notifier populated using this function must be released with a call to * v4l2_async_nf_release() after it has been unregistered and the async * sub-devices are no longer in use, even in the case the function returned an * error. * * Return: 0 on success * -ENOMEM if memory allocation failed * -EINVAL if property parsing failed */ static int v4l2_async_nf_parse_fwnode_sensor(struct device *dev, struct v4l2_async_notifier *notifier) { … } int v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd) { … } EXPORT_SYMBOL_GPL(…); MODULE_DESCRIPTION(…) …; MODULE_LICENSE(…) …; MODULE_AUTHOR(…) …; MODULE_AUTHOR(…) …; MODULE_AUTHOR(…) …;