| .. | .. |
|---|
| 8 | 8 | */ |
|---|
| 9 | 9 | |
|---|
| 10 | 10 | #include <linux/usb/role.h> |
|---|
| 11 | +#include <linux/property.h> |
|---|
| 11 | 12 | #include <linux/device.h> |
|---|
| 12 | 13 | #include <linux/module.h> |
|---|
| 13 | 14 | #include <linux/mutex.h> |
|---|
| .. | .. |
|---|
| 47 | 48 | |
|---|
| 48 | 49 | mutex_lock(&sw->lock); |
|---|
| 49 | 50 | |
|---|
| 50 | | - ret = sw->set(sw->dev.parent, role); |
|---|
| 51 | | - if (!ret) |
|---|
| 51 | + ret = sw->set(sw, role); |
|---|
| 52 | + if (!ret) { |
|---|
| 52 | 53 | sw->role = role; |
|---|
| 54 | + kobject_uevent(&sw->dev.kobj, KOBJ_CHANGE); |
|---|
| 55 | + } |
|---|
| 53 | 56 | |
|---|
| 54 | 57 | mutex_unlock(&sw->lock); |
|---|
| 55 | 58 | |
|---|
| .. | .. |
|---|
| 74 | 77 | mutex_lock(&sw->lock); |
|---|
| 75 | 78 | |
|---|
| 76 | 79 | if (sw->get) |
|---|
| 77 | | - role = sw->get(sw->dev.parent); |
|---|
| 80 | + role = sw->get(sw); |
|---|
| 78 | 81 | else |
|---|
| 79 | 82 | role = sw->role; |
|---|
| 80 | 83 | |
|---|
| .. | .. |
|---|
| 84 | 87 | } |
|---|
| 85 | 88 | EXPORT_SYMBOL_GPL(usb_role_switch_get_role); |
|---|
| 86 | 89 | |
|---|
| 87 | | -static int __switch_match(struct device *dev, const void *name) |
|---|
| 88 | | -{ |
|---|
| 89 | | - return !strcmp((const char *)name, dev_name(dev)); |
|---|
| 90 | | -} |
|---|
| 91 | | - |
|---|
| 92 | | -static void *usb_role_switch_match(struct device_connection *con, int ep, |
|---|
| 90 | +static void *usb_role_switch_match(struct fwnode_handle *fwnode, const char *id, |
|---|
| 93 | 91 | void *data) |
|---|
| 94 | 92 | { |
|---|
| 95 | 93 | struct device *dev; |
|---|
| 96 | 94 | |
|---|
| 97 | | - dev = class_find_device(role_class, NULL, con->endpoint[ep], |
|---|
| 98 | | - __switch_match); |
|---|
| 95 | + if (id && !fwnode_property_present(fwnode, id)) |
|---|
| 96 | + return NULL; |
|---|
| 99 | 97 | |
|---|
| 98 | + dev = class_find_device_by_fwnode(role_class, fwnode); |
|---|
| 99 | + |
|---|
| 100 | + return dev ? to_role_switch(dev) : ERR_PTR(-EPROBE_DEFER); |
|---|
| 101 | +} |
|---|
| 102 | + |
|---|
| 103 | +static struct usb_role_switch * |
|---|
| 104 | +usb_role_switch_is_parent(struct fwnode_handle *fwnode) |
|---|
| 105 | +{ |
|---|
| 106 | + struct fwnode_handle *parent = fwnode_get_parent(fwnode); |
|---|
| 107 | + struct device *dev; |
|---|
| 108 | + |
|---|
| 109 | + if (!fwnode_property_present(parent, "usb-role-switch")) { |
|---|
| 110 | + fwnode_handle_put(parent); |
|---|
| 111 | + return NULL; |
|---|
| 112 | + } |
|---|
| 113 | + |
|---|
| 114 | + dev = class_find_device_by_fwnode(role_class, parent); |
|---|
| 115 | + fwnode_handle_put(parent); |
|---|
| 100 | 116 | return dev ? to_role_switch(dev) : ERR_PTR(-EPROBE_DEFER); |
|---|
| 101 | 117 | } |
|---|
| 102 | 118 | |
|---|
| .. | .. |
|---|
| 111 | 127 | { |
|---|
| 112 | 128 | struct usb_role_switch *sw; |
|---|
| 113 | 129 | |
|---|
| 114 | | - sw = device_connection_find_match(dev, "usb-role-switch", NULL, |
|---|
| 115 | | - usb_role_switch_match); |
|---|
| 130 | + sw = usb_role_switch_is_parent(dev_fwnode(dev)); |
|---|
| 131 | + if (!sw) |
|---|
| 132 | + sw = device_connection_find_match(dev, "usb-role-switch", NULL, |
|---|
| 133 | + usb_role_switch_match); |
|---|
| 116 | 134 | |
|---|
| 117 | 135 | if (!IS_ERR_OR_NULL(sw)) |
|---|
| 118 | 136 | WARN_ON(!try_module_get(sw->dev.parent->driver->owner)); |
|---|
| .. | .. |
|---|
| 120 | 138 | return sw; |
|---|
| 121 | 139 | } |
|---|
| 122 | 140 | EXPORT_SYMBOL_GPL(usb_role_switch_get); |
|---|
| 141 | + |
|---|
| 142 | +/** |
|---|
| 143 | + * fwnode_usb_role_switch_get - Find USB role switch linked with the caller |
|---|
| 144 | + * @fwnode: The caller device node |
|---|
| 145 | + * |
|---|
| 146 | + * This is similar to the usb_role_switch_get() function above, but it searches |
|---|
| 147 | + * the switch using fwnode instead of device entry. |
|---|
| 148 | + */ |
|---|
| 149 | +struct usb_role_switch *fwnode_usb_role_switch_get(struct fwnode_handle *fwnode) |
|---|
| 150 | +{ |
|---|
| 151 | + struct usb_role_switch *sw; |
|---|
| 152 | + |
|---|
| 153 | + sw = usb_role_switch_is_parent(fwnode); |
|---|
| 154 | + if (!sw) |
|---|
| 155 | + sw = fwnode_connection_find_match(fwnode, "usb-role-switch", |
|---|
| 156 | + NULL, usb_role_switch_match); |
|---|
| 157 | + if (!IS_ERR_OR_NULL(sw)) |
|---|
| 158 | + WARN_ON(!try_module_get(sw->dev.parent->driver->owner)); |
|---|
| 159 | + |
|---|
| 160 | + return sw; |
|---|
| 161 | +} |
|---|
| 162 | +EXPORT_SYMBOL_GPL(fwnode_usb_role_switch_get); |
|---|
| 123 | 163 | |
|---|
| 124 | 164 | /** |
|---|
| 125 | 165 | * usb_role_switch_put - Release handle to a switch |
|---|
| .. | .. |
|---|
| 136 | 176 | } |
|---|
| 137 | 177 | EXPORT_SYMBOL_GPL(usb_role_switch_put); |
|---|
| 138 | 178 | |
|---|
| 179 | +/** |
|---|
| 180 | + * usb_role_switch_find_by_fwnode - Find USB role switch with its fwnode |
|---|
| 181 | + * @fwnode: fwnode of the USB Role Switch |
|---|
| 182 | + * |
|---|
| 183 | + * Finds and returns role switch with @fwnode. The reference count for the |
|---|
| 184 | + * found switch is incremented. |
|---|
| 185 | + */ |
|---|
| 186 | +struct usb_role_switch * |
|---|
| 187 | +usb_role_switch_find_by_fwnode(const struct fwnode_handle *fwnode) |
|---|
| 188 | +{ |
|---|
| 189 | + struct device *dev; |
|---|
| 190 | + |
|---|
| 191 | + if (!fwnode) |
|---|
| 192 | + return NULL; |
|---|
| 193 | + |
|---|
| 194 | + dev = class_find_device_by_fwnode(role_class, fwnode); |
|---|
| 195 | + if (dev) |
|---|
| 196 | + WARN_ON(!try_module_get(dev->parent->driver->owner)); |
|---|
| 197 | + |
|---|
| 198 | + return dev ? to_role_switch(dev) : NULL; |
|---|
| 199 | +} |
|---|
| 200 | +EXPORT_SYMBOL_GPL(usb_role_switch_find_by_fwnode); |
|---|
| 201 | + |
|---|
| 139 | 202 | static umode_t |
|---|
| 140 | 203 | usb_role_switch_is_visible(struct kobject *kobj, struct attribute *attr, int n) |
|---|
| 141 | 204 | { |
|---|
| 142 | | - struct device *dev = container_of(kobj, typeof(*dev), kobj); |
|---|
| 205 | + struct device *dev = kobj_to_dev(kobj); |
|---|
| 143 | 206 | struct usb_role_switch *sw = to_role_switch(dev); |
|---|
| 144 | 207 | |
|---|
| 145 | 208 | if (sw->allow_userspace_control) |
|---|
| .. | .. |
|---|
| 266 | 329 | sw->get = desc->get; |
|---|
| 267 | 330 | |
|---|
| 268 | 331 | sw->dev.parent = parent; |
|---|
| 332 | + sw->dev.fwnode = desc->fwnode; |
|---|
| 269 | 333 | sw->dev.class = role_class; |
|---|
| 270 | 334 | sw->dev.type = &usb_role_dev_type; |
|---|
| 271 | | - dev_set_name(&sw->dev, "%s-role-switch", dev_name(parent)); |
|---|
| 335 | + dev_set_drvdata(&sw->dev, desc->driver_data); |
|---|
| 336 | + dev_set_name(&sw->dev, "%s-role-switch", |
|---|
| 337 | + desc->name ? desc->name : dev_name(parent)); |
|---|
| 272 | 338 | |
|---|
| 273 | 339 | ret = device_register(&sw->dev); |
|---|
| 274 | 340 | if (ret) { |
|---|
| .. | .. |
|---|
| 295 | 361 | } |
|---|
| 296 | 362 | EXPORT_SYMBOL_GPL(usb_role_switch_unregister); |
|---|
| 297 | 363 | |
|---|
| 364 | +/** |
|---|
| 365 | + * usb_role_switch_set_drvdata - Assign private data pointer to a switch |
|---|
| 366 | + * @sw: USB Role Switch |
|---|
| 367 | + * @data: Private data pointer |
|---|
| 368 | + */ |
|---|
| 369 | +void usb_role_switch_set_drvdata(struct usb_role_switch *sw, void *data) |
|---|
| 370 | +{ |
|---|
| 371 | + dev_set_drvdata(&sw->dev, data); |
|---|
| 372 | +} |
|---|
| 373 | +EXPORT_SYMBOL_GPL(usb_role_switch_set_drvdata); |
|---|
| 374 | + |
|---|
| 375 | +/** |
|---|
| 376 | + * usb_role_switch_get_drvdata - Get the private data pointer of a switch |
|---|
| 377 | + * @sw: USB Role Switch |
|---|
| 378 | + */ |
|---|
| 379 | +void *usb_role_switch_get_drvdata(struct usb_role_switch *sw) |
|---|
| 380 | +{ |
|---|
| 381 | + return dev_get_drvdata(&sw->dev); |
|---|
| 382 | +} |
|---|
| 383 | +EXPORT_SYMBOL_GPL(usb_role_switch_get_drvdata); |
|---|
| 384 | + |
|---|
| 298 | 385 | static int __init usb_roles_init(void) |
|---|
| 299 | 386 | { |
|---|
| 300 | 387 | role_class = class_create(THIS_MODULE, "usb_role"); |
|---|