diff --git a/drivers/base/power/clock_ops.c b/drivers/base/power/clock_ops.c
index f14b767..840e133 100644
--- a/drivers/base/power/clock_ops.c
+++ b/drivers/base/power/clock_ops.c
@@ -12,21 +12,21 @@
 #include <linux/pm.h>
 #include <linux/pm_clock.h>
 #include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
 #include <linux/slab.h>
 #include <linux/err.h>
 
 #ifdef CONFIG_PM
 
 enum pce_status {
-	PCE_STATUS_NONE = 0,
-	PCE_STATUS_ACQUIRED,
+	PCE_STATUS_ACQUIRED = 0,
+	PCE_STATUS_PREPARED,
 	PCE_STATUS_ENABLED,
-	PCE_STATUS_ERROR,
 };
 
 struct pm_clock_entry {
 	struct list_head node;
-	char *con_id;
 	struct clk *clk;
 	enum pce_status status;
 };
@@ -47,25 +47,13 @@ static inline int __pm_clk_enable(struct device *dev, struct clk *clk)
 }
 
 /**
- * pm_clk_acquire - Acquire a device clock.
- * @dev: Device whose clock is to be acquired.
- * @ce: PM clock entry corresponding to the clock.
+ * pm_clk_add_clk - Start using a device clock for power management.
+ * @dev: Device whose clock is going to be used for power management.
+ * @clk: Clock pointer
+ *
+ * Add the clock to the list of clocks used for the power management of @dev.
  */
-static void pm_clk_acquire(struct device *dev, struct pm_clock_entry *ce)
-{
-	if (!ce->clk)
-		ce->clk = clk_get(dev, ce->con_id);
-	if (IS_ERR(ce->clk)) {
-		ce->status = PCE_STATUS_ERROR;
-	} else {
-		clk_prepare(ce->clk);
-		ce->status = PCE_STATUS_ACQUIRED;
-		dev_dbg(dev, "Clock %s managed by runtime PM.\n", ce->con_id);
-	}
-}
-
-static int __pm_clk_add(struct device *dev, const char *con_id,
-			struct clk *clk)
+int pm_clk_add_clk(struct device *dev, struct clk *clk)
 {
 	struct pm_subsys_data *psd = dev_to_psd(dev);
 	struct pm_clock_entry *ce;
@@ -79,23 +67,19 @@ static int __pm_clk_add(struct device *dev, const char *con_id,
 		return -ENOMEM;
 	}
 
-	if (con_id) {
-		ce->con_id = kstrdup(con_id, GFP_KERNEL);
-		if (!ce->con_id) {
-			dev_err(dev,
-				"Not enough memory for clock connection ID.\n");
-			kfree(ce);
-			return -ENOMEM;
-		}
-	} else {
-		ce->clk = clk;
-	}
+	__clk_get(clk);
 
-	pm_clk_acquire(dev, ce);
+	clk_prepare(clk);
+
+	ce->status = PCE_STATUS_PREPARED;
+	ce->clk = clk;
 
 	spin_lock_irq(&psd->lock);
 	list_add_tail(&ce->node, &psd->clock_list);
 	spin_unlock_irq(&psd->lock);
+
+	dev_dbg(dev, "Clock %s managed by runtime PM.\n", __clk_get_name(clk));
+
 	return 0;
 }
 
