Merge branch 'linux-linaro-lsk-v4.4-android' of git://git.linaro.org/kernel/linux...
[firefly-linux-kernel-4.4.55.git] / drivers / usb / common / common.c
index a00bfb93acc36d56cdbc0487a56218a5a8ee45e6..57643b3ba2c05b475027e7cd582dd423954a84e2 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)
 {
@@ -107,24 +108,85 @@ 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
+ * @arg0: phandle args[0] for phy's with #phy-cells >= 1, or -1 for
+ *        phys which do not have phy-cells
+ *
+ * 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 *np, int arg0)
+{
+       struct device_node *controller = NULL;
+       struct of_phandle_args args;
+       const char *dr_mode;
+       int index;
+       int err;
+
+       do {
+               controller = of_find_node_with_property(controller, "phys");
+               index = 0;
+               do {
+                       if (arg0 == -1) {
+                               args.np = of_parse_phandle(controller, "phys",
+                                                       index);
+                               args.args_count = 0;
+                       } else {
+                               err = of_parse_phandle_with_args(controller,
+                                                       "phys", "#phy-cells",
+                                                       index, &args);
+                               if (err)
+                                       break;
+                       }
+
+                       of_node_put(args.np);
+                       if (args.np == np && (args.args_count == 0 ||
+                                             args.args[0] == arg0))
+                               goto finish;
+                       index++;
+               } while (args.np);
+       } 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)