Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gerg/m68knommu
[deliverable/linux.git] / drivers / phy / phy-core.c
index e7e574dc667a35d6d2c68ddf9e21744453d11bec..b72e9a3b64297dd8a78e75cb2d81bd2d9ce94bfe 100644 (file)
@@ -141,7 +141,7 @@ static struct phy_provider *of_phy_provider_lookup(struct device_node *node)
                if (phy_provider->dev->of_node == node)
                        return phy_provider;
 
-               for_each_child_of_node(phy_provider->dev->of_node, child)
+               for_each_child_of_node(phy_provider->children, child)
                        if (child == node)
                                return phy_provider;
        }
@@ -811,24 +811,59 @@ EXPORT_SYMBOL_GPL(devm_phy_destroy);
 /**
  * __of_phy_provider_register() - create/register phy provider with the framework
  * @dev: struct device of the phy provider
+ * @children: device node containing children (if different from dev->of_node)
  * @owner: the module owner containing of_xlate
  * @of_xlate: function pointer to obtain phy instance from phy provider
  *
  * Creates struct phy_provider from dev and of_xlate function pointer.
  * This is used in the case of dt boot for finding the phy instance from
  * phy provider.
+ *
+ * If the PHY provider doesn't nest children directly but uses a separate
+ * child node to contain the individual children, the @children parameter
+ * can be used to override the default. If NULL, the default (dev->of_node)
+ * will be used. If non-NULL, the device node must be a child (or further
+ * descendant) of dev->of_node. Otherwise an ERR_PTR()-encoded -EINVAL
+ * error code is returned.
  */
 struct phy_provider *__of_phy_provider_register(struct device *dev,
-       struct module *owner, struct phy * (*of_xlate)(struct device *dev,
-       struct of_phandle_args *args))
+       struct device_node *children, struct module *owner,
+       struct phy * (*of_xlate)(struct device *dev,
+                                struct of_phandle_args *args))
 {
        struct phy_provider *phy_provider;
 
+       /*
+        * If specified, the device node containing the children must itself
+        * be the provider's device node or a child (or further descendant)
+        * thereof.
+        */
+       if (children) {
+               struct device_node *parent = of_node_get(children), *next;
+
+               while (parent) {
+                       if (parent == dev->of_node)
+                               break;
+
+                       next = of_get_parent(parent);
+                       of_node_put(parent);
+                       parent = next;
+               }
+
+               if (!parent)
+                       return ERR_PTR(-EINVAL);
+
+               of_node_put(parent);
+       } else {
+               children = dev->of_node;
+       }
+
        phy_provider = kzalloc(sizeof(*phy_provider), GFP_KERNEL);
        if (!phy_provider)
                return ERR_PTR(-ENOMEM);
 
        phy_provider->dev = dev;
+       phy_provider->children = of_node_get(children);
        phy_provider->owner = owner;
        phy_provider->of_xlate = of_xlate;
 
@@ -854,8 +889,9 @@ EXPORT_SYMBOL_GPL(__of_phy_provider_register);
  * on the devres data, then, devres data is freed.
  */
 struct phy_provider *__devm_of_phy_provider_register(struct device *dev,
-       struct module *owner, struct phy * (*of_xlate)(struct device *dev,
-       struct of_phandle_args *args))
+       struct device_node *children, struct module *owner,
+       struct phy * (*of_xlate)(struct device *dev,
+                                struct of_phandle_args *args))
 {
        struct phy_provider **ptr, *phy_provider;
 
@@ -863,7 +899,8 @@ struct phy_provider *__devm_of_phy_provider_register(struct device *dev,
        if (!ptr)
                return ERR_PTR(-ENOMEM);
 
-       phy_provider = __of_phy_provider_register(dev, owner, of_xlate);
+       phy_provider = __of_phy_provider_register(dev, children, owner,
+                                                 of_xlate);
        if (!IS_ERR(phy_provider)) {
                *ptr = phy_provider;
                devres_add(dev, ptr);
@@ -888,6 +925,7 @@ void of_phy_provider_unregister(struct phy_provider *phy_provider)
 
        mutex_lock(&phy_provider_mutex);
        list_del(&phy_provider->list);
+       of_node_put(phy_provider->children);
        kfree(phy_provider);
        mutex_unlock(&phy_provider_mutex);
 }
This page took 0.030522 seconds and 5 git commands to generate.