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 | |
| 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>
| -rw-r--r-- | drivers/usb/otg/otg.c | 80 | ||||
| -rw-r--r-- | include/linux/usb/phy.h | 8 |
2 files changed, 88 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 |
diff --git a/include/linux/usb/phy.h b/include/linux/usb/phy.h index 359db7de61e4..15847cbdb512 100644 --- a/include/linux/usb/phy.h +++ b/include/linux/usb/phy.h | |||
| @@ -167,6 +167,8 @@ extern struct usb_phy *devm_usb_get_phy(struct device *dev, | |||
| 167 | enum usb_phy_type type); | 167 | enum usb_phy_type type); |
| 168 | extern struct usb_phy *usb_get_phy_dev(struct device *dev, u8 index); | 168 | extern struct usb_phy *usb_get_phy_dev(struct device *dev, u8 index); |
| 169 | extern struct usb_phy *devm_usb_get_phy_dev(struct device *dev, u8 index); | 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 | extern void usb_put_phy(struct usb_phy *); | 172 | extern void usb_put_phy(struct usb_phy *); |
| 171 | extern void devm_usb_put_phy(struct device *dev, struct usb_phy *x); | 173 | extern void devm_usb_put_phy(struct device *dev, struct usb_phy *x); |
| 172 | extern int usb_bind_phy(const char *dev_name, u8 index, | 174 | extern int usb_bind_phy(const char *dev_name, u8 index, |
| @@ -193,6 +195,12 @@ static inline struct usb_phy *devm_usb_get_phy_dev(struct device *dev, u8 index) | |||
| 193 | return NULL; | 195 | return NULL; |
| 194 | } | 196 | } |
| 195 | 197 | ||
| 198 | static inline struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev, | ||
| 199 | const char *phandle, u8 index) | ||
| 200 | { | ||
| 201 | return NULL; | ||
| 202 | } | ||
| 203 | |||
| 196 | static inline void usb_put_phy(struct usb_phy *x) | 204 | static inline void usb_put_phy(struct usb_phy *x) |
| 197 | { | 205 | { |
| 198 | } | 206 | } |
