Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 504a3374 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki
Browse files

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: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
Tested-by: default avatarMika Westerberg <mika.westerberg@linux.intel.com>
Acked-by: default avatarLinus Walleij <linus.walleij@linaro.org>
parent d079524a
Loading
Loading
Loading
Loading
+80 −8
Original line number Diff line number Diff line
@@ -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,8 +477,8 @@ 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,
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;
@@ -486,7 +486,7 @@ int acpi_dev_get_property_reference(struct acpi_device *adev,
	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;
}
+0 −20
Original line number Diff line number Diff line
@@ -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
   -------------------------------------------------------------------------- */
+1 −5
Original line number Diff line number Diff line
@@ -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;
}
+53 −5
Original line number Diff line number Diff line
@@ -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))
	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);

@@ -534,6 +541,47 @@ struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev,
	return ret ? ERR_PTR(ret) : lookup.desc;
}

/**
 * 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
+2 −3
Original line number Diff line number Diff line
@@ -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;
	}
Loading