mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 18:51:56 -04:00
Generic device properties framework updates for v4.12-rc1
- Extend the ACPI _DSD properties code and the generic device
properties framework to support the concept of remote endponts
(Mika Westerberg, Sakari Ailus).
- Document the support for ports and endpoints in _DSD properties
and extend the generic device properties framework to make it
more suitable for the handling of ports and endpoints (Sakari
Ailus).
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2
iQIcBAABCAAGBQJZB5jZAAoJEILEb/54YlRxPU0P/34yV01FwLCnOGDWACRq62Iv
yfW+uSb3x679sk4DBZfmuruE7N96fWtXS+Pbt+a1A62md421r9iQCKSh7o9Q8lcX
hUxJt/6NF6hbOygpvDxUXA3XpsV37hKUtVAlqln95JiwgFERBm9TT7GqmTutZaue
vbidgp0f2H75eM4pzhLCl7xgjSuwNe7GU60uVtLUSREoaGtylkcjNjdJmLFF518K
uMDttQOwX7c0S3/IctAuIax4se6xFXMw0AfiRJA5KoLRFRIkrMVb+YlaqhaITD9t
SnjjBQoBQ2z09hLdTQrw0k2qfSkqGx34Qw/JikFLpyUpvJT5tOhtCgR6czLHDkN2
Cz22xWfiHWQS8IH14urxdwhIiLI+VRcrU5GdlP9Rwj9wQCF8W2nWujg6X7gyb2Sg
cV82pAbD9wXVPXcZddbXSOhiGExQLlD6EAQ/+Dw73LPU4biV8aBB4GBalrKeHUIq
SiYaSvHdwHCv0LxTM3aWoxE2qLh0g+8e1K9vJQnh8BQM6q14qQeWvbq5Gmv+T5LZ
FDT/LUCMUx85yiaJ+PU4DFiQ1kutRxzUqtUrFRUCWdHwKd6JnNnEcXM4ouwelJsf
8PuFOLzHLzXXfAbx7EJP7daBbrOmhJs7Y/9UzTnJSquO/1F+k3a26uPfJP2349I+
IfNWjnjjY3QRLYwLKfqF
=Ihme
-----END PGP SIGNATURE-----
Merge tag 'devprop-4.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Pull generic device properties framework updates from Rafael Wysocki:
"These add support for the ports and endpoints concepts, based on the
existing DT support for them, to the generic device properties
framework and update the ACPI _DSD properties code to recognize ports
and endpoints accordingly.
Specifics:
- Extend the ACPI _DSD properties code and the generic device
properties framework to support the concept of remote endponts
(Mika Westerberg, Sakari Ailus).
- Document the support for ports and endpoints in _DSD properties and
extend the generic device properties framework to make it more
suitable for the handling of ports and endpoints (Sakari Ailus)"
* tag 'devprop-4.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
device property: Read strings using string array reading functions
device property: fwnode_property_read_string_array() returns nr of strings
device property: Fix reading pset strings using array access functions
device property: fwnode_property_read_string_array() may return -EILSEQ
ACPI / DSD: Document references, ports and endpoints
device property: Add fwnode_get_next_parent()
device property: Add support for fwnode endpoints
device property: Make dev_fwnode() public
of: Add of_fwnode_handle() to convert device nodes to fwnode_handle
device property: Add fwnode_handle_get()
device property: Add support for remote endpoints
ACPI / property: Add support for remote endpoints
device property: Add fwnode_get_named_child_node()
ACPI / property: Add fwnode_get_next_child_node()
device property: Add fwnode_get_parent()
ACPI / property: Add possiblity to retrieve parent firmware node
This commit is contained in:
commit
5fab10041b
8 changed files with 761 additions and 105 deletions
|
|
@ -15,6 +15,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_graph.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/phy.h>
|
||||
|
|
@ -146,47 +147,45 @@ static int pset_prop_read_string_array(struct property_set *pset,
|
|||
const char *propname,
|
||||
const char **strings, size_t nval)
|
||||
{
|
||||
const struct property_entry *prop;
|
||||
const void *pointer;
|
||||
size_t length = nval * sizeof(*strings);
|
||||
size_t array_len, length;
|
||||
|
||||
/* Find out the array length. */
|
||||
prop = pset_prop_get(pset, propname);
|
||||
if (!prop)
|
||||
return -EINVAL;
|
||||
|
||||
if (!prop->is_array)
|
||||
/* The array length for a non-array string property is 1. */
|
||||
array_len = 1;
|
||||
else
|
||||
/* Find the length of an array. */
|
||||
array_len = pset_prop_count_elems_of_size(pset, propname,
|
||||
sizeof(const char *));
|
||||
|
||||
/* Return how many there are if strings is NULL. */
|
||||
if (!strings)
|
||||
return array_len;
|
||||
|
||||
array_len = min(nval, array_len);
|
||||
length = array_len * sizeof(*strings);
|
||||
|
||||
pointer = pset_prop_find(pset, propname, length);
|
||||
if (IS_ERR(pointer))
|
||||
return PTR_ERR(pointer);
|
||||
|
||||
memcpy(strings, pointer, length);
|
||||
return 0;
|
||||
|
||||
return array_len;
|
||||
}
|
||||
|
||||
static int pset_prop_read_string(struct property_set *pset,
|
||||
const char *propname, const char **strings)
|
||||
{
|
||||
const struct property_entry *prop;
|
||||
const char * const *pointer;
|
||||
|
||||
prop = pset_prop_get(pset, propname);
|
||||
if (!prop)
|
||||
return -EINVAL;
|
||||
if (!prop->is_string)
|
||||
return -EILSEQ;
|
||||
if (prop->is_array) {
|
||||
pointer = prop->pointer.str;
|
||||
if (!pointer)
|
||||
return -ENODATA;
|
||||
} else {
|
||||
pointer = &prop->value.str;
|
||||
if (*pointer && strnlen(*pointer, prop->length) >= prop->length)
|
||||
return -EILSEQ;
|
||||
}
|
||||
|
||||
*strings = *pointer;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline struct fwnode_handle *dev_fwnode(struct device *dev)
|
||||
struct fwnode_handle *dev_fwnode(struct device *dev)
|
||||
{
|
||||
return IS_ENABLED(CONFIG_OF) && dev->of_node ?
|
||||
&dev->of_node->fwnode : dev->fwnode;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dev_fwnode);
|
||||
|
||||
/**
|
||||
* device_property_present - check if a property of a device is present
|
||||
|
|
@ -340,8 +339,8 @@ EXPORT_SYMBOL_GPL(device_property_read_u64_array);
|
|||
* Function reads an array of string properties with @propname from the device
|
||||
* firmware description and stores them to @val if found.
|
||||
*
|
||||
* Return: number of values if @val was %NULL,
|
||||
* %0 if the property was found (success),
|
||||
* Return: number of values read on success if @val is non-NULL,
|
||||
* number of values available on success if @val is NULL,
|
||||
* %-EINVAL if given arguments are not valid,
|
||||
* %-ENODATA if the property does not have a value,
|
||||
* %-EPROTO or %-EILSEQ if the property is not an array of strings,
|
||||
|
|
@ -553,25 +552,8 @@ static int __fwnode_property_read_string_array(struct fwnode_handle *fwnode,
|
|||
return acpi_node_prop_read(fwnode, propname, DEV_PROP_STRING,
|
||||
val, nval);
|
||||
else if (is_pset_node(fwnode))
|
||||
return val ?
|
||||
pset_prop_read_string_array(to_pset_node(fwnode),
|
||||
propname, val, nval) :
|
||||
pset_prop_count_elems_of_size(to_pset_node(fwnode),
|
||||
propname,
|
||||
sizeof(const char *));
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
static int __fwnode_property_read_string(struct fwnode_handle *fwnode,
|
||||
const char *propname, const char **val)
|
||||
{
|
||||
if (is_of_node(fwnode))
|
||||
return of_property_read_string(to_of_node(fwnode), propname, val);
|
||||
else if (is_acpi_node(fwnode))
|
||||
return acpi_node_prop_read(fwnode, propname, DEV_PROP_STRING,
|
||||
val, 1);
|
||||
else if (is_pset_node(fwnode))
|
||||
return pset_prop_read_string(to_pset_node(fwnode), propname, val);
|
||||
return pset_prop_read_string_array(to_pset_node(fwnode),
|
||||
propname, val, nval);
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
|
|
@ -585,11 +567,11 @@ static int __fwnode_property_read_string(struct fwnode_handle *fwnode,
|
|||
* Read an string list property @propname from the given firmware node and store
|
||||
* them to @val if found.
|
||||
*
|
||||
* Return: number of values if @val was %NULL,
|
||||
* %0 if the property was found (success),
|
||||
* Return: number of values read on success if @val is non-NULL,
|
||||
* number of values available on success if @val is NULL,
|
||||
* %-EINVAL if given arguments are not valid,
|
||||
* %-ENODATA if the property does not have a value,
|
||||
* %-EPROTO if the property is not an array of strings,
|
||||
* %-EPROTO or %-EILSEQ if the property is not an array of strings,
|
||||
* %-EOVERFLOW if the size of the property is not as expected,
|
||||
* %-ENXIO if no suitable firmware interface is present.
|
||||
*/
|
||||
|
|
@ -626,14 +608,9 @@ EXPORT_SYMBOL_GPL(fwnode_property_read_string_array);
|
|||
int fwnode_property_read_string(struct fwnode_handle *fwnode,
|
||||
const char *propname, const char **val)
|
||||
{
|
||||
int ret;
|
||||
int ret = fwnode_property_read_string_array(fwnode, propname, val, 1);
|
||||
|
||||
ret = __fwnode_property_read_string(fwnode, propname, val);
|
||||
if (ret == -EINVAL && !IS_ERR_OR_NULL(fwnode) &&
|
||||
!IS_ERR_OR_NULL(fwnode->secondary))
|
||||
ret = __fwnode_property_read_string(fwnode->secondary,
|
||||
propname, val);
|
||||
return ret;
|
||||
return ret < 0 ? ret : 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fwnode_property_read_string);
|
||||
|
||||
|
|
@ -931,6 +908,75 @@ int device_add_properties(struct device *dev,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(device_add_properties);
|
||||
|
||||
/**
|
||||
* fwnode_get_next_parent - Iterate to the node's parent
|
||||
* @fwnode: Firmware whose parent is retrieved
|
||||
*
|
||||
* This is like fwnode_get_parent() except that it drops the refcount
|
||||
* on the passed node, making it suitable for iterating through a
|
||||
* node's parents.
|
||||
*
|
||||
* Returns a node pointer with refcount incremented, use
|
||||
* fwnode_handle_node() on it when done.
|
||||
*/
|
||||
struct fwnode_handle *fwnode_get_next_parent(struct fwnode_handle *fwnode)
|
||||
{
|
||||
struct fwnode_handle *parent = fwnode_get_parent(fwnode);
|
||||
|
||||
fwnode_handle_put(fwnode);
|
||||
|
||||
return parent;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fwnode_get_next_parent);
|
||||
|
||||
/**
|
||||
* fwnode_get_parent - Return parent firwmare node
|
||||
* @fwnode: Firmware whose parent is retrieved
|
||||
*
|
||||
* Return parent firmware node of the given node if possible or %NULL if no
|
||||
* parent was available.
|
||||
*/
|
||||
struct fwnode_handle *fwnode_get_parent(struct fwnode_handle *fwnode)
|
||||
{
|
||||
struct fwnode_handle *parent = NULL;
|
||||
|
||||
if (is_of_node(fwnode)) {
|
||||
struct device_node *node;
|
||||
|
||||
node = of_get_parent(to_of_node(fwnode));
|
||||
if (node)
|
||||
parent = &node->fwnode;
|
||||
} else if (is_acpi_node(fwnode)) {
|
||||
parent = acpi_node_get_parent(fwnode);
|
||||
}
|
||||
|
||||
return parent;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fwnode_get_parent);
|
||||
|
||||
/**
|
||||
* fwnode_get_next_child_node - Return the next child node handle for a node
|
||||
* @fwnode: Firmware node to find the next child node for.
|
||||
* @child: Handle to one of the node's child nodes or a %NULL handle.
|
||||
*/
|
||||
struct fwnode_handle *fwnode_get_next_child_node(struct fwnode_handle *fwnode,
|
||||
struct fwnode_handle *child)
|
||||
{
|
||||
if (is_of_node(fwnode)) {
|
||||
struct device_node *node;
|
||||
|
||||
node = of_get_next_available_child(to_of_node(fwnode),
|
||||
to_of_node(child));
|
||||
if (node)
|
||||
return &node->fwnode;
|
||||
} else if (is_acpi_node(fwnode)) {
|
||||
return acpi_get_next_subnode(fwnode, child);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fwnode_get_next_child_node);
|
||||
|
||||
/**
|
||||
* device_get_next_child_node - Return the next child node handle for a device
|
||||
* @dev: Device to find the next child node for.
|
||||
|
|
@ -939,34 +985,33 @@ EXPORT_SYMBOL_GPL(device_add_properties);
|
|||
struct fwnode_handle *device_get_next_child_node(struct device *dev,
|
||||
struct fwnode_handle *child)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_OF) && dev->of_node) {
|
||||
struct device_node *node;
|
||||
struct acpi_device *adev = ACPI_COMPANION(dev);
|
||||
struct fwnode_handle *fwnode = NULL;
|
||||
|
||||
node = of_get_next_available_child(dev->of_node, to_of_node(child));
|
||||
if (node)
|
||||
return &node->fwnode;
|
||||
} else if (IS_ENABLED(CONFIG_ACPI)) {
|
||||
return acpi_get_next_subnode(dev, child);
|
||||
}
|
||||
return NULL;
|
||||
if (dev->of_node)
|
||||
fwnode = &dev->of_node->fwnode;
|
||||
else if (adev)
|
||||
fwnode = acpi_fwnode_handle(adev);
|
||||
|
||||
return fwnode_get_next_child_node(fwnode, child);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(device_get_next_child_node);
|
||||
|
||||
/**
|
||||
* device_get_named_child_node - Return first matching named child node handle
|
||||
* @dev: Device to find the named child node for.
|
||||
* fwnode_get_named_child_node - Return first matching named child node handle
|
||||
* @fwnode: Firmware node to find the named child node for.
|
||||
* @childname: String to match child node name against.
|
||||
*/
|
||||
struct fwnode_handle *device_get_named_child_node(struct device *dev,
|
||||
struct fwnode_handle *fwnode_get_named_child_node(struct fwnode_handle *fwnode,
|
||||
const char *childname)
|
||||
{
|
||||
struct fwnode_handle *child;
|
||||
|
||||
/*
|
||||
* Find first matching named child node of this device.
|
||||
* Find first matching named child node of this fwnode.
|
||||
* For ACPI this will be a data only sub-node.
|
||||
*/
|
||||
device_for_each_child_node(dev, child) {
|
||||
fwnode_for_each_child_node(fwnode, child) {
|
||||
if (is_of_node(child)) {
|
||||
if (!of_node_cmp(to_of_node(child)->name, childname))
|
||||
return child;
|
||||
|
|
@ -978,8 +1023,31 @@ struct fwnode_handle *device_get_named_child_node(struct device *dev,
|
|||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fwnode_get_named_child_node);
|
||||
|
||||
/**
|
||||
* device_get_named_child_node - Return first matching named child node handle
|
||||
* @dev: Device to find the named child node for.
|
||||
* @childname: String to match child node name against.
|
||||
*/
|
||||
struct fwnode_handle *device_get_named_child_node(struct device *dev,
|
||||
const char *childname)
|
||||
{
|
||||
return fwnode_get_named_child_node(dev_fwnode(dev), childname);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(device_get_named_child_node);
|
||||
|
||||
/**
|
||||
* fwnode_handle_get - Obtain a reference to a device node
|
||||
* @fwnode: Pointer to the device node to obtain the reference to.
|
||||
*/
|
||||
void fwnode_handle_get(struct fwnode_handle *fwnode)
|
||||
{
|
||||
if (is_of_node(fwnode))
|
||||
of_node_get(to_of_node(fwnode));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fwnode_handle_get);
|
||||
|
||||
/**
|
||||
* fwnode_handle_put - Drop reference to a device node
|
||||
* @fwnode: Pointer to the device node to drop the reference to.
|
||||
|
|
@ -1117,3 +1185,157 @@ void *device_get_mac_address(struct device *dev, char *addr, int alen)
|
|||
return device_get_mac_addr(dev, "address", addr, alen);
|
||||
}
|
||||
EXPORT_SYMBOL(device_get_mac_address);
|
||||
|
||||
/**
|
||||
* device_graph_get_next_endpoint - Get next endpoint firmware node
|
||||
* @fwnode: Pointer to the parent firmware node
|
||||
* @prev: Previous endpoint node or %NULL to get the first
|
||||
*
|
||||
* Returns an endpoint firmware node pointer or %NULL if no more endpoints
|
||||
* are available.
|
||||
*/
|
||||
struct fwnode_handle *
|
||||
fwnode_graph_get_next_endpoint(struct fwnode_handle *fwnode,
|
||||
struct fwnode_handle *prev)
|
||||
{
|
||||
struct fwnode_handle *endpoint = NULL;
|
||||
|
||||
if (is_of_node(fwnode)) {
|
||||
struct device_node *node;
|
||||
|
||||
node = of_graph_get_next_endpoint(to_of_node(fwnode),
|
||||
to_of_node(prev));
|
||||
|
||||
if (node)
|
||||
endpoint = &node->fwnode;
|
||||
} else if (is_acpi_node(fwnode)) {
|
||||
endpoint = acpi_graph_get_next_endpoint(fwnode, prev);
|
||||
if (IS_ERR(endpoint))
|
||||
endpoint = NULL;
|
||||
}
|
||||
|
||||
return endpoint;
|
||||
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fwnode_graph_get_next_endpoint);
|
||||
|
||||
/**
|
||||
* fwnode_graph_get_remote_port_parent - Return fwnode of a remote device
|
||||
* @fwnode: Endpoint firmware node pointing to the remote endpoint
|
||||
*
|
||||
* Extracts firmware node of a remote device the @fwnode points to.
|
||||
*/
|
||||
struct fwnode_handle *
|
||||
fwnode_graph_get_remote_port_parent(struct fwnode_handle *fwnode)
|
||||
{
|
||||
struct fwnode_handle *parent = NULL;
|
||||
|
||||
if (is_of_node(fwnode)) {
|
||||
struct device_node *node;
|
||||
|
||||
node = of_graph_get_remote_port_parent(to_of_node(fwnode));
|
||||
if (node)
|
||||
parent = &node->fwnode;
|
||||
} else if (is_acpi_node(fwnode)) {
|
||||
int ret;
|
||||
|
||||
ret = acpi_graph_get_remote_endpoint(fwnode, &parent, NULL,
|
||||
NULL);
|
||||
if (ret)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return parent;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_port_parent);
|
||||
|
||||
/**
|
||||
* fwnode_graph_get_remote_port - Return fwnode of a remote port
|
||||
* @fwnode: Endpoint firmware node pointing to the remote endpoint
|
||||
*
|
||||
* Extracts firmware node of a remote port the @fwnode points to.
|
||||
*/
|
||||
struct fwnode_handle *fwnode_graph_get_remote_port(struct fwnode_handle *fwnode)
|
||||
{
|
||||
struct fwnode_handle *port = NULL;
|
||||
|
||||
if (is_of_node(fwnode)) {
|
||||
struct device_node *node;
|
||||
|
||||
node = of_graph_get_remote_port(to_of_node(fwnode));
|
||||
if (node)
|
||||
port = &node->fwnode;
|
||||
} else if (is_acpi_node(fwnode)) {
|
||||
int ret;
|
||||
|
||||
ret = acpi_graph_get_remote_endpoint(fwnode, NULL, &port, NULL);
|
||||
if (ret)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return port;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_port);
|
||||
|
||||
/**
|
||||
* fwnode_graph_get_remote_endpoint - Return fwnode of a remote endpoint
|
||||
* @fwnode: Endpoint firmware node pointing to the remote endpoint
|
||||
*
|
||||
* Extracts firmware node of a remote endpoint the @fwnode points to.
|
||||
*/
|
||||
struct fwnode_handle *
|
||||
fwnode_graph_get_remote_endpoint(struct fwnode_handle *fwnode)
|
||||
{
|
||||
struct fwnode_handle *endpoint = NULL;
|
||||
|
||||
if (is_of_node(fwnode)) {
|
||||
struct device_node *node;
|
||||
|
||||
node = of_parse_phandle(to_of_node(fwnode), "remote-endpoint",
|
||||
0);
|
||||
if (node)
|
||||
endpoint = &node->fwnode;
|
||||
} else if (is_acpi_node(fwnode)) {
|
||||
int ret;
|
||||
|
||||
ret = acpi_graph_get_remote_endpoint(fwnode, NULL, NULL,
|
||||
&endpoint);
|
||||
if (ret)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return endpoint;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_endpoint);
|
||||
|
||||
/**
|
||||
* fwnode_graph_parse_endpoint - parse common endpoint node properties
|
||||
* @fwnode: pointer to endpoint fwnode_handle
|
||||
* @endpoint: pointer to the fwnode endpoint data structure
|
||||
*
|
||||
* Parse @fwnode representing a graph endpoint node and store the
|
||||
* information in @endpoint. The caller must hold a reference to
|
||||
* @fwnode.
|
||||
*/
|
||||
int fwnode_graph_parse_endpoint(struct fwnode_handle *fwnode,
|
||||
struct fwnode_endpoint *endpoint)
|
||||
{
|
||||
struct fwnode_handle *port_fwnode = fwnode_get_parent(fwnode);
|
||||
|
||||
memset(endpoint, 0, sizeof(*endpoint));
|
||||
|
||||
endpoint->local_fwnode = fwnode;
|
||||
|
||||
if (is_acpi_node(port_fwnode)) {
|
||||
fwnode_property_read_u32(port_fwnode, "port", &endpoint->port);
|
||||
fwnode_property_read_u32(fwnode, "endpoint", &endpoint->id);
|
||||
} else {
|
||||
fwnode_property_read_u32(port_fwnode, "reg", &endpoint->port);
|
||||
fwnode_property_read_u32(fwnode, "reg", &endpoint->id);
|
||||
}
|
||||
|
||||
fwnode_handle_put(port_fwnode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(fwnode_graph_parse_endpoint);
|
||||
|
|
|
|||
Loading…
Reference in a new issue