From 80488a6b1d3c3509b69d38d7c5ac7615889ea7e0 Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Fri, 31 May 2019 17:15:34 +0300 Subject: software node: Add support for static node descriptors Until now the software nodes could only be created dynamically with fwnode_create_software_node() function. This introduces struct software_node data structure, which makes it possible to describe the software nodes also statically. The statically described software nodes can be registered with a new function fwnode_register_software_node(). This also adds a helper fwnode_register_software_nodes() which makes it possible to register an array of struct software_nodes, i.e. multiple nodes at the same time. There is no difference between statically described and dynamically allocated software nodes. Even the registration does not differ, except that during node creation the device properties are only copied if the node is created dynamically. With statically described nodes, the property entries in the descriptor (struct software_node) are assigned directly to the new software node that is being created without any copies. Signed-off-by: Heikki Krogerus Tested-by: Hans de Goede Signed-off-by: Rafael J. Wysocki --- include/linux/property.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'include/linux') diff --git a/include/linux/property.h b/include/linux/property.h index a29369c89e6e..a3813ded52ea 100644 --- a/include/linux/property.h +++ b/include/linux/property.h @@ -332,7 +332,26 @@ int fwnode_graph_parse_endpoint(const struct fwnode_handle *fwnode, /* -------------------------------------------------------------------------- */ /* Software fwnode support - when HW description is incomplete or missing */ +/** + * struct software_node - Software node description + * @name: Name of the software node + * @parent: Parent of the software node + * @properties: Array of device properties + */ +struct software_node { + const char *name; + const struct software_node *parent; + const struct property_entry *properties; +}; + bool is_software_node(const struct fwnode_handle *fwnode); +const struct software_node *to_software_node(struct fwnode_handle *fwnode); +struct fwnode_handle *software_node_fwnode(const struct software_node *node); + +int software_node_register_nodes(const struct software_node *nodes); +void software_node_unregister_nodes(const struct software_node *nodes); + +int software_node_register(const struct software_node *node); int software_node_notify(struct device *dev, unsigned long action); -- cgit v1.2.3 From b06184acf751fa52a3763e4fadfd2807e9703acd Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Fri, 31 May 2019 17:15:36 +0300 Subject: software node: Add software_node_get_reference_args() This makes it possible to support drivers that use fwnode_property_get_reference_args() function. Signed-off-by: Heikki Krogerus Tested-by: Hans de Goede Signed-off-by: Rafael J. Wysocki --- include/linux/property.h | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'include/linux') diff --git a/include/linux/property.h b/include/linux/property.h index a3813ded52ea..abcde2f236a0 100644 --- a/include/linux/property.h +++ b/include/linux/property.h @@ -332,16 +332,44 @@ int fwnode_graph_parse_endpoint(const struct fwnode_handle *fwnode, /* -------------------------------------------------------------------------- */ /* Software fwnode support - when HW description is incomplete or missing */ +struct software_node; + +/** + * struct software_node_ref_args - Reference with additional arguments + * @node: Reference to a software node + * @nargs: Number of elements in @args array + * @args: Integer arguments + */ +struct software_node_ref_args { + const struct software_node *node; + unsigned int nargs; + u64 args[NR_FWNODE_REFERENCE_ARGS]; +}; + +/** + * struct software_node_reference - Named software node reference property + * @name: Name of the property + * @nrefs: Number of elements in @refs array + * @refs: Array of references with optional arguments + */ +struct software_node_reference { + const char *name; + unsigned int nrefs; + const struct software_node_ref_args *refs; +}; + /** * struct software_node - Software node description * @name: Name of the software node * @parent: Parent of the software node * @properties: Array of device properties + * @references: Array of software node reference properties */ struct software_node { const char *name; const struct software_node *parent; const struct property_entry *properties; + const struct software_node_reference *references; }; bool is_software_node(const struct fwnode_handle *fwnode); -- cgit v1.2.3 From dad9bb017865ae794b6cdfac40d60b1466a09195 Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Fri, 31 May 2019 17:15:37 +0300 Subject: driver core: Add helper device_find_child_by_name() It looks like the child device is often matched with a name. This introduces a helper that does it automatically. Signed-off-by: Heikki Krogerus Acked-by: Greg Kroah-Hartman Tested-by: Hans de Goede Signed-off-by: Rafael J. Wysocki --- include/linux/device.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include/linux') diff --git a/include/linux/device.h b/include/linux/device.h index e85264fb6616..5489a759e1c5 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -1250,6 +1250,8 @@ extern int device_for_each_child_reverse(struct device *dev, void *data, int (*fn)(struct device *dev, void *data)); extern struct device *device_find_child(struct device *dev, void *data, int (*match)(struct device *dev, void *data)); +extern struct device *device_find_child_by_name(struct device *parent, + const char *name); extern int device_rename(struct device *dev, const char *new_name); extern int device_move(struct device *dev, struct device *new_parent, enum dpm_order dpm_order); -- cgit v1.2.3 From 83b34afb6b79c69f5478a7249451cab858af97d6 Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Fri, 31 May 2019 17:15:39 +0300 Subject: device property: Introduce fwnode_find_reference() In most cases the references that the drivers look for don't have any arguments. This introduces a wrapper function for fwnode_property_get_reference_args() that looks for references by using only the name and index. Signed-off-by: Heikki Krogerus Tested-by: Hans de Goede Signed-off-by: Rafael J. Wysocki --- include/linux/property.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'include/linux') diff --git a/include/linux/property.h b/include/linux/property.h index abcde2f236a0..088d4db7e949 100644 --- a/include/linux/property.h +++ b/include/linux/property.h @@ -79,6 +79,10 @@ int fwnode_property_get_reference_args(const struct fwnode_handle *fwnode, unsigned int nargs, unsigned int index, struct fwnode_reference_args *args); +struct fwnode_handle *fwnode_find_reference(const struct fwnode_handle *fwnode, + const char *name, + unsigned int index); + struct fwnode_handle *fwnode_get_parent(const struct fwnode_handle *fwnode); struct fwnode_handle *fwnode_get_next_parent( struct fwnode_handle *fwnode); -- cgit v1.2.3 From 3370db35193b241ba5836a66df6ec1a559108389 Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Fri, 31 May 2019 17:15:41 +0300 Subject: usb: typec: Registering real device entries for the muxes Registering real device entries (struct device) for the mode muxes as well as for the orientation switches. The Type-C mux code was deliberately attempting to avoid creation of separate device entries for the orientation switch and the mode switch (alternate modes) because they are not physical devices. They are functions of a single physical multiplexer/demultiplexer switch device. Unfortunately because of the dependency we still have on the underlying mux device driver, we had to put in hacks like the one in the commit 3e3b81965cbf ("usb: typec: mux: Take care of driver module reference counting") to make sure the driver does not disappear from underneath us. Even with those hacks we were still left with a potential NUll pointer dereference scenario, so just creating the device entries, and letting the core take care of the dependencies. No more hacks needed. Signed-off-by: Heikki Krogerus Reviewed-by: Andy Shevchenko Tested-by: Hans de Goede Signed-off-by: Rafael J. Wysocki --- include/linux/usb/typec_mux.h | 62 +++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 34 deletions(-) (limited to 'include/linux') diff --git a/include/linux/usb/typec_mux.h b/include/linux/usb/typec_mux.h index 43f40685e53c..873ace5b0cf8 100644 --- a/include/linux/usb/typec_mux.h +++ b/include/linux/usb/typec_mux.h @@ -3,54 +3,48 @@ #ifndef __USB_TYPEC_MUX #define __USB_TYPEC_MUX -#include #include struct device; +struct typec_mux; +struct typec_switch; +struct fwnode_handle; -/** - * struct typec_switch - USB Type-C cable orientation switch - * @dev: Switch device - * @entry: List entry - * @set: Callback to the driver for setting the orientation - * - * USB Type-C pin flipper switch routing the correct data pairs from the - * connector to the USB controller depending on the orientation of the cable - * plug. - */ -struct typec_switch { - struct device *dev; - struct list_head entry; - - int (*set)(struct typec_switch *sw, enum typec_orientation orientation); -}; +typedef int (*typec_switch_set_fn_t)(struct typec_switch *sw, + enum typec_orientation orientation); -/** - * struct typec_switch - USB Type-C connector pin mux - * @dev: Mux device - * @entry: List entry - * @set: Callback to the driver for setting the state of the mux - * - * Pin Multiplexer/DeMultiplexer switch routing the USB Type-C connector pins to - * different components depending on the requested mode of operation. Used with - * Accessory/Alternate modes. - */ -struct typec_mux { - struct device *dev; - struct list_head entry; - - int (*set)(struct typec_mux *mux, int state); +struct typec_switch_desc { + struct fwnode_handle *fwnode; + typec_switch_set_fn_t set; + void *drvdata; }; struct typec_switch *typec_switch_get(struct device *dev); void typec_switch_put(struct typec_switch *sw); -int typec_switch_register(struct typec_switch *sw); +struct typec_switch * +typec_switch_register(struct device *parent, + const struct typec_switch_desc *desc); void typec_switch_unregister(struct typec_switch *sw); +void typec_switch_set_drvdata(struct typec_switch *sw, void *data); +void *typec_switch_get_drvdata(struct typec_switch *sw); + +typedef int (*typec_mux_set_fn_t)(struct typec_mux *mux, int state); + +struct typec_mux_desc { + struct fwnode_handle *fwnode; + typec_mux_set_fn_t set; + void *drvdata; +}; + struct typec_mux * typec_mux_get(struct device *dev, const struct typec_altmode_desc *desc); void typec_mux_put(struct typec_mux *mux); -int typec_mux_register(struct typec_mux *mux); +struct typec_mux * +typec_mux_register(struct device *parent, const struct typec_mux_desc *desc); void typec_mux_unregister(struct typec_mux *mux); +void typec_mux_set_drvdata(struct typec_mux *mux, void *data); +void *typec_mux_get_drvdata(struct typec_mux *mux); + #endif /* __USB_TYPEC_MUX */ -- cgit v1.2.3 From 33ee09cd59ce154b64f9df942dfa5456db90d5f9 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 13 Jun 2019 19:59:51 +0300 Subject: device property: Add helpers to count items in an array The usual pattern to allocate the necessary space for an array of properties is to count them first by calling: count = device_property_read_uXX_array(dev, propname, NULL, 0); if (count < 0) return count; Introduce helpers device_property_count_uXX() to count items by supplying hard coded last two parameters to device_property_readXX_array(). Signed-off-by: Andy Shevchenko Acked-by: Sakari Ailus Reviewed-by: Heikki Krogerus Signed-off-by: Rafael J. Wysocki --- include/linux/property.h | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) (limited to 'include/linux') diff --git a/include/linux/property.h b/include/linux/property.h index 088d4db7e949..dbacf17fff2e 100644 --- a/include/linux/property.h +++ b/include/linux/property.h @@ -148,6 +148,26 @@ static inline int device_property_read_u64(struct device *dev, return device_property_read_u64_array(dev, propname, val, 1); } +static inline int device_property_count_u8(struct device *dev, const char *propname) +{ + return device_property_read_u8_array(dev, propname, NULL, 0); +} + +static inline int device_property_count_u16(struct device *dev, const char *propname) +{ + return device_property_read_u16_array(dev, propname, NULL, 0); +} + +static inline int device_property_count_u32(struct device *dev, const char *propname) +{ + return device_property_read_u32_array(dev, propname, NULL, 0); +} + +static inline int device_property_count_u64(struct device *dev, const char *propname) +{ + return device_property_read_u64_array(dev, propname, NULL, 0); +} + static inline bool fwnode_property_read_bool(const struct fwnode_handle *fwnode, const char *propname) { @@ -178,6 +198,30 @@ static inline int fwnode_property_read_u64(const struct fwnode_handle *fwnode, return fwnode_property_read_u64_array(fwnode, propname, val, 1); } +static inline int fwnode_property_count_u8(const struct fwnode_handle *fwnode, + const char *propname) +{ + return fwnode_property_read_u8_array(fwnode, propname, NULL, 0); +} + +static inline int fwnode_property_count_u16(const struct fwnode_handle *fwnode, + const char *propname) +{ + return fwnode_property_read_u16_array(fwnode, propname, NULL, 0); +} + +static inline int fwnode_property_count_u32(const struct fwnode_handle *fwnode, + const char *propname) +{ + return fwnode_property_read_u32_array(fwnode, propname, NULL, 0); +} + +static inline int fwnode_property_count_u64(const struct fwnode_handle *fwnode, + const char *propname) +{ + return fwnode_property_read_u64_array(fwnode, propname, NULL, 0); +} + /** * struct property_entry - "Built-in" device property representation. * @name: Name of the property. -- cgit v1.2.3