diff options
Diffstat (limited to 'drivers/usb/roles/class.c')
-rw-r--r-- | drivers/usb/roles/class.c | 80 |
1 files changed, 63 insertions, 17 deletions
diff --git a/drivers/usb/roles/class.c b/drivers/usb/roles/class.c index 86defca6623e..63a00ff26655 100644 --- a/drivers/usb/roles/class.c +++ b/drivers/usb/roles/class.c @@ -85,16 +85,6 @@ enum usb_role usb_role_switch_get_role(struct usb_role_switch *sw) } EXPORT_SYMBOL_GPL(usb_role_switch_get_role); -static int switch_fwnode_match(struct device *dev, const void *fwnode) -{ - return dev_fwnode(dev) == fwnode; -} - -static int switch_name_match(struct device *dev, const void *name) -{ - return !strcmp((const char *)name, dev_name(dev)); -} - static void *usb_role_switch_match(struct device_connection *con, int ep, void *data) { @@ -104,16 +94,27 @@ static void *usb_role_switch_match(struct device_connection *con, int ep, if (con->id && !fwnode_property_present(con->fwnode, con->id)) return NULL; - dev = class_find_device(role_class, NULL, con->fwnode, - switch_fwnode_match); + dev = class_find_device_by_fwnode(role_class, con->fwnode); } else { - dev = class_find_device(role_class, NULL, con->endpoint[ep], - switch_name_match); + dev = class_find_device_by_name(role_class, con->endpoint[ep]); } return dev ? to_role_switch(dev) : ERR_PTR(-EPROBE_DEFER); } +static struct usb_role_switch * +usb_role_switch_is_parent(struct fwnode_handle *fwnode) +{ + struct fwnode_handle *parent = fwnode_get_parent(fwnode); + struct device *dev; + + if (!parent || !fwnode_property_present(parent, "usb-role-switch")) + return NULL; + + dev = class_find_device_by_fwnode(role_class, parent); + return dev ? to_role_switch(dev) : ERR_PTR(-EPROBE_DEFER); +} + /** * usb_role_switch_get - Find USB role switch linked with the caller * @dev: The caller device @@ -125,8 +126,10 @@ struct usb_role_switch *usb_role_switch_get(struct device *dev) { struct usb_role_switch *sw; - sw = device_connection_find_match(dev, "usb-role-switch", NULL, - usb_role_switch_match); + sw = usb_role_switch_is_parent(dev_fwnode(dev)); + if (!sw) + sw = device_connection_find_match(dev, "usb-role-switch", NULL, + usb_role_switch_match); if (!IS_ERR_OR_NULL(sw)) WARN_ON(!try_module_get(sw->dev.parent->driver->owner)); @@ -136,6 +139,28 @@ struct usb_role_switch *usb_role_switch_get(struct device *dev) EXPORT_SYMBOL_GPL(usb_role_switch_get); /** + * fwnode_usb_role_switch_get - Find USB role switch linked with the caller + * @fwnode: The caller device node + * + * This is similar to the usb_role_switch_get() function above, but it searches + * the switch using fwnode instead of device entry. + */ +struct usb_role_switch *fwnode_usb_role_switch_get(struct fwnode_handle *fwnode) +{ + struct usb_role_switch *sw; + + sw = usb_role_switch_is_parent(fwnode); + if (!sw) + sw = fwnode_connection_find_match(fwnode, "usb-role-switch", + NULL, usb_role_switch_match); + if (!IS_ERR_OR_NULL(sw)) + WARN_ON(!try_module_get(sw->dev.parent->driver->owner)); + + return sw; +} +EXPORT_SYMBOL_GPL(fwnode_usb_role_switch_get); + +/** * usb_role_switch_put - Release handle to a switch * @sw: USB Role Switch * @@ -144,12 +169,33 @@ EXPORT_SYMBOL_GPL(usb_role_switch_get); void usb_role_switch_put(struct usb_role_switch *sw) { if (!IS_ERR_OR_NULL(sw)) { - put_device(&sw->dev); module_put(sw->dev.parent->driver->owner); + put_device(&sw->dev); } } EXPORT_SYMBOL_GPL(usb_role_switch_put); +/** + * usb_role_switch_find_by_fwnode - Find USB role switch with its fwnode + * @fwnode: fwnode of the USB Role Switch + * + * Finds and returns role switch with @fwnode. The reference count for the + * found switch is incremented. + */ +struct usb_role_switch * +usb_role_switch_find_by_fwnode(const struct fwnode_handle *fwnode) +{ + struct device *dev; + + if (!fwnode) + return NULL; + + dev = class_find_device_by_fwnode(role_class, fwnode); + + return dev ? to_role_switch(dev) : NULL; +} +EXPORT_SYMBOL_GPL(usb_role_switch_find_by_fwnode); + static umode_t usb_role_switch_is_visible(struct kobject *kobj, struct attribute *attr, int n) { |