msm: smd: migrate 8974 support in smd to device tree

Migrate the SMD support for the 8974 target away from the legacy
platform data mechanism to the new device tree mechanism.

Change-Id: I786b2a8e8b0125fc0a28f2d6a76cdea8b26a8488
Signed-off-by: Jeffrey Hugo <jhugo@codeaurora.org>
diff --git a/Documentation/devicetree/bindings/arm/msm/smem.txt b/Documentation/devicetree/bindings/arm/msm/smem.txt
new file mode 100644
index 0000000..a38984c
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/smem.txt
@@ -0,0 +1,107 @@
+Qualcomm Shared Memory
+
+[Root level node]
+Required properties:
+-compatible : should be "qcom,smem"
+-reg : the location and size of smem, the irq register base memory, and
+	optionally any auxiliary smem areas
+-reg-names : "smem" - string to identify the shared memory region
+	     "irq-reg-base" - string to identify the irq register region
+	     "aux-mem1", "aux-mem2", "aux-mem3", ... - optional strings to
+			identify any auxiliary shared memory regions
+
+[Second level nodes]
+
+qcom,smd
+Required properties:
+-compatible : should be "qcom,smd"
+-qcom,smd-edge : the smd edge
+-qcom,smd-irq-offset : the offset into the irq register base memory for sending
+	interrupts
+-qcom,smd-irq-bitmask : the sending irq bitmask
+-interrupts : the receiving interrupt line
+
+Optional properties:
+-qcom,pil-string : the name to use when loading this edge
+-qcom,irq-no-suspend: configure the incoming irq line as active during suspend
+
+qcom,smsm
+Required properties:
+-compatible : should be "qcom,smsm"
+-qcom,smsm-edge : the smsm edge
+-qcom,smsm-irq-offset : the offset into the irq register base memory for sending
+	interrupts
+-qcom,smsm-irq-bitmask : the sending irq bitmask
+-interrupts : the receiving interrupt line
+
+
+Example:
+
+	qcom,smem@fa00000 {
+		compatible = "qcom,smem";
+		reg = <0xfa00000 0x200000>,
+			<0xfa006000 0x1000>,
+			<0xfc428000 0x4000>;
+		reg-names = "smem", "irq-reg-base", "aux-mem1";
+
+		qcom,smd-modem {
+			compatible = "qcom,smd";
+			qcom,smd-edge = <0>;
+			qcom,smd-irq-offset = <0x8>;
+			qcom,smd-irq-bitmask = <0x1000>;
+			qcom,pil-string = "modem";
+			interrupts = <0 25 1>;
+		};
+
+		qcom,smsm-modem {
+			compatible = "qcom,smsm";
+			qcom,smsm-edge = <0>;
+			qcom,smsm-irq-offset = <0x8>;
+			qcom,smsm-irq-bitmask = <0x2000>;
+			interrupts = <0 26 1>;
+		};
+
+		qcom,smd-adsp {
+			compatible = "qcom,smd";
+			qcom,smd-edge = <1>;
+			qcom,smd-irq-offset = <0x8>;
+			qcom,smd-irq-bitmask = <0x100>;
+			qcom,pil-string = "adsp";
+			interrupts = <0 156 1>;
+		};
+
+		qcom,smsm-adsp {
+			compatible = "qcom,smsm";
+			qcom,smsm-edge = <1>;
+			qcom,smsm-irq-offset = <0x8>;
+			qcom,smsm-irq-bitmask = <0x200>;
+			interrupts = <0 157 1>;
+		};
+
+		qcom,smd-wcnss {
+			compatible = "qcom,smd";
+			qcom,smd-edge = <6>;
+			qcom,smd-irq-offset = <0x8>;
+			qcom,smd-irq-bitmask = <0x20000>;
+			qcom,pil-string = "wcnss";
+			interrupts = <0 142 1>;
+		};
+
+		qcom,smsm-wcnss {
+			compatible = "qcom,smsm";
+			qcom,smsm-edge = <6>;
+			qcom,smsm-irq-offset = <0x8>;
+			qcom,smsm-irq-bitmask = <0x80000>;
+			interrupts = <0 144 1>;
+		};
+
+		qcom,smd-rpm {
+			compatible = "qcom,smd";
+			qcom,smd-edge = <15>;
+			qcom,smd-irq-offset = <0x8>;
+			qcom,smd-irq-bitmask = <0x1>;
+			interrupts = <0 168 1>;
+			qcom,irq-no-syspend;
+		};
+	};
+
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 98f0b3b..0313ada 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -1237,6 +1237,74 @@
                 compatible = "qcom,msm-mem-hole";
                 qcom,memblock-remove = <0x8400000 0x7b00000>; /* Address and Size of Hole */
         };
