]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - rpmsg/rpmsg.git/blob - drivers/usb/common/roles.c
Merge tag 'devicetree-fixes-for-4.19-3' of git://git.kernel.org/pub/scm/linux/kernel...
[rpmsg/rpmsg.git] / drivers / usb / common / roles.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * USB Role Switch Support
4  *
5  * Copyright (C) 2018 Intel Corporation
6  * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com>
7  *         Hans de Goede <hdegoede@redhat.com>
8  */
10 #include <linux/usb/role.h>
11 #include <linux/device.h>
12 #include <linux/module.h>
13 #include <linux/mutex.h>
14 #include <linux/slab.h>
16 static struct class *role_class;
18 struct usb_role_switch {
19         struct device dev;
20         struct mutex lock; /* device lock*/
21         enum usb_role role;
23         /* From descriptor */
24         struct device *usb2_port;
25         struct device *usb3_port;
26         struct device *udc;
27         usb_role_switch_set_t set;
28         usb_role_switch_get_t get;
29         bool allow_userspace_control;
30 };
32 #define to_role_switch(d)       container_of(d, struct usb_role_switch, dev)
34 /**
35  * usb_role_switch_set_role - Set USB role for a switch
36  * @sw: USB role switch
37  * @role: USB role to be switched to
38  *
39  * Set USB role @role for @sw.
40  */
41 int usb_role_switch_set_role(struct usb_role_switch *sw, enum usb_role role)
42 {
43         int ret;
45         if (IS_ERR_OR_NULL(sw))
46                 return 0;
48         mutex_lock(&sw->lock);
50         ret = sw->set(sw->dev.parent, role);
51         if (!ret)
52                 sw->role = role;
54         mutex_unlock(&sw->lock);
56         return ret;
57 }
58 EXPORT_SYMBOL_GPL(usb_role_switch_set_role);
60 /**
61  * usb_role_switch_get_role - Get the USB role for a switch
62  * @sw: USB role switch
63  *
64  * Depending on the role-switch-driver this function returns either a cached
65  * value of the last set role, or reads back the actual value from the hardware.
66  */
67 enum usb_role usb_role_switch_get_role(struct usb_role_switch *sw)
68 {
69         enum usb_role role;
71         if (IS_ERR_OR_NULL(sw))
72                 return USB_ROLE_NONE;
74         mutex_lock(&sw->lock);
76         if (sw->get)
77                 role = sw->get(sw->dev.parent);
78         else
79                 role = sw->role;
81         mutex_unlock(&sw->lock);
83         return role;
84 }
85 EXPORT_SYMBOL_GPL(usb_role_switch_get_role);
87 static int __switch_match(struct device *dev, const void *name)
88 {
89         return !strcmp((const char *)name, dev_name(dev));
90 }
92 static void *usb_role_switch_match(struct device_connection *con, int ep,
93                                    void *data)
94 {
95         struct device *dev;
97         dev = class_find_device(role_class, NULL, con->endpoint[ep],
98                                 __switch_match);
100         return dev ? to_role_switch(dev) : ERR_PTR(-EPROBE_DEFER);
103 /**
104  * usb_role_switch_get - Find USB role switch linked with the caller
105  * @dev: The caller device
106  *
107  * Finds and returns role switch linked with @dev. The reference count for the
108  * found switch is incremented.
109  */
110 struct usb_role_switch *usb_role_switch_get(struct device *dev)
112         struct usb_role_switch *sw;
114         sw = device_connection_find_match(dev, "usb-role-switch", NULL,
115                                           usb_role_switch_match);
117         if (!IS_ERR_OR_NULL(sw))
118                 WARN_ON(!try_module_get(sw->dev.parent->driver->owner));
120         return sw;
122 EXPORT_SYMBOL_GPL(usb_role_switch_get);
124 /**
125  * usb_role_switch_put - Release handle to a switch
126  * @sw: USB Role Switch
127  *
128  * Decrement reference count for @sw.
129  */
130 void usb_role_switch_put(struct usb_role_switch *sw)
132         if (!IS_ERR_OR_NULL(sw)) {
133                 put_device(&sw->dev);
134                 module_put(sw->dev.parent->driver->owner);
135         }
137 EXPORT_SYMBOL_GPL(usb_role_switch_put);
139 static umode_t
140 usb_role_switch_is_visible(struct kobject *kobj, struct attribute *attr, int n)
142         struct device *dev = container_of(kobj, typeof(*dev), kobj);
143         struct usb_role_switch *sw = to_role_switch(dev);
145         if (sw->allow_userspace_control)
146                 return attr->mode;
148         return 0;
151 static const char * const usb_roles[] = {
152         [USB_ROLE_NONE]         = "none",
153         [USB_ROLE_HOST]         = "host",
154         [USB_ROLE_DEVICE]       = "device",
155 };
157 static ssize_t
158 role_show(struct device *dev, struct device_attribute *attr, char *buf)
160         struct usb_role_switch *sw = to_role_switch(dev);
161         enum usb_role role = usb_role_switch_get_role(sw);
163         return sprintf(buf, "%s\n", usb_roles[role]);
166 static ssize_t role_store(struct device *dev, struct device_attribute *attr,
167                           const char *buf, size_t size)
169         struct usb_role_switch *sw = to_role_switch(dev);
170         int ret;
172         ret = sysfs_match_string(usb_roles, buf);
173         if (ret < 0) {
174                 bool res;
176                 /* Extra check if the user wants to disable the switch */
177                 ret = kstrtobool(buf, &res);
178                 if (ret || res)
179                         return -EINVAL;
180         }
182         ret = usb_role_switch_set_role(sw, ret);
183         if (ret)
184                 return ret;
186         return size;
188 static DEVICE_ATTR_RW(role);
190 static struct attribute *usb_role_switch_attrs[] = {
191         &dev_attr_role.attr,
192         NULL,
193 };
195 static const struct attribute_group usb_role_switch_group = {
196         .is_visible = usb_role_switch_is_visible,
197         .attrs = usb_role_switch_attrs,
198 };
200 static const struct attribute_group *usb_role_switch_groups[] = {
201         &usb_role_switch_group,
202         NULL,
203 };
205 static int
206 usb_role_switch_uevent(struct device *dev, struct kobj_uevent_env *env)
208         int ret;
210         ret = add_uevent_var(env, "USB_ROLE_SWITCH=%s", dev_name(dev));
211         if (ret)
212                 dev_err(dev, "failed to add uevent USB_ROLE_SWITCH\n");
214         return ret;
217 static void usb_role_switch_release(struct device *dev)
219         struct usb_role_switch *sw = to_role_switch(dev);
221         kfree(sw);
224 static const struct device_type usb_role_dev_type = {
225         .name = "usb_role_switch",
226         .groups = usb_role_switch_groups,
227         .uevent = usb_role_switch_uevent,
228         .release = usb_role_switch_release,
229 };
231 /**
232  * usb_role_switch_register - Register USB Role Switch
233  * @parent: Parent device for the switch
234  * @desc: Description of the switch
235  *
236  * USB Role Switch is a device capable or choosing the role for USB connector.
237  * On platforms where the USB controller is dual-role capable, the controller
238  * driver will need to register the switch. On platforms where the USB host and
239  * USB device controllers behind the connector are separate, there will be a
240  * mux, and the driver for that mux will need to register the switch.
241  *
242  * Returns handle to a new role switch or ERR_PTR. The content of @desc is
243  * copied.
244  */
245 struct usb_role_switch *
246 usb_role_switch_register(struct device *parent,
247                          const struct usb_role_switch_desc *desc)
249         struct usb_role_switch *sw;
250         int ret;
252         if (!desc || !desc->set)
253                 return ERR_PTR(-EINVAL);
255         sw = kzalloc(sizeof(*sw), GFP_KERNEL);
256         if (!sw)
257                 return ERR_PTR(-ENOMEM);
259         mutex_init(&sw->lock);
261         sw->allow_userspace_control = desc->allow_userspace_control;
262         sw->usb2_port = desc->usb2_port;
263         sw->usb3_port = desc->usb3_port;
264         sw->udc = desc->udc;
265         sw->set = desc->set;
266         sw->get = desc->get;
268         sw->dev.parent = parent;
269         sw->dev.class = role_class;
270         sw->dev.type = &usb_role_dev_type;
271         dev_set_name(&sw->dev, "%s-role-switch", dev_name(parent));
273         ret = device_register(&sw->dev);
274         if (ret) {
275                 put_device(&sw->dev);
276                 return ERR_PTR(ret);
277         }
279         /* TODO: Symlinks for the host port and the device controller. */
281         return sw;
283 EXPORT_SYMBOL_GPL(usb_role_switch_register);
285 /**
286  * usb_role_switch_unregister - Unregsiter USB Role Switch
287  * @sw: USB Role Switch
288  *
289  * Unregister switch that was registered with usb_role_switch_register().
290  */
291 void usb_role_switch_unregister(struct usb_role_switch *sw)
293         if (!IS_ERR_OR_NULL(sw))
294                 device_unregister(&sw->dev);
296 EXPORT_SYMBOL_GPL(usb_role_switch_unregister);
298 static int __init usb_roles_init(void)
300         role_class = class_create(THIS_MODULE, "usb_role");
301         return PTR_ERR_OR_ZERO(role_class);
303 subsys_initcall(usb_roles_init);
305 static void __exit usb_roles_exit(void)
307         class_destroy(role_class);
309 module_exit(usb_roles_exit);
311 MODULE_AUTHOR("Heikki Krogerus <heikki.krogerus@linux.intel.com>");
312 MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
313 MODULE_LICENSE("GPL v2");
314 MODULE_DESCRIPTION("USB Role Class");