diff --git a/Documentation/devicetree/bindings/arm/msm/rpm-master-stats.txt b/Documentation/devicetree/bindings/arm/msm/rpm-master-stats.txt
new file mode 100644
index 0000000000000000000000000000000000000000..02396745dd5ea332a3e18e4200727d4211b597ef
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/rpm-master-stats.txt
@@ -0,0 +1,29 @@
+* RPM Master Stats
+
+RPM maintains each master data in RPM message RAM at a specific
+offset. It tells about the individual masters information at
+any given time like "number of active cores in sub system",
+"number of shutdowns" and "wakeup reason for SS" etc. These stats
+can be show to the user using the debugfs interface of the kernel.
+To achieve this device tree node has been added and it will hold
+the address of the RPM RAM from where master stats are read.
+Added version number to distinguish the type of data structure
+being read from the RAM for different targets.
+
+The required properties for rpm-master-stats are:
+
+- compatible: "qcom,rpm-master-stats".
+- reg: The address on the RPM RAM from where stats are read.
+- qcom,masters: Each master name.
+- qcom,master-offset: Offset required to access each master stats area.
+- qcom,master-stats-version: Version number.
+
+Example:
+
+qcom,rpm-stats@fc428150 {
+		compatible = "qcom,rpm-stats";
+		reg = <0xfc428150 0x1000>;
+		qcom,masters = "APSS", "MPSS", "LPSS", "PRONTO";
+		qcom,master-offset = <2560>;
+		qcom,master-stats-version = <2>;
+};
diff --git a/arch/arm/mach-msm/rpm_master_stat.c b/arch/arm/mach-msm/rpm_master_stat.c
index a8a965e0a6d8835211b510424956e36fd7eb8ac0..3e1789fe8ff8451b353410aeca05c40bdd1c5840 100644
--- a/arch/arm/mach-msm/rpm_master_stat.c
+++ b/arch/arm/mach-msm/rpm_master_stat.c
@@ -22,39 +22,57 @@
 #include <linux/slab.h>
 #include <linux/types.h>
 #include <linux/mm.h>
+#include <linux/of.h>
 #include <asm/uaccess.h>
 
 #include <mach/msm_iomap.h>
 #include "rpm_stats.h"
-#define MSG_RAM_SIZE_PER_MASTER	32
-
-enum {
-	NUMSHUTDOWNS,
-	ACTIVECORES,
-	MASTER_ID_MAX,
-};
-
-static char *msm_rpm_master_stats_id_labels[MASTER_ID_MAX] = {
-	[NUMSHUTDOWNS] = "num_shutdowns",
-	[ACTIVECORES] = "active_cores",
-};
 