+
+	qcom,smem@fa00000 {
+		compatible = "qcom,smem";
+		reg = <0xfa00000 0x200000>,
+			<0xfa006000 0x1000>,
+			<0xfc428000 0x4000>;
+		reg-names = "smem", "irq-reg-base", "aux-mem1";
+
+		qcom,smd-modem {
+			compatible = "qcom,smd";
+			qcom,smd-edge = <0>;
+			qcom,smd-irq-offset = <0x8>;
+			qcom,smd-irq-bitmask = <0x1000>;
+			qcom,pil-string = "modem";
+			interrupts = <0 25 1>;
+		};
+
+		qcom,smsm-modem {
+			compatible = "qcom,smsm";
+			qcom,smsm-edge = <0>;
+			qcom,smsm-irq-offset = <0x8>;
+			qcom,smsm-irq-bitmask = <0x2000>;
+			interrupts = <0 26 1>;
+		};
+
+		qcom,smd-adsp {
+			compatible = "qcom,smd";
+			qcom,smd-edge = <1>;
+			qcom,smd-irq-offset = <0x8>;
+			qcom,smd-irq-bitmask = <0x100>;
+			qcom,pil-string = "adsp";
+			interrupts = <0 156 1>;
+		};
+
+		qcom,smsm-adsp {
+			compatible = "qcom,smsm";
+			qcom,smsm-edge = <1>;
+			qcom,smsm-irq-offset = <0x8>;
+			qcom,smsm-irq-bitmask = <0x200>;
+			interrupts = <0 157 1>;
+		};
+
+		qcom,smd-wcnss {
+			compatible = "qcom,smd";
+			qcom,smd-edge = <6>;
+			qcom,smd-irq-offset = <0x8>;
+			qcom,smd-irq-bitmask = <0x20000>;
+			qcom,pil-string = "wcnss";
+			interrupts = <0 142 1>;
+		};
+
+		qcom,smsm-wcnss {
+			compatible = "qcom,smsm";
+			qcom,smsm-edge = <6>;
+			qcom,smsm-irq-offset = <0x8>;
+			qcom,smsm-irq-bitmask = <0x80000>;
+			interrupts = <0 144 1>;
+		};
+
+		qcom,smd-rpm {
+			compatible = "qcom,smd";
+			qcom,smd-edge = <15>;
+			qcom,smd-irq-offset = <0x8>;
+			qcom,smd-irq-bitmask = <0x1>;
+			interrupts = <0 168 1>;
+			qcom,irq-no-suspend;
+		};
+	};
 };
 
 /include/ "msm-pm8x41-rpm-regulator.dtsi"
diff --git a/arch/arm/mach-msm/board-8974.c b/arch/arm/mach-msm/board-8974.c
index 98a82b1..b092a53 100644
--- a/arch/arm/mach-msm/board-8974.c
+++ b/arch/arm/mach-msm/board-8974.c
@@ -66,168 +66,6 @@
 	return MEMTYPE_EBI1;
 }
 
