msm: rpm: Add sysfs nodes to read driver and fw versions

Add RPM platform driver to export RPM kernel driver and firmware
version using

	cat /sys/devices/platform/msm_rpm/driver_version
	cat /sys/devices/platform/msm_rpm/fw_version

Signed-off-by: Praveen Chidambaram <pchidamb@codeaurora.org>
diff --git a/arch/arm/mach-msm/board-msm8960.c b/arch/arm/mach-msm/board-msm8960.c
index c75971b..15dd7c0 100644
--- a/arch/arm/mach-msm/board-msm8960.c
+++ b/arch/arm/mach-msm/board-msm8960.c
@@ -2628,6 +2628,12 @@
 	.msm_apps_ipc_rpm_val = 4,
 };
 
+static struct platform_device msm_rpm_device = {
+	.name   = "msm_rpm",
+	.id     = -1,
+};
+
+
 static struct spi_board_info spi_board_info[] __initdata = {
 	{
 		.modalias               = "ks8851",
@@ -2725,6 +2731,7 @@
 #ifdef CONFIG_HW_RANDOM_MSM
 	&msm_device_rng,
 #endif
+	&msm_rpm_device,
 };
 
 static struct platform_device *sim_devices[] __initdata = {
@@ -2763,7 +2770,6 @@
 		defined(CONFIG_CRYPTO_DEV_QCEDEV_MODULE)
 	&qcedev_device,
 #endif
-
 };
 
 static struct platform_device *rumi3_devices[] __initdata = {
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index ea28f98c..5393b9f 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -4699,6 +4699,11 @@
 
 #endif /* CONFIG_MSM_SDIO_AL */
 
+static struct platform_device msm_rpm_device = {
+	.name = "msm_rpm",
+	.id = -1,
+};
+
 static struct platform_device *charm_devices[] __initdata = {
 	&msm_charm_modem,
 #ifdef CONFIG_MSM_SDIO_AL
@@ -4893,6 +4898,7 @@
 #endif
 
 	&msm_tsens_device,
+	&msm_rpm_device,
 
 };
 
diff --git a/arch/arm/mach-msm/rpm.c b/arch/arm/mach-msm/rpm.c
index ddd2c82..bee3c3d 100644
--- a/arch/arm/mach-msm/rpm.c
+++ b/arch/arm/mach-msm/rpm.c
@@ -25,6 +25,8 @@
 #include <linux/mutex.h>
 #include <linux/semaphore.h>
 #include <linux/spinlock.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
 #include <asm/hardware/gic.h>
 #include <mach/msm_iomap.h>
 #include <mach/rpm.h>
@@ -771,6 +773,55 @@
 }
 EXPORT_SYMBOL(msm_rpm_unregister_notification);
 
+static uint32_t fw_major, fw_minor, fw_build;
+
+static ssize_t driver_version_show(struct kobject *kobj,
+		struct kobj_attribute *attr, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%u.%u.%u\n",
+			RPM_MAJOR_VER, RPM_MINOR_VER, RPM_BUILD_VER);
+}
+
+static ssize_t fw_version_show(struct kobject *kobj,
+		struct kobj_attribute *attr, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%u.%u.%u\n",
+			fw_major, fw_minor, fw_build);
+}
+
+static struct kobj_attribute driver_version_attr = __ATTR_RO(driver_version);
+static struct kobj_attribute fw_version_attr = __ATTR_RO(fw_version);
+
+static struct attribute *driver_attributes[] = {
+	&driver_version_attr.attr,
+	&fw_version_attr.attr,
+	NULL
+};
+
+static struct attribute_group driver_attr_group = {
+	.attrs = driver_attributes,
+};
+
+static int __devinit msm_rpm_probe(struct platform_device *pdev)
+{
+	return sysfs_create_group(&pdev->dev.kobj, &driver_attr_group);
+}
+
+static int __devexit msm_rpm_remove(struct platform_device *pdev)
+{
+	sysfs_remove_group(&pdev->dev.kobj, &driver_attr_group);
+	return 0;
+}
+
+static struct platform_driver msm_rpm_platform_driver = {
+	.probe = msm_rpm_probe,
+	.remove = __devexit_p(msm_rpm_remove),
+	.driver = {
+		.name = "msm_rpm",
+		.owner = THIS_MODULE,
+	},
+};
+
 static void __init msm_rpm_populate_map(void)
 {
 	int i, k;
@@ -788,26 +839,24 @@
 
 int __init msm_rpm_init(struct msm_rpm_platform_data *data)
 {
-	uint32_t major;
-	uint32_t minor;
-	uint32_t build;
 	unsigned int irq;
 	int rc;
 
 	msm_rpm_platform = data;
 
-	major = msm_rpm_read(MSM_RPM_PAGE_STATUS,
+	fw_major = msm_rpm_read(MSM_RPM_PAGE_STATUS,
 					MSM_RPM_STATUS_ID_VERSION_MAJOR);
-	minor = msm_rpm_read(MSM_RPM_PAGE_STATUS,
+	fw_minor = msm_rpm_read(MSM_RPM_PAGE_STATUS,
 					MSM_RPM_STATUS_ID_VERSION_MINOR);
-	build = msm_rpm_read(MSM_RPM_PAGE_STATUS,
+	fw_build = msm_rpm_read(MSM_RPM_PAGE_STATUS,
 					MSM_RPM_STATUS_ID_VERSION_BUILD);
-	pr_info("%s: RPM firmware %u.%u.%u\n", __func__, major, minor, build);
+	pr_info("%s: RPM firmware %u.%u.%u\n", __func__,
+			fw_major, fw_minor, fw_build);
 
-	if (major != RPM_MAJOR_VER) {
+	if (fw_major != RPM_MAJOR_VER) {
 		pr_err("%s: RPM version %u.%u.%u incompatible with "
 				"this driver version %u.%u.%u\n", __func__,
-				major, minor, build,
+				fw_major, fw_minor, fw_build,
 				RPM_MAJOR_VER, RPM_MINOR_VER, RPM_BUILD_VER);
 		return -EFAULT;
 	}
@@ -838,5 +887,6 @@
 	}
 
 	msm_rpm_populate_map();
-	return 0;
+
+	return platform_driver_register(&msm_rpm_platform_driver);
 }