ACPI / property: Extend device_get_next_child_node() to data-only nodes
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Thu, 27 Aug 2015 02:42:33 +0000 (04:42 +0200)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Mon, 14 Sep 2015 23:47:34 +0000 (01:47 +0200)
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>
drivers/acpi/property.c
drivers/acpi/scan.c
drivers/base/property.c
drivers/gpio/gpiolib-acpi.c
drivers/gpio/gpiolib.c
drivers/gpio/gpiolib.h
include/linux/acpi.h

index e785517..1465443 100644 (file)
@@ -461,9 +461,9 @@ static int acpi_data_get_property_array(struct acpi_device_data *data,
 }
 
 /**
- * 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 @@ static int acpi_data_get_property_array(struct acpi_device_data *data,
  *
  * 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 @@ int acpi_dev_get_property_reference(struct acpi_device *adev,
 
        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 @@ int acpi_node_prop_read(struct fwnode_handle *fwnode,  const char *propname,
        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;
+}
index 01136b8..d1ce377 100644 (file)
@@ -695,26 +695,6 @@ int acpi_device_add(struct acpi_device *device,
        return result;
 }
 
-struct acpi_device *acpi_get_next_child(struct device *dev,
-                                       struct acpi_device *child)
-{
-       struct acpi_device *adev = ACPI_COMPANION(dev);
-       struct list_head *head, *next;
-
-       if (!adev)
-               return NULL;
-
-       head = &adev->children;
-       if (list_empty(head))
-               return NULL;
-
-       if (!child)
-               return list_first_entry(head, struct acpi_device, node);
-
-       next = child->node.next;
-       return next == head ? NULL : list_entry(next, struct acpi_device, node);
-}
-
 /* --------------------------------------------------------------------------
                                  Device Enumeration
    -------------------------------------------------------------------------- */
index ca11816..660ecec 100644 (file)
@@ -493,11 +493,7 @@ struct fwnode_handle *device_get_next_child_node(struct device *dev,
                if (node)
                        return &node->fwnode;
        } else if (IS_ENABLED(CONFIG_ACPI)) {
-               struct acpi_device *node;
-
-               node = acpi_get_next_child(dev, to_acpi_device_node(child));
-               if (node)
-                       return acpi_fwnode_handle(node);
+               return acpi_get_next_subnode(dev, child);
        }
        return NULL;
 }
index a38cf16..69a8362 100644 (file)
@@ -453,7 +453,7 @@ static int acpi_gpio_resource_lookup(struct acpi_gpio_lookup *lookup,
        return 0;
 }
 