-static struct resource smd_resource[] = {
-	{
-		.name	= "modem_smd_in",
-		.start	= 32 + 25,		/* mss_sw_to_kpss_ipc_irq0  */
-		.flags	= IORESOURCE_IRQ,
-	},
-	{
-		.name	= "modem_smsm_in",
-		.start	= 32 + 26,		/* mss_sw_to_kpss_ipc_irq1  */
-		.flags	= IORESOURCE_IRQ,
-	},
-	{
-		.name	= "adsp_smd_in",
-		.start	= 32 + 156,		/* lpass_to_kpss_ipc_irq0  */
-		.flags	= IORESOURCE_IRQ,
-	},
-	{
-		.name	= "adsp_smsm_in",
-		.start	= 32 + 157,		/* lpass_to_kpss_ipc_irq1  */
-		.flags	= IORESOURCE_IRQ,
-	},
-	{
-		.name	= "wcnss_smd_in",
-		.start	= 32 + 142,		/* WcnssAppsSmdMedIrq  */
-		.flags	= IORESOURCE_IRQ,
-	},
-	{
-		.name	= "wcnss_smsm_in",
-		.start	= 32 + 144,		/* RivaAppsWlanSmsmIrq  */
-		.flags	= IORESOURCE_IRQ,
-	},
-	{
-		.name	= "rpm_smd_in",
-		.start	= 32 + 168,		/* rpm_to_kpss_ipc_irq4  */
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static struct smd_subsystem_config smd_config_list[] = {
-	{
-		.irq_config_id = SMD_MODEM,
-		.subsys_name = "modem",
-		.edge = SMD_APPS_MODEM,
-
-		.smd_int.irq_name = "modem_smd_in",
-		.smd_int.flags = IRQF_TRIGGER_RISING,
-		.smd_int.irq_id = -1,
-		.smd_int.device_name = "smd_dev",
-		.smd_int.dev_id = 0,
-		.smd_int.out_bit_pos = 1 << 12,
-		.smd_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
-		.smd_int.out_offset = 0x8,
-
-		.smsm_int.irq_name = "modem_smsm_in",
-		.smsm_int.flags = IRQF_TRIGGER_RISING,
-		.smsm_int.irq_id = -1,
-		.smsm_int.device_name = "smsm_dev",
-		.smsm_int.dev_id = 0,
-		.smsm_int.out_bit_pos = 1 << 13,
-		.smsm_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
-		.smsm_int.out_offset = 0x8,
-	},
-	{
-		.irq_config_id = SMD_Q6,
-		.subsys_name = "adsp",
-		.edge = SMD_APPS_QDSP,
-
-		.smd_int.irq_name = "adsp_smd_in",
-		.smd_int.flags = IRQF_TRIGGER_RISING,
-		.smd_int.irq_id = -1,
-		.smd_int.device_name = "smd_dev",
-		.smd_int.dev_id = 0,
-		.smd_int.out_bit_pos = 1 << 8,
-		.smd_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
-		.smd_int.out_offset = 0x8,
-
-		.smsm_int.irq_name = "adsp_smsm_in",
-		.smsm_int.flags = IRQF_TRIGGER_RISING,
-		.smsm_int.irq_id = -1,
-		.smsm_int.device_name = "smsm_dev",
-		.smsm_int.dev_id = 0,
-		.smsm_int.out_bit_pos = 1 << 9,
-		.smsm_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
-		.smsm_int.out_offset = 0x8,
-	},
-	{
-		.irq_config_id = SMD_WCNSS,
-		.subsys_name = "wcnss",
-		.edge = SMD_APPS_WCNSS,
-
-		.smd_int.irq_name = "wcnss_smd_in",
-		.smd_int.flags = IRQF_TRIGGER_RISING,
-		.smd_int.irq_id = -1,
-		.smd_int.device_name = "smd_dev",
-		.smd_int.dev_id = 0,
-		.smd_int.out_bit_pos = 1 << 17,
-		.smd_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
-		.smd_int.out_offset = 0x8,
-
-		.smsm_int.irq_name = "wcnss_smsm_in",
-		.smsm_int.flags = IRQF_TRIGGER_RISING,
-		.smsm_int.irq_id = -1,
-		.smsm_int.device_name = "smsm_dev",
-		.smsm_int.dev_id = 0,
-		.smsm_int.out_bit_pos = 1 << 19,
-		.smsm_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
-		.smsm_int.out_offset = 0x8,
-	},
-	{
-		.irq_config_id = SMD_RPM,
-		.subsys_name = NULL, /* do not use PIL to load RPM */
-		.edge = SMD_APPS_RPM,
-
-		.smd_int.irq_name = "rpm_smd_in",
-		.smd_int.flags = IRQF_TRIGGER_RISING | IRQF_NO_SUSPEND,
-		.smd_int.irq_id = -1,
-		.smd_int.device_name = "smd_dev",
-		.smd_int.dev_id = 0,
-		.smd_int.out_bit_pos = 1 << 0,
-		.smd_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
-		.smd_int.out_offset = 0x8,
-
-		.smsm_int.irq_name = NULL, /* RPM does not support SMSM */
-		.smsm_int.flags = 0,
-		.smsm_int.irq_id = 0,
-		.smsm_int.device_name = NULL,
-		.smsm_int.dev_id = 0,
-		.smsm_int.out_bit_pos = 0,
-		.smsm_int.out_base = NULL,
-		.smsm_int.out_offset = 0,
-	},
-};
-
-static struct smd_smem_regions aux_smem_areas[] = {
-	{
-		.phys_addr = (void *)(0xfc428000),
-		.size = 0x4000,
-	},
-};
-
-static struct smd_subsystem_restart_config smd_ssr_cfg = {
-	.disable_smsm_reset_handshake = 1,
-};
-
-static struct smd_platform smd_platform_data = {
-	.num_ss_configs = ARRAY_SIZE(smd_config_list),
-	.smd_ss_configs = smd_config_list,
-	.smd_ssr_config = &smd_ssr_cfg,
-	.num_smem_areas = ARRAY_SIZE(aux_smem_areas),
-	.smd_smem_areas = aux_smem_areas,
-};
-
-struct platform_device msm_device_smd_8974 = {
-	.name	= "msm_smd",
-	.id	= -1,
-	.resource = smd_resource,
-	.num_resources = ARRAY_SIZE(smd_resource),
-	.dev = {
-		.platform_data = &smd_platform_data,
-	}
-};
-
 static struct reserve_info msm8974_reserve_info __initdata = {
 	.memtype_reserve_table = msm8974_reserve_table,
 	.paddr_to_memtype = msm8974_paddr_to_memtype,
@@ -426,11 +264,6 @@
 				ARRAY_SIZE(msm_bus_8974_devices));
 };
 
-void __init msm8974_add_devices(void)
-{
-	platform_device_register(&msm_device_smd_8974);
-}
-
 /*
  * Used to satisfy dependencies for devices that need to be
  * run early or in a particular order. Most likely your device doesn't fall
@@ -536,7 +369,6 @@
 	regulator_has_full_constraints();
 	of_platform_populate(NULL, of_default_bus_match_table, adata, NULL);
 
-	msm8974_add_devices();
 	msm8974_add_drivers();
 }
 
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index b1dd1db..7427899 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -36,6 +36,8 @@
 #include <linux/notifier.h>
 #include <linux/sort.h>
 #include <linux/suspend.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
 #include <mach/msm_smd.h>
 #include <mach/msm_iomap.h>
 #include <mach/system.h>
@@ -3502,6 +3504,295 @@
 	return err_ret;
 }
 
+static int __devinit parse_smd_devicetree(struct device_node *node,
+						void *irq_out_base)
+{
+	uint32_t edge;
+	char *key;
+	int ret;
+	uint32_t irq_offset;
+	uint32_t irq_bitmask;
+	uint32_t irq_line;
+	unsigned long irq_flags = IRQF_TRIGGER_RISING;
+	const char *pilstr;
+	struct interrupt_config_item *private_irq;
+
+	key = "qcom,smd-edge";
+	ret = of_property_read_u32(node, key, &edge);
+	if (ret)
+		goto missing_key;
+	SMD_DBG("%s: %s = %d", __func__, key, edge);
+
+	key = "qcom,smd-irq-offset";
+	ret = of_property_read_u32(node, key, &irq_offset);
+	if (ret)
+		goto missing_key;
+	SMD_DBG("%s: %s = %x", __func__, key, irq_offset);
+
+	key = "qcom,smd-irq-bitmask";
+	ret = of_property_read_u32(node, key, &irq_bitmask);
+	if (ret)
+		goto missing_key;
+	SMD_DBG("%s: %s = %x", __func__, key, irq_bitmask);
+
+	key = "interrupts";
+	irq_line = irq_of_parse_and_map(node, 0);
+	if (!irq_line)
+		goto missing_key;
+	SMD_DBG("%s: %s = %d", __func__, key, irq_line);
+
+	key = "qcom,pil-string";
+	pilstr = of_get_property(node, key, NULL);
+	if (pilstr)
+		SMD_DBG("%s: %s = %s", __func__, key, pilstr);
+
+	key = "qcom,irq-no-suspend";
+	ret = of_property_read_bool(node, key);
+	if (ret)
+		irq_flags |= IRQF_NO_SUSPEND;
+
+	private_irq = &private_intr_config[edge_to_pids[edge].remote_pid].smd;
+	private_irq->out_bit_pos = irq_bitmask;
+	private_irq->out_offset = irq_offset;
+	private_irq->out_base = irq_out_base;
+	private_irq->irq_id = irq_line;
+
+	ret = request_irq(irq_line,
+				private_irq->irq_handler,
+				irq_flags,
+				"smd_dev",
+				NULL);
+	if (ret < 0) {
+		pr_err("%s: request_irq() failed on %d\n", __func__, irq_line);
+		return ret;
+	} else {
+		ret = enable_irq_wake(irq_line);
+		if (ret < 0)
+			pr_err("%s: enable_irq_wake() failed on %d\n", __func__,
+					irq_line);
+	}
+
+	if (pilstr)
+		strlcpy(edge_to_pids[edge].subsys_name, pilstr,
+						SMD_MAX_CH_NAME_LEN);
+
+	return 0;
+
+missing_key:
+	pr_err("%s: missing key: %s", __func__, key);
+	return -ENODEV;
+}
+
+static int __devinit parse_smsm_devicetree(struct device_node *node,
+						void *irq_out_base)
+{
+	uint32_t edge;
+	char *key;
+	int ret;
+	uint32_t irq_offset;
+	uint32_t irq_bitmask;
+	uint32_t irq_line;
+	struct interrupt_config_item *private_irq;
+
+	key = "qcom,smsm-edge";
+	ret = of_property_read_u32(node, key, &edge);
+	if (ret)
+		goto missing_key;
+	SMD_DBG("%s: %s = %d", __func__, key, edge);
+
+	key = "qcom,smsm-irq-offset";
+	ret = of_property_read_u32(node, key, &irq_offset);
+	if (ret)
+		goto missing_key;
+	SMD_DBG("%s: %s = %x", __func__, key, irq_offset);
+
+	key = "qcom,smsm-irq-bitmask";
+	ret = of_property_read_u32(node, key, &irq_bitmask);
+	if (ret)
+		goto missing_key;
+	SMD_DBG("%s: %s = %x", __func__, key, irq_bitmask);
+
+	key = "interrupts";
+	irq_line = irq_of_parse_and_map(node, 0);
+	if (!irq_line)
+		goto missing_key;
+	SMD_DBG("%s: %s = %d", __func__, key, irq_line);
+
+	private_irq = &private_intr_config[edge_to_pids[edge].remote_pid].smsm;
+	private_irq->out_bit_pos = irq_bitmask;
+	private_irq->out_offset = irq_offset;
+	private_irq->out_base = irq_out_base;
+	private_irq->irq_id = irq_line;
+
+	ret = request_irq(irq_line,
+				private_irq->irq_handler,
+				IRQF_TRIGGER_RISING,
+				"smsm_dev",
+				NULL);
+	if (ret < 0) {
+		pr_err("%s: request_irq() failed on %d\n", __func__, irq_line);
+		return ret;
+	} else {
+		ret = enable_irq_wake(irq_line);
+		if (ret < 0)
+			pr_err("%s: enable_irq_wake() failed on %d\n", __func__,
+					irq_line);
+	}
+
+	return 0;
+
+missing_key:
+	pr_err("%s: missing key: %s", __func__, key);
+	return -ENODEV;
+}
+
+static void __devinit unparse_smd_devicetree(struct device_node *node)
+{
+	uint32_t irq_line;
+
+	irq_line = irq_of_parse_and_map(node, 0);
+
+	free_irq(irq_line, NULL);
+}
+
+static void __devinit unparse_smsm_devicetree(struct device_node *node)
+{
+	uint32_t irq_line;
+
+	irq_line = irq_of_parse_and_map(node, 0);
+
+	free_irq(irq_line, NULL);
+}
+
+static int __devinit smd_core_devicetree_init(struct platform_device *pdev)
+{
+	char *key;
+	struct resource *r;
+	void *irq_out_base;
+	void *aux_mem_base;
+	uint32_t aux_mem_size;
+	int temp_string_size = 11; /* max 3 digit count */
+	char temp_string[temp_string_size];
+	int count;
+	struct device_node *node;
+	int ret;
+	const char *compatible;
+	int subnode_num = 0;
+
+	disable_smsm_reset_handshake = 1;
+
+	key = "irq-reg-base";
+	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, key);
+	if (!r) {
+		pr_err("%s: missing '%s'\n", __func__, key);
+		return -ENODEV;
+	}
+	irq_out_base = (void *)(r->start);
+	SMD_DBG("%s: %s = %p", __func__, key, irq_out_base);
+
+	count = 1;
+	while (1) {
+		scnprintf(temp_string, temp_string_size, "aux-mem%d", count);
+		r = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+								temp_string);
+		if (!r)
+			break;
+
+		++num_smem_areas;
+		++count;
+		if (count > 999) {
+			pr_err("%s: max num aux mem regions reached\n",
+								__func__);
+			break;
+		}
+	}
+
+	if (num_smem_areas) {
+		smem_areas = kmalloc(sizeof(struct smem_area) * num_smem_areas,
+					GFP_KERNEL);
+		if (!smem_areas) {
+			pr_err("%s: smem areas kmalloc failed\n", __func__);
+			num_smem_areas = 0;
+			return -ENOMEM;
+		}
+		count = 1;
+		while (1) {
+			scnprintf(temp_string, temp_string_size, "aux-mem%d",
+									count);
+			r = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+								temp_string);
+			if (!r)
+				break;
+			aux_mem_base = (void *)(r->start);
+			aux_mem_size = (uint32_t)(resource_size(r));
+			SMD_DBG("%s: %s = %p %x", __func__, temp_string,
+					aux_mem_base, aux_mem_size);
+			smem_areas[count - 1].phys_addr = aux_mem_base;
+			smem_areas[count - 1].size = aux_mem_size;
+			smem_areas[count - 1].virt_addr = ioremap_nocache(
+				(unsigned long)(smem_areas[count-1].phys_addr),
+				smem_areas[count - 1].size);
+			if (!smem_areas[count - 1].virt_addr) {
+				pr_err("%s: ioremap_nocache() of addr:%p size: %x\n",
+					__func__,
+					smem_areas[count - 1].phys_addr,
+					smem_areas[count - 1].size);
+				ret = -ENOMEM;
+				goto free_smem_areas;
+			}
+
+			++count;
+			if (count > 999) {
+				pr_err("%s: max num aux mem regions reached\n",
+								__func__);
+				break;
+			}
+		}
+		sort(smem_areas, num_smem_areas,
+				sizeof(struct smem_area),
+				sort_cmp_func, NULL);
+	}
+
+	for_each_child_of_node(pdev->dev.of_node, node) {
+		compatible = of_get_property(node, "compatible", NULL);
+		if (!strcmp(compatible, "qcom,smd")) {
+			ret = parse_smd_devicetree(node, irq_out_base);
+			if (ret)
+				goto rollback_subnodes;
+		} else if (!strcmp(compatible, "qcom,smsm")) {
+			ret = parse_smsm_devicetree(node, irq_out_base);
+			if (ret)
+				goto rollback_subnodes;
+		} else {
+			pr_err("%s: invalid child node named: %s\n", __func__,
+							compatible);
+			ret = -ENODEV;
+			goto rollback_subnodes;
+		}
+		++subnode_num;
+	}
+
+	return 0;
+
+rollback_subnodes:
+	count = 0;
+	for_each_child_of_node(pdev->dev.of_node, node) {
+		if (count >= subnode_num)
+			break;
+		++count;
+		compatible = of_get_property(node, "compatible", NULL);
+		if (!strcmp(compatible, "qcom,smd"))
+			unparse_smd_devicetree(node);
+		else
+			unparse_smsm_devicetree(node);
+	}
+free_smem_areas:
+	num_smem_areas = 0;
+	kfree(smem_areas);
+	smem_areas = NULL;
+	return ret;
+}
+
 static int __devinit msm_smd_probe(struct platform_device *pdev)
 {
 	int ret;
@@ -3522,8 +3813,12 @@
 
 	if (pdev) {
 		if (pdev->dev.of_node) {
-			pr_err("SMD: Device tree not currently supported\n");
-			return -ENODEV;
+			ret = smd_core_devicetree_init(pdev);
+			if (ret) {
+				pr_err("%s: device tree init failed\n",
+								__func__);
+				return ret;
+			}
 		} else if (pdev->dev.platform_data) {
 			ret = smd_core_platform_init(pdev);
 			if (ret) {
@@ -3600,11 +3895,17 @@
 }
 late_initcall(modem_restart_late_init);
 
+static struct of_device_id msm_smem_match_table[] = {
+	{ .compatible = "qcom,smem" },
+	{},
+};
+
 static struct platform_driver msm_smd_driver = {
 	.probe = msm_smd_probe,
 	.driver = {
 		.name = MODULE_NAME,
 		.owner = THIS_MODULE,
+		.of_match_table = msm_smem_match_table,
 	},
 };