diff --git a/drivers/power/voltdm/Kconfig b/drivers/power/voltdm/Kconfig
index c5353bd..270fdab 100644
--- a/drivers/power/voltdm/Kconfig
+++ b/drivers/power/voltdm/Kconfig
@@ -5,3 +5,8 @@ config VOLTAGE_DOMAIN
 	---help---
 	  Core voltage domain framework using common clock framework's
 	  notifier mechanism.
+
+menu "Voltage Domain Framework Drivers"
+	depends on VOLTAGE_DOMAIN
+
+endmenu
diff --git a/drivers/power/voltdm/Makefile b/drivers/power/voltdm/Makefile
index 3fa4408..fd32040 100644
--- a/drivers/power/voltdm/Makefile
+++ b/drivers/power/voltdm/Makefile
@@ -1,2 +1,5 @@
 # Generic voltage domain
 obj-$(CONFIG_VOLTAGE_DOMAIN)	+= core.o
+
+# Hardware specific voltage domain
+# please keep this section sorted lexicographically by file/directory path name
diff --git a/drivers/power/voltdm/core.c b/drivers/power/voltdm/core.c
index d0ed27e..69f6e81 100644
--- a/drivers/power/voltdm/core.c
+++ b/drivers/power/voltdm/core.c
@@ -10,12 +10,32 @@
  * that scale voltage when a clock changes its output frequency.
  */
 #include <linux/device.h>
+#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/pm_opp.h>
 #include <linux/pm_voltage_domain.h>
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
 
+#include "voltage_domain_private.h"
+
+/**
+ * struct pm_voltdm_dev - internal representation of voltage domain devices
+ * @desc:	voltage domain description
+ * @dev:	voltage domain device
+ * @list:	list to remaining voltage domain devices
+ * @lock:	mutex to control data structure modifications and serialize ops
+ * @notifier_list:	list of notifiers registered for this device
+ */
+struct pm_voltdm_dev {
+	const struct pm_voltdm_desc *desc;
+	struct device *dev;
+	struct list_head list;
+	/* list lock */
+	struct mutex lock;
+	struct list_head notifier_list;
+};
+
 /**
  * struct volt_scale_data - Internal structure to maintain notifier information
  * @dev:	device on behalf of which we register the notifier
@@ -23,6 +43,9 @@
  * @reg:	regulator if any which is used for scaling voltage
  * @tol:	voltage tolerance in %
  * @nb:		notifier block pointer
+ * @list:	list head for the notifier
+ * @vdev:	pointer to voltage domain device for this notifier
+ * @voltdm_data: voltdm driver specific data
  */
 struct volt_scale_data {
 	struct device *dev;
@@ -30,23 +53,208 @@ struct volt_scale_data {
 	struct regulator *reg;
 	int tol;
 	struct notifier_block nb;
+	struct list_head list;
+
+	struct pm_voltdm_dev *vdev;
+	void *voltdm_data;
 };
 
 #define to_volt_scale_data(_nb) container_of(_nb, \
 		struct volt_scale_data, nb)
 
