diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index b156514..b7e1520 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -33,6 +33,13 @@ struct simple_card_data {
 	struct snd_soc_codec_conf *codec_conf;
 };
 
+struct link_dpcm {
+	int dais; /* number of dai  */
+	int link; /* number of link */
+	int conf; /* number of codec_conf */
+	int cpu;  /* CPU / Codec */
+};
+
 #define simple_priv_to_card(priv) (&(priv)->snd_card)
 #define simple_priv_to_props(priv, i) ((priv)->dai_props + (i))
 #define simple_priv_to_dev(priv) (simple_priv_to_card(priv)->dev)
@@ -180,30 +187,42 @@ static void asoc_simple_card_get_conversion(struct device *dev,
 	of_node_put(node);
 }
 
-static int asoc_simple_card_dai_link_of_dpcm(struct device_node *top,
-					     struct device_node *node,
+static int asoc_simple_card_dai_link_of_dpcm(struct simple_card_data *priv,
 					     struct device_node *np,
 					     struct device_node *codec,
-					     struct simple_card_data *priv,
-					     int *dai_idx, int link_idx,
-					     int *conf_idx, int is_fe,
-					     bool is_top_level_node)
+					     struct link_dpcm *ld, int is_top)
 {
 	struct device *dev = simple_priv_to_dev(priv);
-	struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, link_idx);
-	struct simple_dai_props *dai_props = simple_priv_to_props(priv, link_idx);
+	struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, ld->link);
+	struct simple_dai_props *dai_props = simple_priv_to_props(priv, ld->link);
 	struct asoc_simple_dai *dai;
 	struct snd_soc_dai_link_component *codecs = dai_link->codecs;
-
+	struct device_node *top = dev->of_node;
+	struct device_node *node = of_get_parent(np);
 	char prop[128];
 	char *prefix = "";
 	int ret;
 
+	/*
+	 *	 |CPU   |Codec   : turn
+	 * CPU	 |Pass  |return
+	 * Codec |return|Pass
+	 * np
+	 */
+	if (ld->cpu == (np == codec))
+		return 0;
+
+	dev_dbg(dev, "link_of DPCM (%pOF)\n", np);
+
+	ld->link++;
+
+	of_node_put(node);
+
 	/* For single DAI link & old style of DT node */
-	if (is_top_level_node)
+	if (is_top)
 		prefix = PREFIX;
 
