From: Ajay Kumar Gupta <ajay.gupta@xxxxxx> Adds an API to get usb phy by passing a device node phandle value. Since now it's possible to obtain phy by phandle, the checks in usb_add_phy for a valid phy type is removed (now it's just a debug message if a user tries to add a phy with undefined type). This also allows to add multiple phys of same type. [zonque@xxxxxxxxx: rebased to 3.7-rc1] Cc: Richard Zhao <richard.zhao@xxxxxxxxxxxxx> Cc: Marek Vasut <marex@xxxxxxx> Signed-off-by: Kishon Vijay Abraham I <kishon@xxxxxx> Signed-off-by: Ajay Kumar Gupta <ajay.gupta@xxxxxx> --- drivers/usb/otg/otg.c | 95 +++++++++++++++++++++++++++++++++++++++++-------- include/linux/usb/otg.h | 32 +++++++++++++++++ 2 files changed, 113 insertions(+), 14 deletions(-) diff --git a/drivers/usb/otg/otg.c b/drivers/usb/otg/otg.c index a30c041..ff08b34 100644 --- a/drivers/usb/otg/otg.c +++ b/drivers/usb/otg/otg.c @@ -14,6 +14,7 @@ #include <linux/err.h> #include <linux/device.h> #include <linux/slab.h> +#include <linux/of.h> #include <linux/usb/otg.h> @@ -35,6 +36,21 @@ static struct usb_phy *__usb_find_phy(struct list_head *list, return ERR_PTR(-ENODEV); } +static struct usb_phy *__of_usb_find_phy(struct list_head *list, + struct device_node *node) +{ + struct usb_phy *phy; + + list_for_each_entry(phy, list, head) { + if (node != phy->dev->of_node) + continue; + + return phy; + } + + return ERR_PTR(-ENODEV); +} + static void devm_usb_phy_release(struct device *dev, void *res) { struct usb_phy *phy = *(struct usb_phy **)res; @@ -111,6 +127,65 @@ err0: EXPORT_SYMBOL(usb_get_phy); /** + * devm_usb_get_phy_by_phandle - find the USB PHY by phandle + * @dev - device that requests this phy + * @phandle - name of the property holding the phy phandle value + * + * Returns the phy driver associated with the given phandle value, + * after getting a refcount to it; or -ENODEV/NULL if there is no such phy. + * While at that, it also associates the device with the phy using + * devres. On driver detach, release function is invoked on the devres data, + * then, devres data is freed. + * + * For use by USB host and peripheral drivers. + */ +struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev, + const char *phandle) +{ + struct usb_phy *phy = NULL, **ptr; + unsigned long flags; + struct device_node *node; + + if (!dev->of_node) { + dev_dbg(dev, "device does not have a device node entry\n"); + return ERR_PTR(-EINVAL); + } + + ptr = devres_alloc(devm_usb_phy_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) { + dev_dbg(dev, "failed to allocate memory for devres\n"); + return ERR_PTR(-ENOMEM); + } + + spin_lock_irqsave(&phy_lock, flags); + + node = of_parse_phandle(dev->of_node, phandle, 0); + if (!node) { + dev_dbg(dev, "failed to get %s phandle in %s node\n", phandle, + dev->of_node->full_name); + goto err0; + } + + phy = __of_usb_find_phy(&phy_list, node); + if (!IS_ERR(phy)) { + *ptr = phy; + devres_add(dev, ptr); + } else { + pr_err("unable to find transceiver with phandle %s\n", phandle); + devres_free(ptr); + goto err0; + } + + get_device(phy->dev); + +err0: + spin_unlock_irqrestore(&phy_lock, flags); + + return phy; +} +EXPORT_SYMBOL(devm_usb_get_phy_by_phandle); + +/** * devm_usb_put_phy - release the USB PHY * @dev - device that wants to release this phy * @phy - the phy returned by devm_usb_get_phy() @@ -155,32 +230,24 @@ EXPORT_SYMBOL(usb_put_phy); */ int usb_add_phy(struct usb_phy *x, enum usb_phy_type type) { - int ret = 0; unsigned long flags; struct usb_phy *phy; - if (x->type != USB_PHY_TYPE_UNDEFINED) { - dev_err(x->dev, "not accepting initialized PHY %s\n", x->label); - return -EINVAL; - } + if (x && x->type != USB_PHY_TYPE_UNDEFINED) + dev_dbg(x->dev, "add a phy with undefined type %s\n", x->label); spin_lock_irqsave(&phy_lock, flags); - list_for_each_entry(phy, &phy_list, head) { - if (phy->type == type) { - ret = -EBUSY; - dev_err(x->dev, "transceiver type %s already exists\n", + list_for_each_entry(phy, &phy_list, head) + if (phy->type == type) + dev_dbg(x->dev, "transceiver type %s already exists\n", usb_phy_type_string(type)); - goto out; - } - } x->type = type; list_add_tail(&x->head, &phy_list); -out: spin_unlock_irqrestore(&phy_lock, flags); - return ret; + return 0; } EXPORT_SYMBOL(usb_add_phy); diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h index e8a5fe8..bae7599 100644 --- a/include/linux/usb/otg.h +++ b/include/linux/usb/otg.h @@ -37,8 +37,40 @@ struct usb_otg { }; #ifdef CONFIG_USB_OTG_UTILS +extern struct usb_phy *usb_get_phy(enum usb_phy_type type); +extern struct usb_phy *devm_usb_get_phy(struct device *dev, + enum usb_phy_type type); +extern struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev, + const char *phandle); +extern void usb_put_phy(struct usb_phy *); +extern void devm_usb_put_phy(struct device *dev, struct usb_phy *x); extern const char *otg_state_string(enum usb_otg_state state); #else +static inline struct usb_phy *usb_get_phy(enum usb_phy_type type) +{ + return NULL; +} + +static inline struct usb_phy *devm_usb_get_phy(struct device *dev, + enum usb_phy_type type) +{ + return NULL; +} + +extern struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev, + const char *phandle) +{ + return NULL; +} + +static inline void usb_put_phy(struct usb_phy *x) +{ +} + +static inline void devm_usb_put_phy(struct device *dev, struct usb_phy *x) +{ +} + static inline const char *otg_state_string(enum usb_otg_state state) { return NULL; -- 1.7.11.7 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html