Device properties framework updates for 5.19-rc1
- Allow error pointer to be passed to fwnode APIs (Andy Shevchenko). - Introduce fwnode_for_each_parent_node() (Andy Shevchenko, Douglas Anderson). - Advertise fwnode and device property count API calls (Andy Shevchenko). - Clean up fwnode_is_ancestor_of() (Andy Shevchenko). - Convert device_{dma_supported,get_dma_attr} to fwnode (Sakari Ailus). - Release subnode properties with data nodes (Sakari Ailus). - Add ->iomap() and ->irq_get() to fwnode operations (Sakari Ailus). -----BEGIN PGP SIGNATURE----- iQJGBAABCAAwFiEE4fcc61cGeeHD/fCwgsRv/nhiVHEFAmKL4qwSHHJqd0Byand5 c29ja2kubmV0AAoJEILEb/54YlRxO+AP/ir+1VKydUioBbH9vh8grCF1vAoJhknv jb0STEBq+SH7+EwWbpj/J9+ldACvIJ0wnrsZ83vbl9k0z5+mrddw3HiQrrCc2PSc hRfWCi4ihnTlDK2Sctm/suBSNivh8kcGwJUcYOwYaWEVdGoUXrqldWzzRo48DYgo KnHm4e2V5Gob2u4edbdgtOl4BGcBcOPNDdOe15Ra6pjcp+0DUWP55j51kmhpjLSk PuAEtbNLPOzOVIVFpANU4Q7/3G3gjKIwPjKwAsWaa2UKYdsmcLhr8gaBo05UBV6g M6VPq14OHLGBlwxcxrsFgsNy9uBHnxEAHE0NRg7hrA2eHAqiuA7R+itBvzcgx8Wj HRTI9ZFjZabx82rWkb7iKI/K/ok5igzX3/zrbr7Bf3+7QY0+UEMqpmPVak01xqe7 nFk7x3rHgZOsKPs+0ZN8pG16vEyuPFEQLJV0o25fiyhK2ob8tbAZxy3nVBRm8H/o yzuD9rYmZKHHwp3Ff4Bn+S8/T6vpYhsQkEz+NjjGMcXZXMBhbH+wsu9aBtVY/Jdp wVrmkxm/RC3b97oVoisqY05Wv/tgUwybSkPbARZWQjmshuazrvaJAi+N/LWwBuMK gsBVLTivWthjlCiPwRZlADTKbhlpdwSikWaC0xktsyqaO3JDtJFn305V7L9oWpQz tShfSJ2GRBOT =ly4P -----END PGP SIGNATURE----- Merge tag 'devprop-5.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm Pull device properties framework updates from Rafael Wysocki: "These mostly extend the device property API and make it easier to use in some cases. Specifics: - Allow error pointer to be passed to fwnode APIs (Andy Shevchenko). - Introduce fwnode_for_each_parent_node() (Andy Shevchenko, Douglas Anderson). - Advertise fwnode and device property count API calls (Andy Shevchenko). - Clean up fwnode_is_ancestor_of() (Andy Shevchenko). - Convert device_{dma_supported,get_dma_attr} to fwnode (Sakari Ailus). - Release subnode properties with data nodes (Sakari Ailus). - Add ->iomap() and ->irq_get() to fwnode operations (Sakari Ailus)" * tag 'devprop-5.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: device property: Advertise fwnode and device property count API calls device property: Fix recent breakage of fwnode_get_next_parent_dev() device property: Drop 'test' prefix in parameters of fwnode_is_ancestor_of() device property: Introduce fwnode_for_each_parent_node() device property: Allow error pointer to be passed to fwnode APIs ACPI: property: Release subnode properties with data nodes device property: Add irq_get to fwnode operation device property: Add iomap to fwnode operations ACPI: property: Move acpi_fwnode_device_get_match_data() up device property: Convert device_{dma_supported,get_dma_attr} to fwnode
This commit is contained in:
commit
268db333b5
@ -433,6 +433,16 @@ void acpi_init_properties(struct acpi_device *adev)
|
|||||||
acpi_extract_apple_properties(adev);
|
acpi_extract_apple_properties(adev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void acpi_free_device_properties(struct list_head *list)
|
||||||
|
{
|
||||||
|
struct acpi_device_properties *props, *tmp;
|
||||||
|
|
||||||
|
list_for_each_entry_safe(props, tmp, list, list) {
|
||||||
|
list_del(&props->list);
|
||||||
|
kfree(props);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void acpi_destroy_nondev_subnodes(struct list_head *list)
|
static void acpi_destroy_nondev_subnodes(struct list_head *list)
|
||||||
{
|
{
|
||||||
struct acpi_data_node *dn, *next;
|
struct acpi_data_node *dn, *next;
|
||||||
@ -445,22 +455,18 @@ static void acpi_destroy_nondev_subnodes(struct list_head *list)
|
|||||||
wait_for_completion(&dn->kobj_done);
|
wait_for_completion(&dn->kobj_done);
|
||||||
list_del(&dn->sibling);
|
list_del(&dn->sibling);
|
||||||
ACPI_FREE((void *)dn->data.pointer);
|
ACPI_FREE((void *)dn->data.pointer);
|
||||||
|
acpi_free_device_properties(&dn->data.properties);
|
||||||
kfree(dn);
|
kfree(dn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void acpi_free_properties(struct acpi_device *adev)
|
void acpi_free_properties(struct acpi_device *adev)
|
||||||
{
|
{
|
||||||
struct acpi_device_properties *props, *tmp;
|
|
||||||
|
|
||||||
acpi_destroy_nondev_subnodes(&adev->data.subnodes);
|
acpi_destroy_nondev_subnodes(&adev->data.subnodes);
|
||||||
ACPI_FREE((void *)adev->data.pointer);
|
ACPI_FREE((void *)adev->data.pointer);
|
||||||
adev->data.of_compatible = NULL;
|
adev->data.of_compatible = NULL;
|
||||||
adev->data.pointer = NULL;
|
adev->data.pointer = NULL;
|
||||||
list_for_each_entry_safe(props, tmp, &adev->data.properties, list) {
|
acpi_free_device_properties(&adev->data.properties);
|
||||||
list_del(&props->list);
|
|
||||||
kfree(props);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1256,6 +1262,24 @@ static bool acpi_fwnode_device_is_available(const struct fwnode_handle *fwnode)
|
|||||||
return acpi_device_is_present(to_acpi_device_node(fwnode));
|
return acpi_device_is_present(to_acpi_device_node(fwnode));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const void *
|
||||||
|
acpi_fwnode_device_get_match_data(const struct fwnode_handle *fwnode,
|
||||||
|
const struct device *dev)
|
||||||
|
{
|
||||||
|
return acpi_device_get_match_data(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool acpi_fwnode_device_dma_supported(const struct fwnode_handle *fwnode)
|
||||||
|
{
|
||||||
|
return acpi_dma_supported(to_acpi_device_node(fwnode));
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum dev_dma_attr
|
||||||
|
acpi_fwnode_device_get_dma_attr(const struct fwnode_handle *fwnode)
|
||||||
|
{
|
||||||
|
return acpi_get_dma_attr(to_acpi_device_node(fwnode));
|
||||||
|
}
|
||||||
|
|
||||||
static bool acpi_fwnode_property_present(const struct fwnode_handle *fwnode,
|
static bool acpi_fwnode_property_present(const struct fwnode_handle *fwnode,
|
||||||
const char *propname)
|
const char *propname)
|
||||||
{
|
{
|
||||||
@ -1376,17 +1400,26 @@ static int acpi_fwnode_graph_parse_endpoint(const struct fwnode_handle *fwnode,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const void *
|
static int acpi_fwnode_irq_get(const struct fwnode_handle *fwnode,
|
||||||
acpi_fwnode_device_get_match_data(const struct fwnode_handle *fwnode,
|
unsigned int index)
|
||||||
const struct device *dev)
|
|
||||||
{
|
{
|
||||||
return acpi_device_get_match_data(dev);
|
struct resource res;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = acpi_irq_get(ACPI_HANDLE_FWNODE(fwnode), index, &res);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return res.start;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define DECLARE_ACPI_FWNODE_OPS(ops) \
|
#define DECLARE_ACPI_FWNODE_OPS(ops) \
|
||||||
const struct fwnode_operations ops = { \
|
const struct fwnode_operations ops = { \
|
||||||
.device_is_available = acpi_fwnode_device_is_available, \
|
.device_is_available = acpi_fwnode_device_is_available, \
|
||||||
.device_get_match_data = acpi_fwnode_device_get_match_data, \
|
.device_get_match_data = acpi_fwnode_device_get_match_data, \
|
||||||
|
.device_dma_supported = \
|
||||||
|
acpi_fwnode_device_dma_supported, \
|
||||||
|
.device_get_dma_attr = acpi_fwnode_device_get_dma_attr, \
|
||||||
.property_present = acpi_fwnode_property_present, \
|
.property_present = acpi_fwnode_property_present, \
|
||||||
.property_read_int_array = \
|
.property_read_int_array = \
|
||||||
acpi_fwnode_property_read_int_array, \
|
acpi_fwnode_property_read_int_array, \
|
||||||
@ -1404,6 +1437,7 @@ acpi_fwnode_device_get_match_data(const struct fwnode_handle *fwnode,
|
|||||||
acpi_graph_get_remote_endpoint, \
|
acpi_graph_get_remote_endpoint, \
|
||||||
.graph_get_port_parent = acpi_fwnode_get_parent, \
|
.graph_get_port_parent = acpi_fwnode_get_parent, \
|
||||||
.graph_parse_endpoint = acpi_fwnode_graph_parse_endpoint, \
|
.graph_parse_endpoint = acpi_fwnode_graph_parse_endpoint, \
|
||||||
|
.irq_get = acpi_fwnode_irq_get, \
|
||||||
}; \
|
}; \
|
||||||
EXPORT_SYMBOL_GPL(ops)
|
EXPORT_SYMBOL_GPL(ops)
|
||||||
|
|
||||||
|
@ -47,12 +47,14 @@ bool fwnode_property_present(const struct fwnode_handle *fwnode,
|
|||||||
{
|
{
|
||||||
bool ret;
|
bool ret;
|
||||||
|
|
||||||
|
if (IS_ERR_OR_NULL(fwnode))
|
||||||
|
return false;
|
||||||
|
|
||||||
ret = fwnode_call_bool_op(fwnode, property_present, propname);
|
ret = fwnode_call_bool_op(fwnode, property_present, propname);
|
||||||
if (ret == false && !IS_ERR_OR_NULL(fwnode) &&
|
if (ret)
|
||||||
!IS_ERR_OR_NULL(fwnode->secondary))
|
return ret;
|
||||||
ret = fwnode_call_bool_op(fwnode->secondary, property_present,
|
|
||||||
propname);
|
return fwnode_call_bool_op(fwnode->secondary, property_present, propname);
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(fwnode_property_present);
|
EXPORT_SYMBOL_GPL(fwnode_property_present);
|
||||||
|
|
||||||
@ -66,6 +68,9 @@ EXPORT_SYMBOL_GPL(fwnode_property_present);
|
|||||||
* Function reads an array of u8 properties with @propname from the device
|
* Function reads an array of u8 properties with @propname from the device
|
||||||
* firmware description and stores them to @val if found.
|
* firmware description and stores them to @val if found.
|
||||||
*
|
*
|
||||||
|
* It's recommended to call device_property_count_u8() instead of calling
|
||||||
|
* this function with @val equals %NULL and @nval equals 0.
|
||||||
|
*
|
||||||
* Return: number of values if @val was %NULL,
|
* Return: number of values if @val was %NULL,
|
||||||
* %0 if the property was found (success),
|
* %0 if the property was found (success),
|
||||||
* %-EINVAL if given arguments are not valid,
|
* %-EINVAL if given arguments are not valid,
|
||||||
@ -91,6 +96,9 @@ EXPORT_SYMBOL_GPL(device_property_read_u8_array);
|
|||||||
* Function reads an array of u16 properties with @propname from the device
|
* Function reads an array of u16 properties with @propname from the device
|
||||||
* firmware description and stores them to @val if found.
|
* firmware description and stores them to @val if found.
|
||||||
*
|
*
|
||||||
|
* It's recommended to call device_property_count_u16() instead of calling
|
||||||
|
* this function with @val equals %NULL and @nval equals 0.
|
||||||
|
*
|
||||||
* Return: number of values if @val was %NULL,
|
* Return: number of values if @val was %NULL,
|
||||||
* %0 if the property was found (success),
|
* %0 if the property was found (success),
|
||||||
* %-EINVAL if given arguments are not valid,
|
* %-EINVAL if given arguments are not valid,
|
||||||
@ -116,6 +124,9 @@ EXPORT_SYMBOL_GPL(device_property_read_u16_array);
|
|||||||
* Function reads an array of u32 properties with @propname from the device
|
* Function reads an array of u32 properties with @propname from the device
|
||||||
* firmware description and stores them to @val if found.
|
* firmware description and stores them to @val if found.
|
||||||
*
|
*
|
||||||
|
* It's recommended to call device_property_count_u32() instead of calling
|
||||||
|
* this function with @val equals %NULL and @nval equals 0.
|
||||||
|
*
|
||||||
* Return: number of values if @val was %NULL,
|
* Return: number of values if @val was %NULL,
|
||||||
* %0 if the property was found (success),
|
* %0 if the property was found (success),
|
||||||
* %-EINVAL if given arguments are not valid,
|
* %-EINVAL if given arguments are not valid,
|
||||||
@ -141,6 +152,9 @@ EXPORT_SYMBOL_GPL(device_property_read_u32_array);
|
|||||||
* Function reads an array of u64 properties with @propname from the device
|
* Function reads an array of u64 properties with @propname from the device
|
||||||
* firmware description and stores them to @val if found.
|
* firmware description and stores them to @val if found.
|
||||||
*
|
*
|
||||||
|
* It's recommended to call device_property_count_u64() instead of calling
|
||||||
|
* this function with @val equals %NULL and @nval equals 0.
|
||||||
|
*
|
||||||
* Return: number of values if @val was %NULL,
|
* Return: number of values if @val was %NULL,
|
||||||
* %0 if the property was found (success),
|
* %0 if the property was found (success),
|
||||||
* %-EINVAL if given arguments are not valid,
|
* %-EINVAL if given arguments are not valid,
|
||||||
@ -166,6 +180,9 @@ EXPORT_SYMBOL_GPL(device_property_read_u64_array);
|
|||||||
* Function reads an array of string properties with @propname from the device
|
* Function reads an array of string properties with @propname from the device
|
||||||
* firmware description and stores them to @val if found.
|
* firmware description and stores them to @val if found.
|
||||||
*
|
*
|
||||||
|
* It's recommended to call device_property_string_array_count() instead of calling
|
||||||
|
* this function with @val equals %NULL and @nval equals 0.
|
||||||
|
*
|
||||||
* Return: number of values read on success if @val is non-NULL,
|
* Return: number of values read on success if @val is non-NULL,
|
||||||
* number of values available on success if @val is NULL,
|
* number of values available on success if @val is NULL,
|
||||||
* %-EINVAL if given arguments are not valid,
|
* %-EINVAL if given arguments are not valid,
|
||||||
@ -232,15 +249,16 @@ static int fwnode_property_read_int_array(const struct fwnode_handle *fwnode,
|
|||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
if (IS_ERR_OR_NULL(fwnode))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
ret = fwnode_call_int_op(fwnode, property_read_int_array, propname,
|
ret = fwnode_call_int_op(fwnode, property_read_int_array, propname,
|
||||||
elem_size, val, nval);
|
elem_size, val, nval);
|
||||||
if (ret == -EINVAL && !IS_ERR_OR_NULL(fwnode) &&
|
if (ret != -EINVAL)
|
||||||
!IS_ERR_OR_NULL(fwnode->secondary))
|
return ret;
|
||||||
ret = fwnode_call_int_op(
|
|
||||||
fwnode->secondary, property_read_int_array, propname,
|
|
||||||
elem_size, val, nval);
|
|
||||||
|
|
||||||
return ret;
|
return fwnode_call_int_op(fwnode->secondary, property_read_int_array, propname,
|
||||||
|
elem_size, val, nval);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -253,6 +271,9 @@ static int fwnode_property_read_int_array(const struct fwnode_handle *fwnode,
|
|||||||
* Read an array of u8 properties with @propname from @fwnode and stores them to
|
* Read an array of u8 properties with @propname from @fwnode and stores them to
|
||||||
* @val if found.
|
* @val if found.
|
||||||
*
|
*
|
||||||
|
* It's recommended to call fwnode_property_count_u8() instead of calling
|
||||||
|
* this function with @val equals %NULL and @nval equals 0.
|
||||||
|
*
|
||||||
* Return: number of values if @val was %NULL,
|
* Return: number of values if @val was %NULL,
|
||||||
* %0 if the property was found (success),
|
* %0 if the property was found (success),
|
||||||
* %-EINVAL if given arguments are not valid,
|
* %-EINVAL if given arguments are not valid,
|
||||||
@ -279,6 +300,9 @@ EXPORT_SYMBOL_GPL(fwnode_property_read_u8_array);
|
|||||||
* Read an array of u16 properties with @propname from @fwnode and store them to
|
* Read an array of u16 properties with @propname from @fwnode and store them to
|
||||||
* @val if found.
|
* @val if found.
|
||||||
*
|
*
|
||||||
|
* It's recommended to call fwnode_property_count_u16() instead of calling
|
||||||
|
* this function with @val equals %NULL and @nval equals 0.
|
||||||
|
*
|
||||||
* Return: number of values if @val was %NULL,
|
* Return: number of values if @val was %NULL,
|
||||||
* %0 if the property was found (success),
|
* %0 if the property was found (success),
|
||||||
* %-EINVAL if given arguments are not valid,
|
* %-EINVAL if given arguments are not valid,
|
||||||
@ -305,6 +329,9 @@ EXPORT_SYMBOL_GPL(fwnode_property_read_u16_array);
|
|||||||
* Read an array of u32 properties with @propname from @fwnode store them to
|
* Read an array of u32 properties with @propname from @fwnode store them to
|
||||||
* @val if found.
|
* @val if found.
|
||||||
*
|
*
|
||||||
|
* It's recommended to call fwnode_property_count_u32() instead of calling
|
||||||
|
* this function with @val equals %NULL and @nval equals 0.
|
||||||
|
*
|
||||||
* Return: number of values if @val was %NULL,
|
* Return: number of values if @val was %NULL,
|
||||||
* %0 if the property was found (success),
|
* %0 if the property was found (success),
|
||||||
* %-EINVAL if given arguments are not valid,
|
* %-EINVAL if given arguments are not valid,
|
||||||
@ -331,6 +358,9 @@ EXPORT_SYMBOL_GPL(fwnode_property_read_u32_array);
|
|||||||
* Read an array of u64 properties with @propname from @fwnode and store them to
|
* Read an array of u64 properties with @propname from @fwnode and store them to
|
||||||
* @val if found.
|
* @val if found.
|
||||||
*
|
*
|
||||||
|
* It's recommended to call fwnode_property_count_u64() instead of calling
|
||||||
|
* this function with @val equals %NULL and @nval equals 0.
|
||||||
|
*
|
||||||
* Return: number of values if @val was %NULL,
|
* Return: number of values if @val was %NULL,
|
||||||
* %0 if the property was found (success),
|
* %0 if the property was found (success),
|
||||||
* %-EINVAL if given arguments are not valid,
|
* %-EINVAL if given arguments are not valid,
|
||||||
@ -357,6 +387,9 @@ EXPORT_SYMBOL_GPL(fwnode_property_read_u64_array);
|
|||||||
* Read an string list property @propname from the given firmware node and store
|
* Read an string list property @propname from the given firmware node and store
|
||||||
* them to @val if found.
|
* them to @val if found.
|
||||||
*
|
*
|
||||||
|
* It's recommended to call fwnode_property_string_array_count() instead of calling
|
||||||
|
* this function with @val equals %NULL and @nval equals 0.
|
||||||
|
*
|
||||||
* Return: number of values read on success if @val is non-NULL,
|
* Return: number of values read on success if @val is non-NULL,
|
||||||
* number of values available on success if @val is NULL,
|
* number of values available on success if @val is NULL,
|
||||||
* %-EINVAL if given arguments are not valid,
|
* %-EINVAL if given arguments are not valid,
|
||||||
@ -371,14 +404,16 @@ int fwnode_property_read_string_array(const struct fwnode_handle *fwnode,
|
|||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
if (IS_ERR_OR_NULL(fwnode))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
ret = fwnode_call_int_op(fwnode, property_read_string_array, propname,
|
ret = fwnode_call_int_op(fwnode, property_read_string_array, propname,
|
||||||
val, nval);
|
val, nval);
|
||||||
if (ret == -EINVAL && !IS_ERR_OR_NULL(fwnode) &&
|
if (ret != -EINVAL)
|
||||||
!IS_ERR_OR_NULL(fwnode->secondary))
|
return ret;
|
||||||
ret = fwnode_call_int_op(fwnode->secondary,
|
|
||||||
property_read_string_array, propname,
|
return fwnode_call_int_op(fwnode->secondary, property_read_string_array, propname,
|
||||||
val, nval);
|
val, nval);
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(fwnode_property_read_string_array);
|
EXPORT_SYMBOL_GPL(fwnode_property_read_string_array);
|
||||||
|
|
||||||
@ -480,15 +515,19 @@ int fwnode_property_get_reference_args(const struct fwnode_handle *fwnode,
|
|||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
if (IS_ERR_OR_NULL(fwnode))
|
||||||
|
return -ENOENT;
|
||||||
|
|
||||||
ret = fwnode_call_int_op(fwnode, get_reference_args, prop, nargs_prop,
|
ret = fwnode_call_int_op(fwnode, get_reference_args, prop, nargs_prop,
|
||||||
nargs, index, args);
|
nargs, index, args);
|
||||||
|
if (ret == 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
if (ret < 0 && !IS_ERR_OR_NULL(fwnode) &&
|
if (IS_ERR_OR_NULL(fwnode->secondary))
|
||||||
!IS_ERR_OR_NULL(fwnode->secondary))
|
return ret;
|
||||||
ret = fwnode_call_int_op(fwnode->secondary, get_reference_args,
|
|
||||||
prop, nargs_prop, nargs, index, args);
|
|
||||||
|
|
||||||
return ret;
|
return fwnode_call_int_op(fwnode->secondary, get_reference_args, prop, nargs_prop,
|
||||||
|
nargs, index, args);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(fwnode_property_get_reference_args);
|
EXPORT_SYMBOL_GPL(fwnode_property_get_reference_args);
|
||||||
|
|
||||||
@ -587,17 +626,17 @@ EXPORT_SYMBOL_GPL(fwnode_get_next_parent);
|
|||||||
*/
|
*/
|
||||||
struct device *fwnode_get_next_parent_dev(struct fwnode_handle *fwnode)
|
struct device *fwnode_get_next_parent_dev(struct fwnode_handle *fwnode)
|
||||||
{
|
{
|
||||||
|
struct fwnode_handle *parent;
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
|
|
||||||
fwnode_handle_get(fwnode);
|
fwnode_for_each_parent_node(fwnode, parent) {
|
||||||
do {
|
dev = get_dev_from_fwnode(parent);
|
||||||
fwnode = fwnode_get_next_parent(fwnode);
|
if (dev) {
|
||||||
if (!fwnode)
|
fwnode_handle_put(parent);
|
||||||
return NULL;
|
return dev;
|
||||||
dev = get_dev_from_fwnode(fwnode);
|
}
|
||||||
} while (!dev);
|
}
|
||||||
fwnode_handle_put(fwnode);
|
return NULL;
|
||||||
return dev;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -608,13 +647,11 @@ struct device *fwnode_get_next_parent_dev(struct fwnode_handle *fwnode)
|
|||||||
*/
|
*/
|
||||||
unsigned int fwnode_count_parents(const struct fwnode_handle *fwnode)
|
unsigned int fwnode_count_parents(const struct fwnode_handle *fwnode)
|
||||||
{
|
{
|
||||||
struct fwnode_handle *__fwnode;
|
struct fwnode_handle *parent;
|
||||||
unsigned int count;
|
unsigned int count = 0;
|
||||||
|
|
||||||
__fwnode = fwnode_get_parent(fwnode);
|
fwnode_for_each_parent_node(fwnode, parent)
|
||||||
|
count++;
|
||||||
for (count = 0; __fwnode; count++)
|
|
||||||
__fwnode = fwnode_get_next_parent(__fwnode);
|
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
@ -635,40 +672,43 @@ EXPORT_SYMBOL_GPL(fwnode_count_parents);
|
|||||||
struct fwnode_handle *fwnode_get_nth_parent(struct fwnode_handle *fwnode,
|
struct fwnode_handle *fwnode_get_nth_parent(struct fwnode_handle *fwnode,
|
||||||
unsigned int depth)
|
unsigned int depth)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
struct fwnode_handle *parent;
|
||||||
|
|
||||||
fwnode_handle_get(fwnode);
|
if (depth == 0)
|
||||||
|
return fwnode_handle_get(fwnode);
|
||||||
|
|
||||||
for (i = 0; i < depth && fwnode; i++)
|
fwnode_for_each_parent_node(fwnode, parent) {
|
||||||
fwnode = fwnode_get_next_parent(fwnode);
|
if (--depth == 0)
|
||||||
|
return parent;
|
||||||
return fwnode;
|
}
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(fwnode_get_nth_parent);
|
EXPORT_SYMBOL_GPL(fwnode_get_nth_parent);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fwnode_is_ancestor_of - Test if @test_ancestor is ancestor of @test_child
|
* fwnode_is_ancestor_of - Test if @ancestor is ancestor of @child
|
||||||
* @test_ancestor: Firmware which is tested for being an ancestor
|
* @ancestor: Firmware which is tested for being an ancestor
|
||||||
* @test_child: Firmware which is tested for being the child
|
* @child: Firmware which is tested for being the child
|
||||||
*
|
*
|
||||||
* A node is considered an ancestor of itself too.
|
* A node is considered an ancestor of itself too.
|
||||||
*
|
*
|
||||||
* Returns true if @test_ancestor is an ancestor of @test_child.
|
* Returns true if @ancestor is an ancestor of @child. Otherwise, returns false.
|
||||||
* Otherwise, returns false.
|
|
||||||
*/
|
*/
|
||||||
bool fwnode_is_ancestor_of(struct fwnode_handle *test_ancestor,
|
bool fwnode_is_ancestor_of(struct fwnode_handle *ancestor, struct fwnode_handle *child)
|
||||||
struct fwnode_handle *test_child)
|
|
||||||
{
|
{
|
||||||
if (!test_ancestor)
|
struct fwnode_handle *parent;
|
||||||
|
|
||||||
|
if (IS_ERR_OR_NULL(ancestor))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
fwnode_handle_get(test_child);
|
if (child == ancestor)
|
||||||
while (test_child) {
|
return true;
|
||||||
if (test_child == test_ancestor) {
|
|
||||||
fwnode_handle_put(test_child);
|
fwnode_for_each_parent_node(child, parent) {
|
||||||
|
if (parent == ancestor) {
|
||||||
|
fwnode_handle_put(parent);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
test_child = fwnode_get_next_parent(test_child);
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -698,7 +738,7 @@ fwnode_get_next_available_child_node(const struct fwnode_handle *fwnode,
|
|||||||
{
|
{
|
||||||
struct fwnode_handle *next_child = child;
|
struct fwnode_handle *next_child = child;
|
||||||
|
|
||||||
if (!fwnode)
|
if (IS_ERR_OR_NULL(fwnode))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
@ -722,16 +762,16 @@ struct fwnode_handle *device_get_next_child_node(struct device *dev,
|
|||||||
const struct fwnode_handle *fwnode = dev_fwnode(dev);
|
const struct fwnode_handle *fwnode = dev_fwnode(dev);
|
||||||
struct fwnode_handle *next;
|
struct fwnode_handle *next;
|
||||||
|
|
||||||
|
if (IS_ERR_OR_NULL(fwnode))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
/* Try to find a child in primary fwnode */
|
/* Try to find a child in primary fwnode */
|
||||||
next = fwnode_get_next_child_node(fwnode, child);
|
next = fwnode_get_next_child_node(fwnode, child);
|
||||||
if (next)
|
if (next)
|
||||||
return next;
|
return next;
|
||||||
|
|
||||||
/* When no more children in primary, continue with secondary */
|
/* When no more children in primary, continue with secondary */
|
||||||
if (fwnode && !IS_ERR_OR_NULL(fwnode->secondary))
|
return fwnode_get_next_child_node(fwnode->secondary, child);
|
||||||
next = fwnode_get_next_child_node(fwnode->secondary, child);
|
|
||||||
|
|
||||||
return next;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(device_get_next_child_node);
|
EXPORT_SYMBOL_GPL(device_get_next_child_node);
|
||||||
|
|
||||||
@ -798,6 +838,9 @@ EXPORT_SYMBOL_GPL(fwnode_handle_put);
|
|||||||
*/
|
*/
|
||||||
bool fwnode_device_is_available(const struct fwnode_handle *fwnode)
|
bool fwnode_device_is_available(const struct fwnode_handle *fwnode)
|
||||||
{
|
{
|
||||||
|
if (IS_ERR_OR_NULL(fwnode))
|
||||||
|
return false;
|
||||||
|
|
||||||
if (!fwnode_has_op(fwnode, device_is_available))
|
if (!fwnode_has_op(fwnode, device_is_available))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@ -823,33 +866,16 @@ EXPORT_SYMBOL_GPL(device_get_child_node_count);
|
|||||||
|
|
||||||
bool device_dma_supported(struct device *dev)
|
bool device_dma_supported(struct device *dev)
|
||||||
{
|
{
|
||||||
const struct fwnode_handle *fwnode = dev_fwnode(dev);
|
return fwnode_call_bool_op(dev_fwnode(dev), device_dma_supported);
|
||||||
|
|
||||||
/* For DT, this is always supported.
|
|
||||||
* For ACPI, this depends on CCA, which
|
|
||||||
* is determined by the acpi_dma_supported().
|
|
||||||
*/
|
|
||||||
if (is_of_node(fwnode))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return acpi_dma_supported(to_acpi_device_node(fwnode));
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(device_dma_supported);
|
EXPORT_SYMBOL_GPL(device_dma_supported);
|
||||||
|
|
||||||
enum dev_dma_attr device_get_dma_attr(struct device *dev)
|
enum dev_dma_attr device_get_dma_attr(struct device *dev)
|
||||||
{
|
{
|
||||||
const struct fwnode_handle *fwnode = dev_fwnode(dev);
|
if (!fwnode_has_op(dev_fwnode(dev), device_get_dma_attr))
|
||||||
enum dev_dma_attr attr = DEV_DMA_NOT_SUPPORTED;
|
return DEV_DMA_NOT_SUPPORTED;
|
||||||
|
|
||||||
if (is_of_node(fwnode)) {
|
return fwnode_call_int_op(dev_fwnode(dev), device_get_dma_attr);
|
||||||
if (of_dma_is_coherent(to_of_node(fwnode)))
|
|
||||||
attr = DEV_DMA_COHERENT;
|
|
||||||
else
|
|
||||||
attr = DEV_DMA_NON_COHERENT;
|
|
||||||
} else
|
|
||||||
attr = acpi_get_dma_attr(to_acpi_device_node(fwnode));
|
|
||||||
|
|
||||||
return attr;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(device_get_dma_attr);
|
EXPORT_SYMBOL_GPL(device_get_dma_attr);
|
||||||
|
|
||||||
@ -904,10 +930,7 @@ EXPORT_SYMBOL_GPL(device_get_phy_mode);
|
|||||||
*/
|
*/
|
||||||
void __iomem *fwnode_iomap(struct fwnode_handle *fwnode, int index)
|
void __iomem *fwnode_iomap(struct fwnode_handle *fwnode, int index)
|
||||||
{
|
{
|
||||||
if (IS_ENABLED(CONFIG_OF_ADDRESS) && is_of_node(fwnode))
|
return fwnode_call_ptr_op(fwnode, iomap, index);
|
||||||
return of_iomap(to_of_node(fwnode), index);
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(fwnode_iomap);
|
EXPORT_SYMBOL(fwnode_iomap);
|
||||||
|
|
||||||
@ -921,17 +944,7 @@ EXPORT_SYMBOL(fwnode_iomap);
|
|||||||
*/
|
*/
|
||||||
int fwnode_irq_get(const struct fwnode_handle *fwnode, unsigned int index)
|
int fwnode_irq_get(const struct fwnode_handle *fwnode, unsigned int index)
|
||||||
{
|
{
|
||||||
struct resource res;
|
return fwnode_call_int_op(fwnode, irq_get, index);
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (is_of_node(fwnode))
|
|
||||||
return of_irq_get(to_of_node(fwnode), index);
|
|
||||||
|
|
||||||
ret = acpi_irq_get(ACPI_HANDLE_FWNODE(fwnode), index, &res);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
return res.start;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(fwnode_irq_get);
|
EXPORT_SYMBOL(fwnode_irq_get);
|
||||||
|
|
||||||
@ -988,14 +1001,14 @@ fwnode_graph_get_next_endpoint(const struct fwnode_handle *fwnode,
|
|||||||
parent = fwnode_graph_get_port_parent(prev);
|
parent = fwnode_graph_get_port_parent(prev);
|
||||||
else
|
else
|
||||||
parent = fwnode;
|
parent = fwnode;
|
||||||
|
if (IS_ERR_OR_NULL(parent))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
ep = fwnode_call_ptr_op(parent, graph_get_next_endpoint, prev);
|
ep = fwnode_call_ptr_op(parent, graph_get_next_endpoint, prev);
|
||||||
|
if (ep)
|
||||||
|
return ep;
|
||||||
|
|
||||||
if (IS_ERR_OR_NULL(ep) &&
|
return fwnode_graph_get_next_endpoint(parent->secondary, NULL);
|
||||||
!IS_ERR_OR_NULL(parent) && !IS_ERR_OR_NULL(parent->secondary))
|
|
||||||
ep = fwnode_graph_get_next_endpoint(parent->secondary, NULL);
|
|
||||||
|
|
||||||
return ep;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(fwnode_graph_get_next_endpoint);
|
EXPORT_SYMBOL_GPL(fwnode_graph_get_next_endpoint);
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#define pr_fmt(fmt) "OF: " fmt
|
#define pr_fmt(fmt) "OF: " fmt
|
||||||
|
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
|
#include <linux/of_address.h>
|
||||||
#include <linux/of_device.h>
|
#include <linux/of_device.h>
|
||||||
#include <linux/of_graph.h>
|
#include <linux/of_graph.h>
|
||||||
#include <linux/of_irq.h>
|
#include <linux/of_irq.h>
|
||||||
@ -872,6 +873,20 @@ static bool of_fwnode_device_is_available(const struct fwnode_handle *fwnode)
|
|||||||
return of_device_is_available(to_of_node(fwnode));
|
return of_device_is_available(to_of_node(fwnode));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool of_fwnode_device_dma_supported(const struct fwnode_handle *fwnode)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum dev_dma_attr
|
||||||
|
of_fwnode_device_get_dma_attr(const struct fwnode_handle *fwnode)
|
||||||
|
{
|
||||||
|
if (of_dma_is_coherent(to_of_node(fwnode)))
|
||||||
|
return DEV_DMA_COHERENT;
|
||||||
|
else
|
||||||
|
return DEV_DMA_NON_COHERENT;
|
||||||
|
}
|
||||||
|
|
||||||
static bool of_fwnode_property_present(const struct fwnode_handle *fwnode,
|
static bool of_fwnode_property_present(const struct fwnode_handle *fwnode,
|
||||||
const char *propname)
|
const char *propname)
|
||||||
{
|
{
|
||||||
@ -1450,6 +1465,21 @@ static int of_link_property(struct device_node *con_np, const char *prop_name)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void __iomem *of_fwnode_iomap(struct fwnode_handle *fwnode, int index)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_OF_ADDRESS
|
||||||
|
return of_iomap(to_of_node(fwnode), index);
|
||||||
|
#else
|
||||||
|
return NULL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static int of_fwnode_irq_get(const struct fwnode_handle *fwnode,
|
||||||
|
unsigned int index)
|
||||||
|
{
|
||||||
|
return of_irq_get(to_of_node(fwnode), index);
|
||||||
|
}
|
||||||
|
|
||||||
static int of_fwnode_add_links(struct fwnode_handle *fwnode)
|
static int of_fwnode_add_links(struct fwnode_handle *fwnode)
|
||||||
{
|
{
|
||||||
struct property *p;
|
struct property *p;
|
||||||
@ -1472,6 +1502,8 @@ const struct fwnode_operations of_fwnode_ops = {
|
|||||||
.put = of_fwnode_put,
|
.put = of_fwnode_put,
|
||||||
.device_is_available = of_fwnode_device_is_available,
|
.device_is_available = of_fwnode_device_is_available,
|
||||||
.device_get_match_data = of_fwnode_device_get_match_data,
|
.device_get_match_data = of_fwnode_device_get_match_data,
|
||||||
|
.device_dma_supported = of_fwnode_device_dma_supported,
|
||||||
|
.device_get_dma_attr = of_fwnode_device_get_dma_attr,
|
||||||
.property_present = of_fwnode_property_present,
|
.property_present = of_fwnode_property_present,
|
||||||
.property_read_int_array = of_fwnode_property_read_int_array,
|
.property_read_int_array = of_fwnode_property_read_int_array,
|
||||||
.property_read_string_array = of_fwnode_property_read_string_array,
|
.property_read_string_array = of_fwnode_property_read_string_array,
|
||||||
@ -1485,6 +1517,8 @@ const struct fwnode_operations of_fwnode_ops = {
|
|||||||
.graph_get_remote_endpoint = of_fwnode_graph_get_remote_endpoint,
|
.graph_get_remote_endpoint = of_fwnode_graph_get_remote_endpoint,
|
||||||
.graph_get_port_parent = of_fwnode_graph_get_port_parent,
|
.graph_get_port_parent = of_fwnode_graph_get_port_parent,
|
||||||
.graph_parse_endpoint = of_fwnode_graph_parse_endpoint,
|
.graph_parse_endpoint = of_fwnode_graph_parse_endpoint,
|
||||||
|
.iomap = of_fwnode_iomap,
|
||||||
|
.irq_get = of_fwnode_irq_get,
|
||||||
.add_links = of_fwnode_add_links,
|
.add_links = of_fwnode_add_links,
|
||||||
};
|
};
|
||||||
EXPORT_SYMBOL_GPL(of_fwnode_ops);
|
EXPORT_SYMBOL_GPL(of_fwnode_ops);
|
||||||
|
@ -113,6 +113,9 @@ struct fwnode_operations {
|
|||||||
bool (*device_is_available)(const struct fwnode_handle *fwnode);
|
bool (*device_is_available)(const struct fwnode_handle *fwnode);
|
||||||
const void *(*device_get_match_data)(const struct fwnode_handle *fwnode,
|
const void *(*device_get_match_data)(const struct fwnode_handle *fwnode,
|
||||||
const struct device *dev);
|
const struct device *dev);
|
||||||
|
bool (*device_dma_supported)(const struct fwnode_handle *fwnode);
|
||||||
|
enum dev_dma_attr
|
||||||
|
(*device_get_dma_attr)(const struct fwnode_handle *fwnode);
|
||||||
bool (*property_present)(const struct fwnode_handle *fwnode,
|
bool (*property_present)(const struct fwnode_handle *fwnode,
|
||||||
const char *propname);
|
const char *propname);
|
||||||
int (*property_read_int_array)(const struct fwnode_handle *fwnode,
|
int (*property_read_int_array)(const struct fwnode_handle *fwnode,
|
||||||
@ -145,15 +148,17 @@ struct fwnode_operations {
|
|||||||
(*graph_get_port_parent)(struct fwnode_handle *fwnode);
|
(*graph_get_port_parent)(struct fwnode_handle *fwnode);
|
||||||
int (*graph_parse_endpoint)(const struct fwnode_handle *fwnode,
|
int (*graph_parse_endpoint)(const struct fwnode_handle *fwnode,
|
||||||
struct fwnode_endpoint *endpoint);
|
struct fwnode_endpoint *endpoint);
|
||||||
|
void __iomem *(*iomap)(struct fwnode_handle *fwnode, int index);
|
||||||
|
int (*irq_get)(const struct fwnode_handle *fwnode, unsigned int index);
|
||||||
int (*add_links)(struct fwnode_handle *fwnode);
|
int (*add_links)(struct fwnode_handle *fwnode);
|
||||||
};
|
};
|
||||||
|
|
||||||
#define fwnode_has_op(fwnode, op) \
|
#define fwnode_has_op(fwnode, op) \
|
||||||
((fwnode) && (fwnode)->ops && (fwnode)->ops->op)
|
(!IS_ERR_OR_NULL(fwnode) && (fwnode)->ops && (fwnode)->ops->op)
|
||||||
|
|
||||||
#define fwnode_call_int_op(fwnode, op, ...) \
|
#define fwnode_call_int_op(fwnode, op, ...) \
|
||||||
(fwnode ? (fwnode_has_op(fwnode, op) ? \
|
(fwnode_has_op(fwnode, op) ? \
|
||||||
(fwnode)->ops->op(fwnode, ## __VA_ARGS__) : -ENXIO) : \
|
(fwnode)->ops->op(fwnode, ## __VA_ARGS__) : (IS_ERR_OR_NULL(fwnode) ? -EINVAL : -ENXIO))
|
||||||
-EINVAL)
|
|
||||||
|
|
||||||
#define fwnode_call_bool_op(fwnode, op, ...) \
|
#define fwnode_call_bool_op(fwnode, op, ...) \
|
||||||
(fwnode_has_op(fwnode, op) ? \
|
(fwnode_has_op(fwnode, op) ? \
|
||||||
|
@ -83,15 +83,19 @@ struct fwnode_handle *fwnode_find_reference(const struct fwnode_handle *fwnode,
|
|||||||
|
|
||||||
const char *fwnode_get_name(const struct fwnode_handle *fwnode);
|
const char *fwnode_get_name(const struct fwnode_handle *fwnode);
|
||||||
const char *fwnode_get_name_prefix(const struct fwnode_handle *fwnode);
|
const char *fwnode_get_name_prefix(const struct fwnode_handle *fwnode);
|
||||||
|
|
||||||
struct fwnode_handle *fwnode_get_parent(const struct fwnode_handle *fwnode);
|
struct fwnode_handle *fwnode_get_parent(const struct fwnode_handle *fwnode);
|
||||||
struct fwnode_handle *fwnode_get_next_parent(
|
struct fwnode_handle *fwnode_get_next_parent(struct fwnode_handle *fwnode);
|
||||||
struct fwnode_handle *fwnode);
|
|
||||||
|
#define fwnode_for_each_parent_node(fwnode, parent) \
|
||||||
|
for (parent = fwnode_get_parent(fwnode); parent; \
|
||||||
|
parent = fwnode_get_next_parent(parent))
|
||||||
|
|
||||||
struct device *fwnode_get_next_parent_dev(struct fwnode_handle *fwnode);
|
struct device *fwnode_get_next_parent_dev(struct fwnode_handle *fwnode);
|
||||||
unsigned int fwnode_count_parents(const struct fwnode_handle *fwn);
|
unsigned int fwnode_count_parents(const struct fwnode_handle *fwn);
|
||||||
struct fwnode_handle *fwnode_get_nth_parent(struct fwnode_handle *fwn,
|
struct fwnode_handle *fwnode_get_nth_parent(struct fwnode_handle *fwn,
|
||||||
unsigned int depth);
|
unsigned int depth);
|
||||||
bool fwnode_is_ancestor_of(struct fwnode_handle *test_ancestor,
|
bool fwnode_is_ancestor_of(struct fwnode_handle *ancestor, struct fwnode_handle *child);
|
||||||
struct fwnode_handle *test_child);
|
|
||||||
struct fwnode_handle *fwnode_get_next_child_node(
|
struct fwnode_handle *fwnode_get_next_child_node(
|
||||||
const struct fwnode_handle *fwnode, struct fwnode_handle *child);
|
const struct fwnode_handle *fwnode, struct fwnode_handle *child);
|
||||||
struct fwnode_handle *fwnode_get_next_available_child_node(
|
struct fwnode_handle *fwnode_get_next_available_child_node(
|
||||||
|
Loading…
Reference in New Issue
Block a user