+static DEFINE_MUTEX(pm_voltdm_list_lock);
+static LIST_HEAD(pm_voltdm_list);
+
+static inline bool voltmd_skip_check(struct pm_voltdm_dev *vdev)
+{
+	bool ret = false;
+
+	if (vdev) {
+		const struct pm_voltdm_desc *desc;
+
+		if (IS_ERR(vdev))
+			return false;
+
+		mutex_lock(&vdev->lock);
+		desc = vdev->desc;
+
+		if (desc->flags & VOLTAGE_DOMAIN_FLAG_NOTIFY_ALL)
+			ret = true;
+		mutex_unlock(&vdev->lock);
+	}
+
+	return ret;
+}
+
+static inline int voltmd_scale_voltage(struct volt_scale_data *vsd,
+				       unsigned long flags, int volt, int tol)
+{
+	int ret;
+	struct pm_voltdm_dev *vdev = vsd->vdev;
+
+	if (vdev) {
+		const struct pm_voltdm_ops *ops;
+
+		if (IS_ERR(vdev))
+			return PTR_ERR(vdev);
+
+		mutex_lock(&vdev->lock);
+		ops = vdev->desc->ops;
+
+		ret = ops->voltdm_do_transition(vdev->dev,
+						vsd->voltdm_data,
+						flags, volt, tol);
+		mutex_unlock(&vdev->lock);
+	} else {
+		ret = regulator_set_voltage_tol(vsd->reg, volt, tol);
+	}
+
+	return ret;
+}
+
+static struct pm_voltdm_dev *voltdm_parse_of(struct device_node *np,
+					     const char *supply,
+					     struct of_phandle_args *args)
+{
+	char prop_name[32];	/* 32 is max size of property name */
+	bool found = false;
+	struct device_node *voltdm_np;
+	struct pm_voltdm_dev *vdev = NULL;
+	int ret;
+
+	snprintf(prop_name, sizeof(prop_name), "%s-voltdm", supply);
+	voltdm_np = of_parse_phandle(np, prop_name, 0);
+	if (voltdm_np) {
+		ret = of_parse_phandle_with_args(np, prop_name, "#voltdm-cells",
+						 0, args);
+		if (ret)
+			return ERR_PTR(ret);
+
+		mutex_lock(&pm_voltdm_list_lock);
+		list_for_each_entry(vdev, &pm_voltdm_list, list)
+		    if (vdev->dev->parent && voltdm_np == vdev->dev->of_node) {
+			found = true;
+			break;
+		}
+		mutex_unlock(&pm_voltdm_list_lock);
+
+		/* if node is present and not ready, then defer */
+		if (!found)
+			return ERR_PTR(-EPROBE_DEFER);
+	} else {
+		return NULL;
+	}
+
+	return vdev;
+}
+
+static int voltdm_get(struct volt_scale_data *vsd, struct device_node *np,
+		      const char *supply, struct of_phandle_args *args,
+		      bool *skip_reg)
+{
+	struct pm_voltdm_dev *vdev = vsd->vdev;
+	struct device *dev = vsd->dev;
+	int ret = 0;
+
+	if (vdev) {
+		const struct pm_voltdm_ops *ops;
+		if (IS_ERR(vdev))
+			return PTR_ERR(vdev);
+
+		mutex_lock(&vdev->lock);
+		if (!try_module_get(vdev->dev->driver->owner)) {
+			ret = -ENODEV;
+		} else {
+			ops = vdev->desc->ops;
+			if (ops->voltdm_get)
+				ret = ops->voltdm_get(vdev->dev, dev, np,
+						      args, supply,
+						      &vsd->voltdm_data);
+			if (ret)
+				module_put(vdev->dev->driver->owner);
+		}
+		if (!ret)
+			list_add(&vsd->list, &vdev->notifier_list);
+
+		mutex_unlock(&vdev->lock);
+	} else {
+		vsd->reg = regulator_get_optional(dev, supply);
+		if (IS_ERR(vsd->reg))
+			ret = PTR_ERR(vsd->reg);
+		/* Regulator is not mandatory */
+		if (ret != -EPROBE_DEFER) {
+			ret = 0;
+			*skip_reg = false;
+			dev_dbg(dev, "%s: Failed to get %s regulator:%d\n",
+				__func__, supply, ret);
+		}
+	}
+
+	return ret;
+}
+
+static void voltdm_put(struct volt_scale_data *vsd)
+{
+	struct pm_voltdm_dev *vdev = vsd->vdev;
+
+	if (vdev) {
+		const struct pm_voltdm_ops *ops;
+
+		if (IS_ERR(vdev))
+			return;
+
+		mutex_lock(&vdev->lock);
+		ops = vdev->desc->ops;
+		if (ops->voltdm_put)
+			ops->voltdm_put(vdev->dev, vsd->dev, vsd->voltdm_data);
+		list_del(&vsd->list);
+		module_put(vdev->dev->driver->owner);
+		mutex_unlock(&vdev->lock);
+	} else {
+		if (!IS_ERR(vsd->reg))
+			regulator_put(vsd->reg);
+	}
+}
+
+static int voltdm_get_latency(struct volt_scale_data *vsd, int min, int max)
+{
+	struct pm_voltdm_dev *vdev = vsd->vdev;
+	const struct pm_voltdm_ops *ops;
+	int ret;
+
+	if (!vdev)
+		return regulator_set_voltage_time(vsd->reg, min, max);
+
+	if (IS_ERR(vdev))
+		return PTR_ERR(vdev);
+
+	mutex_lock(&vdev->lock);
+	ops = vdev->desc->ops;
+
+	if (!ops->voltdm_latency)
+		ret = -ENXIO;
+	else
+		ret = ops->voltdm_latency(vdev->dev, vsd->voltdm_data,
+					  min, max);
+	mutex_unlock(&vdev->lock);
+
+	return ret;
+}
+
 static int clk_volt_notifier_handler(struct notifier_block *nb,
 				     unsigned long flags, void *data)
 {
 	struct clk_notifier_data *cnd = data;
 	struct volt_scale_data *vsd = to_volt_scale_data(nb);
+	struct pm_voltdm_dev *vdev = vsd->vdev;
 	int ret, volt, tol;
 	struct dev_pm_opp *opp;
 	unsigned long old_rate = cnd->old_rate;
 	unsigned long new_rate = cnd->new_rate;
 
-	if ((new_rate < old_rate && flags == PRE_RATE_CHANGE) ||
-	    (new_rate > old_rate && flags == POST_RATE_CHANGE))
+	if (!voltmd_skip_check(vdev) &&
+	    ((new_rate < old_rate && flags == PRE_RATE_CHANGE) ||
+	     (new_rate > old_rate && flags == POST_RATE_CHANGE)))
 		return NOTIFY_OK;
 
 	rcu_read_lock();
@@ -69,7 +277,7 @@ static int clk_volt_notifier_handler(struct notifier_block *nb,
 	dev_dbg(vsd->dev, "%s: %lu -> %lu, V=%d, tol=%d, clk_flag=%lu\n",
 		__func__, old_rate, new_rate, volt, tol, flags);
 
-	ret = regulator_set_voltage_tol(vsd->reg, volt, tol);
+	ret = voltmd_scale_voltage(vsd, flags, volt, tol);
 	if (ret) {
 		dev_err(vsd->dev,
 			"%s: Failed to scale voltage(%u): %d\n", __func__,
@@ -101,6 +309,14 @@ struct notifier_block *of_pm_voltdm_notifier_register(struct device *dev,
 	struct dev_pm_opp *opp;
 	unsigned long min, max, freq;
 	int ret;
+	struct of_phandle_args voltdm_args = {NULL};
+	struct pm_voltdm_dev *vdev = NULL;
+	bool skip_reg = false;
+
+	/* First look for voltdm of node */
+	vdev = voltdm_parse_of(np, supply, &voltdm_args);
+	if (IS_ERR(vdev))
+		return (struct notifier_block *)vdev;
 
 	vsd = kzalloc(sizeof(*vsd), GFP_KERNEL);
 	if (!vsd)
@@ -109,19 +325,16 @@ struct notifier_block *of_pm_voltdm_notifier_register(struct device *dev,
 	vsd->dev = dev;
 	vsd->clk = clk;
 	vsd->nb.notifier_call = clk_volt_notifier_handler;
-	vsd->reg = regulator_get_optional(dev, supply);
-	ret = 0;
-	if (IS_ERR(vsd->reg))
-		ret = PTR_ERR(vsd->reg);
-	/* regulator is not mandatory */
-	if (ret != -EPROBE_DEFER) {
-		dev_warn(dev, "%s: Failed to get %s regulator:%d\n",
+	vsd->vdev = vdev;
+	ret = voltdm_get(vsd, np, supply, &voltdm_args, &skip_reg);
+
+	if (ret) {
+		dev_warn(dev, "%s: Failed to get %s regulator/voltdm: %d\n",
 			 __func__, supply, ret);
-		ret = 0;
 		goto err_free_vsd;
 	}
-	/* For devices that are not ready.... */
-	if (ret)
+	/* if not mandatory... */
+	if (skip_reg)
 		goto err_free_vsd;
 
 	rcu_read_lock();
@@ -138,7 +351,7 @@ struct notifier_block *of_pm_voltdm_notifier_register(struct device *dev,
 	max = dev_pm_opp_get_voltage(opp);
 	rcu_read_unlock();
 
-	*voltage_latency = regulator_set_voltage_time(vsd->reg, min, max);
+	*voltage_latency = voltdm_get_latency(vsd, min, max);
 	if (*voltage_latency < 0) {
 		dev_warn(dev,
 			 "%s: Fail calculating voltage latency[%ld<->%ld]:%d\n",
@@ -163,7 +376,7 @@ err_bad_opp:
 	dev_err(dev, "%s: failed to get OPP, %d\n", __func__, ret);
 
 err_free_reg:
-	regulator_put(vsd->reg);
+	voltdm_put(vsd);
 
 err_free_vsd:
 	kfree(vsd);
@@ -187,9 +400,109 @@ void of_pm_voltdm_notifier_unregister(struct notifier_block *nb)
 	vsd = to_volt_scale_data(nb);
 	clk = vsd->clk;
 	clk_notifier_unregister(clk, nb);
-	if (!IS_ERR(vsd->reg))
-		regulator_put(vsd->reg);
+	voltdm_put(vsd);
 
 	kfree(vsd);
 }
 EXPORT_SYMBOL_GPL(of_pm_voltdm_notifier_unregister);
+
+static void devm_voltdm_release(struct device *dev, void *res)
+{
+	struct pm_voltdm_dev *vdev = *(struct pm_voltdm_dev **)res;
+	struct volt_scale_data *vsd;
+
+	mutex_lock(&pm_voltdm_list_lock);
+	mutex_lock(&vdev->lock);
+	list_for_each_entry(vsd, &vdev->notifier_list, list) {
+		dev_warn(dev, "%s: pending notifier from device %s!\n",
+			 __func__, dev_name(vsd->dev));
+		vsd->vdev = ERR_PTR(-EINVAL);
+	}
+	mutex_unlock(&vdev->lock);
+
+	list_del(&vdev->list);
+	mutex_unlock(&pm_voltdm_list_lock);
+
+	kfree(vdev);
+}
+
+/**
+ * devm_voltdm_register - Resource managed voltage domain registration
+ * @dev: pointer to the device representing the voltage domain
+ * @desc: voltage domain descriptor
+ *
+ * Called by voltage domain drivers to register a voltagedomain.  Returns a
+ * valid pointer to struct pm_voltdm_dev on success or an ERR_PTR() on
+ * error.  The voltagedomain will automatically be released when the device
+ * is unbound.
+ */
+struct pm_voltdm_dev *devm_voltdm_register(struct device *dev,
+					   const struct pm_voltdm_desc *desc)
+{
+	struct pm_voltdm_dev **ptr, *vdev;
+
+	if (!dev || !desc)
+		return ERR_PTR(-EINVAL);
+
+	if (!desc->ops)
+		return ERR_PTR(-EINVAL);
+
+	/* Mandatory to have notify transition */
+	if (!desc->ops->voltdm_do_transition) {
+		dev_err(dev, "%s: Bad desc -do_transition missing\n", __func__);
+		return ERR_PTR(-EINVAL);
+	}
+
+	vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
+	if (!vdev)
+		return ERR_PTR(-ENOMEM);
+
+	ptr = devres_alloc(devm_voltdm_release, sizeof(*ptr), GFP_KERNEL);
+	if (!ptr) {
+		kfree(vdev);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	vdev->desc = desc;
+	vdev->dev = dev;
+	mutex_init(&vdev->lock);
+	INIT_LIST_HEAD(&vdev->notifier_list);
+	mutex_lock(&pm_voltdm_list_lock);
+	list_add(&vdev->list, &pm_voltdm_list);
+	mutex_unlock(&pm_voltdm_list_lock);
+
+	*ptr = vdev;
+	devres_add(dev, ptr);
+
+	return vdev;
+}
+EXPORT_SYMBOL_GPL(devm_voltdm_register);
+
+static int devm_vdev_match(struct device *dev, void *res, void *data)
+{
+	struct pm_voltdm_dev **r = res;
+	if (!r || !*r) {
+		WARN_ON(!r || !*r);
+		return 0;
+	}
+	return *r == data;
+}
+
+/**
+ * devm_voltdm_unregister - Resource managed voltagedomain unregister
+ * @vdev: voltage domain device returned by devm_voltdm_register()
+ *
+ * Unregister a voltdm registered with devm_voltdm_register().
+ * Normally this function will not need to be called and the resource
+ * management code will ensure that the resource is freed.
+ */
+void devm_voltdm_unregister(struct pm_voltdm_dev *vdev)
+{
+	int rc;
+	struct device *dev = vdev->dev;
+
+	rc = devres_release(dev, devm_voltdm_release, devm_vdev_match, vdev);
+	if (rc != 0)
+		WARN_ON(rc);
+}
+EXPORT_SYMBOL_GPL(devm_voltdm_unregister);
diff --git a/drivers/power/voltdm/voltage_domain_private.h b/drivers/power/voltdm/voltage_domain_private.h
new file mode 100644
index 0000000..e63c2b1
--- /dev/null
+++ b/drivers/power/voltdm/voltage_domain_private.h
@@ -0,0 +1,86 @@
+/*
+ * Voltage Domain private header for voltage domain drivers
+ *
+ * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/
+ *	Nishanth Menon
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __PM_VOLTAGE_DOMAIN_PRIVATE__
+#define __PM_VOLTAGE_DOMAIN_PRIVATE__
+
+#include <linux/pm_voltage_domain.h>
+
+struct pm_voltdm_dev;
+
+/**
+ * struct pm_voltdm_ops - Operations functions for voltage domain
+ * @voltdm_get: (optional) invoked when notifier is to be registered.
+ * @voltdm_put: (optional) invoked when notifier is unregistered.
+ * @voltdm_latency:	(optional) compute and provide voltage domain
+ *			transition latency.
+ * @voltdm_do_transition: (mandatory) callback for notification
+ *
+ * np_args - is arguments to the node phandle - useful when specific voltage
+ * domain is refered to using indices.
+ * voltdm_data - is the voltage domain driver specific data corresponding to
+ * driver information per registration (may point to domain driver specific
+ * data including reference to index. This is always provided back to the
+ * driver at various follow on operations.
+ * clk_notifier_flags - follows the standard clk notification flags
+ */
+struct pm_voltdm_ops {
+	int (*voltdm_get)(struct device *voltdm_dev,
+			  struct device *request_dev,
+			  struct device_node *np,
+			  struct of_phandle_args *np_args,
+			  const char *supply,
+			  void **voltdm_data);
+	int (*voltdm_latency)(struct device *voltdm_dev, void *voltdm_data,
+			      unsigned long min_uv, unsigned long max_uv);
+	int (*voltdm_do_transition)(struct device *voltdm_dev,
+				    void *voltdm_data,
+				    unsigned long clk_notifier_flags,
+				    int uv, int tol_uv);
+	void (*voltdm_put)(struct device *voltdm_dev,
+			   struct device *request_dev,
+			   void *voltdm_data);
+};
+
+#define VOLTAGE_DOMAIN_FLAG_NOTIFY_ALL		(0x1 << 0)
+
+/**
+ * struct pm_voltdm_desc - Descriptor for the voltage domain
+ * @ops:	operations for the voltage domain
+ * @flags:	flags controlling the various operations
+ */
+struct pm_voltdm_desc {
+	const struct pm_voltdm_ops *ops;
+	u16 flags;
+};
+
+#if defined(CONFIG_VOLTAGE_DOMAIN)
+struct pm_voltdm_dev *devm_voltdm_register(struct device *dev,
+					   const struct pm_voltdm_desc *desc);
+void devm_voltdm_unregister(struct pm_voltdm_dev *vdev);
+#else
+static inline struct pm_voltdm_dev *devm_voltdm_register(struct device *dev,
+					   const struct pm_voltdm_desc *desc)
+{
+	return ERR_PTR(-ENODEV);
+}
+
+static inline void devm_voltdm_unregister(struct pm_voltdm_dev *vdev)
+{
+}
+#endif				/* VOLTAGE_DOMAIN */
+
+#endif				/* __PM_VOLTAGE_DOMAIN_PRIVATE__ */