-	if (is_fe) {
+	if (ld->cpu) {
 		int is_single_links = 0;
 
 		/* BE is dummy */
@@ -216,7 +235,7 @@ static int asoc_simple_card_dai_link_of_dpcm(struct device_node *top,
 		dai_link->dpcm_merged_format	= 1;
 
 		dai =
-		dai_props->cpu_dai	= &priv->dais[(*dai_idx)++];
+		dai_props->cpu_dai	= &priv->dais[ld->dais++];
 
 		ret = asoc_simple_card_parse_cpu(np, dai_link, DAI, CELL,
 						 &is_single_links);
@@ -247,10 +266,10 @@ static int asoc_simple_card_dai_link_of_dpcm(struct device_node *top,
 		dai_link->be_hw_params_fixup	= asoc_simple_card_be_hw_params_fixup;
 
 		dai =
-		dai_props->codec_dai	= &priv->dais[(*dai_idx)++];
+		dai_props->codec_dai	= &priv->dais[ld->dais++];
 
 		cconf =
-		dai_props->codec_conf	= &priv->codec_conf[(*conf_idx)++];
+		dai_props->codec_conf	= &priv->codec_conf[ld->conf++];
 
 		ret = asoc_simple_card_parse_codec(np, dai_link, DAI, CELL);
 		if (ret < 0)
@@ -303,53 +322,50 @@ static int asoc_simple_card_dai_link_of_dpcm(struct device_node *top,
 	return 0;
 }
 
-static int asoc_simple_card_dai_link_of(struct device_node *top,
-					struct device_node *node,
-					struct simple_card_data *priv,
-					int *dai_idx, int link_idx,
-					bool is_top_level_node)
+static int asoc_simple_card_dai_link_of(struct simple_card_data *priv,
+					struct device_node *np,
+					struct device_node *codec,
+					struct link_dpcm *ld, int is_top)
 {
 	struct device *dev = simple_priv_to_dev(priv);
-	struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, link_idx);
-	struct simple_dai_props *dai_props = simple_priv_to_props(priv, link_idx);
+	struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, ld->link);
+	struct simple_dai_props *dai_props = simple_priv_to_props(priv, ld->link);
 	struct asoc_simple_dai *cpu_dai;
 	struct asoc_simple_dai *codec_dai;
+	struct device_node *top = dev->of_node;
 	struct device_node *cpu = NULL;
+	struct device_node *node = NULL;
 	struct device_node *plat = NULL;
-	struct device_node *codec = NULL;
 	char prop[128];
 	char *prefix = "";
 	int ret, single_cpu;
 
-	/* For single DAI link & old style of DT node */
-	if (is_top_level_node)
-		prefix = PREFIX;
+	/*
+	 *	 |CPU   |Codec   : turn
+	 * CPU	 |Pass  |return
+	 * Codec |return|return
+	 * np
+	 */
+	if (!ld->cpu || np == codec)
+		return 0;
 
-	snprintf(prop, sizeof(prop), "%scpu", prefix);
-	cpu = of_get_child_by_name(node, prop);
+	cpu  = np;
+	node = of_get_parent(np);
+	ld->link++;
 
-	if (!cpu) {
-		ret = -EINVAL;
-		dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop);
-		goto dai_link_of_err;
-	}
+	dev_dbg(dev, "link_of (%pOF)\n", node);
+
+	/* For single DAI link & old style of DT node */
+	if (is_top)
+		prefix = PREFIX;
 
 	snprintf(prop, sizeof(prop), "%splat", prefix);
 	plat = of_get_child_by_name(node, prop);
 
-	snprintf(prop, sizeof(prop), "%scodec", prefix);
-	codec = of_get_child_by_name(node, prop);
-
-	if (!codec) {
-		ret = -EINVAL;
-		dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop);
-		goto dai_link_of_err;
-	}
-
 	cpu_dai			=
-	dai_props->cpu_dai	= &priv->dais[(*dai_idx)++];
+	dai_props->cpu_dai	= &priv->dais[ld->dais++];
 	codec_dai		=
-	dai_props->codec_dai	= &priv->dais[(*dai_idx)++];
+	dai_props->codec_dai	= &priv->dais[ld->dais++];
 
 	ret = asoc_simple_card_parse_daifmt(dev, node, codec,
 					    prefix, &dai_link->dai_fmt);
@@ -408,7 +424,7 @@ static int asoc_simple_card_dai_link_of(struct device_node *top,
 	asoc_simple_card_canonicalize_cpu(dai_link, single_cpu);
 
 dai_link_of_err:
-	of_node_put(cpu);
+	of_node_put(node);
 	of_node_put(codec);
 
 	return ret;
@@ -445,18 +461,79 @@ static int asoc_simple_card_parse_aux_devs(struct device_node *node,
 	return 0;
 }
 
+static int asoc_simple_card_for_each_link(struct simple_card_data *priv,
+			struct link_dpcm *ld,
+			int (*func_noml)(struct simple_card_data *priv,
+					 struct device_node *np,
+					 struct device_node *codec,
+					 struct link_dpcm *ld, int is_top),
+			int (*func_dpcm)(struct simple_card_data *priv,
+					 struct device_node *np,
+					 struct device_node *codec,
+					 struct link_dpcm *ld, int is_top))
+{
+	struct device *dev = simple_priv_to_dev(priv);
+	struct device_node *top = dev->of_node;
+	struct device_node *node;
+	int is_top = 0;
+
+	/* Check if it has dai-link */
+	node = of_get_child_by_name(top, PREFIX "dai-link");
+	if (!node) {
+		node = top;
+		is_top = 1;
+	}
+
+	/* loop for all dai-link */
+	do {
+		struct asoc_simple_card_data adata;
+		struct device_node *codec;
+		struct device_node *np;
+		int num = of_get_child_count(node);
+		int ret;
+
+		/* get codec */
+		codec = of_get_child_by_name(node, is_top ?
+					     PREFIX "codec" : "codec");
+		if (!codec)
+			return -ENODEV;
+
+		/* get convert-xxx property */
+		memset(&adata, 0, sizeof(adata));
+		for_each_child_of_node(node, np)
+			asoc_simple_card_get_conversion(dev, np, &adata);
+
+		/* loop for all CPU/Codec node */
+		for_each_child_of_node(node, np) {
+			/*
+			 * It is DPCM
+			 * if it has many CPUs,
+			 * or has convert-xxx property
+			 */
+			if (num > 2 ||
+			    adata.convert_rate || adata.convert_channels)
+				ret = func_dpcm(priv, np, codec, ld, is_top);
+			/* else normal sound */
+			else
+				ret = func_noml(priv, np, codec, ld, is_top);
+
+			if (ret < 0)
+				return ret;
+		}
+
+		node = of_get_next_child(top, node);
+	} while (!is_top && node);
+
+	return 0;
+}
+
 static int asoc_simple_card_parse_of(struct simple_card_data *priv)
 {
 	struct device *dev = simple_priv_to_dev(priv);
 	struct device_node *top = dev->of_node;
 	struct snd_soc_card *card = simple_priv_to_card(priv);
-	struct device_node *node;
-	struct device_node *np;
-	struct device_node *codec;
-	struct asoc_simple_card_data adata;
-	bool is_fe;
-	int ret, loop;
-	int dai_idx, link_idx, conf_idx;
+	struct link_dpcm ld;
+	int ret;
 
 	if (!top)
 		return -EINVAL;
@@ -470,51 +547,27 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv)
 		return ret;
 
 	/* Single/Muti DAI link(s) & New style of DT node */
-	loop		= 1;
-	link_idx	= 0;
-	dai_idx		= 0;
-	conf_idx	= 0;
-	node = of_get_child_by_name(top, PREFIX "dai-link");
-	if (!node) {
-		node = dev->of_node;
-		loop = 0;
+	memset(&ld, 0, sizeof(ld));
+	for (ld.cpu = 1; ld.cpu >= 0; ld.cpu--) {
+		/*
+		 * Detect all CPU first, and Detect all Codec 2nd.
+		 *
+		 * In Normal sound case, all DAIs are detected
+		 * as "CPU-Codec".
+		 *
+		 * In DPCM sound case,
+		 * all CPUs   are detected as "CPU-dummy", and
+		 * all Codecs are detected as "dummy-Codec".
+		 * To avoid random sub-device numbering,
+		 * detect "dummy-Codec" in last;
+		 */
+		ret = asoc_simple_card_for_each_link(priv, &ld,
+						     asoc_simple_card_dai_link_of,
+						     asoc_simple_card_dai_link_of_dpcm);
+		if (ret < 0)
+			return ret;
 	}
 
-	do  {
-		memset(&adata, 0, sizeof(adata));
-		for_each_child_of_node(node, np)
-			asoc_simple_card_get_conversion(dev, np, &adata);
-
-		/* DPCM */
-		if (of_get_child_count(node) > 2 ||
-		    adata.convert_rate || adata.convert_channels) {
-			for_each_child_of_node(node, np) {
-				codec = of_get_child_by_name(node,
-							loop ?	"codec" :
-								PREFIX "codec");
-				if (!codec)
-					return -ENODEV;
-
-				is_fe = (np != codec);
-
-				ret = asoc_simple_card_dai_link_of_dpcm(
-						top, node, np, codec, priv,
-						&dai_idx, link_idx++, &conf_idx,
-						is_fe, !loop);
-				if (ret < 0)
-					return ret;
-			}
-		} else {
-			ret = asoc_simple_card_dai_link_of(
-						top, node, priv,
-						&dai_idx, link_idx++, !loop);
-			if (ret < 0)
-				return ret;
-		}
-
-		node = of_get_next_child(top, node);
-	} while (loop && node);
-
 	ret = asoc_simple_card_parse_card_name(card, PREFIX);
 	if (ret < 0)
 		return ret;
@@ -524,17 +577,35 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv)
 	return ret;
 }
 
-static void asoc_simple_card_get_dais_count(struct device *dev,
-					    int *link_num,
-					    int *dais_num,
-					    int *ccnf_num)
+static int asoc_simple_card_count_noml(struct simple_card_data *priv,
+				       struct device_node *np,
+				       struct device_node *codec,
+				       struct link_dpcm *ld, int is_top)
 {
-	struct device_node *top = dev->of_node;
-	struct device_node *node;
-	struct device_node *np;
-	struct asoc_simple_card_data adata;
-	int loop;
-	int num;
+	ld->dais++; /* CPU or Codec */
+	if (np != codec)
+		ld->link++; /* CPU-Codec */
+
+	return 0;
+}
+
+static int asoc_simple_card_count_dpcm(struct simple_card_data *priv,
+				       struct device_node *np,
+				       struct device_node *codec,
+				       struct link_dpcm *ld, int is_top)
+{
+	ld->dais++; /* CPU or Codec */
+	ld->link++; /* CPU-dummy or dummy-Codec */
+	if (np == codec)
+		ld->conf++;
+
+	return 0;
+}
+
+static void asoc_simple_card_get_dais_count(struct simple_card_data *priv,
+					    struct link_dpcm *ld)
+{
+	struct device *dev = simple_priv_to_dev(priv);
 
 	/*
 	 * link_num :	number of links.
@@ -582,36 +653,12 @@ static void asoc_simple_card_get_dais_count(struct device *dev,
 	 *	=> 4 DAIs  = 2xCPU + 2xCodec
 	 *	=> 1 ccnf  = 1xdummy-Codec
 	 */
-	if (!top) {
-		(*link_num) = 1;
-		(*dais_num) = 2;
-		(*ccnf_num) = 0;
-		return;
-	}
-
-	loop = 1;
-	node = of_get_child_by_name(top, PREFIX "dai-link");
-	if (!node) {
-		node = top;
-		loop = 0;
-	}
-
-	do {
-		memset(&adata, 0, sizeof(adata));
-		for_each_child_of_node(node, np)
-			asoc_simple_card_get_conversion(dev, np, &adata);
+	asoc_simple_card_for_each_link(priv, ld,
+				       asoc_simple_card_count_noml,
+				       asoc_simple_card_count_dpcm);
 
-		num = of_get_child_count(node);
-		(*dais_num) += num;
-		if (num > 2 ||
-		    adata.convert_rate || adata.convert_channels) {
-			(*link_num) += num;
-			(*ccnf_num)++;
-		} else {
-			(*link_num)++;
-		}
-		node = of_get_next_child(top, node);
-	} while (loop && node);
+	dev_dbg(dev, "link %d, dais %d, ccnf %d\n",
+		ld->link, ld->dais, ld->conf);
 }
 
 static int asoc_simple_soc_card_probe(struct snd_soc_card *card)
@@ -640,7 +687,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
 	struct device_node *np = dev->of_node;
 	struct snd_soc_card *card;
 	struct snd_soc_codec_conf *cconf;
-	int lnum = 0, dnum = 0, cnum = 0;
+	struct link_dpcm ld;
 	int ret, i;
 
 	/* Allocate the private data and the DAI link array */
@@ -648,14 +695,20 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
 	if (!priv)
 		return -ENOMEM;
 
-	asoc_simple_card_get_dais_count(dev, &lnum, &dnum, &cnum);
-	if (!lnum || !dnum)
+	card = simple_priv_to_card(priv);
+	card->owner		= THIS_MODULE;
+	card->dev		= dev;
+	card->probe		= asoc_simple_soc_card_probe;
+
+	memset(&ld, 0, sizeof(ld));
+	asoc_simple_card_get_dais_count(priv, &ld);
+	if (!ld.link || !ld.dais)
 		return -EINVAL;
 
-	dai_props = devm_kcalloc(dev, lnum, sizeof(*dai_props), GFP_KERNEL);
-	dai_link  = devm_kcalloc(dev, lnum, sizeof(*dai_link),  GFP_KERNEL);
-	dais      = devm_kcalloc(dev, dnum, sizeof(*dais),      GFP_KERNEL);
-	cconf     = devm_kcalloc(dev, cnum, sizeof(*cconf),     GFP_KERNEL);
+	dai_props = devm_kcalloc(dev, ld.link, sizeof(*dai_props), GFP_KERNEL);
+	dai_link  = devm_kcalloc(dev, ld.link, sizeof(*dai_link),  GFP_KERNEL);
+	dais      = devm_kcalloc(dev, ld.dais, sizeof(*dais),      GFP_KERNEL);
+	cconf     = devm_kcalloc(dev, ld.conf, sizeof(*cconf),     GFP_KERNEL);
 	if (!dai_props || !dai_link || !dais)
 		return -ENOMEM;
 
@@ -665,26 +718,21 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
 	 * see
 	 *	soc-core.c :: snd_soc_init_multicodec()
 	 */
-	for (i = 0; i < lnum; i++) {
+	for (i = 0; i < ld.link; i++) {
 		dai_link[i].codecs	= &dai_props[i].codecs;
 		dai_link[i].num_codecs	= 1;
 		dai_link[i].platform	= &dai_props[i].platform;
 	}
 
-	priv->dai_props			= dai_props;
-	priv->dai_link			= dai_link;
-	priv->dais			= dais;
-	priv->codec_conf		= cconf;
+	priv->dai_props		= dai_props;
+	priv->dai_link		= dai_link;
+	priv->dais		= dais;
+	priv->codec_conf	= cconf;
 
-	/* Init snd_soc_card */
-	card = simple_priv_to_card(priv);
-	card->owner		= THIS_MODULE;
-	card->dev		= dev;
-	card->dai_link		= priv->dai_link;
-	card->num_links		= lnum;
+	card->dai_link		= dai_link;
+	card->num_links		= ld.link;
 	card->codec_conf	= cconf;
-	card->num_configs	= cnum;
-	card->probe		= asoc_simple_soc_card_probe;
+	card->num_configs	= ld.conf;
 
 	if (np && of_device_is_available(np)) {
 
