ACPI / property: Extend device_get_next_child_node() to data-only nodes

Make device_get_next_child_node() work with ACPI data-only subnodes
introduced previously.

Namely, replace acpi_get_next_child() with acpi_get_next_subnode()
that can handle (and return) child device objects as well as child
data-only subnodes of the given device and modify the ACPI part
of the GPIO subsystem to handle data-only subnodes returned by it.

To that end, introduce acpi_node_get_gpiod() taking a struct
fwnode_handle pointer as the first argument.  That argument may
point to an ACPI device object as well as to a data-only subnode
and the function should do the right thing (ie. look for the matching
GPIO descriptor correctly) in either case.

Next, modify fwnode_get_named_gpiod() to use acpi_node_get_gpiod()
instead of acpi_get_gpiod_by_index() which automatically causes
devm_get_gpiod_from_child() to work with ACPI data-only subnodes
that may be returned by device_get_next_child_node() which in turn
is required by the users of that function (the gpio_keys_polled
and gpio-leds drivers).

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c
index e785517..1465443 100644
--- a/drivers/acpi/property.c
+++ b/drivers/acpi/property.c
@@ -461,9 +461,9 @@
 }
 
 /**
- * acpi_dev_get_property_reference - returns handle to the referenced object
- * @adev: ACPI device to get property
- * @name: Name of the property
+ * acpi_data_get_property_reference - returns handle to the referenced object
+ * @data: ACPI device data object containing the property
+ * @propname: Name of the property
  * @index: Index of the reference to return
  * @args: Location to store the returned reference with optional arguments
  *
@@ -477,16 +477,16 @@
  *
  * Return: %0 on success, negative error code on failure.
  */
-int acpi_dev_get_property_reference(struct acpi_device *adev,
-				    const char *name, size_t index,
-				    struct acpi_reference_args *args)
+static int acpi_data_get_property_reference(struct acpi_device_data *data,
+					    const char *propname, size_t index,
+					    struct acpi_reference_args *args)
 {
 	const union acpi_object *element, *end;
 	const union acpi_object *obj;
 	struct acpi_device *device;
 	int ret, idx = 0;
 
-	ret = acpi_dev_get_property(adev, name, ACPI_TYPE_ANY, &obj);
+	ret = acpi_data_get_property(data, propname, ACPI_TYPE_ANY, &obj);
 	if (ret)
 		return ret;
 
@@ -561,7 +561,23 @@
 
 	return -EPROTO;
 }
-EXPORT_SYMBOL_GPL(acpi_dev_get_property_reference);
+
+/**
+ * acpi_node_get_property_reference - get a handle to the referenced object.
+ * @fwnode: Firmware node to get the property from.
+ * @propname: Name of the property.
+ * @index: Index of the reference to return.
+ * @args: Location to store the returned reference with optional arguments.
+ */
+int acpi_node_get_property_reference(struct fwnode_handle *fwnode,
+				     const char *name, size_t index,
+				     struct acpi_reference_args *args)
+{
+	struct acpi_device_data *data = acpi_device_data_of_node(fwnode);
+
+	return data ? acpi_data_get_property_reference(data, name, index, args) : -EINVAL;
+}
+EXPORT_SYMBOL_GPL(acpi_node_get_property_reference);
 
 static int acpi_data_prop_read_single(struct acpi_device_data *data,
 				      const char *propname,
@@ -768,3 +784,59 @@
 	return acpi_data_prop_read(acpi_device_data_of_node(fwnode),
 				   propname, proptype, val, nval);
 }
+
+/**
+ * acpi_get_next_subnode - Return the next child node handle for a device.
+ * @dev: Device to find the next child node for.
+ * @child: Handle to one of the device's child nodes or a null handle.
+ */
+struct fwnode_handle *acpi_get_next_subnode(struct device *dev,
+					    struct fwnode_handle *child)
+{
+	struct acpi_device *adev = ACPI_COMPANION(dev);
+	struct list_head *head, *next;
+
+	if (!adev)
+		return NULL;
+
+	if (!child || child->type == FWNODE_ACPI) {
+		head = &adev->children;
+		if (list_empty(head))
+			goto nondev;
+
+		if (child) {
+			adev = to_acpi_device_node(child);
+			next = adev->node.next;
+			if (next == head) {
+				child = NULL;
+				goto nondev;
+			}
+			adev = list_entry(next, struct acpi_device, node);
+		} else {
+			adev = list_first_entry(head, struct acpi_device, node);
+		}
+		return acpi_fwnode_handle(adev);
+	}
+
+ nondev:
+	if (!child || child->type == FWNODE_ACPI_DATA) {
+		struct acpi_data_node *dn;
+
+		head = &adev->data.subnodes;
+		if (list_empty(head))
+			return NULL;
+
+		if (child) {
+			dn = to_acpi_data_node(child);
+			next = dn->sibling.next;
+			if (next == head)
+				return NULL;
+
+			dn = list_entry(next, struct acpi_data_node, sibling);
+		} else {
+			dn = list_first_entry(head, struct acpi_data_node, sibling);
+		}
+		return &dn->fwnode;
+	}
+	return NULL;
+}