diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index ba69751..5c4fe16 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -394,3 +394,4 @@ source "drivers/power/reset/Kconfig"
 endif # POWER_SUPPLY
 
 source "drivers/power/avs/Kconfig"
+source "drivers/power/voltdm/Kconfig"
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index ee54a3e..3d47072 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -58,3 +58,4 @@ obj-$(CONFIG_POWER_AVS)		+= avs/
 obj-$(CONFIG_CHARGER_SMB347)	+= smb347-charger.o
 obj-$(CONFIG_CHARGER_TPS65090)	+= tps65090-charger.o
 obj-$(CONFIG_POWER_RESET)	+= reset/
+obj-$(CONFIG_VOLTAGE_DOMAIN)	+= voltdm/
diff --git a/drivers/power/voltdm/Kconfig b/drivers/power/voltdm/Kconfig
new file mode 100644
index 0000000..c5353bd
--- /dev/null
+++ b/drivers/power/voltdm/Kconfig
@@ -0,0 +1,7 @@
+config VOLTAGE_DOMAIN
+	bool
+	depends on COMMON_CLK && OF && PM_OPP
+	default y if COMMON_CLK
+	---help---
+	  Core voltage domain framework using common clock framework's
+	  notifier mechanism.
diff --git a/drivers/power/voltdm/Makefile b/drivers/power/voltdm/Makefile
new file mode 100644
index 0000000..3fa4408
--- /dev/null
+++ b/drivers/power/voltdm/Makefile
@@ -0,0 +1,2 @@
+# Generic voltage domain
+obj-$(CONFIG_VOLTAGE_DOMAIN)	+= core.o
diff --git a/drivers/power/voltdm/core.c b/drivers/power/voltdm/core.c
new file mode 100644
index 0000000..d0ed27e
--- /dev/null
+++ b/drivers/power/voltdm/core.c
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2013 Linaro Ltd <mturquette@linaro.org>
+ * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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.
+ *
+ * Helper functions for registering clock rate-change notifier handlers
+ * that scale voltage when a clock changes its output frequency.
+ */
+#include <linux/device.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>
+
+/**
+ * struct volt_scale_data - Internal structure to maintain notifier information
+ * @dev:	device on behalf of which we register the notifier
+ * @clk:	clk on which we registered the notifier
+ * @reg:	regulator if any which is used for scaling voltage
+ * @tol:	voltage tolerance in %
+ * @nb:		notifier block pointer
+ */
+struct volt_scale_data {
+	struct device *dev;
+	struct clk *clk;
+	struct regulator *reg;
+	int tol;
+	struct notifier_block nb;
+};
+
+#define to_volt_scale_data(_nb) container_of(_nb, \
+		struct volt_scale_data, nb)
+
+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);
+	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))
+		return NOTIFY_OK;
+
+	rcu_read_lock();
+	if (flags != ABORT_RATE_CHANGE)
+		opp = dev_pm_opp_find_freq_ceil(vsd->dev, &new_rate);
+	else
+		opp = dev_pm_opp_find_freq_ceil(vsd->dev, &old_rate);
+	if (IS_ERR(opp)) {
+		rcu_read_unlock();
+		dev_err(vsd->dev, "%s: Failed to find OPP for %lu\n",
+			__func__, new_rate);
+		return notifier_from_errno(PTR_ERR(opp));
+	}
+
+	volt = dev_pm_opp_get_voltage(opp);
+	rcu_read_unlock();
+
+	tol = volt * vsd->tol / 100;
+
+	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);
+	if (ret) {
+		dev_err(vsd->dev,
+			"%s: Failed to scale voltage(%u): %d\n", __func__,
+			volt, ret);
+		return notifier_from_errno(ret);
+	}
+
+	return NOTIFY_OK;
+}
+
+/**
+ * of_pm_voltdm_notifier_register() - register voltage domain notifier
+ * @dev:	device for which to register notifier for
+ * @np:		node pointer of the device for which we register
+ * @clk:	clk pointer around which the notifier is expected to trigger
+ * @supply:	default regulator supply name(regulator id string)
+ * @voltage_latency:	returns the latency for the voltage domain
+ *
+ * Return: notifier block which is registered with the common clock framework's
+ * notifier for the clk node requested.
+ */
+struct notifier_block *of_pm_voltdm_notifier_register(struct device *dev,
+						      struct device_node *np,
+						      struct clk *clk,
+						      const char *supply,
+						      int *voltage_latency)
+{
+	struct volt_scale_data *vsd;
+	struct dev_pm_opp *opp;
+	unsigned long min, max, freq;
+	int ret;
+
+	vsd = kzalloc(sizeof(*vsd), GFP_KERNEL);
+	if (!vsd)
+		return ERR_PTR(-ENOMEM);
+
+	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",
+			 __func__, supply, ret);
+		ret = 0;
+		goto err_free_vsd;
+	}
+	/* For devices that are not ready.... */
+	if (ret)
+		goto err_free_vsd;
+
+	rcu_read_lock();
+	freq = 0;
+	opp = dev_pm_opp_find_freq_ceil(dev, &freq);
+	if (IS_ERR(opp))
+		goto err_bad_opp;
+	min = dev_pm_opp_get_voltage(opp);
+
+	freq = ULONG_MAX;
+	opp = dev_pm_opp_find_freq_floor(dev, &freq);
+	if (IS_ERR(opp))
+		goto err_bad_opp;
+	max = dev_pm_opp_get_voltage(opp);
+	rcu_read_unlock();
+
+	*voltage_latency = regulator_set_voltage_time(vsd->reg, min, max);
+	if (*voltage_latency < 0) {
+		dev_warn(dev,
+			 "%s: Fail calculating voltage latency[%ld<->%ld]:%d\n",
+			 __func__, min, max, *voltage_latency);
+	}
+
+	of_property_read_u32(np, "voltage-tolerance", &vsd->tol);
+
+	ret = clk_notifier_register(clk, &vsd->nb);
+
+	if (ret) {
+		dev_err(dev, "%s: Failed to Register Notifier, %d\n", __func__,
+			ret);
+		goto err_free_reg;
+	}
+
+	return &vsd->nb;
+
+err_bad_opp:
+	rcu_read_unlock();
+	ret = PTR_ERR(opp);
+	dev_err(dev, "%s: failed to get OPP, %d\n", __func__, ret);
+
+err_free_reg:
+	regulator_put(vsd->reg);
+
+err_free_vsd:
+	kfree(vsd);
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(of_pm_voltdm_notifier_register);
+
+/**
+ * of_pm_voltdm_notifier_unregister() - unregister notifier for volt domain
+ * @nb:	notifier block returned by of_pm_voltdm_notifier_register
+ */
+void of_pm_voltdm_notifier_unregister(struct notifier_block *nb)
+{
+	struct volt_scale_data *vsd;
+	struct clk *clk;
+
+	/* if caller send us back error value */
+	if (IS_ERR(nb))
+		return;
+
+	vsd = to_volt_scale_data(nb);
+	clk = vsd->clk;
+	clk_notifier_unregister(clk, nb);
+	if (!IS_ERR(vsd->reg))
+		regulator_put(vsd->reg);
+
+	kfree(vsd);
+}
+EXPORT_SYMBOL_GPL(of_pm_voltdm_notifier_unregister);
diff --git a/include/linux/pm_voltage_domain.h b/include/linux/pm_voltage_domain.h
new file mode 100644
index 0000000..1ee7343
--- /dev/null
+++ b/include/linux/pm_voltage_domain.h
@@ -0,0 +1,47 @@
+/*
+ * Voltage Domain header for users of voltage domain interface
+ *
+ * Copyright (C) 2013 Linaro Ltd <mturquette@linaro.org>
+ * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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__
+#define __PM_VOLTAGE_DOMAIN__
+
+#include <linux/clk.h>
+
+#if defined(CONFIG_VOLTAGE_DOMAIN)
+struct notifier_block *of_pm_voltdm_notifier_register(struct device *dev,
+						      struct device_node *np,
+						      struct clk *clk,
+						      const char *supply,
+						      int *voltage_latency);
+void of_pm_voltdm_notifier_unregister(struct notifier_block *nb);
+
+#else
+static inline struct notifier_block *of_pm_voltdm_notifier_register(
+						      struct device *dev,
+						      struct device_node *np,
+						      struct clk *clk,
+						      const char *supply,
+						      int *voltage_latency);
+{
+	return ERR_PTR(-ENODEV);
+}
+
+static inline void of_pm_voltdm_notifier_unregister(struct notifier_block *nb)
+{
+}
+
+#endif				/* VOLTAGE_DOMAIN */
+
+#endif				/* __PM_VOLTAGE_DOMAIN__ */
