From: Alban Bedel <al...@free.fr>

Signed-off-by: Alban Bedel <al...@free.fr>
---
 drivers/phy/phy-core.c  | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/phy/phy.h |  4 ++++
 2 files changed, 52 insertions(+)

diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c
index a268f4d..e6c55af 100644
--- a/drivers/phy/phy-core.c
+++ b/drivers/phy/phy-core.c
@@ -22,6 +22,8 @@
 #include <linux/idr.h>
 #include <linux/pm_runtime.h>
 #include <linux/regulator/consumer.h>
+#include <linux/reset.h>
+#include <linux/clk.h>
 
 static struct class *phy_class;
 static DEFINE_MUTEX(phy_provider_mutex);
@@ -286,6 +288,12 @@ int phy_power_on(struct phy *phy)
                        goto out;
        }
 
+       if (phy->clk) {
+               ret = clk_prepare_enable(phy->clk);
+               if (ret)
+                       goto err_clk_enable;
+       }
+
        ret = phy_pm_runtime_get_sync(phy);
        if (ret < 0 && ret != -ENOTSUPP)
                goto err_pm_sync;
@@ -293,6 +301,11 @@ int phy_power_on(struct phy *phy)
        ret = 0; /* Override possible ret == -ENOTSUPP */
 
        mutex_lock(&phy->mutex);
+       if (phy->power_count == 0 && phy->reset) {
+               ret = reset_control_deassert(phy->reset);
+               if (ret)
+                       goto err_reset_deassert;
+       }
        if (phy->power_count == 0 && phy->ops->power_on) {
                ret = phy->ops->power_on(phy);
                if (ret < 0) {
@@ -305,9 +318,15 @@ int phy_power_on(struct phy *phy)
        return 0;
 
 err_pwr_on:
+       if (phy->reset)
+               reset_control_assert(phy->reset);
+err_reset_deassert:
        mutex_unlock(&phy->mutex);
        phy_pm_runtime_put_sync(phy);
 err_pm_sync:
+       if (phy->clk)
+               clk_disable_unprepare(phy->clk);
+err_clk_enable:
        if (phy->pwr)
                regulator_disable(phy->pwr);
 out:
@@ -331,10 +350,18 @@ int phy_power_off(struct phy *phy)
                        return ret;
                }
        }
+       if (phy->power_count == 1 && phy->reset) {
+               ret = reset_control_assert(phy->reset);
+               if (ret < 0)
+                       dev_warn(&phy->dev,
+                               "phy reset assert failed --> %d\n", ret);
+       }
        --phy->power_count;
        mutex_unlock(&phy->mutex);
        phy_pm_runtime_put(phy);
 
+       if (phy->clk)
+               clk_disable_unprepare(phy->clk);
        if (phy->pwr)
                regulator_disable(phy->pwr);
 
@@ -755,6 +782,24 @@ struct phy *phy_create(struct device *dev, struct 
device_node *node,
                phy->pwr = NULL;
        }
 
+       phy->clk = clk_get(dev, "phy");
+       if (IS_ERR(phy->clk)) {
+               ret = PTR_ERR(phy->clk);
+               if (ret == -ENOENT)
+                       phy->clk = NULL;
+               else
+                       goto put_dev;
+       }
+
+       phy->reset = reset_control_get(dev, "phy");
+       if (IS_ERR(phy->reset)) {
+               ret = PTR_ERR(phy->reset);
+               if (ret == -ENOENT || ret == -ENOTSUPP)
+                       phy->reset = NULL;
+               else
+                       goto put_dev;
+       }
+
        ret = device_add(&phy->dev);
        if (ret)
                goto put_dev;
@@ -991,6 +1036,9 @@ static void phy_release(struct device *dev)
 
        phy = to_phy(dev);
        dev_vdbg(dev, "releasing '%s'\n", dev_name(dev));
+       if (phy->reset)
+               reset_control_put(phy->reset);
+       clk_put(phy->clk);
        regulator_put(phy->pwr);
        ida_simple_remove(&phy_ida, phy->id);
        kfree(phy);
diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h
index 78bb0d7..cc67d33 100644
--- a/include/linux/phy/phy.h
+++ b/include/linux/phy/phy.h
@@ -21,6 +21,8 @@
 #include <linux/regulator/consumer.h>
 
 struct phy;
+struct clk;
+struct reset_control;
 
 enum phy_mode {
        PHY_MODE_INVALID,
@@ -77,6 +79,8 @@ struct phy {
        int                     power_count;
        struct phy_attrs        attrs;
        struct regulator        *pwr;
+       struct clk              *clk;
+       struct reset_control    *reset;
 };
 
 /**
-- 
2.7.4

Reply via email to