1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Provides code common for host and device side USB. |
4 | * |
5 | * If either host side (ie. CONFIG_USB=y) or device side USB stack |
6 | * (ie. CONFIG_USB_GADGET=y) is compiled in the kernel, this module is |
7 | * compiled-in as well. Otherwise, if either of the two stacks is |
8 | * compiled as module, this file is compiled as module as well. |
9 | */ |
10 | |
11 | #include <linux/kernel.h> |
12 | #include <linux/module.h> |
13 | #include <linux/of.h> |
14 | #include <linux/platform_device.h> |
15 | #include <linux/usb/ch9.h> |
16 | #include <linux/usb/of.h> |
17 | #include <linux/usb/otg.h> |
18 | #include <linux/of_platform.h> |
19 | #include <linux/debugfs.h> |
20 | #include "common.h" |
21 | |
22 | static const char *const ep_type_names[] = { |
23 | [USB_ENDPOINT_XFER_CONTROL] = "ctrl" , |
24 | [USB_ENDPOINT_XFER_ISOC] = "isoc" , |
25 | [USB_ENDPOINT_XFER_BULK] = "bulk" , |
26 | [USB_ENDPOINT_XFER_INT] = "intr" , |
27 | }; |
28 | |
29 | /** |
30 | * usb_ep_type_string() - Returns human readable-name of the endpoint type. |
31 | * @ep_type: The endpoint type to return human-readable name for. If it's not |
32 | * any of the types: USB_ENDPOINT_XFER_{CONTROL, ISOC, BULK, INT}, |
33 | * usually got by usb_endpoint_type(), the string 'unknown' will be returned. |
34 | */ |
35 | const char *usb_ep_type_string(int ep_type) |
36 | { |
37 | if (ep_type < 0 || ep_type >= ARRAY_SIZE(ep_type_names)) |
38 | return "unknown" ; |
39 | |
40 | return ep_type_names[ep_type]; |
41 | } |
42 | EXPORT_SYMBOL_GPL(usb_ep_type_string); |
43 | |
44 | const char *usb_otg_state_string(enum usb_otg_state state) |
45 | { |
46 | static const char *const names[] = { |
47 | [OTG_STATE_A_IDLE] = "a_idle" , |
48 | [OTG_STATE_A_WAIT_VRISE] = "a_wait_vrise" , |
49 | [OTG_STATE_A_WAIT_BCON] = "a_wait_bcon" , |
50 | [OTG_STATE_A_HOST] = "a_host" , |
51 | [OTG_STATE_A_SUSPEND] = "a_suspend" , |
52 | [OTG_STATE_A_PERIPHERAL] = "a_peripheral" , |
53 | [OTG_STATE_A_WAIT_VFALL] = "a_wait_vfall" , |
54 | [OTG_STATE_A_VBUS_ERR] = "a_vbus_err" , |
55 | [OTG_STATE_B_IDLE] = "b_idle" , |
56 | [OTG_STATE_B_SRP_INIT] = "b_srp_init" , |
57 | [OTG_STATE_B_PERIPHERAL] = "b_peripheral" , |
58 | [OTG_STATE_B_WAIT_ACON] = "b_wait_acon" , |
59 | [OTG_STATE_B_HOST] = "b_host" , |
60 | }; |
61 | |
62 | if (state < 0 || state >= ARRAY_SIZE(names)) |
63 | return "UNDEFINED" ; |
64 | |
65 | return names[state]; |
66 | } |
67 | EXPORT_SYMBOL_GPL(usb_otg_state_string); |
68 | |
69 | static const char *const speed_names[] = { |
70 | [USB_SPEED_UNKNOWN] = "UNKNOWN" , |
71 | [USB_SPEED_LOW] = "low-speed" , |
72 | [USB_SPEED_FULL] = "full-speed" , |
73 | [USB_SPEED_HIGH] = "high-speed" , |
74 | [USB_SPEED_WIRELESS] = "wireless" , |
75 | [USB_SPEED_SUPER] = "super-speed" , |
76 | [USB_SPEED_SUPER_PLUS] = "super-speed-plus" , |
77 | }; |
78 | |
79 | static const char *const ssp_rate[] = { |
80 | [USB_SSP_GEN_UNKNOWN] = "UNKNOWN" , |
81 | [USB_SSP_GEN_2x1] = "super-speed-plus-gen2x1" , |
82 | [USB_SSP_GEN_1x2] = "super-speed-plus-gen1x2" , |
83 | [USB_SSP_GEN_2x2] = "super-speed-plus-gen2x2" , |
84 | }; |
85 | |
86 | /** |
87 | * usb_speed_string() - Returns human readable-name of the speed. |
88 | * @speed: The speed to return human-readable name for. If it's not |
89 | * any of the speeds defined in usb_device_speed enum, string for |
90 | * USB_SPEED_UNKNOWN will be returned. |
91 | */ |
92 | const char *usb_speed_string(enum usb_device_speed speed) |
93 | { |
94 | if (speed < 0 || speed >= ARRAY_SIZE(speed_names)) |
95 | speed = USB_SPEED_UNKNOWN; |
96 | return speed_names[speed]; |
97 | } |
98 | EXPORT_SYMBOL_GPL(usb_speed_string); |
99 | |
100 | /** |
101 | * usb_get_maximum_speed - Get maximum requested speed for a given USB |
102 | * controller. |
103 | * @dev: Pointer to the given USB controller device |
104 | * |
105 | * The function gets the maximum speed string from property "maximum-speed", |
106 | * and returns the corresponding enum usb_device_speed. |
107 | */ |
108 | enum usb_device_speed usb_get_maximum_speed(struct device *dev) |
109 | { |
110 | const char *maximum_speed; |
111 | int ret; |
112 | |
113 | ret = device_property_read_string(dev, propname: "maximum-speed" , val: &maximum_speed); |
114 | if (ret < 0) |
115 | return USB_SPEED_UNKNOWN; |
116 | |
117 | ret = match_string(array: ssp_rate, ARRAY_SIZE(ssp_rate), string: maximum_speed); |
118 | if (ret > 0) |
119 | return USB_SPEED_SUPER_PLUS; |
120 | |
121 | ret = match_string(array: speed_names, ARRAY_SIZE(speed_names), string: maximum_speed); |
122 | return (ret < 0) ? USB_SPEED_UNKNOWN : ret; |
123 | } |
124 | EXPORT_SYMBOL_GPL(usb_get_maximum_speed); |
125 | |
126 | /** |
127 | * usb_get_maximum_ssp_rate - Get the signaling rate generation and lane count |
128 | * of a SuperSpeed Plus capable device. |
129 | * @dev: Pointer to the given USB controller device |
130 | * |
131 | * If the string from "maximum-speed" property is super-speed-plus-genXxY where |
132 | * 'X' is the generation number and 'Y' is the number of lanes, then this |
133 | * function returns the corresponding enum usb_ssp_rate. |
134 | */ |
135 | enum usb_ssp_rate usb_get_maximum_ssp_rate(struct device *dev) |
136 | { |
137 | const char *maximum_speed; |
138 | int ret; |
139 | |
140 | ret = device_property_read_string(dev, propname: "maximum-speed" , val: &maximum_speed); |
141 | if (ret < 0) |
142 | return USB_SSP_GEN_UNKNOWN; |
143 | |
144 | ret = match_string(array: ssp_rate, ARRAY_SIZE(ssp_rate), string: maximum_speed); |
145 | return (ret < 0) ? USB_SSP_GEN_UNKNOWN : ret; |
146 | } |
147 | EXPORT_SYMBOL_GPL(usb_get_maximum_ssp_rate); |
148 | |
149 | /** |
150 | * usb_state_string - Returns human readable name for the state. |
151 | * @state: The state to return a human-readable name for. If it's not |
152 | * any of the states devices in usb_device_state_string enum, |
153 | * the string UNKNOWN will be returned. |
154 | */ |
155 | const char *usb_state_string(enum usb_device_state state) |
156 | { |
157 | static const char *const names[] = { |
158 | [USB_STATE_NOTATTACHED] = "not attached" , |
159 | [USB_STATE_ATTACHED] = "attached" , |
160 | [USB_STATE_POWERED] = "powered" , |
161 | [USB_STATE_RECONNECTING] = "reconnecting" , |
162 | [USB_STATE_UNAUTHENTICATED] = "unauthenticated" , |
163 | [USB_STATE_DEFAULT] = "default" , |
164 | [USB_STATE_ADDRESS] = "addressed" , |
165 | [USB_STATE_CONFIGURED] = "configured" , |
166 | [USB_STATE_SUSPENDED] = "suspended" , |
167 | }; |
168 | |
169 | if (state < 0 || state >= ARRAY_SIZE(names)) |
170 | return "UNKNOWN" ; |
171 | |
172 | return names[state]; |
173 | } |
174 | EXPORT_SYMBOL_GPL(usb_state_string); |
175 | |
176 | static const char *const usb_dr_modes[] = { |
177 | [USB_DR_MODE_UNKNOWN] = "" , |
178 | [USB_DR_MODE_HOST] = "host" , |
179 | [USB_DR_MODE_PERIPHERAL] = "peripheral" , |
180 | [USB_DR_MODE_OTG] = "otg" , |
181 | }; |
182 | |
183 | static enum usb_dr_mode usb_get_dr_mode_from_string(const char *str) |
184 | { |
185 | int ret; |
186 | |
187 | ret = match_string(array: usb_dr_modes, ARRAY_SIZE(usb_dr_modes), string: str); |
188 | return (ret < 0) ? USB_DR_MODE_UNKNOWN : ret; |
189 | } |
190 | |
191 | enum usb_dr_mode usb_get_dr_mode(struct device *dev) |
192 | { |
193 | const char *dr_mode; |
194 | int err; |
195 | |
196 | err = device_property_read_string(dev, propname: "dr_mode" , val: &dr_mode); |
197 | if (err < 0) |
198 | return USB_DR_MODE_UNKNOWN; |
199 | |
200 | return usb_get_dr_mode_from_string(str: dr_mode); |
201 | } |
202 | EXPORT_SYMBOL_GPL(usb_get_dr_mode); |
203 | |
204 | /** |
205 | * usb_get_role_switch_default_mode - Get default mode for given device |
206 | * @dev: Pointer to the given device |
207 | * |
208 | * The function gets string from property 'role-switch-default-mode', |
209 | * and returns the corresponding enum usb_dr_mode. |
210 | */ |
211 | enum usb_dr_mode usb_get_role_switch_default_mode(struct device *dev) |
212 | { |
213 | const char *str; |
214 | int ret; |
215 | |
216 | ret = device_property_read_string(dev, propname: "role-switch-default-mode" , val: &str); |
217 | if (ret < 0) |
218 | return USB_DR_MODE_UNKNOWN; |
219 | |
220 | return usb_get_dr_mode_from_string(str); |
221 | } |
222 | EXPORT_SYMBOL_GPL(usb_get_role_switch_default_mode); |
223 | |
224 | /** |
225 | * usb_decode_interval - Decode bInterval into the time expressed in 1us unit |
226 | * @epd: The descriptor of the endpoint |
227 | * @speed: The speed that the endpoint works as |
228 | * |
229 | * Function returns the interval expressed in 1us unit for servicing |
230 | * endpoint for data transfers. |
231 | */ |
232 | unsigned int usb_decode_interval(const struct usb_endpoint_descriptor *epd, |
233 | enum usb_device_speed speed) |
234 | { |
235 | unsigned int interval = 0; |
236 | |
237 | switch (usb_endpoint_type(epd)) { |
238 | case USB_ENDPOINT_XFER_CONTROL: |
239 | /* uframes per NAK */ |
240 | if (speed == USB_SPEED_HIGH) |
241 | interval = epd->bInterval; |
242 | break; |
243 | case USB_ENDPOINT_XFER_ISOC: |
244 | interval = 1 << (epd->bInterval - 1); |
245 | break; |
246 | case USB_ENDPOINT_XFER_BULK: |
247 | /* uframes per NAK */ |
248 | if (speed == USB_SPEED_HIGH && usb_endpoint_dir_out(epd)) |
249 | interval = epd->bInterval; |
250 | break; |
251 | case USB_ENDPOINT_XFER_INT: |
252 | if (speed >= USB_SPEED_HIGH) |
253 | interval = 1 << (epd->bInterval - 1); |
254 | else |
255 | interval = epd->bInterval; |
256 | break; |
257 | } |
258 | |
259 | interval *= (speed >= USB_SPEED_HIGH) ? 125 : 1000; |
260 | |
261 | return interval; |
262 | } |
263 | EXPORT_SYMBOL_GPL(usb_decode_interval); |
264 | |
265 | #ifdef CONFIG_OF |
266 | /** |
267 | * of_usb_get_dr_mode_by_phy - Get dual role mode for the controller device |
268 | * which is associated with the given phy device_node |
269 | * @np: Pointer to the given phy device_node |
270 | * @arg0: phandle args[0] for phy's with #phy-cells >= 1, or -1 for |
271 | * phys which do not have phy-cells |
272 | * |
273 | * In dts a usb controller associates with phy devices. The function gets |
274 | * the string from property 'dr_mode' of the controller associated with the |
275 | * given phy device node, and returns the correspondig enum usb_dr_mode. |
276 | */ |
277 | enum usb_dr_mode of_usb_get_dr_mode_by_phy(struct device_node *np, int arg0) |
278 | { |
279 | struct device_node *controller = NULL; |
280 | struct of_phandle_args args; |
281 | const char *dr_mode; |
282 | int index; |
283 | int err; |
284 | |
285 | do { |
286 | controller = of_find_node_with_property(from: controller, prop_name: "phys" ); |
287 | if (!of_device_is_available(device: controller)) |
288 | continue; |
289 | index = 0; |
290 | do { |
291 | if (arg0 == -1) { |
292 | args.np = of_parse_phandle(np: controller, phandle_name: "phys" , |
293 | index); |
294 | args.args_count = 0; |
295 | } else { |
296 | err = of_parse_phandle_with_args(np: controller, |
297 | list_name: "phys" , cells_name: "#phy-cells" , |
298 | index, out_args: &args); |
299 | if (err) |
300 | break; |
301 | } |
302 | |
303 | of_node_put(node: args.np); |
304 | if (args.np == np && (args.args_count == 0 || |
305 | args.args[0] == arg0)) |
306 | goto finish; |
307 | index++; |
308 | } while (args.np); |
309 | } while (controller); |
310 | |
311 | finish: |
312 | err = of_property_read_string(np: controller, propname: "dr_mode" , out_string: &dr_mode); |
313 | of_node_put(node: controller); |
314 | |
315 | if (err < 0) |
316 | return USB_DR_MODE_UNKNOWN; |
317 | |
318 | return usb_get_dr_mode_from_string(str: dr_mode); |
319 | } |
320 | EXPORT_SYMBOL_GPL(of_usb_get_dr_mode_by_phy); |
321 | |
322 | /** |
323 | * of_usb_host_tpl_support - to get if Targeted Peripheral List is supported |
324 | * for given targeted hosts (non-PC hosts) |
325 | * @np: Pointer to the given device_node |
326 | * |
327 | * The function gets if the targeted hosts support TPL or not |
328 | */ |
329 | bool of_usb_host_tpl_support(struct device_node *np) |
330 | { |
331 | return of_property_read_bool(np, propname: "tpl-support" ); |
332 | } |
333 | EXPORT_SYMBOL_GPL(of_usb_host_tpl_support); |
334 | |
335 | /** |
336 | * of_usb_update_otg_caps - to update usb otg capabilities according to |
337 | * the passed properties in DT. |
338 | * @np: Pointer to the given device_node |
339 | * @otg_caps: Pointer to the target usb_otg_caps to be set |
340 | * |
341 | * The function updates the otg capabilities |
342 | */ |
343 | int of_usb_update_otg_caps(struct device_node *np, |
344 | struct usb_otg_caps *otg_caps) |
345 | { |
346 | u32 otg_rev; |
347 | |
348 | if (!otg_caps) |
349 | return -EINVAL; |
350 | |
351 | if (!of_property_read_u32(np, propname: "otg-rev" , out_value: &otg_rev)) { |
352 | switch (otg_rev) { |
353 | case 0x0100: |
354 | case 0x0120: |
355 | case 0x0130: |
356 | case 0x0200: |
357 | /* Choose the lesser one if it's already been set */ |
358 | if (otg_caps->otg_rev) |
359 | otg_caps->otg_rev = min_t(u16, otg_rev, |
360 | otg_caps->otg_rev); |
361 | else |
362 | otg_caps->otg_rev = otg_rev; |
363 | break; |
364 | default: |
365 | pr_err("%pOF: unsupported otg-rev: 0x%x\n" , |
366 | np, otg_rev); |
367 | return -EINVAL; |
368 | } |
369 | } else { |
370 | /* |
371 | * otg-rev is mandatory for otg properties, if not passed |
372 | * we set it to be 0 and assume it's a legacy otg device. |
373 | * Non-dt platform can set it afterwards. |
374 | */ |
375 | otg_caps->otg_rev = 0; |
376 | } |
377 | |
378 | if (of_property_read_bool(np, propname: "hnp-disable" )) |
379 | otg_caps->hnp_support = false; |
380 | if (of_property_read_bool(np, propname: "srp-disable" )) |
381 | otg_caps->srp_support = false; |
382 | if (of_property_read_bool(np, propname: "adp-disable" ) || |
383 | (otg_caps->otg_rev < 0x0200)) |
384 | otg_caps->adp_support = false; |
385 | |
386 | return 0; |
387 | } |
388 | EXPORT_SYMBOL_GPL(of_usb_update_otg_caps); |
389 | |
390 | /** |
391 | * usb_of_get_companion_dev - Find the companion device |
392 | * @dev: the device pointer to find a companion |
393 | * |
394 | * Find the companion device from platform bus. |
395 | * |
396 | * Takes a reference to the returned struct device which needs to be dropped |
397 | * after use. |
398 | * |
399 | * Return: On success, a pointer to the companion device, %NULL on failure. |
400 | */ |
401 | struct device *usb_of_get_companion_dev(struct device *dev) |
402 | { |
403 | struct device_node *node; |
404 | struct platform_device *pdev = NULL; |
405 | |
406 | node = of_parse_phandle(np: dev->of_node, phandle_name: "companion" , index: 0); |
407 | if (node) |
408 | pdev = of_find_device_by_node(np: node); |
409 | |
410 | of_node_put(node); |
411 | |
412 | return pdev ? &pdev->dev : NULL; |
413 | } |
414 | EXPORT_SYMBOL_GPL(usb_of_get_companion_dev); |
415 | #endif |
416 | |
417 | struct dentry *usb_debug_root; |
418 | EXPORT_SYMBOL_GPL(usb_debug_root); |
419 | |
420 | static int __init usb_common_init(void) |
421 | { |
422 | usb_debug_root = debugfs_create_dir(name: "usb" , NULL); |
423 | ledtrig_usb_init(); |
424 | return 0; |
425 | } |
426 | |
427 | static void __exit usb_common_exit(void) |
428 | { |
429 | ledtrig_usb_exit(); |
430 | debugfs_remove_recursive(dentry: usb_debug_root); |
431 | } |
432 | |
433 | subsys_initcall(usb_common_init); |
434 | module_exit(usb_common_exit); |
435 | |
436 | MODULE_LICENSE("GPL" ); |
437 | |