Commit 5d3c28b5a42df5ceaa854901ba2cccb76883c77e

Authored by Kishon Vijay Abraham I
Committed by Felipe Balbi
1 parent 0fa4fab4ee

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 }