+#define RPM_MASTERS_BUF_LEN 400
+
+#define SNPRINTF(buf, size, format, ...) \
+	do { \
+		if (size > 0) { \
+			int ret; \
+			ret = snprintf(buf, size, format, ## __VA_ARGS__); \
+			if (ret > size) { \
+				buf += size; \
+				size = 0; \
+			} else { \
+				buf += ret; \
+				size -= ret; \
+			} \
+		} \
+	} while (0)
+
+#define GET_MASTER_NAME(a, prvdata) \
+	((a >= prvdata->num_masters) ? "Invalid Master Name" : \
+	 prvdata->master_names[a])
+
+#define GET_FIELD(a) ((strnstr(#a, ".", 80) + 1))
 
 struct msm_rpm_master_stats {
-	unsigned long numshutdowns;
-	unsigned long active_cores;
+	uint32_t active_cores;
+	uint32_t numshutdowns;
+	uint64_t shutdown_req;
+	uint64_t wakeup_ind;
+	uint64_t bringup_req;
+	uint64_t bringup_ack;
+	uint32_t wakeup_reason; /* 0 = rude wakeup, 1 = scheduled wakeup */
+	uint32_t last_sleep_transition_duration;
+	uint32_t last_wake_transition_duration;
 };
 
 struct msm_rpm_master_stats_private_data {
 	void __iomem *reg_base;
 	u32 len;
 	char **master_names;
-	u32 nomasters;
-	char buf[256];
+	u32 num_masters;
+	char buf[RPM_MASTERS_BUF_LEN];
 	struct msm_rpm_master_stats_platform_data *platform_data;
 };
 
-static int msm_rpm_master_stats_file_close(struct inode *inode,
+int msm_rpm_master_stats_file_close(struct inode *inode,
 		struct file *file)
 {
 	struct msm_rpm_master_stats_private_data *private = file->private_data;
@@ -67,53 +85,138 @@ static int msm_rpm_master_stats_file_close(struct inode *inode,
 }
 
 static int msm_rpm_master_copy_stats(
-		struct msm_rpm_master_stats_private_data *pdata)
+		struct msm_rpm_master_stats_private_data *prvdata)
 {
 	struct msm_rpm_master_stats record;
-	static int nomasters;
-	int count;
+	struct msm_rpm_master_stats_platform_data *pdata;
+	static int master_cnt;
+	int count, j = 0;
+	char *buf;
 	static DEFINE_MUTEX(msm_rpm_master_stats_mutex);
-	int j = 0;
 
 	mutex_lock(&msm_rpm_master_stats_mutex);
-	/*
-	 * iterrate possible nomasters times.
-	 * 8960, 8064 have 5 masters.
-	 * 8930 has 4 masters.
-	 * 9x15 has 3 masters.
-	 */
-	if (nomasters > pdata->nomasters - 1) {
-		nomasters = 0;
+
+	/* Iterate possible number of masters */
+	if (master_cnt > prvdata->num_masters - 1) {
+		master_cnt = 0;
 		mutex_unlock(&msm_rpm_master_stats_mutex);
 		return 0;
 	}
 
-	record.numshutdowns = readl_relaxed(pdata->reg_base +
-			(nomasters * MSG_RAM_SIZE_PER_MASTER));
-	record.active_cores = readl_relaxed(pdata->reg_base +
-				(nomasters * MSG_RAM_SIZE_PER_MASTER + 4));
-
-	count = snprintf(pdata->buf, sizeof(pdata->buf),
-		"%s\n\t%s:%lu\n\t%s:%lu\n",
-		pdata->master_names[nomasters],
-		msm_rpm_master_stats_id_labels[0],
-		record.numshutdowns,
-		msm_rpm_master_stats_id_labels[1],
-		record.active_cores);
+	pdata = prvdata->platform_data;
+	count = RPM_MASTERS_BUF_LEN;
+	buf = prvdata->buf;
+
+	if (prvdata->platform_data->version == 2) {
+		SNPRINTF(buf, count, "%s\n",
+				GET_MASTER_NAME(master_cnt, prvdata));
+
+		record.shutdown_req = readll_relaxed(prvdata->reg_base +
+			(master_cnt * pdata->master_offset +
+			offsetof(struct msm_rpm_master_stats, shutdown_req)));
+
+		SNPRINTF(buf, count, "\t%s:0x%llX\n",
+			GET_FIELD(record.shutdown_req),
+			record.shutdown_req);
+
+		record.wakeup_ind = readll_relaxed(prvdata->reg_base +
+			(master_cnt * pdata->master_offset +
+			offsetof(struct msm_rpm_master_stats, wakeup_ind)));
+
+		SNPRINTF(buf, count, "\t%s:0x%llX\n",
+			GET_FIELD(record.wakeup_ind),
+			record.wakeup_ind);
+
+		record.bringup_req = readll_relaxed(prvdata->reg_base +
+			(master_cnt * pdata->master_offset +
+			offsetof(struct msm_rpm_master_stats, bringup_req)));
+
+		SNPRINTF(buf, count, "\t%s:0x%llX\n",
+			GET_FIELD(record.bringup_req),
+			record.bringup_req);
+
+		record.bringup_ack = readll_relaxed(prvdata->reg_base +
+			(master_cnt * pdata->master_offset +
+			offsetof(struct msm_rpm_master_stats, bringup_ack)));
+
+		SNPRINTF(buf, count, "\t%s:0x%llX\n",
+			GET_FIELD(record.bringup_ack),
+			record.bringup_ack);
+
+		record.last_sleep_transition_duration =
+				readl_relaxed(prvdata->reg_base +
+				(master_cnt * pdata->master_offset +
+				offsetof(struct msm_rpm_master_stats,
+				last_sleep_transition_duration)));
+
+		SNPRINTF(buf, count, "\t%s:0x%x\n",
+			GET_FIELD(record.last_sleep_transition_duration),
+			record.last_sleep_transition_duration);
+
+		record.last_wake_transition_duration =
+				readl_relaxed(prvdata->reg_base +
+				(master_cnt * pdata->master_offset +
+				offsetof(struct msm_rpm_master_stats,
+				last_wake_transition_duration)));
+
+		SNPRINTF(buf, count, "\t%s:0x%x\n",
+			GET_FIELD(record.last_wake_transition_duration),
+			record.last_wake_transition_duration);
+
+		record.wakeup_reason = readl_relaxed(prvdata->reg_base +
+					(master_cnt * pdata->master_offset +
+					offsetof(struct msm_rpm_master_stats,
+					wakeup_reason)));
+
+		SNPRINTF(buf, count, "\t%s:0x%x\n",
+			GET_FIELD(record.wakeup_reason),
+			record.wakeup_reason);
+
+		record.numshutdowns = readl_relaxed(prvdata->reg_base +
+			(master_cnt * pdata->master_offset +
+			 offsetof(struct msm_rpm_master_stats, numshutdowns)));
+
+		SNPRINTF(buf, count, "\t%s:0x%x\n",
+			GET_FIELD(record.numshutdowns),
+			record.numshutdowns);
+
+		record.active_cores = readl_relaxed(prvdata->reg_base +
+			(master_cnt * pdata->master_offset) +
+			offsetof(struct msm_rpm_master_stats, active_cores));
+
+		SNPRINTF(buf, count, "\t%s:0x%x\n",
+			GET_FIELD(record.active_cores),
+			record.active_cores);
+	} else {
+		SNPRINTF(buf, count, "%s\n",
+				GET_MASTER_NAME(master_cnt, prvdata));
+
+		record.numshutdowns = readl_relaxed(prvdata->reg_base +
+				(master_cnt * pdata->master_offset) + 0x0);
+
+		SNPRINTF(buf, count, "\t%s:0x%0x\n",
+			GET_FIELD(record.numshutdowns),
+			record.numshutdowns);
+
+		record.active_cores = readl_relaxed(prvdata->reg_base +
+				(master_cnt * pdata->master_offset) + 0x4);
+
+		SNPRINTF(buf, count, "\t%s:0x%0x\n",
+			GET_FIELD(record.active_cores),
+			record.active_cores);
+	}
 
-	j = find_first_bit(&record.active_cores, BITS_PER_LONG);
+	j = find_first_bit((unsigned long *)&record.active_cores,
+							BITS_PER_LONG);
 	while (j < BITS_PER_LONG) {
-		count += snprintf(pdata->buf + count,
-			sizeof(pdata->buf) - count,
-			"\t\tcore%d\n", j);
-		j = find_next_bit(&record.active_cores,
+		SNPRINTF(buf, count, "\t\tcore%d\n", j);
+		j = find_next_bit((unsigned long *)&record.active_cores,
 				BITS_PER_LONG, j + 1);
 	}
 
-
-	nomasters++;
+	master_cnt++;
 	mutex_unlock(&msm_rpm_master_stats_mutex);
-	return count;
+	return RPM_MASTERS_BUF_LEN - count;
 }
 
 static int msm_rpm_master_stats_file_read(struct file *file, char __user *bufu,
@@ -151,7 +254,7 @@ static int msm_rpm_master_stats_file_open(struct inode *inode,
 	pdata = inode->i_private;
 
 	file->private_data =
-		kmalloc(sizeof(struct msm_rpm_master_stats_private_data),
+		kzalloc(sizeof(struct msm_rpm_master_stats_private_data),
 			GFP_KERNEL);
 
 	if (!file->private_data)
@@ -159,7 +262,7 @@ static int msm_rpm_master_stats_file_open(struct inode *inode,
 	prvdata = file->private_data;
 
 	prvdata->reg_base = ioremap(pdata->phys_addr_base,
-		pdata->phys_size);
+						pdata->phys_size);
 	if (!prvdata->reg_base) {
 		kfree(file->private_data);
 		prvdata = NULL;
@@ -170,7 +273,7 @@ static int msm_rpm_master_stats_file_open(struct inode *inode,
 	}
 
 	prvdata->len = 0;
-	prvdata->nomasters = pdata->num_masters;
+	prvdata->num_masters = pdata->num_masters;
 	prvdata->master_names = pdata->masters;
 	prvdata->platform_data = pdata;
 	return 0;
@@ -184,27 +287,108 @@ static const struct file_operations msm_rpm_master_stats_fops = {
 	.llseek   = no_llseek,
 };
 
+static struct msm_rpm_master_stats_platform_data
+			*msm_rpm_master_populate_pdata(struct device *dev)
+{
+	struct msm_rpm_master_stats_platform_data *pdata;
+	struct device_node *node = dev->of_node;
+	int rc = 0, i;
+
+	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata) {
+		dev_err(dev, "could not allocate memory for platform data\n");
+		goto err;
+	}
+
+	rc = of_property_read_u32(node, "qcom,master-stats-version",
+							&pdata->version);
+	if (rc) {
+		dev_err(dev, "master-stats-version missing rc=%d\n", rc);
+		goto err;
+	}
+
+	rc = of_property_read_u32(node, "qcom,master-offset",
+							&pdata->master_offset);
+	if (rc) {
+		dev_err(dev, "master-offset missing rc=%d\n", rc);
+		goto err;
+	}
+
+	pdata->num_masters = of_property_count_strings(node, "qcom,masters");
+	if (pdata->num_masters < 0) {
+		dev_err(dev, "Failed to get number of masters =%d\n",
+						pdata->num_masters);
+		goto err;
+	}
+
+	pdata->masters = devm_kzalloc(dev, sizeof(char *) * pdata->num_masters,
+								GFP_KERNEL);
+	if (!pdata->masters) {
+		dev_err(dev, "%s:Failed to allocated memory\n", __func__);
+		goto err;
+	}
+
+	/*
+	 * Read master names from DT
+	 */
+	for (i = 0; i < pdata->num_masters; i++) {
+		const char *master_name;
+		of_property_read_string_index(node, "qcom,masters",
+							i, &master_name);
+		pdata->masters[i] = devm_kzalloc(dev, sizeof(char) *
+				strlen(master_name) + 1, GFP_KERNEL);
+		if (!pdata->masters[i]) {
+			dev_err(dev, "%s:Failed to get memory\n", __func__);
+			goto err;
+		}
+		strlcpy(pdata->masters[i], master_name,
+					strlen(master_name) + 1);
+	}
+	return pdata;
+err:
+	return NULL;
+}
+
 static  int __devinit msm_rpm_master_stats_probe(struct platform_device *pdev)
 {
 	struct dentry *dent;
 	struct msm_rpm_master_stats_platform_data *pdata;
-	struct resource *res;
+	struct resource *res = NULL;
 
-	pdata = pdev->dev.platform_data;
-	if (!pdata)
+	if (!pdev)
 		return -EINVAL;
 
+	if (pdev->dev.of_node)
+		pdata = msm_rpm_master_populate_pdata(&pdev->dev);
+	else
+		pdata = pdev->dev.platform_data;
+
+	if (!pdata) {
+		dev_err(&pdev->dev, "%s: Unable to get pdata\n", __func__);
+		return -ENOMEM;
+	}
+
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	if (!res) {
+		dev_err(&pdev->dev,
+			"%s: Failed to get IO resource from platform device",
+			__func__);
+		return -ENXIO;
+	}
+
 	pdata->phys_addr_base = res->start;
 	pdata->phys_size = resource_size(res);
 
 	dent = debugfs_create_file("rpm_master_stats", S_IRUGO, NULL,
-			pdev->dev.platform_data, &msm_rpm_master_stats_fops);
+					pdata, &msm_rpm_master_stats_fops);
 
 	if (!dent) {
-		pr_err("%s: ERROR debugfs_create_file failed\n", __func__);
+		dev_err(&pdev->dev, "%s: ERROR debugfs_create_file failed\n",
+								__func__);
 		return -ENOMEM;
 	}
+
 	platform_set_drvdata(pdev, dent);
 	return 0;
 }
@@ -219,12 +403,18 @@ static int __devexit msm_rpm_master_stats_remove(struct platform_device *pdev)
 	return 0;
 }
 
+static struct of_device_id rpm_master_table[] = {
+	{.compatible = "qcom,rpm-master-stats"},
+	{},
+};
+
 static struct platform_driver msm_rpm_master_stats_driver = {
 	.probe	= msm_rpm_master_stats_probe,
 	.remove = __devexit_p(msm_rpm_master_stats_remove),
 	.driver = {
 		.name = "msm_rpm_master_stats",
 		.owner = THIS_MODULE,
+		.of_match_table = rpm_master_table,
 	},
 };