[RFC PATCH] drivers: usb: otg: add device tree support to otg library

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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.

Cc: Richard Zhao <richard.zhao@xxxxxxxxxxxxx>
Cc: Marek Vasut <marex@xxxxxxx>
Signed-off-by: Kishon Vijay Abraham I <kishon@xxxxxx>
---
Had to remove the restricion on adding multiple phys of same type as now it
would be possible to get the phys by phandle value. However there is no
clear way to get a phy when there are multiple phys of same type without
a phandle (non-dt). So in non-dt environment, adding and getting phy API's
should be used with caution. Currently multiple-phys of the same type
doesn't exist in kernel.
 drivers/usb/otg/otg.c   |   95 ++++++++++++++++++++++++++++++++++++++++-------
 include/linux/usb/otg.h |    8 ++++
 2 files changed, 89 insertions(+), 14 deletions(-)

diff --git a/drivers/usb/otg/otg.c b/drivers/usb/otg/otg.c
index 0fa4d8c..b36a647 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;
@@ -110,6 +126,65 @@ struct usb_phy *usb_get_phy(enum usb_phy_type type)
 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()
@@ -154,32 +229,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 && 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 0cb2ec2..4636d39 100644
--- a/include/linux/usb/otg.h
+++ b/include/linux/usb/otg.h
@@ -187,6 +187,8 @@ usb_phy_shutdown(struct usb_phy *x)
 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);
@@ -202,6 +204,12 @@ static inline struct usb_phy *devm_usb_get_phy(struct device *dev,
 	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)
 {
 }
-- 
1.7.5.4

--
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


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux