diff --git a/include/sound/graph_card.h b/include/sound/graph_card.h
index c7b632d3e5ff..8bc8a78c0d03 100644
--- a/include/sound/graph_card.h
+++ b/include/sound/graph_card.h
@@ -18,6 +18,7 @@ struct graph_custom_hooks {
 	int (*hook_post)(struct asoc_simple_priv *priv);
 	GRAPH_CUSTOM custom_normal;
 	GRAPH_CUSTOM custom_dpcm;
+	GRAPH_CUSTOM custom_c2c;
 };
 
 int audio_graph_parse_of(struct asoc_simple_priv *priv, struct device *dev);
@@ -28,5 +29,7 @@ int rich_graph_link_normal(struct asoc_simple_priv *priv,
 			   struct device_node *lnk, struct link_info *li);
 int rich_graph_link_dpcm(struct asoc_simple_priv *priv,
 			 struct device_node *lnk, struct link_info *li);
+int rich_graph_link_c2c(struct asoc_simple_priv *priv,
+			struct device_node *lnk, struct link_info *li);
 
 #endif /* __GRAPH_CARD_H */
diff --git a/sound/soc/generic/rich-graph-card.c b/sound/soc/generic/rich-graph-card.c
index e69fb5e73d62..5a972eda037f 100644
--- a/sound/soc/generic/rich-graph-card.c
+++ b/sound/soc/generic/rich-graph-card.c
@@ -176,17 +176,54 @@ links indicates connection part of CPU side (= A).
 	};
  };
 
+ ************************************
+	Codec to Codec
+ ************************************
+
+ +--+
+ |  |<-- Codec0 <- IN
+ |  |--> Codec1 -> OUT
+ +--+
+
+ sound {
+	compatible = "rich-graph-card";
+
+	routing = "OUT" ,"DAI1 Playback",
+		  "DAI0 Capture", "IN";
+
+	links = <&c2c>;
+
+	codec2codec {
+		ports {
+			rate = <48000>;
+		c2c:	port@0 { c2cf_ep: endpoint { remote-endpoint = <&codec0_ep>; }; };
+			port@1 { c2cb_ep: endpoint { remote-endpoint = <&codec1_ep>; }; };
+	};
+ };
+
+ Codec {
+	ports {
+		port@0 {
+			bitclock-master;
+			frame-master;
+			 codec0_ep: endpoint { remote-endpoint = <&c2cf_ep>; }; };
+		port@1 { codec1_ep: endpoint { remote-endpoint = <&c2cb_ep>; }; };
+	};
+ };
+
 */
 
 enum graph_type {
 	GRAPH_NORMAL,
 	GRAPH_DPCM,
+	GRAPH_C2C,
 
 	GRAPH_MULTI,	/* don't use ! Use this only in __graph_get_type() */
 };
 
 #define GRAPH_NODENAME_MULTI	"multi"
 #define GRAPH_NODENAME_DPCM	"dpcm"
+#define GRAPH_NODENAME_C2C	"codec2codec"
 
 #define port_to_endpoint(port) of_get_child_by_name(port, "endpoint")
 
@@ -212,6 +249,9 @@ static enum graph_type __graph_get_type(struct device_node *lnk)
 	if (of_node_name_eq(np, GRAPH_NODENAME_DPCM))
 		return GRAPH_DPCM;
 
+	if (of_node_name_eq(np, GRAPH_NODENAME_C2C))
+		return GRAPH_C2C;
+
 	return GRAPH_NORMAL;
 }
 
@@ -236,6 +276,9 @@ static enum graph_type graph_get_type(struct asoc_simple_priv *priv,
 			else
 				str = "DPCM Back-End";
 			break;
+		case GRAPH_C2C:
+			str = "Codec2Codec";
+			break;
 		default:
 			break;
 		}
@@ -494,6 +537,13 @@ static int __graph_parse_node(struct asoc_simple_priv *priv,
 				asoc_simple_set_dailink_name(dev, dai_link, "be.%pOFP.%s%s",
 						codecs->of_node, codecs->dai_name, codec_multi);
 			break;
+		case GRAPH_C2C:
+			/* run is_cpu only. see rich_graph_link_c2c() */
+			if (is_cpu)
+				asoc_simple_set_dailink_name(dev, dai_link, "c2c.%s%s-%s%s",
+							     cpus->dai_name,   cpu_multi,
+							     codecs->dai_name, codec_multi);
+			break;
 		default:
 			break;
 		}
@@ -792,6 +842,88 @@ int rich_graph_link_dpcm(struct asoc_simple_priv *priv,
 }
 EXPORT_SYMBOL_GPL(rich_graph_link_dpcm);
 