@@ -109,19 +93,23 @@ static int __pm_clk_add(struct device *dev, const char *con_id,
  */
 int pm_clk_add(struct device *dev, const char *con_id)
 {
-	return __pm_clk_add(dev, con_id, NULL);
-}
+	struct clk *clk;
+	int retval;
 
-/**
- * pm_clk_add_clk - Start using a device clock for power management.
- * @dev: Device whose clock is going to be used for power management.
- * @clk: Clock pointer
- *
- * Add the clock to the list of clocks used for the power management of @dev.
- */
-int pm_clk_add_clk(struct device *dev, struct clk *clk)
-{
-	return __pm_clk_add(dev, NULL, clk);
+	clk = clk_get(dev, con_id);
+	if (IS_ERR(clk)) {
+		retval = PTR_ERR(clk);
+		dev_err(dev, "Failed to locate lock (con_id %s): %d\n",
+			con_id, retval);
+		return retval;
+	}
+
+	retval = pm_clk_add_clk(dev, clk);
+
+	/* pm_clk_add_clk takes its own reference to clk */
+	clk_put(clk);
+
+	return retval;
 }
 
 /**
@@ -133,32 +121,30 @@ static void __pm_clk_remove(struct pm_clock_entry *ce)
 	if (!ce)
 		return;
 
-	if (ce->status < PCE_STATUS_ERROR) {
-		if (ce->status == PCE_STATUS_ENABLED)
-			clk_disable(ce->clk);
+	if (ce->status == PCE_STATUS_ENABLED)
+		clk_disable(ce->clk);
 
-		if (ce->status >= PCE_STATUS_ACQUIRED) {
-			clk_unprepare(ce->clk);
-			clk_put(ce->clk);
-		}
+	if (ce->status >= PCE_STATUS_ACQUIRED) {
+		clk_unprepare(ce->clk);
+		clk_put(ce->clk);
 	}
 
-	kfree(ce->con_id);
 	kfree(ce);
 }
 
 /**
  * pm_clk_remove - Stop using a device clock for power management.
  * @dev: Device whose clock should not be used for PM any more.
- * @con_id: Connection ID of the clock.
+ * @clk: Clock pointer
  *
- * Remove the clock represented by @con_id from the list of clocks used for
- * the power management of @dev.
+ * Remove the clock from the list of clocks used for the power
+ * management of @dev.
  */
-void pm_clk_remove(struct device *dev, const char *con_id)
+
+void pm_clk_remove_clk(struct device *dev, struct clk *clk)
 {
 	struct pm_subsys_data *psd = dev_to_psd(dev);
-	struct pm_clock_entry *ce;
+	struct pm_clock_entry *ce, *matching_ce = NULL;
 
 	if (!psd)
 		return;
@@ -166,22 +152,35 @@ void pm_clk_remove(struct device *dev, const char *con_id)
 	spin_lock_irq(&psd->lock);
 
 	list_for_each_entry(ce, &psd->clock_list, node) {
-		if (!con_id && !ce->con_id)
-			goto remove;
-		else if (!con_id || !ce->con_id)
-			continue;
-		else if (!strcmp(con_id, ce->con_id))
-			goto remove;
+		if (ce->clk == clk) {
+			matching_ce = ce;
+			list_del(&ce->node);
+			break;
+		}
 	}
 
 	spin_unlock_irq(&psd->lock);
-	return;
 
- remove:
-	list_del(&ce->node);
-	spin_unlock_irq(&psd->lock);
+	__pm_clk_remove(matching_ce);
+}
+
+/**
+ * pm_clk_remove - Stop using a device clock for power management.
+ * @dev: Device whose clock should not be used for PM any more.
+ * @con_id: Connection ID of the clock.
+ *
+ * Remove the clock represented by @con_id from the list of clocks used for
+ * the power management of @dev.
+ */
+void pm_clk_remove(struct device *dev, const char *con_id)
+{
+	struct clk *clk;
 
-	__pm_clk_remove(ce);
+	clk = clk_get(dev, con_id);
+	if (!IS_ERR(clk)) {
+		pm_clk_remove_clk(dev, clk);
+		clk_put(clk);
+	}
 }
 
 /**
@@ -266,10 +265,9 @@ int pm_clk_suspend(struct device *dev)
 	spin_lock_irqsave(&psd->lock, flags);
 
 	list_for_each_entry_reverse(ce, &psd->clock_list, node) {
-		if (ce->status < PCE_STATUS_ERROR) {
-			if (ce->status == PCE_STATUS_ENABLED)
-				clk_disable(ce->clk);
-			ce->status = PCE_STATUS_ACQUIRED;
+		if (ce->status == PCE_STATUS_ENABLED) {
+			clk_disable(ce->clk);
+			ce->status = PCE_STATUS_PREPARED;
 		}
 	}
 
@@ -297,11 +295,9 @@ int pm_clk_resume(struct device *dev)
 	spin_lock_irqsave(&psd->lock, flags);
 
 	list_for_each_entry(ce, &psd->clock_list, node) {
-		if (ce->status < PCE_STATUS_ERROR) {
-			ret = __pm_clk_enable(dev, ce->clk);
-			if (!ret)
-				ce->status = PCE_STATUS_ENABLED;
-		}
+		ret = __pm_clk_enable(dev, ce->clk);
+		if (!ret)
+			ce->status = PCE_STATUS_ENABLED;
 	}
 
 	spin_unlock_irqrestore(&psd->lock, flags);
@@ -390,10 +386,9 @@ int pm_clk_suspend(struct device *dev)
 	spin_lock_irqsave(&psd->lock, flags);
 
 	list_for_each_entry_reverse(ce, &psd->clock_list, node) {
-		if (ce->status < PCE_STATUS_ERROR) {
-			if (ce->status == PCE_STATUS_ENABLED)
-				clk_disable(ce->clk);
-			ce->status = PCE_STATUS_ACQUIRED;
+		if (ce->status == PCE_STATUS_ENABLED) {
+			clk_disable(ce->clk);
+			ce->status = PCE_STATUS_PREPARED;
 		}
 	}
 
@@ -422,11 +417,9 @@ int pm_clk_resume(struct device *dev)
 	spin_lock_irqsave(&psd->lock, flags);
 
 	list_for_each_entry(ce, &psd->clock_list, node) {
-		if (ce->status < PCE_STATUS_ERROR) {
-			ret = __pm_clk_enable(dev, ce->clk);
-			if (!ret)
-				ce->status = PCE_STATUS_ENABLED;
-		}
+		ret = __pm_clk_enable(dev, ce->clk);
+		if (!ret)
+			ce->status = PCE_STATUS_ENABLED;
 	}
 
 	spin_unlock_irqrestore(&psd->lock, flags);
