1
2
3
4
5
6
7
8
9
10
11#include <linux/kernel.h>
12#include <linux/export.h>
13#include <linux/err.h>
14#include <linux/device.h>
15#include <linux/module.h>
16#include <linux/slab.h>
17#include <linux/of.h>
18
19#include <linux/usb/phy.h>
20
21static LIST_HEAD(phy_list);
22static LIST_HEAD(phy_bind_list);
23static DEFINE_SPINLOCK(phy_lock);
24
25struct phy_devm {
26 struct usb_phy *phy;
27 struct notifier_block *nb;
28};
29
30static struct usb_phy *__usb_find_phy(struct list_head *list,
31 enum usb_phy_type type)
32{
33 struct usb_phy *phy = NULL;
34
35 list_for_each_entry(phy, list, head) {
36 if (phy->type != type)
37 continue;
38
39 return phy;
40 }
41
42 return ERR_PTR(-ENODEV);
43}
44
45static struct usb_phy *__usb_find_phy_dev(struct device *dev,
46 struct list_head *list, u8 index)
47{
48 struct usb_phy_bind *phy_bind = NULL;
49
50 list_for_each_entry(phy_bind, list, list) {
51 if (!(strcmp(phy_bind->dev_name, dev_name(dev))) &&
52 phy_bind->index == index) {
53 if (phy_bind->phy)
54 return phy_bind->phy;
55 else
56 return ERR_PTR(-EPROBE_DEFER);
57 }
58 }
59
60 return ERR_PTR(-ENODEV);
61}
62
63static struct usb_phy *__of_usb_find_phy(struct device_node *node)
64{
65 struct usb_phy *phy;
66
67 if (!of_device_is_available(node))
68 return ERR_PTR(-ENODEV);
69
70 list_for_each_entry(phy, &phy_list, head) {
71 if (node != phy->dev->of_node)
72 continue;
73
74 return phy;
75 }
76
77 return ERR_PTR(-EPROBE_DEFER);
78}
79
80static void devm_usb_phy_release(struct device *dev, void *res)
81{
82 struct usb_phy *phy = *(struct usb_phy **)res;
83
84 usb_put_phy(phy);
85}
86
87static void devm_usb_phy_release2(struct device *dev, void *_res)
88{
89 struct phy_devm *res = _res;
90
91 if (res->nb)
92 usb_unregister_notifier(res->phy, res->nb);
93 usb_put_phy(res->phy);
94}
95
96static int devm_usb_phy_match(struct device *dev, void *res, void *match_data)
97{
98 struct usb_phy **phy = res;
99
100 return *phy == match_data;
101}
102
103static int usb_add_extcon(struct usb_phy *x)
104{
105 int ret;
106
107 if (of_property_read_bool(x->dev->of_node, "extcon")) {
108 x->edev = extcon_get_edev_by_phandle(x->dev, 0);
109 if (IS_ERR(x->edev))
110 return PTR_ERR(x->edev);
111
112 x->id_edev = extcon_get_edev_by_phandle(x->dev, 1);
113 if (IS_ERR(x->id_edev)) {
114 x->id_edev = NULL;
115 dev_info(x->dev, "No separate ID extcon device\n");
116 }
117
118 if (x->vbus_nb.notifier_call) {
119 ret = devm_extcon_register_notifier(x->dev, x->edev,
120 EXTCON_USB,
121 &x->vbus_nb);
122 if (ret < 0) {
123 dev_err(x->dev,
124 "register VBUS notifier failed\n");
125 return ret;
126 }
127 }
128
129 if (x->id_nb.notifier_call) {
130 struct extcon_dev *id_ext;
131
132 if (x->id_edev)
133 id_ext = x->id_edev;
134 else
135 id_ext = x->edev;
136
137 ret = devm_extcon_register_notifier(x->dev, id_ext,
138 EXTCON_USB_HOST,
139 &x->id_nb);
140 if (ret < 0) {
141 dev_err(x->dev,
142 "register ID notifier failed\n");
143 return ret;
144 }
145 }
146 }
147
148 return 0;
149}
150
151
152
153
154
155
156
157
158
159
160
161
162struct usb_phy *devm_usb_get_phy(struct device *dev, enum usb_phy_type type)
163{
164 struct usb_phy **ptr, *phy;
165
166 ptr = devres_alloc(devm_usb_phy_release, sizeof(*ptr), GFP_KERNEL);
167 if (!ptr)
168 return ERR_PTR(-ENOMEM);
169
170 phy = usb_get_phy(type);
171 if (!IS_ERR(phy)) {
172 *ptr = phy;
173 devres_add(dev, ptr);
174 } else
175 devres_free(ptr);
176
177 return phy;
178}
179EXPORT_SYMBOL_GPL(devm_usb_get_phy);
180
181
182
183
184
185
186
187
188
189
190
191struct usb_phy *usb_get_phy(enum usb_phy_type type)
192{
193 struct usb_phy *phy = NULL;
194 unsigned long flags;
195
196 spin_lock_irqsave(&phy_lock, flags);
197
198 phy = __usb_find_phy(&phy_list, type);
199 if (IS_ERR(phy) || !try_module_get(phy->dev->driver->owner)) {
200 pr_debug("PHY: unable to find transceiver of type %s\n",
201 usb_phy_type_string(type));
202 if (!IS_ERR(phy))
203 phy = ERR_PTR(-ENODEV);
204
205 goto err0;
206 }
207
208 get_device(phy->dev);
209
210err0:
211 spin_unlock_irqrestore(&phy_lock, flags);
212
213 return phy;
214}
215EXPORT_SYMBOL_GPL(usb_get_phy);
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233struct usb_phy *devm_usb_get_phy_by_node(struct device *dev,
234 struct device_node *node,
235 struct notifier_block *nb)
236{
237 struct usb_phy *phy = ERR_PTR(-ENOMEM);
238 struct phy_devm *ptr;
239 unsigned long flags;
240
241 ptr = devres_alloc(devm_usb_phy_release2, sizeof(*ptr), GFP_KERNEL);
242 if (!ptr) {
243 dev_dbg(dev, "failed to allocate memory for devres\n");
244 goto err0;
245 }
246
247 spin_lock_irqsave(&phy_lock, flags);
248
249 phy = __of_usb_find_phy(node);
250 if (IS_ERR(phy)) {
251 devres_free(ptr);
252 goto err1;
253 }
254
255 if (!try_module_get(phy->dev->driver->owner)) {
256 phy = ERR_PTR(-ENODEV);
257 devres_free(ptr);
258 goto err1;
259 }
260 if (nb)
261 usb_register_notifier(phy, nb);
262 ptr->phy = phy;
263 ptr->nb = nb;
264 devres_add(dev, ptr);
265
266 get_device(phy->dev);
267
268err1:
269 spin_unlock_irqrestore(&phy_lock, flags);
270
271err0:
272
273 return phy;
274}
275EXPORT_SYMBOL_GPL(devm_usb_get_phy_by_node);
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev,
293 const char *phandle, u8 index)
294{
295 struct device_node *node;
296 struct usb_phy *phy;
297
298 if (!dev->of_node) {
299 dev_dbg(dev, "device does not have a device node entry\n");
300 return ERR_PTR(-EINVAL);
301 }
302
303 node = of_parse_phandle(dev->of_node, phandle, index);
304 if (!node) {
305 dev_dbg(dev, "failed to get %s phandle in %s node\n", phandle,
306 dev->of_node->full_name);
307 return ERR_PTR(-ENODEV);
308 }
309 phy = devm_usb_get_phy_by_node(dev, node, NULL);
310 of_node_put(node);
311 return phy;
312}
313EXPORT_SYMBOL_GPL(devm_usb_get_phy_by_phandle);
314
315
316
317
318
319
320
321
322
323
324
325
326struct usb_phy *usb_get_phy_dev(struct device *dev, u8 index)
327{
328 struct usb_phy *phy = NULL;
329 unsigned long flags;
330
331 spin_lock_irqsave(&phy_lock, flags);
332
333 phy = __usb_find_phy_dev(dev, &phy_bind_list, index);
334 if (IS_ERR(phy) || !try_module_get(phy->dev->driver->owner)) {
335 dev_dbg(dev, "unable to find transceiver\n");
336 if (!IS_ERR(phy))
337 phy = ERR_PTR(-ENODEV);
338
339 goto err0;
340 }
341
342 get_device(phy->dev);
343
344err0:
345 spin_unlock_irqrestore(&phy_lock, flags);
346
347 return phy;
348}
349EXPORT_SYMBOL_GPL(usb_get_phy_dev);
350
351
352
353
354
355
356
357
358
359
360
361
362struct usb_phy *devm_usb_get_phy_dev(struct device *dev, u8 index)
363{
364 struct usb_phy **ptr, *phy;
365
366 ptr = devres_alloc(devm_usb_phy_release, sizeof(*ptr), GFP_KERNEL);
367 if (!ptr)
368 return NULL;
369
370 phy = usb_get_phy_dev(dev, index);
371 if (!IS_ERR(phy)) {
372 *ptr = phy;
373 devres_add(dev, ptr);
374 } else
375 devres_free(ptr);
376
377 return phy;
378}
379EXPORT_SYMBOL_GPL(devm_usb_get_phy_dev);
380
381
382
383
384
385
386
387
388
389
390
391void devm_usb_put_phy(struct device *dev, struct usb_phy *phy)
392{
393 int r;
394
395 r = devres_destroy(dev, devm_usb_phy_release, devm_usb_phy_match, phy);
396 dev_WARN_ONCE(dev, r, "couldn't find PHY resource\n");
397}
398EXPORT_SYMBOL_GPL(devm_usb_put_phy);
399
400
401
402
403
404
405
406
407
408void usb_put_phy(struct usb_phy *x)
409{
410 if (x) {
411 struct module *owner = x->dev->driver->owner;
412
413 put_device(x->dev);
414 module_put(owner);
415 }
416}
417EXPORT_SYMBOL_GPL(usb_put_phy);
418
419
420
421
422
423
424
425
426
427
428int usb_add_phy(struct usb_phy *x, enum usb_phy_type type)
429{
430 int ret = 0;
431 unsigned long flags;
432 struct usb_phy *phy;
433
434 if (x->type != USB_PHY_TYPE_UNDEFINED) {
435 dev_err(x->dev, "not accepting initialized PHY %s\n", x->label);
436 return -EINVAL;
437 }
438
439 ret = usb_add_extcon(x);
440 if (ret)
441 return ret;
442
443 ATOMIC_INIT_NOTIFIER_HEAD(&x->notifier);
444
445 spin_lock_irqsave(&phy_lock, flags);
446
447 list_for_each_entry(phy, &phy_list, head) {
448 if (phy->type == type) {
449 ret = -EBUSY;
450 dev_err(x->dev, "transceiver type %s already exists\n",
451 usb_phy_type_string(type));
452 goto out;
453 }
454 }
455
456 x->type = type;
457 list_add_tail(&x->head, &phy_list);
458
459out:
460 spin_unlock_irqrestore(&phy_lock, flags);
461 return ret;
462}
463EXPORT_SYMBOL_GPL(usb_add_phy);
464
465
466
467
468
469
470
471
472
473int usb_add_phy_dev(struct usb_phy *x)
474{
475 struct usb_phy_bind *phy_bind;
476 unsigned long flags;
477 int ret;
478
479 if (!x->dev) {
480 dev_err(x->dev, "no device provided for PHY\n");
481 return -EINVAL;
482 }
483
484 ret = usb_add_extcon(x);
485 if (ret)
486 return ret;
487
488 ATOMIC_INIT_NOTIFIER_HEAD(&x->notifier);
489
490 spin_lock_irqsave(&phy_lock, flags);
491 list_for_each_entry(phy_bind, &phy_bind_list, list)
492 if (!(strcmp(phy_bind->phy_dev_name, dev_name(x->dev))))
493 phy_bind->phy = x;
494
495 list_add_tail(&x->head, &phy_list);
496
497 spin_unlock_irqrestore(&phy_lock, flags);
498 return 0;
499}
500EXPORT_SYMBOL_GPL(usb_add_phy_dev);
501
502
503
504
505
506
507
508void usb_remove_phy(struct usb_phy *x)
509{
510 unsigned long flags;
511 struct usb_phy_bind *phy_bind;
512
513 spin_lock_irqsave(&phy_lock, flags);
514 if (x) {
515 list_for_each_entry(phy_bind, &phy_bind_list, list)
516 if (phy_bind->phy == x)
517 phy_bind->phy = NULL;
518 list_del(&x->head);
519 }
520 spin_unlock_irqrestore(&phy_lock, flags);
521}
522EXPORT_SYMBOL_GPL(usb_remove_phy);
523
524
525
526
527
528
529
530
531
532
533
534
535
536int usb_bind_phy(const char *dev_name, u8 index,
537 const char *phy_dev_name)
538{
539 struct usb_phy_bind *phy_bind;
540 unsigned long flags;
541
542 phy_bind = kzalloc(sizeof(*phy_bind), GFP_KERNEL);
543 if (!phy_bind)
544 return -ENOMEM;
545
546 phy_bind->dev_name = dev_name;
547 phy_bind->phy_dev_name = phy_dev_name;
548 phy_bind->index = index;
549
550 spin_lock_irqsave(&phy_lock, flags);
551 list_add_tail(&phy_bind->list, &phy_bind_list);
552 spin_unlock_irqrestore(&phy_lock, flags);
553
554 return 0;
555}
556EXPORT_SYMBOL_GPL(usb_bind_phy);
557
558
559
560
561
562
563
564void usb_phy_set_event(struct usb_phy *x, unsigned long event)
565{
566 x->last_event = event;
567}
568EXPORT_SYMBOL_GPL(usb_phy_set_event);
569