diff options
author | Kishon Vijay Abraham I <kishon@ti.com> | 2013-01-24 21:33:25 -0500 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2013-01-25 03:20:14 -0500 |
commit | 5d3c28b5a42df5ceaa854901ba2cccb76883c77e (patch) | |
tree | ae1e50d90d5ce1e5925dd552971224f775b574f3 /drivers/usb/otg | |
parent | 0fa4fab4ee46470ccd463c83be95434936942e05 (diff) |
usb: otg: add device tree support to otg library
Added an API devm_usb_get_phy_by_phandle(), to get usb phy by passing a
device node phandle value. This function will return a pointer to
the phy on success, -EPROBE_DEFER if there is a device_node for the phandle,
but the phy has not been added, or a ERR_PTR() otherwise.
Cc: Marc Kleine-Budde <mkl@pengutronix.de>
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb/otg')
-rw-r--r-- | drivers/usb/otg/otg.c | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/drivers/usb/otg/otg.c b/drivers/usb/otg/otg.c index 4bb4333c9653..e1814397ca3a 100644 --- a/drivers/usb/otg/otg.c +++ b/drivers/usb/otg/otg.c | |||
@@ -13,7 +13,9 @@ | |||
13 | #include <linux/export.h> | 13 | #include <linux/export.h> |
14 | #include <linux/err.h> | 14 | #include <linux/err.h> |
15 | #include <linux/device.h> | 15 | #include <linux/device.h> |
16 | #include <linux/module.h> | ||
16 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
18 | #include <linux/of.h> | ||
17 | 19 | ||
18 | #include <linux/usb/otg.h> | 20 | #include <linux/usb/otg.h> |
19 | 21 | ||
@@ -54,6 +56,20 @@ static struct usb_phy *__usb_find_phy_dev(struct device *dev, | |||
54 | return ERR_PTR(-ENODEV); | 56 | return ERR_PTR(-ENODEV); |
55 | } | 57 | } |
56 | 58 | ||
59 | static struct usb_phy *__of_usb_find_phy(struct device_node *node) | ||
60 | { | ||
61 | struct usb_phy *phy; | ||
62 | |||
63 | list_for_each_entry(phy, &phy_list, head) { | ||
64 | if (node != phy->dev->of_node) | ||
65 | continue; | ||
66 | |||
67 | return phy; | ||
68 | } | ||
69 | |||
70 | return ERR_PTR(-ENODEV); | ||
71 | } | ||
72 | |||
57 | static void devm_usb_phy_release(struct device *dev, void *res) | 73 | static void devm_usb_phy_release(struct device *dev, void *res) |
58 | { | 74 | { |
59 | struct usb_phy *phy = *(struct usb_phy **)res; | 75 | struct usb_phy *phy = *(struct usb_phy **)res; |
@@ -129,6 +145,70 @@ err0: | |||
129 | } | 145 | } |
130 | EXPORT_SYMBOL(usb_get_phy); | 146 | EXPORT_SYMBOL(usb_get_phy); |
131 | 147 | ||
148 | /** | ||
149 | * devm_usb_get_phy_by_phandle - find the USB PHY by phandle | ||
150 | * @dev - device that requests this phy | ||
151 | * @phandle - name of the property holding the phy phandle value | ||
152 | * @index - the index of the phy | ||
153 | * | ||
154 | * Returns the phy driver associated with the given phandle value, | ||
155 | * after getting a refcount to it, -ENODEV if there is no such phy or | ||
156 | * -EPROBE_DEFER if there is a phandle to the phy, but the device is | ||
157 | * not yet loaded. While at that, it also associates the device with | ||
158 | * the phy using devres. On driver detach, release function is invoked | ||
159 | * on the devres data, then, devres data is freed. | ||
160 | * | ||
161 | * For use by USB host and peripheral drivers. | ||
162 | */ | ||
163 | struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev, | ||
164 | const char *phandle, u8 index) | ||
165 | { | ||
166 | struct usb_phy *phy = ERR_PTR(-ENOMEM), **ptr; | ||
167 | unsigned long flags; | ||
168 | struct device_node *node; | ||
169 | |||
170 | if (!dev->of_node) { | ||
171 | dev_dbg(dev, "device does not have a device node entry\n"); | ||
172 | return ERR_PTR(-EINVAL); | ||
173 | } | ||
174 | |||
175 | node = of_parse_phandle(dev->of_node, phandle, index); | ||
176 | if (!node) { | ||
177 | dev_dbg(dev, "failed to get %s phandle in %s node\n", phandle, | ||
178 | dev->of_node->full_name); | ||
179 | return ERR_PTR(-ENODEV); | ||
180 | } | ||
181 | |||
182 | ptr = devres_alloc(devm_usb_phy_release, sizeof(*ptr), GFP_KERNEL); | ||
183 | if (!ptr) { | ||
184 | dev_dbg(dev, "failed to allocate memory for devres\n"); | ||
185 | goto err0; | ||
186 | } | ||
187 | |||
188 | spin_lock_irqsave(&phy_lock, flags); | ||
189 | |||
190 | phy = __of_usb_find_phy(node); | ||
191 | if (IS_ERR(phy) || !try_module_get(phy->dev->driver->owner)) { | ||
192 | phy = ERR_PTR(-EPROBE_DEFER); | ||
193 | devres_free(ptr); | ||
194 | goto err1; | ||
195 | } | ||
196 | |||
197 | *ptr = phy; | ||
198 | devres_add(dev, ptr); | ||
199 | |||
200 | get_device(phy->dev); | ||
201 | |||
202 | err1: | ||
203 | spin_unlock_irqrestore(&phy_lock, flags); | ||
204 | |||
205 | err0: | ||
206 | of_node_put(node); | ||
207 | |||
208 | return phy; | ||
209 | } | ||
210 | EXPORT_SYMBOL(devm_usb_get_phy_by_phandle); | ||
211 | |||
132 | /** | 212 | /** |
133 | * usb_get_phy_dev - find the USB PHY | 213 | * usb_get_phy_dev - find the USB PHY |
134 | * @dev - device that requests this phy | 214 | * @dev - device that requests this phy |