From 68ef162152120220aea4415f4ea72e16eb8215c0 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 19 Jun 2017 16:40:15 +0300 Subject: [PATCH] BACKPORT: device property: Introduce fwnode_property_get_reference_args The new fwnode_property_get_reference_args() interface amends the fwnode property API with the functionality of both of_parse_phandle_with_args() and __acpi_node_get_property_reference(). The semantics is slightly different: the cells property is ignored on ACPI as the number of arguments can be explicitly obtained from the firmware interface. Signed-off-by: Sakari Ailus (cherry picked from commit 3e3119d3088f41106f3581d39e7694a50ca3fc02) Signed-off-by: Brian J Lovin Brian L: Had to de-constify this commit, and picks are unclean due to the number of commits skipped for this kernel. Conflicts: drivers/acpi/property.c drivers/base/property.c include/linux/fwnode.h BUG=b:64133998 TEST=media device topology shows subdevs registered successfully TEST=no camera regression Change-Id: I982255df1aabaadb9de09fc71e6db5c4b99b0e02 Reviewed-on: https://chromium-review.googlesource.com/693682 Commit-Ready: Tomasz Figa Tested-by: Hyungwoo Yang Reviewed-by: Tomasz Figa Signed-off-by: Jacob Chen --- drivers/acpi/property.c | 27 +++++++++++++++++++++++++++ drivers/base/property.c | 28 ++++++++++++++++++++++++++++ drivers/of/property.c | 31 +++++++++++++++++++++++++++++++ include/linux/fwnode.h | 19 +++++++++++++++++++ include/linux/property.h | 4 ++++ 5 files changed, 109 insertions(+) diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index 476a52c60cf3..1b5eaad29ec8 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c @@ -1187,6 +1187,32 @@ acpi_fwnode_get_named_child_node(struct fwnode_handle *fwnode, return NULL; } +static int +acpi_fwnode_get_reference_args(struct fwnode_handle *fwnode, + const char *prop, const char *nargs_prop, + unsigned int args_count, unsigned int index, + struct fwnode_reference_args *args) +{ + struct acpi_reference_args acpi_args; + unsigned int i; + int ret; + + ret = __acpi_node_get_property_reference(fwnode, prop, index, + args_count, &acpi_args); + if (ret < 0) + return ret; + if (!args) + return 0; + + args->nargs = acpi_args.nargs; + args->fwnode = acpi_fwnode_handle(acpi_args.adev); + + for (i = 0; i < NR_OF_FWNODE_REFERENCE_ARGS; i++) + args->args[i] = i < acpi_args.nargs ? acpi_args.args[i] : 0; + + return 0; +} + static struct fwnode_handle * acpi_fwnode_graph_get_next_endpoint(struct fwnode_handle *fwnode, struct fwnode_handle *prev) @@ -1231,6 +1257,7 @@ const struct fwnode_operations acpi_fwnode_ops = { .get_parent = acpi_node_get_parent, .get_next_child_node = acpi_get_next_subnode, .get_named_child_node = acpi_fwnode_get_named_child_node, + .get_reference_args = acpi_fwnode_get_reference_args, .graph_get_next_endpoint = acpi_fwnode_graph_get_next_endpoint, .graph_get_remote_endpoint = acpi_fwnode_graph_get_remote_endpoint, .graph_get_port_parent = acpi_node_get_parent, diff --git a/drivers/base/property.c b/drivers/base/property.c index d268b83e4148..14866be5f7b5 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -652,6 +652,34 @@ out: } EXPORT_SYMBOL_GPL(fwnode_property_match_string); +/** + * fwnode_property_get_reference_args() - Find a reference with arguments + * @fwnode: Firmware node where to look for the reference + * @prop: The name of the property + * @nargs_prop: The name of the property telling the number of + * arguments in the referred node. NULL if @nargs is known, + * otherwise @nargs is ignored. Only relevant on OF. + * @nargs: Number of arguments. Ignored if @nargs_prop is non-NULL. + * @index: Index of the reference, from zero onwards. + * @args: Result structure with reference and integer arguments. + * + * Obtain a reference based on a named property in an fwnode, with + * integer arguments. + * + * Caller is responsible to call fwnode_handle_put() on the returned + * args->fwnode pointer. + * + */ +int fwnode_property_get_reference_args(struct fwnode_handle *fwnode, + const char *prop, const char *nargs_prop, + unsigned int nargs, unsigned int index, + struct fwnode_reference_args *args) +{ + return fwnode_call_int_op(fwnode, get_reference_args, prop, nargs_prop, + nargs, index, args); +} +EXPORT_SYMBOL_GPL(fwnode_property_get_reference_args); + /** * pset_free_set - releases memory allocated for copied property set * @pset: Property set to release diff --git a/drivers/of/property.c b/drivers/of/property.c index 249b6999cae0..2c201e2c257d 100644 --- a/drivers/of/property.c +++ b/drivers/of/property.c @@ -849,6 +849,36 @@ of_fwnode_get_named_child_node(struct fwnode_handle *fwnode, return NULL; } +static int +of_fwnode_get_reference_args(struct fwnode_handle *fwnode, + const char *prop, const char *nargs_prop, + unsigned int nargs, unsigned int index, + struct fwnode_reference_args *args) +{ + struct of_phandle_args of_args; + unsigned int i; + int ret; + + if (nargs_prop) + ret = of_parse_phandle_with_args(to_of_node(fwnode), prop, + nargs_prop, index, &of_args); + else + ret = of_parse_phandle_with_fixed_args(to_of_node(fwnode), prop, + nargs, index, &of_args); + if (ret < 0) + return ret; + if (!args) + return 0; + + args->nargs = of_args.args_count; + args->fwnode = of_fwnode_handle(of_args.np); + + for (i = 0; i < NR_OF_FWNODE_REFERENCE_ARGS; i++) + args->args[i] = i < of_args.args_count ? of_args.args[i] : 0; + + return 0; +} + static struct fwnode_handle * of_fwnode_graph_get_next_endpoint(struct fwnode_handle *fwnode, struct fwnode_handle *prev) @@ -907,6 +937,7 @@ const struct fwnode_operations of_fwnode_ops = { .get_parent = of_fwnode_get_parent, .get_next_child_node = of_fwnode_get_next_child_node, .get_named_child_node = of_fwnode_get_named_child_node, + .get_reference_args = of_fwnode_get_reference_args, .graph_get_next_endpoint = of_fwnode_graph_get_next_endpoint, .graph_get_remote_endpoint = of_fwnode_graph_get_remote_endpoint, .graph_get_port_parent = of_fwnode_graph_get_port_parent, diff --git a/include/linux/fwnode.h b/include/linux/fwnode.h index 98679d7f7485..c3ea0a27d17c 100644 --- a/include/linux/fwnode.h +++ b/include/linux/fwnode.h @@ -43,6 +43,20 @@ struct fwnode_endpoint { const struct fwnode_handle *local_fwnode; }; +#define NR_OF_FWNODE_REFERENCE_ARGS 8 + +/** + * struct fwnode_reference_args - Fwnode reference with additional arguments + * @fwnode:- A reference to the base fwnode + * @nargs: Number of elements in @args array + * @args: Integer arguments on the fwnode + */ +struct fwnode_reference_args { + struct fwnode_handle *fwnode; + unsigned int nargs; + unsigned int args[NR_OF_FWNODE_REFERENCE_ARGS]; +}; + /** * struct fwnode_operations - Operations for fwnode interface * @get: Get a reference to an fwnode. @@ -56,6 +70,7 @@ struct fwnode_endpoint { * @get_parent: Return the parent of an fwnode. * @get_next_child_node: Return the next child node in an iteration. * @get_named_child_node: Return a child node with a given name. + * @get_reference_args: Return a reference pointed to by a property, with args * @graph_get_next_endpoint: Return an endpoint node in an iteration. * @graph_get_remote_endpoint: Return the remote endpoint node of a local * endpoint node. @@ -81,6 +96,10 @@ struct fwnode_operations { struct fwnode_handle *child); struct fwnode_handle * (*get_named_child_node)(struct fwnode_handle *fwnode, const char *name); + int (*get_reference_args)(struct fwnode_handle *fwnode, + const char *prop, const char *nargs_prop, + unsigned int nargs, unsigned int index, + struct fwnode_reference_args *args); struct fwnode_handle * (*graph_get_next_endpoint)(struct fwnode_handle *fwnode, struct fwnode_handle *prev); diff --git a/include/linux/property.h b/include/linux/property.h index 30e62f19ae73..935ce0a6df15 100644 --- a/include/linux/property.h +++ b/include/linux/property.h @@ -72,6 +72,10 @@ int fwnode_property_read_string(struct fwnode_handle *fwnode, const char *propname, const char **val); int fwnode_property_match_string(struct fwnode_handle *fwnode, const char *propname, const char *string); +int fwnode_property_get_reference_args(struct fwnode_handle *fwnode, + const char *prop, const char *nargs_prop, + unsigned int nargs, unsigned int index, + struct fwnode_reference_args *args); struct fwnode_handle *fwnode_get_parent(struct fwnode_handle *fwnode); struct fwnode_handle *fwnode_get_next_parent(struct fwnode_handle *fwnode);