xref: /openbmc/linux/drivers/usb/roles/class.c (revision 2c6467d2)
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  */
9 
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>
15 
16 static struct class *role_class;
17 
18 struct usb_role_switch {
19 	struct device dev;
20 	struct mutex lock; /* device lock*/
21 	enum usb_role role;
22 
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 };
31 
32 #define to_role_switch(d)	container_of(d, struct usb_role_switch, dev)
33 
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;
44 
45 	if (IS_ERR_OR_NULL(sw))
46 		return 0;
47 
48 	mutex_lock(&sw->lock);
49 
50 	ret = sw->set(sw->dev.parent, role);
51 	if (!ret)
52 		sw->role = role;
53 
54 	mutex_unlock(&sw->lock);
55 
56 	return ret;
57 }
58 EXPORT_SYMBOL_GPL(usb_role_switch_set_role);
59 
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;
70 
71 	if (IS_ERR_OR_NULL(sw))
72 		return USB_ROLE_NONE;
73 
74 	mutex_lock(&sw->lock);
75 
76 	if (sw->get)
77 		role = sw->get(sw->dev.parent);
78 	else
79 		role = sw->role;
80 
81 	mutex_unlock(&sw->lock);
82 
83 	return role;
84 }
85 EXPORT_SYMBOL_GPL(usb_role_switch_get_role);
86 
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,
93 				   void *data)
94 {
95 	struct device *dev;
96 
97 	dev = class_find_device(role_class, NULL, con->endpoint[ep],
98 				__switch_match);
99 
100 	return dev ? to_role_switch(dev) : ERR_PTR(-EPROBE_DEFER);
101 }
102 
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)
111 {
112 	struct usb_role_switch *sw;
113 
114 	sw = device_connection_find_match(dev, "usb-role-switch", NULL,
115 					  usb_role_switch_match);
116 
117 	if (!IS_ERR_OR_NULL(sw))
118 		WARN_ON(!try_module_get(sw->dev.parent->driver->owner));
119 
120 	return sw;
121 }
122 EXPORT_SYMBOL_GPL(usb_role_switch_get);
123 
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)
131 {
132 	if (!IS_ERR_OR_NULL(sw)) {
133 		put_device(&sw->dev);
134 		module_put(sw->dev.parent->driver->owner);
135 	}
136 }
137 EXPORT_SYMBOL_GPL(usb_role_switch_put);
138 
139 static umode_t
140 usb_role_switch_is_visible(struct kobject *kobj, struct attribute *attr, int n)
141 {
142 	struct device *dev = container_of(kobj, typeof(*dev), kobj);
143 	struct usb_role_switch *sw = to_role_switch(dev);
144 
145 	if (sw->allow_userspace_control)
146 		return attr->mode;
147 
148 	return 0;
149 }
150 
151 static const char * const usb_roles[] = {
152 	[USB_ROLE_NONE]		= "none",
153 	[USB_ROLE_HOST]		= "host",
154 	[USB_ROLE_DEVICE]	= "device",
155 };
156 
157 static ssize_t
158 role_show(struct device *dev, struct device_attribute *attr, char *buf)
159 {
160 	struct usb_role_switch *sw = to_role_switch(dev);
161 	enum usb_role role = usb_role_switch_get_role(sw);
162 
163 	return sprintf(buf, "%s\n", usb_roles[role]);
164 }
165 
166 static ssize_t role_store(struct device *dev, struct device_attribute *attr,
167 			  const char *buf, size_t size)
168 {
169 	struct usb_role_switch *sw = to_role_switch(dev);
170 	int ret;
171 
172 	ret = sysfs_match_string(usb_roles, buf);
173 	if (ret < 0) {
174 		bool res;
175 
176 		/* Extra check if the user wants to disable the switch */
177 		ret = kstrtobool(buf, &res);
178 		if (ret || res)
179 			return -EINVAL;
180 	}
181 
182 	ret = usb_role_switch_set_role(sw, ret);
183 	if (ret)
184 		return ret;
185 
186 	return size;
187 }
188 static DEVICE_ATTR_RW(role);
189 
190 static struct attribute *usb_role_switch_attrs[] = {
191 	&dev_attr_role.attr,
192 	NULL,
193 };
194 
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 };
199 
200 static const struct attribute_group *usb_role_switch_groups[] = {
201 	&usb_role_switch_group,
202 	NULL,
203 };
204 
205 static int
206 usb_role_switch_uevent(struct device *dev, struct kobj_uevent_env *env)
207 {
208 	int ret;
209 
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");
213 
214 	return ret;
215 }
216 
217 static void usb_role_switch_release(struct device *dev)
218 {
219 	struct usb_role_switch *sw = to_role_switch(dev);
220 
221 	kfree(sw);
222 }
223 
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 };
230 
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)
248 {
249 	struct usb_role_switch *sw;
250 	int ret;
251 
252 	if (!desc || !desc->set)
253 		return ERR_PTR(-EINVAL);
254 
255 	sw = kzalloc(sizeof(*sw), GFP_KERNEL);
256 	if (!sw)
257 		return ERR_PTR(-ENOMEM);
258 
259 	mutex_init(&sw->lock);
260 
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;
267 
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));
272 
273 	ret = device_register(&sw->dev);
274 	if (ret) {
275 		put_device(&sw->dev);
276 		return ERR_PTR(ret);
277 	}
278 
279 	/* TODO: Symlinks for the host port and the device controller. */
280 
281 	return sw;
282 }
283 EXPORT_SYMBOL_GPL(usb_role_switch_register);
284 
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)
292 {
293 	if (!IS_ERR_OR_NULL(sw))
294 		device_unregister(&sw->dev);
295 }
296 EXPORT_SYMBOL_GPL(usb_role_switch_unregister);
297 
298 static int __init usb_roles_init(void)
299 {
300 	role_class = class_create(THIS_MODULE, "usb_role");
301 	return PTR_ERR_OR_ZERO(role_class);
302 }
303 subsys_initcall(usb_roles_init);
304 
305 static void __exit usb_roles_exit(void)
306 {
307 	class_destroy(role_class);
308 }
309 module_exit(usb_roles_exit);
310 
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");
315