gpio: msm: Make msmgpio a platform device

The gpio driver was not a true platform driver and hence wasn't
supported by device tree. This patch fixes that for non-DT targets
by making sure the device gets added early on during board init.
For DT-targets, adding the gpio-controller property for the device
makes sure the msmgpio device gets probed.
This change is done for all TLMM_v2 targets (msm8660 and future)
TLMM_V1 targets remain unaffected.

Change-Id: I8a55ab1e2af0366b3e6893b334ba2396d2a83190
Signed-off-by: Rohit Vaswani <rvaswani@codeaurora.org>
diff --git a/Documentation/devicetree/bindings/gpio/gpio-msm.txt b/Documentation/devicetree/bindings/gpio/gpio-msm.txt
new file mode 100644
index 0000000..359d700
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/gpio-msm.txt
@@ -0,0 +1,39 @@
+MSM GPIO controller bindings
+
+Required properties:
+- compatible:
+  - "qcom,msm-gpio" for MSM controllers
+- #gpio-cells : Should be two.
+  - first cell is the pin number
+  - second cell is used to specify optional parameters (unused)
+- gpio-controller : Marks the device node as a GPIO controller.
+- #interrupt-cells : Should be 2.
+- interrupt-controller: Mark the device node as an interrupt controller
+
+Example:
+
+	msmgpio: gpio@fd510000 {
+		compatible = "qcom,msm-gpio";
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+		reg = <0xfd510000 0x4000>;
+	};
+
+To specify gpios for a device:
+
+	device1@f991f000 {
+		compatible = "qcom,msm-device-v1";
+		reg = <0xf991f000 0x1000>;
+		gpios = <&msmgpio 45 0>;
+		cs-gpios = <&msmgpio 46 0>;
+	};
+
+45, 46 - gpio numbers.
+The driver for device1 can call of_get_gpio() to extract the
+gpio45. In order to extract gpio46, the driver needs to call
+of_get_named_gpio with "cs-gpios" as the name parameter.
+Please refer to the file: include/linux/of_gpio.h for the
+complete list of APIs the driver can use to extract gpio
+information from the device tree.
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index e3dad4f..446f310 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -33,10 +33,11 @@
 
 	msmgpio: gpio@fd510000 {
 		compatible = "qcom,msm-gpio";
+		gpio-controller;
+		#gpio-cells = <2>;
 		interrupt-controller;
 		#interrupt-cells = <2>;
 		reg = <0xfd510000 0x4000>;
-		#gpio-cells = <2>;
 	};
 
 	timer {
diff --git a/arch/arm/boot/dts/msm9625.dts b/arch/arm/boot/dts/msm9625.dts
index deddc5f..42425ed 100644
--- a/arch/arm/boot/dts/msm9625.dts
+++ b/arch/arm/boot/dts/msm9625.dts
@@ -37,6 +37,8 @@
 
 	msmgpio: gpio@fd510000 {
 		compatible = "qcom,msm-gpio";
+		gpio-controller;
+		#gpio-cells = <2>;
 		interrupt-controller;
 		#interrupt-cells = <2>;
 		reg = <0xfd510000 0x4000>;
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 4b4e006..665b861 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -2913,6 +2913,7 @@
 static void __init apq8064_common_init(void)
 {
 	u32 platform_version;
+	platform_device_register(&msm_gpio_device);
 	msm_tsens_early_init(&apq_tsens_pdata);
 	msm_thermal_init(&msm_thermal_pdata);
 	if (socinfo_init() < 0)
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index 444580f..b80d62d 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -2572,6 +2572,7 @@
 	if (meminfo_init(SYS_MEMORY, SZ_256M) < 0)
 		pr_err("meminfo_init() failed!\n");
 
+	platform_device_register(&msm_gpio_device);
 	msm_tsens_early_init(&msm_tsens_pdata);
 	msm_thermal_init(&msm_thermal_pdata);
 	BUG_ON(msm_rpm_init(&msm8930_rpm_data));
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 7d88ea6..ad788bc 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -3082,6 +3082,7 @@
 	if (meminfo_init(SYS_MEMORY, SZ_256M) < 0)
 		pr_err("meminfo_init() failed!\n");
 
+	platform_device_register(&msm_gpio_device);
 	msm_tsens_early_init(&msm_tsens_pdata);
 	msm_thermal_init(&msm_thermal_pdata);
 	BUG_ON(msm_rpm_init(&msm8960_rpm_data));
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index a312e2b..f885774 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -976,6 +976,7 @@
 				msm_android_usb_hsic_device.dev.platform_data;
 
 	msm9615_device_init();
+	platform_device_register(&msm_gpio_device);
 	msm9615_init_gpiomux();
 	msm9615_i2c_init();
 	regulator_suppress_info_printing();
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index 50b1ac5..38f1170 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -10213,6 +10213,7 @@
 #endif
 	pmic_reset_irq = PM8058_IRQ_BASE + PM8058_RESOUT_IRQ;
 
+	platform_device_register(&msm_gpio_device);
 	/*
 	 * Initialize RPM first as other drivers and devices may need
 	 * it for their initialization.
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index e07301a..680770e 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -4017,6 +4017,11 @@
 	},
 };
 
+struct platform_device msm_gpio_device = {
+	.name = "msmgpio",
+	.id = -1,
+};
+
 struct platform_device mdm_sglte_device = {
 	.name		= "mdm2_modem",
 	.id		= -1,
diff --git a/arch/arm/mach-msm/devices-9615.c b/arch/arm/mach-msm/devices-9615.c
index 9f03878..fff8e0d 100644
--- a/arch/arm/mach-msm/devices-9615.c
+++ b/arch/arm/mach-msm/devices-9615.c
@@ -1372,6 +1372,10 @@
 	},
 };
 
+struct platform_device msm_gpio_device = {
+	.name = "msmgpio",
+	.id = -1,
+};
 
 void __init msm9615_device_init(void)
 {
@@ -1382,7 +1386,6 @@
 		msm_rpmrs_levels[0].latency_us;
 	msm_android_usb_hsic_pdata.swfi_latency =
 		msm_rpmrs_levels[0].latency_us;
-
 }
 
 #define MSM_SHARED_RAM_PHYS 0x40000000
diff --git a/arch/arm/mach-msm/devices-msm8x60.c b/arch/arm/mach-msm/devices-msm8x60.c
index 9ea817f..5402251 100644
--- a/arch/arm/mach-msm/devices-msm8x60.c
+++ b/arch/arm/mach-msm/devices-msm8x60.c
@@ -100,6 +100,11 @@
 #define MSM_UART9DM_PHYS    (MSM_GSBI9_PHYS + 0x40000)
 #define INT_UART9DM_IRQ     GSBI9_UARTDM_IRQ
 
+struct platform_device msm_gpio_device = {
+	.name = "msmgpio",
+	.id = -1,
+};
+
 static void charm_ap2mdm_kpdpwr_on(void)
 {
 	gpio_direction_output(AP2MDM_PMIC_RESET_N, 0);
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 6726e60..8e2ab7d 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -436,3 +436,5 @@
 extern struct platform_device msm8930aa_device_acpuclk;
 extern struct platform_device msm8960_device_acpuclk;
 extern struct platform_device msm9615_device_acpuclk;
+
+extern struct platform_device msm_gpio_device;
diff --git a/drivers/gpio/gpio-msm-common.c b/drivers/gpio/gpio-msm-common.c
index bdb8171..46f6460 100644
--- a/drivers/gpio/gpio-msm-common.c
+++ b/drivers/gpio/gpio-msm-common.c
@@ -23,6 +23,7 @@
 #include <linux/irqdomain.h>
 #include <linux/of.h>
 #include <linux/err.h>
+#include <linux/platform_device.h>
 
 #include <asm/mach/irq.h>
 
@@ -402,59 +403,6 @@
 	.irq_disable	= msm_gpio_irq_disable,
 };
 
-/*
- * This lock class tells lockdep that GPIO irqs are in a different
- * category than their parent, so it won't report false recursion.
- */
-static struct lock_class_key msm_gpio_lock_class;
-
-/* TODO: This should be a real platform_driver */
-static int __devinit msm_gpio_probe(void)
-{
-	int ret;
-#ifndef CONFIG_OF
-	int irq, i;
-#endif
-
-	spin_lock_init(&tlmm_lock);
-	bitmap_zero(msm_gpio.enabled_irqs, NR_MSM_GPIOS);
-	bitmap_zero(msm_gpio.wake_irqs, NR_MSM_GPIOS);
-	bitmap_zero(msm_gpio.dual_edge_irqs, NR_MSM_GPIOS);
-	ret = gpiochip_add(&msm_gpio.gpio_chip);
-	if (ret < 0)
-		return ret;
-
-#ifndef CONFIG_OF
-	for (i = 0; i < msm_gpio.gpio_chip.ngpio; ++i) {
-		irq = msm_gpio_to_irq(&msm_gpio.gpio_chip, i);
-		irq_set_lockdep_class(irq, &msm_gpio_lock_class);
-		irq_set_chip_and_handler(irq, &msm_gpio_irq_chip,
-					 handle_level_irq);
-		set_irq_flags(irq, IRQF_VALID);
-	}
-#endif
-	ret = request_irq(TLMM_MSM_SUMMARY_IRQ, msm_summary_irq_handler,
-			IRQF_TRIGGER_HIGH, "msmgpio", NULL);
-	if (ret) {
-		pr_err("Request_irq failed for TLMM_MSM_SUMMARY_IRQ - %d\n",
-				ret);
-		return ret;
-	}
-	return 0;
-}
-
-static int __devexit msm_gpio_remove(void)
-{
-	int ret = gpiochip_remove(&msm_gpio.gpio_chip);
-
-	if (ret < 0)
-		return ret;
-
-	irq_set_handler(TLMM_MSM_SUMMARY_IRQ, NULL);
-
-	return 0;
-}
-
 #ifdef CONFIG_PM
 static int msm_gpio_suspend(void)
 {
@@ -518,22 +466,6 @@
 	.resume = msm_gpio_resume,
 };
 
-static int __init msm_gpio_init(void)
-{
-	msm_gpio_probe();
-	register_syscore_ops(&msm_gpio_syscore_ops);
-	return 0;
-}
-
-static void __exit msm_gpio_exit(void)
-{
-	unregister_syscore_ops(&msm_gpio_syscore_ops);
-	msm_gpio_remove();
-}
-
-postcore_initcall(msm_gpio_init);
-module_exit(msm_gpio_exit);
-
 static void msm_tlmm_set_field(const struct tlmm_field_cfg *configs,
 			       unsigned id, unsigned width, unsigned val)
 {
@@ -594,6 +526,89 @@
 }
 EXPORT_SYMBOL(msm_gpio_install_direct_irq);
 
+/*
+ * This lock class tells lockdep that GPIO irqs are in a different
+ * category than their parent, so it won't report false recursion.
+ */
+static struct lock_class_key msm_gpio_lock_class;
+
+static int __devinit msm_gpio_probe(struct platform_device *pdev)
+{
+	int ret;
+#ifndef CONFIG_OF
+	int irq, i;
+#endif
+	msm_gpio.gpio_chip.dev = &pdev->dev;
+	spin_lock_init(&tlmm_lock);
+	bitmap_zero(msm_gpio.enabled_irqs, NR_MSM_GPIOS);
+	bitmap_zero(msm_gpio.wake_irqs, NR_MSM_GPIOS);
+	bitmap_zero(msm_gpio.dual_edge_irqs, NR_MSM_GPIOS);
+	ret = gpiochip_add(&msm_gpio.gpio_chip);
+	if (ret < 0)
+		return ret;
+
+#ifndef CONFIG_OF
+	for (i = 0; i < msm_gpio.gpio_chip.ngpio; ++i) {
+		irq = msm_gpio_to_irq(&msm_gpio.gpio_chip, i);
+		irq_set_lockdep_class(irq, &msm_gpio_lock_class);
+		irq_set_chip_and_handler(irq, &msm_gpio_irq_chip,
+					 handle_level_irq);
+		set_irq_flags(irq, IRQF_VALID);
+	}
+#endif
+	ret = request_irq(TLMM_MSM_SUMMARY_IRQ, msm_summary_irq_handler,
+			IRQF_TRIGGER_HIGH, "msmgpio", NULL);
+	if (ret) {
+		pr_err("Request_irq failed for TLMM_MSM_SUMMARY_IRQ - %d\n",
+				ret);
+		return ret;
+	}
+	register_syscore_ops(&msm_gpio_syscore_ops);
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static struct of_device_id msm_gpio_of_match[] __devinitdata = {
+	{.compatible = "qcom,msm-gpio", },
+	{ },
+};
+#endif
+
+static int __devexit msm_gpio_remove(struct platform_device *pdev)
+{
+	int ret;
+
+	unregister_syscore_ops(&msm_gpio_syscore_ops);
+	ret = gpiochip_remove(&msm_gpio.gpio_chip);
+	if (ret < 0)
+		return ret;
+	irq_set_handler(TLMM_MSM_SUMMARY_IRQ, NULL);
+
+	return 0;
+}
+
+static struct platform_driver msm_gpio_driver = {
+	.probe = msm_gpio_probe,
+	.remove = __devexit_p(msm_gpio_remove),
+	.driver = {
+		.name = "msmgpio",
+		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(msm_gpio_of_match),
+	},
+};
+
+static void __exit msm_gpio_exit(void)
+{
+	platform_driver_unregister(&msm_gpio_driver);
+}
+module_exit(msm_gpio_exit);
+
+static int __init msm_gpio_init(void)
+{
+	return platform_driver_register(&msm_gpio_driver);
+}
+postcore_initcall(msm_gpio_init);
+
 #ifdef CONFIG_OF
 static int msm_gpio_irq_domain_xlate(struct irq_domain *d,
 				     struct device_node *controller,