-static int acpi_gpio_property_lookup(struct acpi_device *adev,
+static int acpi_gpio_property_lookup(struct fwnode_handle *fwnode,
                                     const char *propname, int index,
                                     struct acpi_gpio_lookup *lookup)
 {
@@ -461,10 +461,16 @@ static int acpi_gpio_property_lookup(struct acpi_device *adev,
        int ret;
 
        memset(&args, 0, sizeof(args));
-       ret = acpi_dev_get_property_reference(adev, propname, index, &args);
-       if (ret && !acpi_get_driver_gpio_data(adev, propname, index, &args))
-               return ret;
+       ret = acpi_node_get_property_reference(fwnode, propname, index, &args);
+       if (ret) {
+               struct acpi_device *adev = to_acpi_device_node(fwnode);
 
+               if (!adev)
+                       return ret;
+
+               if (!acpi_get_driver_gpio_data(adev, propname, index, &args))
+                       return ret;
+       }
        /*
         * The property was found and resolved, so need to lookup the GPIO based
         * on returned args.
@@ -518,7 +524,8 @@ struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev,
        if (propname) {
                dev_dbg(&adev->dev, "GPIO: looking up %s\n", propname);
 
-               ret = acpi_gpio_property_lookup(adev, propname, index, &lookup);
+               ret = acpi_gpio_property_lookup(acpi_fwnode_handle(adev),
+                                               propname, index, &lookup);
                if (ret)
                        return ERR_PTR(ret);
 
@@ -535,6 +542,47 @@ struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev,
 }
 
 /**
+ * acpi_node_get_gpiod() - get a GPIO descriptor from ACPI resources
+ * @fwnode: pointer to an ACPI firmware node to get the GPIO information from
+ * @propname: Property name of the GPIO
+ * @index: index of GpioIo/GpioInt resource (starting from %0)
+ * @info: info pointer to fill in (optional)
+ *
+ * If @fwnode is an ACPI device object, call %acpi_get_gpiod_by_index() for it.
+ * Otherwise (ie. it is a data-only non-device object), use the property-based
+ * GPIO lookup to get to the GPIO resource with the relevant information and use
+ * that to obtain the GPIO descriptor to return.
+ */
+struct gpio_desc *acpi_node_get_gpiod(struct fwnode_handle *fwnode,
+                                     const char *propname, int index,
+                                     struct acpi_gpio_info *info)
+{
+       struct acpi_gpio_lookup lookup;
+       struct acpi_device *adev;
+       int ret;
+
+       adev = to_acpi_device_node(fwnode);
+       if (adev)
+               return acpi_get_gpiod_by_index(adev, propname, index, info);
+
+       if (!is_acpi_data_node(fwnode))
+               return ERR_PTR(-ENODEV);
+
+       if (!propname)
+               return ERR_PTR(-EINVAL);
+
+       memset(&lookup, 0, sizeof(lookup));
+       lookup.index = index;
+
+       ret = acpi_gpio_property_lookup(fwnode, propname, index, &lookup);
+       if (ret)
+               return ERR_PTR(ret);
+
+       ret = acpi_gpio_resource_lookup(&lookup, info);
+       return ret ? ERR_PTR(ret) : lookup.desc;
+}
+
+/**
  * acpi_dev_gpio_irq_get() - Find GpioInt and translate it to Linux IRQ number
  * @adev: pointer to a ACPI device to get IRQ from
  * @index: index of GpioInt resource (starting from %0)
index f43e808..7d61b50 100644 (file)
@@ -2083,11 +2083,10 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
                                                &flags);
                if (!IS_ERR(desc))
                        active_low = flags & OF_GPIO_ACTIVE_LOW;
-       } else if (is_acpi_device_node(fwnode)) {
+       } else if (is_acpi_node(fwnode)) {
                struct acpi_gpio_info info;
 
-               desc = acpi_get_gpiod_by_index(to_acpi_device_node(fwnode),
-                                              propname, 0, &info);
+               desc = acpi_node_get_gpiod(fwnode, propname, 0, &info);
                if (!IS_ERR(desc))
                        active_low = info.active_low;
        }
index bf34300..e69c715 100644 (file)
@@ -42,6 +42,9 @@ void acpi_gpiochip_free_interrupts(struct gpio_chip *chip);
 struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev,
                                          const char *propname, int index,
                                          struct acpi_gpio_info *info);
+struct gpio_desc *acpi_node_get_gpiod(struct fwnode_handle *fwnode,
+                                     const char *propname, int index,
+                                     struct acpi_gpio_info *info);
 
 int acpi_gpio_count(struct device *dev, const char *con_id);
 #else
@@ -60,7 +63,12 @@ acpi_get_gpiod_by_index(struct acpi_device *adev, const char *propname,
 {
        return ERR_PTR(-ENOSYS);
 }
-
+static inline struct gpio_desc *
+acpi_node_get_gpiod(struct fwnode_handle *fwnode, const char *propname,
+                   int index, struct acpi_gpio_info *info)
+{
+       return ERR_PTR(-ENXIO);
+}
 static inline int acpi_gpio_count(struct device *dev, const char *con_id)
 {
        return -ENODEV;
index 6be94ba..865d948 100644 (file)
@@ -758,9 +758,9 @@ struct acpi_reference_args {
 #ifdef CONFIG_ACPI
 int acpi_dev_get_property(struct acpi_device *adev, const char *name,
                          acpi_object_type type, const union acpi_object **obj);
-int acpi_dev_get_property_reference(struct acpi_device *adev,
-                                   const char *name, size_t index,
-                                   struct acpi_reference_args *args);
+int acpi_node_get_property_reference(struct fwnode_handle *fwnode,
+                                    const char *name, size_t index,
+                                    struct acpi_reference_args *args);
 
 int acpi_node_prop_get(struct fwnode_handle *fwnode, const char *propname,
                       void **valptr);
@@ -771,8 +771,8 @@ int acpi_node_prop_read(struct fwnode_handle *fwnode, const char *propname,
 int acpi_dev_prop_read(struct acpi_device *adev, const char *propname,
                       enum dev_prop_type proptype, void *val, size_t nval);
 
-struct acpi_device *acpi_get_next_child(struct device *dev,
-                                       struct acpi_device *child);
+struct fwnode_handle *acpi_get_next_subnode(struct device *dev,
+                                           struct fwnode_handle *subnode);
 #else
 static inline int acpi_dev_get_property(struct acpi_device *adev,
                                        const char *name, acpi_object_type type,
@@ -781,7 +781,7 @@ static inline int acpi_dev_get_property(struct acpi_device *adev,
        return -ENXIO;
 }
 
-static inline int acpi_dev_get_property_reference(struct acpi_device *adev,
+static inline int acpi_node_get_property_reference(struct fwnode_handle *fwnode,
                                const char *name, const char *cells_name,
                                size_t index, struct acpi_reference_args *args)
 {
@@ -826,12 +826,11 @@ static inline int acpi_dev_prop_read(struct acpi_device *adev,
        return -ENXIO;
 }
 
-static inline struct acpi_device *acpi_get_next_child(struct device *dev,
-                                                     struct acpi_device *child)
+static inline struct fwnode_handle *acpi_get_next_subnode(struct device *dev,
+                                               struct fwnode_handle *subnode)
 {
        return NULL;
 }
-
 #endif
 
 #endif /*_LINUX_ACPI_H*/