+int rich_graph_link_c2c(struct asoc_simple_priv *priv,
+			struct device_node *lnk,
+			struct link_info *li)
+{
+	struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
+	struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link);
+	struct snd_soc_pcm_stream *c2c_conf = dai_props->c2c_conf;
+	struct device_node *port0, *port1, *ports;
+	struct device_node *codec0_port, *codec1_port;
+	struct device_node *ep0, *ep1;
+	u32 val;
+	int ret = -EINVAL;
+
+	/*
+	 * codec2codec {
+	 *	ports {
+	 *		rate = <48000>;
+	 * =>	lnk:	port@0 { c2c0_ep: { ... = codec0_ep; }; };
+	 *		port@1 { c2c1_ep: { ... = codec1_ep; }; };
+	 *	};
+	 * };
+	 *
+	 * Codec {
+	 *	ports {
+	 *		port@0 { codec0_ep: ... }; };
+	 *		port@1 { codec1_ep: ... }; };
+	 *	};
+	 * };
+	 */
+	of_node_get(lnk);
+	port0 = lnk;
+	ports = of_get_parent(port0);
+	port1 = of_get_next_child(ports, lnk);
+
+	if (!of_get_property(ports, "rate", &val)) {
+		struct device *dev = simple_priv_to_dev(priv);
+
+		dev_err(dev, "Codec2Codec needs rate settings\n");
+		goto err;
+	}
+
+	c2c_conf->formats	= SNDRV_PCM_FMTBIT_S32_LE; /* update ME */
+	c2c_conf->rate_min	=
+	c2c_conf->rate_max	= val;
+	c2c_conf->channels_min	=
+	c2c_conf->channels_max	= 2; /* update ME */
+	dai_link->params	= c2c_conf;
+
+	ep0 = port_to_endpoint(port0);
+	ep1 = port_to_endpoint(port1);
+
+	codec0_port = of_graph_get_remote_port(ep0);
+	codec1_port = of_graph_get_remote_port(ep1);
+
+	/*
+	 * call Codec first.
+	 * see
+	 *	__graph_parse_node() :: DAI Naming
+	 */
+	ret = graph_parse_node(priv, GRAPH_C2C, codec1_port, li, 0);
+	if (ret < 0)
+		goto err;
+
+	/*
+	 * call CPU, and set DAI Name
+	 */
+	ret = graph_parse_node(priv, GRAPH_C2C, codec0_port, li, 1);
+	if (ret < 0)
+		goto err;
+
+	graph_link_init(priv, codec0_port, li, 1);
+err:
+	of_node_put(ports);
+	of_node_put(port0);
+	of_node_put(port1);
+	of_node_put(ep0);
+	of_node_put(ep1);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(rich_graph_link_c2c);
+
 static int graph_link(struct asoc_simple_priv *priv,
 		      struct graph_custom_hooks *hooks,
 		      enum graph_type gtype,
@@ -815,6 +947,12 @@ static int graph_link(struct asoc_simple_priv *priv,
 		else
 			func = rich_graph_link_dpcm;
 		break;
+	case GRAPH_C2C:
+		if (hooks && hooks->custom_c2c)
+			func = hooks->custom_c2c;
+		else
+			func = rich_graph_link_c2c;
+		break;
 	default:
 		break;
 	}
@@ -916,6 +1054,43 @@ static int graph_count_dpcm(struct asoc_simple_priv *priv,
 	return 0;
 }
 
+static int graph_count_c2c(struct asoc_simple_priv *priv,
+			   struct device_node *lnk,
+			   struct link_info *li)
+{
+	struct device_node *ports = of_get_parent(lnk);
+	struct device_node *port0 = lnk;
+	struct device_node *port1 = of_get_next_child(ports, lnk);
+	struct device_node *ep0 = port_to_endpoint(port0);
+	struct device_node *ep1 = port_to_endpoint(port1);
+	struct device_node *codec0 = of_graph_get_remote_port(ep0);
+	struct device_node *codec1 = of_graph_get_remote_port(ep1);
+
+	of_node_get(lnk);
+
+	/*
+	 * codec2codec {
+	 *	ports {
+	 * =>	lnk:	port@0 { endpoint { ... }; };
+	 *		port@1 { endpoint { ... }; };
+	 *	};
+	 * };
+	 */
+	li->num[li->link].cpus		=
+	li->num[li->link].platforms	= graph_counter(codec0);
+	li->num[li->link].codecs	= graph_counter(codec1);
+	li->num[li->link].c2c		= 1;
+
+	of_node_put(ports);
+	of_node_put(port1);
+	of_node_put(ep0);
+	of_node_put(ep1);
+	of_node_put(codec0);
+	of_node_put(codec1);
+
+	return 0;
+}
+
 static int graph_count(struct asoc_simple_priv *priv,
 		       struct graph_custom_hooks *hooks,
 		       enum graph_type gtype,
@@ -938,6 +1113,9 @@ static int graph_count(struct asoc_simple_priv *priv,
 	case GRAPH_DPCM:
 		func = graph_count_dpcm;
 		break;
+	case GRAPH_C2C:
+		func = graph_count_c2c;
+		break;
 	default:
 	}
 
