// SPDX-License-Identifier: GPL-2.0 /* * USB Role Switch Support * * Copyright (C) 2018 Intel Corporation * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com> * Hans de Goede <hdegoede@redhat.com>
*/
/** * usb_role_switch_set_role - Set USB role for a switch * @sw: USB role switch * @role: USB role to be switched to * * Set USB role @role for @sw.
*/ int usb_role_switch_set_role(struct usb_role_switch *sw, enum usb_role role)
{ int ret;
if (IS_ERR_OR_NULL(sw)) return 0;
if (!sw->registered) return -EOPNOTSUPP;
mutex_lock(&sw->lock);
ret = sw->set(sw, role); if (!ret) {
sw->role = role;
kobject_uevent(&sw->dev.kobj, KOBJ_CHANGE);
}
/** * usb_role_switch_get_role - Get the USB role for a switch * @sw: USB role switch * * Depending on the role-switch-driver this function returns either a cached * value of the last set role, or reads back the actual value from the hardware.
*/ enum usb_role usb_role_switch_get_role(struct usb_role_switch *sw)
{ enum usb_role role;
if (IS_ERR_OR_NULL(sw) || !sw->registered) return USB_ROLE_NONE;
mutex_lock(&sw->lock);
if (sw->get)
role = sw->get(sw); else
role = sw->role;
if (!fwnode_property_present(parent, "usb-role-switch")) {
fwnode_handle_put(parent); return NULL;
}
dev = class_find_device_by_fwnode(&role_class, parent);
fwnode_handle_put(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 * * Finds and returns role switch linked with @dev. The reference count for the * found switch is incremented.
*/ struct usb_role_switch *usb_role_switch_get(struct device *dev)
{ struct usb_role_switch *sw;
/** * 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->module));
/** * usb_role_switch_put - Release handle to a switch * @sw: USB Role Switch * * Decrement reference count for @sw.
*/ void usb_role_switch_put(struct usb_role_switch *sw)
{ if (!IS_ERR_OR_NULL(sw)) {
module_put(sw->module);
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(conststruct fwnode_handle *fwnode)
{ struct device *dev; struct usb_role_switch *sw = NULL;
if (!fwnode) return NULL;
dev = class_find_device_by_fwnode(&role_class, fwnode); if (dev) {
sw = to_role_switch(dev);
WARN_ON(!try_module_get(sw->module));
}
/** * usb_role_switch_register - Register USB Role Switch * @parent: Parent device for the switch * @desc: Description of the switch * * USB Role Switch is a device capable or choosing the role for USB connector. * On platforms where the USB controller is dual-role capable, the controller * driver will need to register the switch. On platforms where the USB host and * USB device controllers behind the connector are separate, there will be a * mux, and the driver for that mux will need to register the switch. * * Returns handle to a new role switch or ERR_PTR. The content of @desc is * copied.
*/ struct usb_role_switch *
usb_role_switch_register(struct device *parent, conststruct usb_role_switch_desc *desc)
{ struct usb_role_switch *sw; int ret;
if (!desc || !desc->set) return ERR_PTR(-EINVAL);
sw = kzalloc(sizeof(*sw), GFP_KERNEL); if (!sw) return ERR_PTR(-ENOMEM);
/** * usb_role_switch_unregister - Unregsiter USB Role Switch * @sw: USB Role Switch * * Unregister switch that was registered with usb_role_switch_register().
*/ void usb_role_switch_unregister(struct usb_role_switch *sw)
{ if (IS_ERR_OR_NULL(sw)) return;
sw->registered = false; if (dev_fwnode(&sw->dev))
component_del(&sw->dev, &connector_ops);
device_unregister(&sw->dev);
}
EXPORT_SYMBOL_GPL(usb_role_switch_unregister);
/** * usb_role_switch_set_drvdata - Assign private data pointer to a switch * @sw: USB Role Switch * @data: Private data pointer
*/ void usb_role_switch_set_drvdata(struct usb_role_switch *sw, void *data)
{
dev_set_drvdata(&sw->dev, data);
}
EXPORT_SYMBOL_GPL(usb_role_switch_set_drvdata);
/** * usb_role_switch_get_drvdata - Get the private data pointer of a switch * @sw: USB Role Switch
*/ void *usb_role_switch_get_drvdata(struct usb_role_switch *sw)
{ return dev_get_drvdata(&sw->dev);
}
EXPORT_SYMBOL_GPL(usb_role_switch_get_drvdata);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.