Commit 5d3c28b5a42df5ceaa854901ba2cccb76883c77e
Committed by
Felipe Balbi
1 parent
0fa4fab4ee
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
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>
Showing 2 changed files with 88 additions and 0 deletions Side-by-side Diff
drivers/usb/otg/otg.c
... | ... | @@ -13,7 +13,9 @@ |
13 | 13 | #include <linux/export.h> |
14 | 14 | #include <linux/err.h> |
15 | 15 | #include <linux/device.h> |
16 | +#include <linux/module.h> | |
16 | 17 | #include <linux/slab.h> |
18 | +#include <linux/of.h> | |
17 | 19 | |
18 | 20 | #include <linux/usb/otg.h> |
19 | 21 | |
... | ... | @@ -54,6 +56,20 @@ |
54 | 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 | 73 | static void devm_usb_phy_release(struct device *dev, void *res) |
58 | 74 | { |
59 | 75 | struct usb_phy *phy = *(struct usb_phy **)res; |
... | ... | @@ -128,6 +144,70 @@ |
128 | 144 | return phy; |
129 | 145 | } |
130 | 146 | EXPORT_SYMBOL(usb_get_phy); |
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); | |
131 | 211 | |
132 | 212 | /** |
133 | 213 | * usb_get_phy_dev - find the USB PHY |
include/linux/usb/phy.h
... | ... | @@ -167,6 +167,8 @@ |
167 | 167 | enum usb_phy_type type); |
168 | 168 | extern struct usb_phy *usb_get_phy_dev(struct device *dev, u8 index); |
169 | 169 | extern struct usb_phy *devm_usb_get_phy_dev(struct device *dev, u8 index); |
170 | +extern struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev, | |
171 | + const char *phandle, u8 index); | |
170 | 172 | extern void usb_put_phy(struct usb_phy *); |
171 | 173 | extern void devm_usb_put_phy(struct device *dev, struct usb_phy *x); |
172 | 174 | extern int usb_bind_phy(const char *dev_name, u8 index, |
... | ... | @@ -189,6 +191,12 @@ |
189 | 191 | } |
190 | 192 | |
191 | 193 | static inline struct usb_phy *devm_usb_get_phy_dev(struct device *dev, u8 index) |
194 | +{ | |
195 | + return NULL; | |
196 | +} | |
197 | + | |
198 | +static inline struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev, | |
199 | + const char *phandle, u8 index) | |
192 | 200 | { |
193 | 201 | return NULL; |
194 | 202 | } |