.. | .. |
---|
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"); |
---|