Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
otg.c
Go to the documentation of this file.
1 /*
2  * otg.c -- USB OTG utility code
3  *
4  * Copyright (C) 2004 Texas Instruments
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  */
11 
12 #include <linux/kernel.h>
13 #include <linux/export.h>
14 #include <linux/err.h>
15 #include <linux/device.h>
16 #include <linux/slab.h>
17 
18 #include <linux/usb/otg.h>
19 
20 static LIST_HEAD(phy_list);
21 static DEFINE_SPINLOCK(phy_lock);
22 
23 static struct usb_phy *__usb_find_phy(struct list_head *list,
24  enum usb_phy_type type)
25 {
26  struct usb_phy *phy = NULL;
27 
28  list_for_each_entry(phy, list, head) {
29  if (phy->type != type)
30  continue;
31 
32  return phy;
33  }
34 
35  return ERR_PTR(-ENODEV);
36 }
37 
38 static void devm_usb_phy_release(struct device *dev, void *res)
39 {
40  struct usb_phy *phy = *(struct usb_phy **)res;
41 
42  usb_put_phy(phy);
43 }
44 
45 static int devm_usb_phy_match(struct device *dev, void *res, void *match_data)
46 {
47  return res == match_data;
48 }
49 
61 struct usb_phy *devm_usb_get_phy(struct device *dev, enum usb_phy_type type)
62 {
63  struct usb_phy **ptr, *phy;
64 
65  ptr = devres_alloc(devm_usb_phy_release, sizeof(*ptr), GFP_KERNEL);
66  if (!ptr)
67  return NULL;
68 
69  phy = usb_get_phy(type);
70  if (!IS_ERR(phy)) {
71  *ptr = phy;
72  devres_add(dev, ptr);
73  } else
74  devres_free(ptr);
75 
76  return phy;
77 }
79 
90 struct usb_phy *usb_get_phy(enum usb_phy_type type)
91 {
92  struct usb_phy *phy = NULL;
93  unsigned long flags;
94 
95  spin_lock_irqsave(&phy_lock, flags);
96 
97  phy = __usb_find_phy(&phy_list, type);
98  if (IS_ERR(phy)) {
99  pr_err("unable to find transceiver of type %s\n",
100  usb_phy_type_string(type));
101  goto err0;
102  }
103 
104  get_device(phy->dev);
105 
106 err0:
107  spin_unlock_irqrestore(&phy_lock, flags);
108 
109  return phy;
110 }
112 
123 void devm_usb_put_phy(struct device *dev, struct usb_phy *phy)
124 {
125  int r;
126 
127  r = devres_destroy(dev, devm_usb_phy_release, devm_usb_phy_match, phy);
128  dev_WARN_ONCE(dev, r, "couldn't find PHY resource\n");
129 }
131 
140 void usb_put_phy(struct usb_phy *x)
141 {
142  if (x)
143  put_device(x->dev);
144 }
146 
156 int usb_add_phy(struct usb_phy *x, enum usb_phy_type type)
157 {
158  int ret = 0;
159  unsigned long flags;
160  struct usb_phy *phy;
161 
162  if (x->type != USB_PHY_TYPE_UNDEFINED) {
163  dev_err(x->dev, "not accepting initialized PHY %s\n", x->label);
164  return -EINVAL;
165  }
166 
167  spin_lock_irqsave(&phy_lock, flags);
168 
169  list_for_each_entry(phy, &phy_list, head) {
170  if (phy->type == type) {
171  ret = -EBUSY;
172  dev_err(x->dev, "transceiver type %s already exists\n",
173  usb_phy_type_string(type));
174  goto out;
175  }
176  }
177 
178  x->type = type;
179  list_add_tail(&x->head, &phy_list);
180 
181 out:
182  spin_unlock_irqrestore(&phy_lock, flags);
183  return ret;
184 }
186 
193 void usb_remove_phy(struct usb_phy *x)
194 {
195  unsigned long flags;
196 
197  spin_lock_irqsave(&phy_lock, flags);
198  if (x)
199  list_del(&x->head);
200  spin_unlock_irqrestore(&phy_lock, flags);
201 }
203 
205 {
206  switch (state) {
207  case OTG_STATE_A_IDLE:
208  return "a_idle";
210  return "a_wait_vrise";
212  return "a_wait_bcon";
213  case OTG_STATE_A_HOST:
214  return "a_host";
215  case OTG_STATE_A_SUSPEND:
216  return "a_suspend";
218  return "a_peripheral";
220  return "a_wait_vfall";
222  return "a_vbus_err";
223  case OTG_STATE_B_IDLE:
224  return "b_idle";
226  return "b_srp_init";
228  return "b_peripheral";
230  return "b_wait_acon";
231  case OTG_STATE_B_HOST:
232  return "b_host";
233  default:
234  return "UNDEFINED";
235  }
236 }