usb: of: add an api to get dr_mode by the phy node
authorBin Liu <b-liu@ti.com>
Tue, 3 Nov 2015 17:51:15 +0000 (11:51 -0600)
committerFelipe Balbi <balbi@ti.com>
Tue, 15 Dec 2015 15:12:41 +0000 (09:12 -0600)
Some USB phy drivers have different handling for the controller in each
dr_mode. But the phy driver does not have visibility to the dr_mode of
the controller.

This adds an api to return the dr_mode of the controller which
associates the given phy node.

Signed-off-by: Bin Liu <b-liu@ti.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
drivers/usb/common/common.c
include/linux/usb/of.h

index 673d53038ed221c3b2e0c7c0d78d9309d307420a..e6ec125e4485096276b685fd12932aae44dccc87 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/usb/ch9.h>
 #include <linux/usb/of.h>
 #include <linux/usb/otg.h>
+#include <linux/of_platform.h>
 
 const char *usb_otg_state_string(enum usb_otg_state state)
 {
@@ -106,24 +107,71 @@ static const char *const usb_dr_modes[] = {
        [USB_DR_MODE_OTG]               = "otg",
 };
 
+static enum usb_dr_mode usb_get_dr_mode_from_string(const char *str)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(usb_dr_modes); i++)
+               if (!strcmp(usb_dr_modes[i], str))
+                       return i;
+
+       return USB_DR_MODE_UNKNOWN;
+}
+
 enum usb_dr_mode usb_get_dr_mode(struct device *dev)
 {
        const char *dr_mode;
-       int err, i;
+       int err;
 
        err = device_property_read_string(dev, "dr_mode", &dr_mode);
        if (err < 0)
                return USB_DR_MODE_UNKNOWN;
 
-       for (i = 0; i < ARRAY_SIZE(usb_dr_modes); i++)
-               if (!strcmp(dr_mode, usb_dr_modes[i]))
-                       return i;
-
-       return USB_DR_MODE_UNKNOWN;
+       return usb_get_dr_mode_from_string(dr_mode);
 }
 EXPORT_SYMBOL_GPL(usb_get_dr_mode);
 
 #ifdef CONFIG_OF
+/**
+ * of_usb_get_dr_mode_by_phy - Get dual role mode for the controller device
+ * which is associated with the given phy device_node
+ * @np:        Pointer to the given phy device_node
+ *
+ * In dts a usb controller associates with phy devices.  The function gets
+ * the string from property 'dr_mode' of the controller associated with the
+ * given phy device node, and returns the correspondig enum usb_dr_mode.
+ */
+enum usb_dr_mode of_usb_get_dr_mode_by_phy(struct device_node *phy_np)
+{
+       struct device_node *controller = NULL;
+       struct device_node *phy;
+       const char *dr_mode;
+       int index;
+       int err;
+
+       do {
+               controller = of_find_node_with_property(controller, "phys");
+               index = 0;
+               do {
+                       phy = of_parse_phandle(controller, "phys", index);
+                       of_node_put(phy);
+                       if (phy == phy_np)
+                               goto finish;
+                       index++;
+               } while (phy);
+       } while (controller);
+
+finish:
+       err = of_property_read_string(controller, "dr_mode", &dr_mode);
+       of_node_put(controller);
+
+       if (err < 0)
+               return USB_DR_MODE_UNKNOWN;
+
+       return usb_get_dr_mode_from_string(dr_mode);
+}
+EXPORT_SYMBOL_GPL(of_usb_get_dr_mode_by_phy);
+
 /**
  * of_usb_host_tpl_support - to get if Targeted Peripheral List is supported
  * for given targeted hosts (non-PC hosts)
index c3fe9e48ce27cb251e069247e0dec09b9848a09d..3805757dcdc26b18ca6c6ed393bc2e406ba9a7d9 100644 (file)
 #include <linux/usb/phy.h>
 
 #if IS_ENABLED(CONFIG_OF)
+enum usb_dr_mode of_usb_get_dr_mode_by_phy(struct device_node *phy_np);
 bool of_usb_host_tpl_support(struct device_node *np);
 int of_usb_update_otg_caps(struct device_node *np,
                        struct usb_otg_caps *otg_caps);
 #else
+enum usb_dr_mode of_usb_get_dr_mode_by_phy(struct device_node *phy_np)
+{
+       return USB_DR_MODE_UNKNOWN;
+}
 static inline bool of_usb_host_tpl_support(struct device_node *np)
 {
        return false;