Merge branch 'asoc-fix-rcar' into HEAD
diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt
index 2dd690b..f316ce1 100644
--- a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt
+++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt
@@ -29,9 +29,17 @@
 - shared-pin			: if shared clock pin
 - pio-transfer			: use PIO transfer mode
 - no-busif			: BUSIF is not ussed when [mem -> SSI] via DMA case
+- dma				: Should contain Audio DMAC entry
+- dma-names			: SSI  case "rx"  (=playback), "tx"  (=capture)
+				  SSIU case "rxu" (=playback), "txu" (=capture)
 
 SRC subnode properties:
-no properties at this point
+- dma				: Should contain Audio DMAC entry
+- dma-names			: "rx" (=playback), "tx" (=capture)
+
+DVC subnode properties:
+- dma				: Should contain Audio DMAC entry
+- dma-names			: "tx" (=playback/capture)
 
 DAI subnode properties:
 - playback			: list of playback modules
@@ -45,56 +53,145 @@
 	reg =	<0 0xec500000 0 0x1000>, /* SCU */
 		<0 0xec5a0000 0 0x100>,  /* ADG */
 		<0 0xec540000 0 0x1000>, /* SSIU */
-		<0 0xec541000 0 0x1280>; /* SSI */
+		<0 0xec541000 0 0x1280>, /* SSI */
+		<0 0xec740000 0 0x200>;  /* Audio DMAC peri peri*/
+	reg-names = "scu", "adg", "ssiu", "ssi", "audmapp";
+
+	clocks = <&mstp10_clks R8A7790_CLK_SSI_ALL>,
+		<&mstp10_clks R8A7790_CLK_SSI9>, <&mstp10_clks R8A7790_CLK_SSI8>,
+		<&mstp10_clks R8A7790_CLK_SSI7>, <&mstp10_clks R8A7790_CLK_SSI6>,
+		<&mstp10_clks R8A7790_CLK_SSI5>, <&mstp10_clks R8A7790_CLK_SSI4>,
+		<&mstp10_clks R8A7790_CLK_SSI3>, <&mstp10_clks R8A7790_CLK_SSI2>,
+		<&mstp10_clks R8A7790_CLK_SSI1>, <&mstp10_clks R8A7790_CLK_SSI0>,
+		<&mstp10_clks R8A7790_CLK_SCU_SRC9>, <&mstp10_clks R8A7790_CLK_SCU_SRC8>,
+		<&mstp10_clks R8A7790_CLK_SCU_SRC7>, <&mstp10_clks R8A7790_CLK_SCU_SRC6>,
+		<&mstp10_clks R8A7790_CLK_SCU_SRC5>, <&mstp10_clks R8A7790_CLK_SCU_SRC4>,
+		<&mstp10_clks R8A7790_CLK_SCU_SRC3>, <&mstp10_clks R8A7790_CLK_SCU_SRC2>,
+		<&mstp10_clks R8A7790_CLK_SCU_SRC1>, <&mstp10_clks R8A7790_CLK_SCU_SRC0>,
+		<&mstp10_clks R8A7790_CLK_SCU_DVC0>, <&mstp10_clks R8A7790_CLK_SCU_DVC1>,
+		<&audio_clk_a>, <&audio_clk_b>, <&audio_clk_c>, <&m2_clk>;
+	clock-names = "ssi-all",
+			"ssi.9", "ssi.8", "ssi.7", "ssi.6", "ssi.5",
+			"ssi.4", "ssi.3", "ssi.2", "ssi.1", "ssi.0",
+			"src.9", "src.8", "src.7", "src.6", "src.5",
+			"src.4", "src.3", "src.2", "src.1", "src.0",
+			"dvc.0", "dvc.1",
+			"clk_a", "clk_b", "clk_c", "clk_i";
 
 	rcar_sound,dvc {
-		dvc0: dvc@0 { };
-		dvc1: dvc@1 { };
+		dvc0: dvc@0 {
+			dmas = <&audma0 0xbc>;
+			dma-names = "tx";
+		};
+		dvc1: dvc@1 {
+			dmas = <&audma0 0xbe>;
+			dma-names = "tx";
+		};
 	};
 
 	rcar_sound,src {
-		src0: src@0 { };
-		src1: src@1 { };
-		src2: src@2 { };
-		src3: src@3 { };
-		src4: src@4 { };
-		src5: src@5 { };
-		src6: src@6 { };
-		src7: src@7 { };
-		src8: src@8 { };
-		src9: src@9 { };
+		src0: src@0 {
+			interrupts = <0 352 IRQ_TYPE_LEVEL_HIGH>;
+			dmas = <&audma0 0x85>, <&audma1 0x9a>;
+			dma-names = "rx", "tx";
+		};
+		src1: src@1 {
+			interrupts = <0 353 IRQ_TYPE_LEVEL_HIGH>;
+			dmas = <&audma0 0x87>, <&audma1 0x9c>;
+			dma-names = "rx", "tx";
+		};
+		src2: src@2 {
+			interrupts = <0 354 IRQ_TYPE_LEVEL_HIGH>;
+			dmas = <&audma0 0x89>, <&audma1 0x9e>;
+			dma-names = "rx", "tx";
+		};
+		src3: src@3 {
+			interrupts = <0 355 IRQ_TYPE_LEVEL_HIGH>;
+			dmas = <&audma0 0x8b>, <&audma1 0xa0>;
+			dma-names = "rx", "tx";
+		};
+		src4: src@4 {
+			interrupts = <0 356 IRQ_TYPE_LEVEL_HIGH>;
+			dmas = <&audma0 0x8d>, <&audma1 0xb0>;
+			dma-names = "rx", "tx";
+		};
+		src5: src@5 {
+			interrupts = <0 357 IRQ_TYPE_LEVEL_HIGH>;
+			dmas = <&audma0 0x8f>, <&audma1 0xb2>;
+			dma-names = "rx", "tx";
+		};
+		src6: src@6 {
+			interrupts = <0 358 IRQ_TYPE_LEVEL_HIGH>;
+			dmas = <&audma0 0x91>, <&audma1 0xb4>;
+			dma-names = "rx", "tx";
+		};
+		src7: src@7 {
+			interrupts = <0 359 IRQ_TYPE_LEVEL_HIGH>;
+			dmas = <&audma0 0x93>, <&audma1 0xb6>;
+			dma-names = "rx", "tx";
+		};
+		src8: src@8 {
+			interrupts = <0 360 IRQ_TYPE_LEVEL_HIGH>;
+			dmas = <&audma0 0x95>, <&audma1 0xb8>;
+			dma-names = "rx", "tx";
+		};
+		src9: src@9 {
+			interrupts = <0 361 IRQ_TYPE_LEVEL_HIGH>;
+			dmas = <&audma0 0x97>, <&audma1 0xba>;
+			dma-names = "rx", "tx";
+		};
 	};
 
 	rcar_sound,ssi {
 		ssi0: ssi@0 {
 			interrupts = <0 370 IRQ_TYPE_LEVEL_HIGH>;
+			dmas = <&audma0 0x01>, <&audma1 0x02>, <&audma0 0x15>, <&audma1 0x16>;
+			dma-names = "rx", "tx", "rxu", "txu";
 		};
 		ssi1: ssi@1 {
 			interrupts = <0 371 IRQ_TYPE_LEVEL_HIGH>;
+			dmas = <&audma0 0x03>, <&audma1 0x04>, <&audma0 0x49>, <&audma1 0x4a>;
+			dma-names = "rx", "tx", "rxu", "txu";
 		};
 		ssi2: ssi@2 {
 			interrupts = <0 372 IRQ_TYPE_LEVEL_HIGH>;
+			dmas = <&audma0 0x05>, <&audma1 0x06>, <&audma0 0x63>, <&audma1 0x64>;
+			dma-names = "rx", "tx", "rxu", "txu";
 		};
 		ssi3: ssi@3 {
 			interrupts = <0 373 IRQ_TYPE_LEVEL_HIGH>;
+			dmas = <&audma0 0x07>, <&audma1 0x08>, <&audma0 0x6f>, <&audma1 0x70>;
+			dma-names = "rx", "tx", "rxu", "txu";
 		};
 		ssi4: ssi@4 {
 			interrupts = <0 374 IRQ_TYPE_LEVEL_HIGH>;
+			dmas = <&audma0 0x09>, <&audma1 0x0a>, <&audma0 0x71>, <&audma1 0x72>;
+			dma-names = "rx", "tx", "rxu", "txu";
 		};
 		ssi5: ssi@5 {
 			interrupts = <0 375 IRQ_TYPE_LEVEL_HIGH>;
+			dmas = <&audma0 0x0b>, <&audma1 0x0c>, <&audma0 0x73>, <&audma1 0x74>;
+			dma-names = "rx", "tx", "rxu", "txu";
 		};
 		ssi6: ssi@6 {
 			interrupts = <0 376 IRQ_TYPE_LEVEL_HIGH>;
+			dmas = <&audma0 0x0d>, <&audma1 0x0e>, <&audma0 0x75>, <&audma1 0x76>;
+			dma-names = "rx", "tx", "rxu", "txu";
 		};
 		ssi7: ssi@7 {
 			interrupts = <0 377 IRQ_TYPE_LEVEL_HIGH>;
+			dmas = <&audma0 0x0f>, <&audma1 0x10>, <&audma0 0x79>, <&audma1 0x7a>;
+			dma-names = "rx", "tx", "rxu", "txu";
 		};
 		ssi8: ssi@8 {
 			interrupts = <0 378 IRQ_TYPE_LEVEL_HIGH>;
+			dmas = <&audma0 0x11>, <&audma1 0x12>, <&audma0 0x7b>, <&audma1 0x7c>;
+			dma-names = "rx", "tx", "rxu", "txu";
 		};
 		ssi9: ssi@9 {
 			interrupts = <0 379 IRQ_TYPE_LEVEL_HIGH>;
+			dmas = <&audma0 0x13>, <&audma1 0x14>, <&audma0 0x7d>, <&audma1 0x7e>;
+			dma-names = "rx", "tx", "rxu", "txu";
 		};
 	};
 
diff --git a/Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt b/Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt
new file mode 100644
index 0000000..c641550
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt
@@ -0,0 +1,67 @@
+Renesas Sampling Rate Convert Sound Card:
+
+Renesas Sampling Rate Convert Sound Card specifies audio DAI connections of SoC <-> codec.
+
+Required properties:
+
+- compatible				: "renesas,rsrc-card,<board>"
+					  Examples with soctypes are:
+					    - "renesas,rsrc-card,lager"
+					    - "renesas,rsrc-card,koelsch"
+Optional properties:
+
+- card_name				: User specified audio sound card name, one string
+					  property.
+- cpu					: CPU   sub-node
+- codec					: CODEC sub-node
+
+Optional subnode properties:
+
+- format				: CPU/CODEC common audio format.
+					  "i2s", "right_j", "left_j" , "dsp_a"
+					  "dsp_b", "ac97", "pdm", "msb", "lsb"
+- frame-master				: Indicates dai-link frame master.
+					  phandle to a cpu or codec subnode.
+- bitclock-master			: Indicates dai-link bit clock master.
+					  phandle to a cpu or codec subnode.
+- bitclock-inversion			: bool property. Add this if the
+					  dai-link uses bit clock inversion.
+- frame-inversion			: bool property. Add this if the
+					  dai-link uses frame clock inversion.
+- convert-rate				: platform specified sampling rate convert
+
+Required CPU/CODEC subnodes properties:
+
+- sound-dai				: phandle and port of CPU/CODEC
+
+Optional CPU/CODEC subnodes properties:
+
+- clocks / system-clock-frequency	: specify subnode's clock if needed.
+					  it can be specified via "clocks" if system has
+					  clock node (= common clock), or "system-clock-frequency"
+					  (if system doens't support common clock)
+					  If a clock is specified, it is
+					  enabled with clk_prepare_enable()
+					  in dai startup() and disabled with
+					  clk_disable_unprepare() in dai
+					  shutdown().
+
+Example
+
+sound {
+	compatible = "renesas,rsrc-card,lager";
+
+	card-name = "rsnd-ak4643";
+	format = "left_j";
+	bitclock-master = <&sndcodec>;
+	frame-master = <&sndcodec>;
+
+	sndcpu: cpu {
+		sound-dai = <&rcar_sound>;
+	};
+
+	sndcodec: codec {
+		sound-dai = <&ak4643>;
+		system-clock-frequency = <11289600>;
+	};
+};
diff --git a/drivers/dma/of-dma.c b/drivers/dma/of-dma.c
index ca31f1b..cbd4a8a 100644
--- a/drivers/dma/of-dma.c
+++ b/drivers/dma/of-dma.c
@@ -194,6 +194,7 @@
 
 	return ERR_PTR(ret_no_channel);
 }
+EXPORT_SYMBOL_GPL(of_dma_request_slave_channel);
 
 /**
  * of_dma_simple_xlate - Simple DMA engine translation function
diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig
index 80245b6..2b30304 100644
--- a/sound/soc/sh/Kconfig
+++ b/sound/soc/sh/Kconfig
@@ -41,6 +41,11 @@
 	help
 	  This option enables R-Car SUR/SCU/SSIU/SSI sound support
 
+config SND_SOC_RSRC_CARD
+	tristate "Renesas Sampling Rate Convert Sound Card"
+	help
+	  This option enables simple sound if you need sampling rate convert
+
 ##
 ## Boards
 ##
diff --git a/sound/soc/sh/rcar/Makefile b/sound/soc/sh/rcar/Makefile
index 9ac5364..f1b4451 100644
--- a/sound/soc/sh/rcar/Makefile
+++ b/sound/soc/sh/rcar/Makefile
@@ -1,2 +1,5 @@
-snd-soc-rcar-objs	:= core.o gen.o src.o adg.o ssi.o dvc.o
-obj-$(CONFIG_SND_SOC_RCAR)	+= snd-soc-rcar.o
\ No newline at end of file
+snd-soc-rcar-objs	:= core.o gen.o dma.o src.o adg.o ssi.o dvc.o
+obj-$(CONFIG_SND_SOC_RCAR)	+= snd-soc-rcar.o
+
+snd-soc-rsrc-card-objs	:= rsrc-card.o
+obj-$(CONFIG_SND_SOC_RSRC_CARD)	+= snd-soc-rsrc-card.o
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c
index 7ac35c9..7af374b 100644
--- a/sound/soc/sh/rcar/adg.c
+++ b/sound/soc/sh/rcar/adg.c
@@ -183,6 +183,8 @@
 
 	rsnd_mod_bset(mod, DIV_EN, en, en);
 
+	dev_dbg(dev, "convert rate %d <-> %d\n", src_rate, dst_rate);
+
 	return 0;
 }
 
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
index 6046c10..770247c 100644
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/sh/rcar/core.c
@@ -94,7 +94,6 @@
  *
  */
 #include <linux/pm_runtime.h>
-#include <linux/shdma-base.h>
 #include "rsnd.h"
 
 #define RSND_RATES SNDRV_PCM_RATE_8000_96000
@@ -108,7 +107,7 @@
 	.flags = RSND_GEN2,
 };
 
-static struct of_device_id rsnd_of_match[] = {
+static const struct of_device_id rsnd_of_match[] = {
 	{ .compatible = "renesas,rcar_sound-gen1", .data = &rsnd_of_data_gen1 },
 	{ .compatible = "renesas,rcar_sound-gen2", .data = &rsnd_of_data_gen2 },
 	{},
@@ -138,15 +137,12 @@
 	return mod->ops->name;
 }
 
-char *rsnd_mod_dma_name(struct rsnd_mod *mod)
+struct dma_chan *rsnd_mod_dma_req(struct rsnd_mod *mod)
 {
-	if (!mod || !mod->ops)
-		return "unknown";
+	if (!mod || !mod->ops || !mod->ops->dma_req)
+		return NULL;
 
-	if (!mod->ops->dma_name)
-		return mod->ops->name;
-
-	return mod->ops->dma_name(mod);
+	return mod->ops->dma_req(mod);
 }
 
 int rsnd_mod_init(struct rsnd_mod *mod,
@@ -175,228 +171,6 @@
 }
 
 /*
- *	rsnd_dma functions
- */
-void rsnd_dma_stop(struct rsnd_dma *dma)
-{
-	dmaengine_terminate_all(dma->chan);
-}
-
-static void rsnd_dma_complete(void *data)
-{
-	struct rsnd_dma *dma = (struct rsnd_dma *)data;
-	struct rsnd_mod *mod = rsnd_dma_to_mod(dma);
-	struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
-
-	/*
-	 * Renesas sound Gen1 needs 1 DMAC,
-	 * Gen2 needs 2 DMAC.
-	 * In Gen2 case, it are Audio-DMAC, and Audio-DMAC-peri-peri.
-	 * But, Audio-DMAC-peri-peri doesn't have interrupt,
-	 * and this driver is assuming that here.
-	 *
-	 * If Audio-DMAC-peri-peri has interrpt,
-	 * rsnd_dai_pointer_update() will be called twice,
-	 * ant it will breaks io->byte_pos
-	 */
-
-	rsnd_dai_pointer_update(io, io->byte_per_period);
-}
-
-void rsnd_dma_start(struct rsnd_dma *dma)
-{
-	struct rsnd_mod *mod = rsnd_dma_to_mod(dma);
-	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-	struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
-	struct snd_pcm_substream *substream = io->substream;
-	struct device *dev = rsnd_priv_to_dev(priv);
-	struct dma_async_tx_descriptor *desc;
-
-	desc = dmaengine_prep_dma_cyclic(dma->chan,
-					 (dma->addr) ? dma->addr :
-					 substream->runtime->dma_addr,
-					 snd_pcm_lib_buffer_bytes(substream),
-					 snd_pcm_lib_period_bytes(substream),
-					 dma->dir,
-					 DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-
-	if (!desc) {
-		dev_err(dev, "dmaengine_prep_slave_sg() fail\n");
-		return;
-	}
-
-	desc->callback		= rsnd_dma_complete;
-	desc->callback_param	= dma;
-
-	if (dmaengine_submit(desc) < 0) {
-		dev_err(dev, "dmaengine_submit() fail\n");
-		return;
-	}
-
-	dma_async_issue_pending(dma->chan);
-}
-
-int rsnd_dma_available(struct rsnd_dma *dma)
-{
-	return !!dma->chan;
-}
-
-#define DMA_NAME_SIZE 16
-#define MOD_MAX 4 /* MEM/SSI/SRC/DVC */
-static int _rsnd_dma_of_name(char *dma_name, struct rsnd_mod *mod)
-{
-	if (mod)
-		return snprintf(dma_name, DMA_NAME_SIZE / 2, "%s%d",
-			 rsnd_mod_dma_name(mod), rsnd_mod_id(mod));
-	else
-		return snprintf(dma_name, DMA_NAME_SIZE / 2, "mem");
-
-}
-
-static void rsnd_dma_of_name(struct rsnd_mod *mod_from,
-			     struct rsnd_mod *mod_to,
-			     char *dma_name)
-{
-	int index = 0;
-
-	index = _rsnd_dma_of_name(dma_name + index, mod_from);
-	*(dma_name + index++) = '_';
-	index = _rsnd_dma_of_name(dma_name + index, mod_to);
-}
-
-static void rsnd_dma_of_path(struct rsnd_dma *dma,
-			     int is_play,
-			     struct rsnd_mod **mod_from,
-			     struct rsnd_mod **mod_to)
-{
-	struct rsnd_mod *this = rsnd_dma_to_mod(dma);
-	struct rsnd_dai_stream *io = rsnd_mod_to_io(this);
-	struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io);
-	struct rsnd_mod *src = rsnd_io_to_mod_src(io);
-	struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io);
-	struct rsnd_mod *mod[MOD_MAX];
-	int i, index;
-
-
-	for (i = 0; i < MOD_MAX; i++)
-		mod[i] = NULL;
-
-	/*
-	 * in play case...
-	 *
-	 * src -> dst
-	 *
-	 * mem -> SSI
-	 * mem -> SRC -> SSI
-	 * mem -> SRC -> DVC -> SSI
-	 */
-	mod[0] = NULL; /* for "mem" */
-	index = 1;
-	for (i = 1; i < MOD_MAX; i++) {
-		if (!src) {
-			mod[i] = ssi;
-		} else if (!dvc) {
-			mod[i] = src;
-			src = NULL;
-		} else {
-			if ((!is_play) && (this == src))
-				this = dvc;
-
-			mod[i] = (is_play) ? src : dvc;
-			i++;
-			mod[i] = (is_play) ? dvc : src;
-			src = NULL;
-			dvc = NULL;
-		}
-
-		if (mod[i] == this)
-			index = i;
-
-		if (mod[i] == ssi)
-			break;
-	}
-
-	if (is_play) {
-		*mod_from = mod[index - 1];
-		*mod_to   = mod[index];
-	} else {
-		*mod_from = mod[index];
-		*mod_to   = mod[index - 1];
-	}
-}
-
-int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma,
-		  int is_play, int id)
-{
-	struct device *dev = rsnd_priv_to_dev(priv);
-	struct dma_slave_config cfg;
-	struct rsnd_mod *mod_from;
-	struct rsnd_mod *mod_to;
-	char dma_name[DMA_NAME_SIZE];
-	dma_cap_mask_t mask;
-	int ret;
-
-	if (dma->chan) {
-		dev_err(dev, "it already has dma channel\n");
-		return -EIO;
-	}
-
-	dma_cap_zero(mask);
-	dma_cap_set(DMA_SLAVE, mask);
-
-	rsnd_dma_of_path(dma, is_play, &mod_from, &mod_to);
-	rsnd_dma_of_name(mod_from, mod_to, dma_name);
-
-	cfg.slave_id	= id;
-	cfg.direction	= is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
-	cfg.src_addr	= rsnd_gen_dma_addr(priv, mod_from, is_play, 1);
-	cfg.dst_addr	= rsnd_gen_dma_addr(priv, mod_to,   is_play, 0);
-	cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-	cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-
-	dev_dbg(dev, "dma : %s %pad -> %pad\n",
-		dma_name, &cfg.src_addr, &cfg.dst_addr);
-
-	dma->chan = dma_request_slave_channel_compat(mask, shdma_chan_filter,
-						     (void *)id, dev,
-						     dma_name);
-	if (!dma->chan) {
-		dev_err(dev, "can't get dma channel\n");
-		goto rsnd_dma_channel_err;
-	}
-
-	ret = dmaengine_slave_config(dma->chan, &cfg);
-	if (ret < 0)
-		goto rsnd_dma_init_err;
-
-	dma->addr = is_play ? cfg.src_addr : cfg.dst_addr;
-	dma->dir = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
-
-	return 0;
-
-rsnd_dma_init_err:
-	rsnd_dma_quit(priv, dma);
-rsnd_dma_channel_err:
-
-	/*
-	 * DMA failed. try to PIO mode
-	 * see
-	 *	rsnd_ssi_fallback()
-	 *	rsnd_rdai_continuance_probe()
-	 */
-	return -EAGAIN;
-}
-
-void  rsnd_dma_quit(struct rsnd_priv *priv,
-		    struct rsnd_dma *dma)
-{
-	if (dma->chan)
-		dma_release_channel(dma->chan);
-
-	dma->chan = NULL;
-}
-
-/*
  *	settting function
  */
 u32 rsnd_get_adinr(struct rsnd_mod *mod)
@@ -471,7 +245,7 @@
 		struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
 		struct device *dev = rsnd_priv_to_dev(priv);
 
-		dev_err(dev, "%s%d is not empty\n",
+		dev_err(dev, "%s[%d] is not empty\n",
 			rsnd_mod_name(mod),
 			rsnd_mod_id(mod));
 		return -EIO;
@@ -887,20 +661,28 @@
 		drv[i].name	= rdai[i].name;
 		drv[i].ops	= &rsnd_soc_dai_ops;
 		if (pmod) {
+			snprintf(rdai[i].playback.name, RSND_DAI_NAME_SIZE,
+				 "DAI%d Playback", i);
+
 			drv[i].playback.rates		= RSND_RATES;
 			drv[i].playback.formats		= RSND_FMTS;
 			drv[i].playback.channels_min	= 2;
 			drv[i].playback.channels_max	= 2;
+			drv[i].playback.stream_name	= rdai[i].playback.name;
 
 			rdai[i].playback.info = &info->dai_info[i].playback;
 			rdai[i].playback.rdai = rdai + i;
 			rsnd_path_init(priv, &rdai[i], &rdai[i].playback);
 		}
 		if (cmod) {
+			snprintf(rdai[i].capture.name, RSND_DAI_NAME_SIZE,
+				 "DAI%d Capture", i);
+
 			drv[i].capture.rates		= RSND_RATES;
 			drv[i].capture.formats		= RSND_FMTS;
 			drv[i].capture.channels_min	= 2;
 			drv[i].capture.channels_max	= 2;
+			drv[i].capture.stream_name	= rdai[i].capture.name;
 
 			rdai[i].capture.info = &info->dai_info[i].capture;
 			rdai[i].capture.rdai = rdai + i;
@@ -1210,6 +992,7 @@
 			    const struct rsnd_of_data *of_data,
 			    struct rsnd_priv *priv) = {
 		rsnd_gen_probe,
+		rsnd_dma_probe,
 		rsnd_ssi_probe,
 		rsnd_src_probe,
 		rsnd_dvc_probe,
diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c
new file mode 100644
index 0000000..cd7b79a
--- /dev/null
+++ b/sound/soc/sh/rcar/dma.c
@@ -0,0 +1,620 @@
+/*
+ * Renesas R-Car Audio DMAC support
+ *
+ * Copyright (C) 2015 Renesas Electronics Corp.
+ * Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/delay.h>
+#include <linux/of_dma.h>
+#include "rsnd.h"
+
+/*
+ * Audio DMAC peri peri register
+ */
+#define PDMASAR		0x00
+#define PDMADAR		0x04
+#define PDMACHCR	0x0c
+
+/* PDMACHCR */
+#define PDMACHCR_DE		(1 << 0)
+
+struct rsnd_dma_ctrl {
+	void __iomem *base;
+	int dmapp_num;
+};
+
+#define rsnd_priv_to_dmac(p)	((struct rsnd_dma_ctrl *)(p)->dma)
+
+/*
+ *		Audio DMAC
+ */
+static void rsnd_dmaen_complete(void *data)
+{
+	struct rsnd_dma *dma = (struct rsnd_dma *)data;
+	struct rsnd_mod *mod = rsnd_dma_to_mod(dma);
+	struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
+
+	/*
+	 * Renesas sound Gen1 needs 1 DMAC,
+	 * Gen2 needs 2 DMAC.
+	 * In Gen2 case, it are Audio-DMAC, and Audio-DMAC-peri-peri.
+	 * But, Audio-DMAC-peri-peri doesn't have interrupt,
+	 * and this driver is assuming that here.
+	 *
+	 * If Audio-DMAC-peri-peri has interrpt,
+	 * rsnd_dai_pointer_update() will be called twice,
+	 * ant it will breaks io->byte_pos
+	 */
+
+	rsnd_dai_pointer_update(io, io->byte_per_period);
+}
+
+static void rsnd_dmaen_stop(struct rsnd_dma *dma)
+{
+	struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
+
+	dmaengine_terminate_all(dmaen->chan);
+}
+
+static void rsnd_dmaen_start(struct rsnd_dma *dma)
+{
+	struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
+	struct rsnd_mod *mod = rsnd_dma_to_mod(dma);
+	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+	struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
+	struct snd_pcm_substream *substream = io->substream;
+	struct device *dev = rsnd_priv_to_dev(priv);
+	struct dma_async_tx_descriptor *desc;
+	int is_play = rsnd_io_is_play(io);
+
+	desc = dmaengine_prep_dma_cyclic(dmaen->chan,
+					 substream->runtime->dma_addr,
+					 snd_pcm_lib_buffer_bytes(substream),
+					 snd_pcm_lib_period_bytes(substream),
+					 is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM,
+					 DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+
+	if (!desc) {
+		dev_err(dev, "dmaengine_prep_slave_sg() fail\n");
+		return;
+	}
+
+	desc->callback		= rsnd_dmaen_complete;
+	desc->callback_param	= dma;
+
+	if (dmaengine_submit(desc) < 0) {
+		dev_err(dev, "dmaengine_submit() fail\n");
+		return;
+	}
+
+	dma_async_issue_pending(dmaen->chan);
+}
+
+struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node,
+					  struct rsnd_mod *mod, char *name)
+{
+	struct dma_chan *chan;
+	struct device_node *np;
+	int i = 0;
+
+	for_each_child_of_node(of_node, np) {
+		if (i == rsnd_mod_id(mod))
+			break;
+		i++;
+	}
+
+	chan = of_dma_request_slave_channel(np, name);
+
+	of_node_put(np);
+	of_node_put(of_node);
+
+	return chan;
+}
+
+static struct dma_chan *rsnd_dmaen_request_channel(struct rsnd_mod *mod_from,
+						   struct rsnd_mod *mod_to)
+{
+	if ((!mod_from && !mod_to) ||
+	    (mod_from && mod_to))
+		return NULL;
+
+	if (mod_from)
+		return rsnd_mod_dma_req(mod_from);
+	else
+		return rsnd_mod_dma_req(mod_to);
+}
+
+static int rsnd_dmaen_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id,
+			   struct rsnd_mod *mod_from, struct rsnd_mod *mod_to)
+{
+	struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
+	struct device *dev = rsnd_priv_to_dev(priv);
+	struct dma_slave_config cfg = {};
+	struct rsnd_mod *mod = rsnd_dma_to_mod(dma);
+	struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
+	int is_play = rsnd_io_is_play(io);
+	int ret;
+
+	if (dmaen->chan) {
+		dev_err(dev, "it already has dma channel\n");
+		return -EIO;
+	}
+
+	dev_dbg(dev, "Audio DMAC init\n");
+
+	if (dev->of_node) {
+		dmaen->chan = rsnd_dmaen_request_channel(mod_from, mod_to);
+	} else {
+		dma_cap_mask_t mask;
+
+		dma_cap_zero(mask);
+		dma_cap_set(DMA_SLAVE, mask);
+
+		dmaen->chan = dma_request_channel(mask, shdma_chan_filter,
+						  (void *)id);
+	}
+	if (IS_ERR_OR_NULL(dmaen->chan)) {
+		dev_err(dev, "can't get dma channel\n");
+		goto rsnd_dma_channel_err;
+	}
+
+	cfg.direction	= is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
+	cfg.src_addr	= dma->src_addr;
+	cfg.dst_addr	= dma->dst_addr;
+	cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+	cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+
+	dev_dbg(dev, "dma : %pad -> %pad\n",
+		&cfg.src_addr, &cfg.dst_addr);
+
+	ret = dmaengine_slave_config(dmaen->chan, &cfg);
+	if (ret < 0)
+		goto rsnd_dma_init_err;
+
+	return 0;
+
+rsnd_dma_init_err:
+	rsnd_dma_quit(dma);
+rsnd_dma_channel_err:
+
+	/*
+	 * DMA failed. try to PIO mode
+	 * see
+	 *	rsnd_ssi_fallback()
+	 *	rsnd_rdai_continuance_probe()
+	 */
+	return -EAGAIN;
+}
+
+static void rsnd_dmaen_quit(struct rsnd_dma *dma)
+{
+	struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
+
+	if (dmaen->chan)
+		dma_release_channel(dmaen->chan);
+
+	dmaen->chan = NULL;
+}
+
+static struct rsnd_dma_ops rsnd_dmaen_ops = {
+	.start	= rsnd_dmaen_start,
+	.stop	= rsnd_dmaen_stop,
+	.init	= rsnd_dmaen_init,
+	.quit	= rsnd_dmaen_quit,
+};
+
+/*
+ *		Audio DMAC peri peri
+ */
+static const u8 gen2_id_table_ssiu[] = {
+	0x00, /* SSI00 */
+	0x04, /* SSI10 */
+	0x08, /* SSI20 */
+	0x0c, /* SSI3  */
+	0x0d, /* SSI4  */
+	0x0e, /* SSI5  */
+	0x0f, /* SSI6  */
+	0x10, /* SSI7  */
+	0x11, /* SSI8  */
+	0x12, /* SSI90 */
+};
+static const u8 gen2_id_table_scu[] = {
+	0x2d, /* SCU_SRCI0 */
+	0x2e, /* SCU_SRCI1 */
+	0x2f, /* SCU_SRCI2 */
+	0x30, /* SCU_SRCI3 */
+	0x31, /* SCU_SRCI4 */
+	0x32, /* SCU_SRCI5 */
+	0x33, /* SCU_SRCI6 */
+	0x34, /* SCU_SRCI7 */
+	0x35, /* SCU_SRCI8 */
+	0x36, /* SCU_SRCI9 */
+};
+static const u8 gen2_id_table_cmd[] = {
+	0x37, /* SCU_CMD0 */
+	0x38, /* SCU_CMD1 */
+};
+
+static u32 rsnd_dmapp_get_id(struct rsnd_mod *mod)
+{
+	struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
+	struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io);
+	struct rsnd_mod *src = rsnd_io_to_mod_src(io);
+	struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io);
+	const u8 *entry = NULL;
+	int id = rsnd_mod_id(mod);
+	int size = 0;
+
+	if (mod == ssi) {
+		entry = gen2_id_table_ssiu;
+		size = ARRAY_SIZE(gen2_id_table_ssiu);
+	} else if (mod == src) {
+		entry = gen2_id_table_scu;
+		size = ARRAY_SIZE(gen2_id_table_scu);
+	} else if (mod == dvc) {
+		entry = gen2_id_table_cmd;
+		size = ARRAY_SIZE(gen2_id_table_cmd);
+	}
+
+	if (!entry)
+		return 0xFF;
+
+	if (size <= id)
+		return 0xFF;
+
+	return entry[id];
+}
+
+static u32 rsnd_dmapp_get_chcr(struct rsnd_mod *mod_from,
+			       struct rsnd_mod *mod_to)
+{
+	return	(rsnd_dmapp_get_id(mod_from) << 24) +
+		(rsnd_dmapp_get_id(mod_to) << 16);
+}
+
+#define rsnd_dmapp_addr(dmac, dma, reg) \
+	(dmac->base + 0x20 + reg + \
+	 (0x10 * rsnd_dma_to_dmapp(dma)->dmapp_id))
+static void rsnd_dmapp_write(struct rsnd_dma *dma, u32 data, u32 reg)
+{
+	struct rsnd_mod *mod = rsnd_dma_to_mod(dma);
+	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+	struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
+	struct device *dev = rsnd_priv_to_dev(priv);
+
+	dev_dbg(dev, "w %p : %08x\n", rsnd_dmapp_addr(dmac, dma, reg), data);
+
+	iowrite32(data, rsnd_dmapp_addr(dmac, dma, reg));
+}
+
+static u32 rsnd_dmapp_read(struct rsnd_dma *dma, u32 reg)
+{
+	struct rsnd_mod *mod = rsnd_dma_to_mod(dma);
+	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+	struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
+
+	return ioread32(rsnd_dmapp_addr(dmac, dma, reg));
+}
+
+static void rsnd_dmapp_stop(struct rsnd_dma *dma)
+{
+	int i;
+
+	rsnd_dmapp_write(dma, 0, PDMACHCR);
+
+	for (i = 0; i < 1024; i++) {
+		if (0 == rsnd_dmapp_read(dma, PDMACHCR))
+			return;
+		udelay(1);
+	}
+}
+
+static void rsnd_dmapp_start(struct rsnd_dma *dma)
+{
+	struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma);
+
+	rsnd_dmapp_write(dma, dma->src_addr,	PDMASAR);
+	rsnd_dmapp_write(dma, dma->dst_addr,	PDMADAR);
+	rsnd_dmapp_write(dma, dmapp->chcr,	PDMACHCR);
+}
+
+static int rsnd_dmapp_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id,
+			   struct rsnd_mod *mod_from, struct rsnd_mod *mod_to)
+{
+	struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma);
+	struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
+	struct device *dev = rsnd_priv_to_dev(priv);
+
+	dev_dbg(dev, "Audio DMAC peri peri init\n");
+
+	dmapp->dmapp_id = dmac->dmapp_num;
+	dmapp->chcr = rsnd_dmapp_get_chcr(mod_from, mod_to) | PDMACHCR_DE;
+
+	dmac->dmapp_num++;
+
+	rsnd_dmapp_stop(dma);
+
+	dev_dbg(dev, "id/src/dst/chcr = %d/%pad/%pad/%08x\n",
+		dmapp->dmapp_id, &dma->src_addr, &dma->dst_addr, dmapp->chcr);
+
+	return 0;
+}
+
+static struct rsnd_dma_ops rsnd_dmapp_ops = {
+	.start	= rsnd_dmapp_start,
+	.stop	= rsnd_dmapp_stop,
+	.init	= rsnd_dmapp_init,
+	.quit	= rsnd_dmapp_stop,
+};
+
+/*
+ *		Common DMAC Interface
+ */
+
+/*
+ *	DMA read/write register offset
+ *
+ *	RSND_xxx_I_N	for Audio DMAC input
+ *	RSND_xxx_O_N	for Audio DMAC output
+ *	RSND_xxx_I_P	for Audio DMAC peri peri input
+ *	RSND_xxx_O_P	for Audio DMAC peri peri output
+ *
+ *	ex) R-Car H2 case
+ *	      mod        / DMAC in    / DMAC out   / DMAC PP in / DMAC pp out
+ *	SSI : 0xec541000 / 0xec241008 / 0xec24100c
+ *	SSIU: 0xec541000 / 0xec100000 / 0xec100000 / 0xec400000 / 0xec400000
+ *	SCU : 0xec500000 / 0xec000000 / 0xec004000 / 0xec300000 / 0xec304000
+ *	CMD : 0xec500000 /            / 0xec008000                0xec308000
+ */
+#define RDMA_SSI_I_N(addr, i)	(addr ##_reg - 0x00300000 + (0x40 * i) + 0x8)
+#define RDMA_SSI_O_N(addr, i)	(addr ##_reg - 0x00300000 + (0x40 * i) + 0xc)
+
+#define RDMA_SSIU_I_N(addr, i)	(addr ##_reg - 0x00441000 + (0x1000 * i))
+#define RDMA_SSIU_O_N(addr, i)	(addr ##_reg - 0x00441000 + (0x1000 * i))
+
+#define RDMA_SSIU_I_P(addr, i)	(addr ##_reg - 0x00141000 + (0x1000 * i))
+#define RDMA_SSIU_O_P(addr, i)	(addr ##_reg - 0x00141000 + (0x1000 * i))
+
+#define RDMA_SRC_I_N(addr, i)	(addr ##_reg - 0x00500000 + (0x400 * i))
+#define RDMA_SRC_O_N(addr, i)	(addr ##_reg - 0x004fc000 + (0x400 * i))
+
+#define RDMA_SRC_I_P(addr, i)	(addr ##_reg - 0x00200000 + (0x400 * i))
+#define RDMA_SRC_O_P(addr, i)	(addr ##_reg - 0x001fc000 + (0x400 * i))
+
+#define RDMA_CMD_O_N(addr, i)	(addr ##_reg - 0x004f8000 + (0x400 * i))
+#define RDMA_CMD_O_P(addr, i)	(addr ##_reg - 0x001f8000 + (0x400 * i))
+
+static dma_addr_t
+rsnd_gen2_dma_addr(struct rsnd_priv *priv,
+		   struct rsnd_mod *mod,
+		   int is_play, int is_from)
+{
+	struct device *dev = rsnd_priv_to_dev(priv);
+	struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
+	phys_addr_t ssi_reg = rsnd_gen_get_phy_addr(priv, RSND_GEN2_SSI);
+	phys_addr_t src_reg = rsnd_gen_get_phy_addr(priv, RSND_GEN2_SCU);
+	int is_ssi = !!(rsnd_io_to_mod_ssi(io) == mod);
+	int use_src = !!rsnd_io_to_mod_src(io);
+	int use_dvc = !!rsnd_io_to_mod_dvc(io);
+	int id = rsnd_mod_id(mod);
+	struct dma_addr {
+		dma_addr_t out_addr;
+		dma_addr_t in_addr;
+	} dma_addrs[3][2][3] = {
+		/* SRC */
+		{{{ 0,				0 },
+		  /* Capture */
+		  { RDMA_SRC_O_N(src, id),	RDMA_SRC_I_P(src, id) },
+		  { RDMA_CMD_O_N(src, id),	RDMA_SRC_I_P(src, id) } },
+		 /* Playback */
+		 {{ 0,				0, },
+		  { RDMA_SRC_O_P(src, id),	RDMA_SRC_I_N(src, id) },
+		  { RDMA_CMD_O_P(src, id),	RDMA_SRC_I_N(src, id) } }
+		},
+		/* SSI */
+		/* Capture */
+		{{{ RDMA_SSI_O_N(ssi, id),	0 },
+		  { RDMA_SSIU_O_P(ssi, id),	0 },
+		  { RDMA_SSIU_O_P(ssi, id),	0 } },
+		 /* Playback */
+		 {{ 0,				RDMA_SSI_I_N(ssi, id) },
+		  { 0,				RDMA_SSIU_I_P(ssi, id) },
+		  { 0,				RDMA_SSIU_I_P(ssi, id) } }
+		},
+		/* SSIU */
+		/* Capture */
+		{{{ RDMA_SSIU_O_N(ssi, id),	0 },
+		  { RDMA_SSIU_O_P(ssi, id),	0 },
+		  { RDMA_SSIU_O_P(ssi, id),	0 } },
+		 /* Playback */
+		 {{ 0,				RDMA_SSIU_I_N(ssi, id) },
+		  { 0,				RDMA_SSIU_I_P(ssi, id) },
+		  { 0,				RDMA_SSIU_I_P(ssi, id) } } },
+	};
+
+	/* it shouldn't happen */
+	if (use_dvc && !use_src)
+		dev_err(dev, "DVC is selected without SRC\n");
+
+	/* use SSIU or SSI ? */
+	if (is_ssi && rsnd_ssi_use_busif(mod))
+		is_ssi++;
+
+	return (is_from) ?
+		dma_addrs[is_ssi][is_play][use_src + use_dvc].out_addr :
+		dma_addrs[is_ssi][is_play][use_src + use_dvc].in_addr;
+}
+
+static dma_addr_t rsnd_dma_addr(struct rsnd_priv *priv,
+				struct rsnd_mod *mod,
+				int is_play, int is_from)
+{
+	/*
+	 * gen1 uses default DMA addr
+	 */
+	if (rsnd_is_gen1(priv))
+		return 0;
+
+	if (!mod)
+		return 0;
+
+	return rsnd_gen2_dma_addr(priv, mod, is_play, is_from);
+}
+
+#define MOD_MAX 4 /* MEM/SSI/SRC/DVC */
+static void rsnd_dma_of_path(struct rsnd_dma *dma,
+			     int is_play,
+			     struct rsnd_mod **mod_from,
+			     struct rsnd_mod **mod_to)
+{
+	struct rsnd_mod *this = rsnd_dma_to_mod(dma);
+	struct rsnd_dai_stream *io = rsnd_mod_to_io(this);
+	struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io);
+	struct rsnd_mod *src = rsnd_io_to_mod_src(io);
+	struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io);
+	struct rsnd_mod *mod[MOD_MAX];
+	int i, index;
+
+
+	for (i = 0; i < MOD_MAX; i++)
+		mod[i] = NULL;
+
+	/*
+	 * in play case...
+	 *
+	 * src -> dst
+	 *
+	 * mem -> SSI
+	 * mem -> SRC -> SSI
+	 * mem -> SRC -> DVC -> SSI
+	 */
+	mod[0] = NULL; /* for "mem" */
+	index = 1;
+	for (i = 1; i < MOD_MAX; i++) {
+		if (!src) {
+			mod[i] = ssi;
+		} else if (!dvc) {
+			mod[i] = src;
+			src = NULL;
+		} else {
+			if ((!is_play) && (this == src))
+				this = dvc;
+
+			mod[i] = (is_play) ? src : dvc;
+			i++;
+			mod[i] = (is_play) ? dvc : src;
+			src = NULL;
+			dvc = NULL;
+		}
+
+		if (mod[i] == this)
+			index = i;
+
+		if (mod[i] == ssi)
+			break;
+	}
+
+	if (is_play) {
+		*mod_from = mod[index - 1];
+		*mod_to   = mod[index];
+	} else {
+		*mod_from = mod[index];
+		*mod_to   = mod[index - 1];
+	}
+}
+
+void rsnd_dma_stop(struct rsnd_dma *dma)
+{
+	dma->ops->stop(dma);
+}
+
+void rsnd_dma_start(struct rsnd_dma *dma)
+{
+	dma->ops->start(dma);
+}
+
+void rsnd_dma_quit(struct rsnd_dma *dma)
+{
+	struct rsnd_mod *mod = rsnd_dma_to_mod(dma);
+	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+	struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
+
+	if (!dmac)
+		return;
+
+	dma->ops->quit(dma);
+}
+
+int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id)
+{
+	struct rsnd_mod *mod = rsnd_dma_to_mod(dma);
+	struct rsnd_mod *mod_from;
+	struct rsnd_mod *mod_to;
+	struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
+	struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
+	int is_play = rsnd_io_is_play(io);
+
+	/*
+	 * DMA failed. try to PIO mode
+	 * see
+	 *	rsnd_ssi_fallback()
+	 *	rsnd_rdai_continuance_probe()
+	 */
+	if (!dmac)
+		return -EAGAIN;
+
+	rsnd_dma_of_path(dma, is_play, &mod_from, &mod_to);
+
+	dma->src_addr = rsnd_dma_addr(priv, mod_from, is_play, 1);
+	dma->dst_addr = rsnd_dma_addr(priv, mod_to,   is_play, 0);
+
+	/* for Gen2 */
+	if (mod_from && mod_to)
+		dma->ops = &rsnd_dmapp_ops;
+	else
+		dma->ops = &rsnd_dmaen_ops;
+
+	/* for Gen1, overwrite */
+	if (rsnd_is_gen1(priv))
+		dma->ops = &rsnd_dmaen_ops;
+
+	return dma->ops->init(priv, dma, id, mod_from, mod_to);
+}
+
+int rsnd_dma_probe(struct platform_device *pdev,
+		   const struct rsnd_of_data *of_data,
+		   struct rsnd_priv *priv)
+{
+	struct device *dev = rsnd_priv_to_dev(priv);
+	struct rsnd_dma_ctrl *dmac;
+	struct resource *res;
+
+	/*
+	 * for Gen1
+	 */
+	if (rsnd_is_gen1(priv))
+		return 0;
+
+	/*
+	 * for Gen2
+	 */
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "audmapp");
+	dmac = devm_kzalloc(dev, sizeof(*dmac), GFP_KERNEL);
+	if (!dmac || !res) {
+		dev_err(dev, "dma allocate failed\n");
+		return 0; /* it will be PIO mode */
+	}
+
+	dmac->dmapp_num = 0;
+	dmac->base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(dmac->base))
+		return PTR_ERR(dmac->base);
+
+	priv->dma = dmac;
+
+	return 0;
+}
diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c
index 261997a..aab4526 100644
--- a/sound/soc/sh/rcar/dvc.c
+++ b/sound/soc/sh/rcar/dvc.c
@@ -24,6 +24,9 @@
 	struct rsnd_kctrl_cfg_s rdown;	/* Ramp Rate Down */
 };
 
+#define rsnd_dvc_of_node(priv) \
+	of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dvc")
+
 #define rsnd_mod_to_dvc(_mod)	\
 	container_of((_mod), struct rsnd_dvc, mod)
 
@@ -33,7 +36,7 @@
 	     ((pos) = (struct rsnd_dvc *)(priv)->dvc + i);	\
 	     i++)
 
-static const char const *dvc_ramp_rate[] = {
+static const char * const dvc_ramp_rate[] = {
 	"128 dB/1 step",	 /* 00000 */
 	"64 dB/1 step",		 /* 00001 */
 	"32 dB/1 step",		 /* 00010 */
@@ -269,8 +272,17 @@
 	return 0;
 }
 
+static struct dma_chan *rsnd_dvc_dma_req(struct rsnd_mod *mod)
+{
+	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+
+	return rsnd_dma_request_channel(rsnd_dvc_of_node(priv),
+					mod, "tx");
+}
+
 static struct rsnd_mod_ops rsnd_dvc_ops = {
 	.name		= DVC_NAME,
+	.dma_req	= rsnd_dvc_dma_req,
 	.probe		= rsnd_dvc_probe_gen2,
 	.remove		= rsnd_dvc_remove_gen2,
 	.init		= rsnd_dvc_init,
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c
index de0685f..a17a504 100644
--- a/sound/soc/sh/rcar/gen.c
+++ b/sound/soc/sh/rcar/gen.c
@@ -28,6 +28,7 @@
 
 	struct regmap *regmap[RSND_BASE_MAX];
 	struct regmap_field *regs[RSND_REG_MAX];
+	phys_addr_t res[RSND_REG_MAX];
 };
 
 #define rsnd_priv_to_gen(p)	((struct rsnd_gen *)(p)->gen)
@@ -118,11 +119,19 @@
 				  mask, data);
 }
 
-#define rsnd_gen_regmap_init(priv, id_size, reg_id, conf)		\
-	_rsnd_gen_regmap_init(priv, id_size, reg_id, conf, ARRAY_SIZE(conf))
+phys_addr_t rsnd_gen_get_phy_addr(struct rsnd_priv *priv, int reg_id)
+{
+	struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
+
+	return	gen->res[reg_id];
+}
+
+#define rsnd_gen_regmap_init(priv, id_size, reg_id, name, conf)		\
+	_rsnd_gen_regmap_init(priv, id_size, reg_id, name, conf, ARRAY_SIZE(conf))
 static int _rsnd_gen_regmap_init(struct rsnd_priv *priv,
 				 int id_size,
 				 int reg_id,
+				 const char *name,
 				 struct rsnd_regmap_field_conf *conf,
 				 int conf_size)
 {
@@ -141,8 +150,11 @@
 	regc.reg_bits = 32;
 	regc.val_bits = 32;
 	regc.reg_stride = 4;
+	regc.name = name;
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, reg_id);
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
+	if (!res)
+		res = platform_get_resource(pdev, IORESOURCE_MEM, reg_id);
 	if (!res)
 		return -ENODEV;
 
@@ -156,6 +168,7 @@
 
 	gen->base[reg_id] = base;
 	gen->regmap[reg_id] = regmap;
+	gen->res[reg_id] = res->start;
 
 	for (i = 0; i < conf_size; i++) {
 
@@ -176,119 +189,6 @@
 }
 
 /*
- *	DMA read/write register offset
- *
- *	RSND_xxx_I_N	for Audio DMAC input
- *	RSND_xxx_O_N	for Audio DMAC output
- *	RSND_xxx_I_P	for Audio DMAC peri peri input
- *	RSND_xxx_O_P	for Audio DMAC peri peri output
- *
- *	ex) R-Car H2 case
- *	      mod        / DMAC in    / DMAC out   / DMAC PP in / DMAC pp out
- *	SSI : 0xec541000 / 0xec241008 / 0xec24100c
- *	SSIU: 0xec541000 / 0xec100000 / 0xec100000 / 0xec400000 / 0xec400000
- *	SCU : 0xec500000 / 0xec000000 / 0xec004000 / 0xec300000 / 0xec304000
- *	CMD : 0xec500000 /            / 0xec008000                0xec308000
- */
-#define RDMA_SSI_I_N(addr, i)	(addr ##_reg - 0x00300000 + (0x40 * i) + 0x8)
-#define RDMA_SSI_O_N(addr, i)	(addr ##_reg - 0x00300000 + (0x40 * i) + 0xc)
-
-#define RDMA_SSIU_I_N(addr, i)	(addr ##_reg - 0x00441000 + (0x1000 * i))
-#define RDMA_SSIU_O_N(addr, i)	(addr ##_reg - 0x00441000 + (0x1000 * i))
-
-#define RDMA_SSIU_I_P(addr, i)	(addr ##_reg - 0x00141000 + (0x1000 * i))
-#define RDMA_SSIU_O_P(addr, i)	(addr ##_reg - 0x00141000 + (0x1000 * i))
-
-#define RDMA_SRC_I_N(addr, i)	(addr ##_reg - 0x00500000 + (0x400 * i))
-#define RDMA_SRC_O_N(addr, i)	(addr ##_reg - 0x004fc000 + (0x400 * i))
-
-#define RDMA_SRC_I_P(addr, i)	(addr ##_reg - 0x00200000 + (0x400 * i))
-#define RDMA_SRC_O_P(addr, i)	(addr ##_reg - 0x001fc000 + (0x400 * i))
-
-#define RDMA_CMD_O_N(addr, i)	(addr ##_reg - 0x004f8000 + (0x400 * i))
-#define RDMA_CMD_O_P(addr, i)	(addr ##_reg - 0x001f8000 + (0x400 * i))
-
-static dma_addr_t
-rsnd_gen2_dma_addr(struct rsnd_priv *priv,
-		   struct rsnd_mod *mod,
-		   int is_play, int is_from)
-{
-	struct platform_device *pdev = rsnd_priv_to_pdev(priv);
-	struct device *dev = rsnd_priv_to_dev(priv);
-	struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
-	dma_addr_t ssi_reg = platform_get_resource(pdev,
-				IORESOURCE_MEM, RSND_GEN2_SSI)->start;
-	dma_addr_t src_reg = platform_get_resource(pdev,
-				IORESOURCE_MEM, RSND_GEN2_SCU)->start;
-	int is_ssi = !!(rsnd_io_to_mod_ssi(io) == mod);
-	int use_src = !!rsnd_io_to_mod_src(io);
-	int use_dvc = !!rsnd_io_to_mod_dvc(io);
-	int id = rsnd_mod_id(mod);
-	struct dma_addr {
-		dma_addr_t out_addr;
-		dma_addr_t in_addr;
-	} dma_addrs[3][2][3] = {
-		/* SRC */
-		{{{ 0,				0 },
-		/* Capture */
-		  { RDMA_SRC_O_N(src, id),	RDMA_SRC_I_P(src, id) },
-		  { RDMA_CMD_O_N(src, id),	RDMA_SRC_I_P(src, id) } },
-		 /* Playback */
-		 {{ 0,				0, },
-		  { RDMA_SRC_O_P(src, id),	RDMA_SRC_I_N(src, id) },
-		  { RDMA_CMD_O_P(src, id),	RDMA_SRC_I_N(src, id) } }
-		},
-		/* SSI */
-		/* Capture */
-		{{{ RDMA_SSI_O_N(ssi, id),	0 },
-		  { RDMA_SSIU_O_P(ssi, id),	0 },
-		  { RDMA_SSIU_O_P(ssi, id),	0 } },
-		 /* Playback */
-		 {{ 0,				RDMA_SSI_I_N(ssi, id) },
-		  { 0,				RDMA_SSIU_I_P(ssi, id) },
-		  { 0,				RDMA_SSIU_I_P(ssi, id) } }
-		},
-		/* SSIU */
-		/* Capture */
-		{{{ RDMA_SSIU_O_N(ssi, id),	0 },
-		  { RDMA_SSIU_O_P(ssi, id),	0 },
-		  { RDMA_SSIU_O_P(ssi, id),	0 } },
-		 /* Playback */
-		 {{ 0,				RDMA_SSIU_I_N(ssi, id) },
-		  { 0,				RDMA_SSIU_I_P(ssi, id) },
-		  { 0,				RDMA_SSIU_I_P(ssi, id) } } },
-	};
-
-	/* it shouldn't happen */
-	if (use_dvc && !use_src)
-		dev_err(dev, "DVC is selected without SRC\n");
-
-	/* use SSIU or SSI ? */
-	if (is_ssi && (0 == strcmp(rsnd_mod_dma_name(mod), "ssiu")))
-		is_ssi++;
-
-	return (is_from) ?
-		dma_addrs[is_ssi][is_play][use_src + use_dvc].out_addr :
-		dma_addrs[is_ssi][is_play][use_src + use_dvc].in_addr;
-}
-
-dma_addr_t rsnd_gen_dma_addr(struct rsnd_priv *priv,
-			     struct rsnd_mod *mod,
-			     int is_play, int is_from)
-{
-	/*
-	 * gen1 uses default DMA addr
-	 */
-	if (rsnd_is_gen1(priv))
-		return 0;
-
-	if (!mod)
-		return 0;
-
-	return rsnd_gen2_dma_addr(priv, mod, is_play, is_from);
-}
-
-/*
  *		Gen2
  */
 static int rsnd_gen2_probe(struct platform_device *pdev,
@@ -368,10 +268,10 @@
 	int ret_adg;
 	int ret_ssi;
 
-	ret_ssiu = rsnd_gen_regmap_init(priv, 10, RSND_GEN2_SSIU, conf_ssiu);
-	ret_scu  = rsnd_gen_regmap_init(priv, 10, RSND_GEN2_SCU,  conf_scu);
-	ret_adg  = rsnd_gen_regmap_init(priv, 10, RSND_GEN2_ADG,  conf_adg);
-	ret_ssi  = rsnd_gen_regmap_init(priv, 10, RSND_GEN2_SSI,  conf_ssi);
+	ret_ssiu = rsnd_gen_regmap_init(priv, 10, RSND_GEN2_SSIU, "ssiu", conf_ssiu);
+	ret_scu  = rsnd_gen_regmap_init(priv, 10, RSND_GEN2_SCU,  "scu",  conf_scu);
+	ret_adg  = rsnd_gen_regmap_init(priv, 10, RSND_GEN2_ADG,  "adg",  conf_adg);
+	ret_ssi  = rsnd_gen_regmap_init(priv, 10, RSND_GEN2_SSI,  "ssi",  conf_ssi);
 	if (ret_ssiu < 0 ||
 	    ret_scu  < 0 ||
 	    ret_adg  < 0 ||
@@ -440,9 +340,9 @@
 	int ret_adg;
 	int ret_ssi;
 
-	ret_sru  = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_SRU,  conf_sru);
-	ret_adg  = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_ADG,  conf_adg);
-	ret_ssi  = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_SSI,  conf_ssi);
+	ret_sru  = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_SRU, "sru", conf_sru);
+	ret_adg  = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_ADG, "adg", conf_adg);
+	ret_ssi  = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_SSI, "ssi", conf_ssi);
 	if (ret_sru  < 0 ||
 	    ret_adg  < 0 ||
 	    ret_ssi  < 0)
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h
index 1bccc55..f7af0be 100644
--- a/sound/soc/sh/rcar/rsnd.h
+++ b/sound/soc/sh/rcar/rsnd.h
@@ -170,21 +170,47 @@
 /*
  *	R-Car DMA
  */
-struct rsnd_dma {
-	struct sh_dmae_slave	slave;
-	struct dma_chan		*chan;
-	enum dma_transfer_direction dir;
-	dma_addr_t		addr;
+struct rsnd_dma;
+struct rsnd_dma_ops {
+	void (*start)(struct rsnd_dma *dma);
+	void (*stop)(struct rsnd_dma *dma);
+	int (*init)(struct rsnd_priv *priv, struct rsnd_dma *dma, int id,
+		    struct rsnd_mod *mod_from, struct rsnd_mod *mod_to);
+	void  (*quit)(struct rsnd_dma *dma);
 };
 
+struct rsnd_dmaen {
+	struct dma_chan		*chan;
+};
+
+struct rsnd_dmapp {
+	int			dmapp_id;
+	u32			chcr;
+};
+
+struct rsnd_dma {
+	struct rsnd_dma_ops	*ops;
+	dma_addr_t		src_addr;
+	dma_addr_t		dst_addr;
+	union {
+		struct rsnd_dmaen en;
+		struct rsnd_dmapp pp;
+	} dma;
+};
+#define rsnd_dma_to_dmaen(dma)	(&(dma)->dma.en)
+#define rsnd_dma_to_dmapp(dma)	(&(dma)->dma.pp)
+
 void rsnd_dma_start(struct rsnd_dma *dma);
 void rsnd_dma_stop(struct rsnd_dma *dma);
-int rsnd_dma_available(struct rsnd_dma *dma);
-int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma,
-	int is_play, int id);
-void  rsnd_dma_quit(struct rsnd_priv *priv,
-		    struct rsnd_dma *dma);
+int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, int id);
+void  rsnd_dma_quit(struct rsnd_dma *dma);
+int rsnd_dma_probe(struct platform_device *pdev,
+		   const struct rsnd_of_data *of_data,
+		   struct rsnd_priv *priv);
+struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node,
+					  struct rsnd_mod *mod, char *name);
 
+#define rsnd_dma_to_mod(_dma) container_of((_dma), struct rsnd_mod, dma)
 
 /*
  *	R-Car sound mod
@@ -198,7 +224,7 @@
 
 struct rsnd_mod_ops {
 	char *name;
-	char* (*dma_name)(struct rsnd_mod *mod);
+	struct dma_chan* (*dma_req)(struct rsnd_mod *mod);
 	int (*probe)(struct rsnd_mod *mod,
 		     struct rsnd_priv *priv);
 	int (*remove)(struct rsnd_mod *mod,
@@ -257,7 +283,6 @@
 
 #define rsnd_mod_to_priv(mod) (rsnd_io_to_priv(rsnd_mod_to_io(mod)))
 #define rsnd_mod_to_dma(mod) (&(mod)->dma)
-#define rsnd_dma_to_mod(_dma) container_of((_dma), struct rsnd_mod, dma)
 #define rsnd_mod_to_io(mod) ((mod)->io)
 #define rsnd_mod_id(mod) ((mod)->id)
 #define rsnd_mod_hw_start(mod)	clk_enable((mod)->clk)
@@ -270,13 +295,14 @@
 		   int id);
 void rsnd_mod_quit(struct rsnd_mod *mod);
 char *rsnd_mod_name(struct rsnd_mod *mod);
-char *rsnd_mod_dma_name(struct rsnd_mod *mod);
+struct dma_chan *rsnd_mod_dma_req(struct rsnd_mod *mod);
 
 /*
  *	R-Car sound DAI
  */
 #define RSND_DAI_NAME_SIZE	16
 struct rsnd_dai_stream {
+	char name[RSND_DAI_NAME_SIZE];
 	struct snd_pcm_substream *substream;
 	struct rsnd_mod *mod[RSND_MOD_MAX];
 	struct rsnd_dai_path_info *info; /* rcar_snd.h */
@@ -332,9 +358,7 @@
 void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv,
 			       struct rsnd_mod *mod,
 			       enum rsnd_reg reg);
-dma_addr_t rsnd_gen_dma_addr(struct rsnd_priv *priv,
-		       struct rsnd_mod *mod,
-		       int is_play,  int is_from);
+phys_addr_t rsnd_gen_get_phy_addr(struct rsnd_priv *priv, int reg_id);
 
 #define rsnd_is_gen1(s)		(((s)->info->flags & RSND_GEN_MASK) == RSND_GEN1)
 #define rsnd_is_gen2(s)		(((s)->info->flags & RSND_GEN_MASK) == RSND_GEN2)
@@ -390,6 +414,11 @@
 	void *adg;
 
 	/*
+	 * below value will be filled on rsnd_dma_probe()
+	 */
+	void *dma;
+
+	/*
 	 * below value will be filled on rsnd_ssi_probe()
 	 */
 	void *ssi;
@@ -415,19 +444,6 @@
 #define rsnd_lock(priv, flags) spin_lock_irqsave(&priv->lock, flags)
 #define rsnd_unlock(priv, flags) spin_unlock_irqrestore(&priv->lock, flags)
 
-#define rsnd_info_is_playback(priv, type)				\
-({									\
-	struct rcar_snd_info *info = rsnd_priv_to_info(priv);		\
-	int i, is_play = 0;						\
-	for (i = 0; i < info->dai_info_nr; i++) {			\
-		if (info->dai_info[i].playback.type == (type)->info) {	\
-			is_play = 1;					\
-			break;						\
-		}							\
-	}								\
-	is_play;							\
-})
-
 /*
  *	rsnd_kctrl
  */
@@ -506,6 +522,7 @@
 struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id);
 int rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod);
 int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod);
+int rsnd_ssi_use_busif(struct rsnd_mod *mod);
 
 /*
  *	R-Car DVC
diff --git a/sound/soc/sh/rcar/rsrc-card.c b/sound/soc/sh/rcar/rsrc-card.c
new file mode 100644
index 0000000..a68517a
--- /dev/null
+++ b/sound/soc/sh/rcar/rsrc-card.c
@@ -0,0 +1,512 @@
+/*
+ * Renesas Sampling Rate Convert Sound Card for DPCM
+ *
+ * Copyright (C) 2015 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * based on ${LINUX}/sound/soc/generic/simple-card.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/string.h>
+#include <sound/jack.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+
+struct rsrc_card_of_data {
+	const char *prefix;
+	const struct snd_soc_dapm_route *routes;
+	int num_routes;
+};
+
+static const struct snd_soc_dapm_route routes_ssi0_ak4642[] = {
+	{"ak4642 Playback", NULL, "DAI0 Playback"},
+	{"DAI0 Capture", NULL, "ak4642 Capture"},
+};
+
+static const struct rsrc_card_of_data routes_of_ssi0_ak4642 = {
+	.prefix		= "ak4642",
+	.routes		= routes_ssi0_ak4642,
+	.num_routes	= ARRAY_SIZE(routes_ssi0_ak4642),
+};
+
+static const struct of_device_id rsrc_card_of_match[] = {
+	{ .compatible = "renesas,rsrc-card,lager",	.data = &routes_of_ssi0_ak4642 },
+	{ .compatible = "renesas,rsrc-card,koelsch",	.data = &routes_of_ssi0_ak4642 },
+	{},
+};
+MODULE_DEVICE_TABLE(of, rsrc_card_of_match);
+
+struct rsrc_card_dai {
+	const char *name;
+	unsigned int fmt;
+	unsigned int sysclk;
+	struct clk *clk;
+};
+
+#define RSRC_FB_NUM	2 /* FE/BE */
+#define IDX_CPU		0
+#define IDX_CODEC	1
+struct rsrc_card_priv {
+	struct snd_soc_card snd_card;
+	struct rsrc_card_dai_props {
+		struct rsrc_card_dai cpu_dai;
+		struct rsrc_card_dai codec_dai;
+	} dai_props[RSRC_FB_NUM];
+	struct snd_soc_codec_conf codec_conf;
+	struct snd_soc_dai_link dai_link[RSRC_FB_NUM];
+	u32 convert_rate;
+};
+
+#define rsrc_priv_to_dev(priv) ((priv)->snd_card.dev)
+#define rsrc_priv_to_link(priv, i) ((priv)->snd_card.dai_link + i)
+#define rsrc_priv_to_props(priv, i) ((priv)->dai_props + i)
+#define rsrc_dev_to_of_data(dev) (of_match_device(rsrc_card_of_match, (dev))->data)
+
+static int rsrc_card_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct rsrc_card_priv *priv =	snd_soc_card_get_drvdata(rtd->card);
+	struct rsrc_card_dai_props *dai_props =
+		&priv->dai_props[rtd - rtd->card->rtd];
+	int ret;
+
+	ret = clk_prepare_enable(dai_props->cpu_dai.clk);
+	if (ret)
+		return ret;
+
+	ret = clk_prepare_enable(dai_props->codec_dai.clk);
+	if (ret)
+		clk_disable_unprepare(dai_props->cpu_dai.clk);
+
+	return ret;
+}
+
+static void rsrc_card_shutdown(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct rsrc_card_priv *priv =	snd_soc_card_get_drvdata(rtd->card);
+	struct rsrc_card_dai_props *dai_props =
+		&priv->dai_props[rtd - rtd->card->rtd];
+
+	clk_disable_unprepare(dai_props->cpu_dai.clk);
+
+	clk_disable_unprepare(dai_props->codec_dai.clk);
+}
+
+static struct snd_soc_ops rsrc_card_ops = {
+	.startup = rsrc_card_startup,
+	.shutdown = rsrc_card_shutdown,
+};
+
+static int __rsrc_card_dai_init(struct snd_soc_dai *dai,
+				struct rsrc_card_dai *set)
+{
+	int ret;
+
+	if (set->fmt) {
+		ret = snd_soc_dai_set_fmt(dai, set->fmt);
+		if (ret && ret != -ENOTSUPP) {
+			dev_err(dai->dev, "set_fmt error\n");
+			goto err;
+		}
+	}
+
+	if (set->sysclk) {
+		ret = snd_soc_dai_set_sysclk(dai, 0, set->sysclk, 0);
+		if (ret && ret != -ENOTSUPP) {
+			dev_err(dai->dev, "set_sysclk error\n");
+			goto err;
+		}
+	}
+
+	ret = 0;
+
+err:
+	return ret;
+}
+
+static int rsrc_card_dai_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct rsrc_card_priv *priv =	snd_soc_card_get_drvdata(rtd->card);
+	struct snd_soc_dai *codec = rtd->codec_dai;
+	struct snd_soc_dai *cpu = rtd->cpu_dai;
+	struct rsrc_card_dai_props *dai_props;
+	int num, ret;
+
+	num = rtd - rtd->card->rtd;
+	dai_props = &priv->dai_props[num];
+	ret = __rsrc_card_dai_init(codec, &dai_props->codec_dai);
+	if (ret < 0)
+		return ret;
+
+	ret = __rsrc_card_dai_init(cpu, &dai_props->cpu_dai);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int rsrc_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+					struct snd_pcm_hw_params *params)
+{
+	struct rsrc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card);
+	struct snd_interval *rate = hw_param_interval(params,
+						      SNDRV_PCM_HW_PARAM_RATE);
+
+	if (!priv->convert_rate)
+		return 0;
+
+	rate->min = rate->max = priv->convert_rate;
+
+	return 0;
+}
+
+static int
+rsrc_card_sub_parse_of(struct rsrc_card_priv *priv,
+		       struct device_node *np,
+		       struct rsrc_card_dai *dai,
+		       struct snd_soc_dai_link *dai_link,
+		       int *args_count)
+{
+	struct device *dev = rsrc_priv_to_dev(priv);
+	const struct rsrc_card_of_data *of_data = rsrc_dev_to_of_data(dev);
+	struct of_phandle_args args;
+	struct device_node **p_node;
+	struct clk *clk;
+	const char **dai_name;
+	const char **name;
+	u32 val;
+	int ret;
+
+	if (args_count) {
+		p_node		= &dai_link->cpu_of_node;
+		dai_name	= &dai_link->cpu_dai_name;
+		name		= &dai_link->cpu_name;
+	} else {
+		p_node		= &dai_link->codec_of_node;
+		dai_name	= &dai_link->codec_dai_name;
+		name		= &dai_link->codec_name;
+	}
+
+	if (!np) {
+		/* use snd-soc-dummy */
+		*p_node		= NULL;
+		*dai_name	= "snd-soc-dummy-dai";
+		*name		= "snd-soc-dummy";
+		return 0;
+	}
+
+	/*
+	 * Get node via "sound-dai = <&phandle port>"
+	 * it will be used as xxx_of_node on soc_bind_dai_link()
+	 */
+	ret = of_parse_phandle_with_args(np, "sound-dai",
+					 "#sound-dai-cells", 0, &args);
+	if (ret)
+		return ret;
+
+	*p_node = args.np;
+
+	/* Get dai->name */
+	ret = snd_soc_of_get_dai_name(np, dai_name);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * FIXME
+	 *
+	 * rsrc assumes DPCM playback/capture
+	 */
+	dai_link->dpcm_playback = 1;
+	dai_link->dpcm_capture = 1;
+
+	if (args_count) {
+		*args_count = args.args_count;
+		dai_link->dynamic = 1;
+	} else {
+		dai_link->no_pcm = 1;
+		priv->codec_conf.of_node = (*p_node);
+		priv->codec_conf.name_prefix = of_data->prefix;
+	}
+
+	/*
+	 * Parse dai->sysclk come from "clocks = <&xxx>"
+	 * (if system has common clock)
+	 *  or "system-clock-frequency = <xxx>"
+	 *  or device's module clock.
+	 */
+	if (of_property_read_bool(np, "clocks")) {
+		clk = of_clk_get(np, 0);
+		if (IS_ERR(clk)) {
+			ret = PTR_ERR(clk);
+			return ret;
+		}
+
+		dai->sysclk = clk_get_rate(clk);
+		dai->clk = clk;
+	} else if (!of_property_read_u32(np, "system-clock-frequency", &val)) {
+		dai->sysclk = val;
+	} else {
+		clk = of_clk_get(args.np, 0);
+		if (!IS_ERR(clk))
+			dai->sysclk = clk_get_rate(clk);
+	}
+
+	return 0;
+}
+
+static int rsrc_card_parse_daifmt(struct device_node *node,
+				  struct rsrc_card_priv *priv,
+				  struct device_node *codec,
+				  int idx)
+{
+	struct device_node *bitclkmaster = NULL;
+	struct device_node *framemaster = NULL;
+	struct rsrc_card_dai_props *dai_props = rsrc_priv_to_props(priv, idx);
+	struct rsrc_card_dai *cpu_dai = &dai_props->cpu_dai;
+	struct rsrc_card_dai *codec_dai = &dai_props->codec_dai;
+	unsigned int daifmt;
+
+	daifmt = snd_soc_of_parse_daifmt(node, NULL,
+					 &bitclkmaster, &framemaster);
+	daifmt &= ~SND_SOC_DAIFMT_MASTER_MASK;
+
+	if (!bitclkmaster && !framemaster)
+		return -EINVAL;
+
+	if (codec == bitclkmaster)
+		daifmt |= (codec == framemaster) ?
+			SND_SOC_DAIFMT_CBM_CFM : SND_SOC_DAIFMT_CBM_CFS;
+	else
+		daifmt |= (codec == framemaster) ?
+			SND_SOC_DAIFMT_CBS_CFM : SND_SOC_DAIFMT_CBS_CFS;
+
+	cpu_dai->fmt	= daifmt;
+	codec_dai->fmt	= daifmt;
+
+	of_node_put(bitclkmaster);
+	of_node_put(framemaster);
+
+	return 0;
+}
+
+static int rsrc_card_dai_link_of(struct device_node *node,
+				 struct rsrc_card_priv *priv,
+				 int idx)
+{
+	struct device *dev = rsrc_priv_to_dev(priv);
+	struct snd_soc_dai_link *dai_link = rsrc_priv_to_link(priv, idx);
+	struct rsrc_card_dai_props *dai_props = rsrc_priv_to_props(priv, idx);
+	struct device_node *cpu = NULL;
+	struct device_node *codec = NULL;
+	char *name;
+	char prop[128];
+	int ret, cpu_args;
+
+	cpu = of_get_child_by_name(node, "cpu");
+	codec = of_get_child_by_name(node, "codec");
+
+	if (!cpu || !codec) {
+		ret = -EINVAL;
+		dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop);
+		goto dai_link_of_err;
+	}
+
+	ret = rsrc_card_parse_daifmt(node, priv, codec, idx);
+	if (ret < 0)
+		goto dai_link_of_err;
+
+	ret = rsrc_card_sub_parse_of(priv, (idx == IDX_CPU) ? cpu : NULL,
+				     &dai_props->cpu_dai,
+				     dai_link,
+				     &cpu_args);
+	if (ret < 0)
+		goto dai_link_of_err;
+
+	ret = rsrc_card_sub_parse_of(priv, (idx == IDX_CODEC) ? codec : NULL,
+				     &dai_props->codec_dai,
+				     dai_link,
+				     NULL);
+	if (ret < 0)
+		goto dai_link_of_err;
+
+	if (!dai_link->cpu_dai_name || !dai_link->codec_dai_name) {
+		ret = -EINVAL;
+		goto dai_link_of_err;
+	}
+
+	/* Simple Card assumes platform == cpu */
+	dai_link->platform_of_node = dai_link->cpu_of_node;
+
+	/* DAI link name is created from CPU/CODEC dai name */
+	name = devm_kzalloc(dev,
+			    strlen(dai_link->cpu_dai_name)   +
+			    strlen(dai_link->codec_dai_name) + 2,
+			    GFP_KERNEL);
+	if (!name) {
+		ret = -ENOMEM;
+		goto dai_link_of_err;
+	}
+
+	sprintf(name, "%s-%s", dai_link->cpu_dai_name,
+		dai_link->codec_dai_name);
+	dai_link->name = dai_link->stream_name = name;
+	dai_link->ops = &rsrc_card_ops;
+	dai_link->init = rsrc_card_dai_init;
+
+	if (idx == IDX_CODEC)
+		dai_link->be_hw_params_fixup = rsrc_card_be_hw_params_fixup;
+
+	dev_dbg(dev, "\tname : %s\n", dai_link->stream_name);
+	dev_dbg(dev, "\tcpu : %s / %04x / %d\n",
+		dai_link->cpu_dai_name,
+		dai_props->cpu_dai.fmt,
+		dai_props->cpu_dai.sysclk);
+	dev_dbg(dev, "\tcodec : %s / %04x / %d\n",
+		dai_link->codec_dai_name,
+		dai_props->codec_dai.fmt,
+		dai_props->codec_dai.sysclk);
+
+	/*
+	 * In soc_bind_dai_link() will check cpu name after
+	 * of_node matching if dai_link has cpu_dai_name.
+	 * but, it will never match if name was created by
+	 * fmt_single_name() remove cpu_dai_name if cpu_args
+	 * was 0. See:
+	 *	fmt_single_name()
+	 *	fmt_multiple_name()
+	 */
+	if (!cpu_args)
+		dai_link->cpu_dai_name = NULL;
+
+dai_link_of_err:
+	of_node_put(cpu);
+	of_node_put(codec);
+
+	return ret;
+}
+
+static int rsrc_card_parse_of(struct device_node *node,
+			      struct rsrc_card_priv *priv)
+{
+	struct device *dev = rsrc_priv_to_dev(priv);
+	const struct rsrc_card_of_data *of_data = rsrc_dev_to_of_data(dev);
+	int ret;
+	int i;
+
+	if (!node)
+		return -EINVAL;
+
+	/* Parse the card name from DT */
+	snd_soc_of_parse_card_name(&priv->snd_card, "card-name");
+
+	/* DAPM routes */
+	priv->snd_card.of_dapm_routes		= of_data->routes;
+	priv->snd_card.num_of_dapm_routes	= of_data->num_routes;
+
+	/* sampling rate convert */
+	of_property_read_u32(node, "convert-rate", &priv->convert_rate);
+
+	dev_dbg(dev, "New rsrc-audio-card: %s (%d)\n",
+		priv->snd_card.name ? priv->snd_card.name : "",
+		priv->convert_rate);
+
+	/* FE/BE */
+	for (i = 0; i < RSRC_FB_NUM; i++) {
+		ret = rsrc_card_dai_link_of(node, priv, i);
+		if (ret < 0)
+			return ret;
+	}
+
+	if (!priv->snd_card.name)
+		priv->snd_card.name = priv->snd_card.dai_link->name;
+
+	return 0;
+}
+
+/* Decrease the reference count of the device nodes */
+static int rsrc_card_unref(struct snd_soc_card *card)
+{
+	struct snd_soc_dai_link *dai_link;
+	int num_links;
+
+	for (num_links = 0, dai_link = card->dai_link;
+	     num_links < card->num_links;
+	     num_links++, dai_link++) {
+		of_node_put(dai_link->cpu_of_node);
+		of_node_put(dai_link->codec_of_node);
+	}
+	return 0;
+}
+
+static int rsrc_card_probe(struct platform_device *pdev)
+{
+	struct rsrc_card_priv *priv;
+	struct snd_soc_dai_link *dai_link;
+	struct device_node *np = pdev->dev.of_node;
+	struct device *dev = &pdev->dev;
+	int ret;
+
+	/* Allocate the private data */
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	/* Init snd_soc_card */
+	priv->snd_card.owner = THIS_MODULE;
+	priv->snd_card.dev = dev;
+	dai_link = priv->dai_link;
+	priv->snd_card.dai_link = dai_link;
+	priv->snd_card.num_links = RSRC_FB_NUM;
+	priv->snd_card.codec_conf = &priv->codec_conf;
+	priv->snd_card.num_configs = 1;
+
+	ret = rsrc_card_parse_of(np, priv);
+	if (ret < 0) {
+		if (ret != -EPROBE_DEFER)
+			dev_err(dev, "parse error %d\n", ret);
+		goto err;
+	}
+
+	snd_soc_card_set_drvdata(&priv->snd_card, priv);
+
+	ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card);
+	if (ret >= 0)
+		return ret;
+err:
+	rsrc_card_unref(&priv->snd_card);
+
+	return ret;
+}
+
+static int rsrc_card_remove(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+	return rsrc_card_unref(card);
+}
+
+static struct platform_driver rsrc_card = {
+	.driver = {
+		.name = "renesas-src-audio-card",
+		.of_match_table = rsrc_card_of_match,
+	},
+	.probe = rsrc_card_probe,
+	.remove = rsrc_card_remove,
+};
+
+module_platform_driver(rsrc_card);
+
+MODULE_ALIAS("platform:renesas-src-audio-card");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Renesas Sampling Rate Convert Sound Card");
+MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c
index c77d059..6099a8e 100644
--- a/sound/soc/sh/rcar/src.c
+++ b/sound/soc/sh/rcar/src.c
@@ -28,10 +28,11 @@
 #define RSND_SRC_NAME_SIZE 16
 
 #define rsnd_src_convert_rate(p) ((p)->info->convert_rate)
+#define rsnd_src_of_node(priv) \
+	of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,src")
+
 #define rsnd_mod_to_src(_mod)				\
 	container_of((_mod), struct rsnd_src, mod)
-#define rsnd_src_dma_available(src) \
-	rsnd_dma_available(rsnd_mod_to_dma(&(src)->mod))
 
 #define for_each_rsnd_src(pos, priv, i)				\
 	for ((i) = 0;						\
@@ -113,6 +114,17 @@
 /*
  *		Gen1/Gen2 common functions
  */
+static struct dma_chan *rsnd_src_dma_req(struct rsnd_mod *mod)
+{
+	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+	struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
+	int is_play = rsnd_io_is_play(io);
+
+	return rsnd_dma_request_channel(rsnd_src_of_node(priv),
+					mod,
+					is_play ? "rx" : "tx");
+}
+
 int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod,
 			int use_busif)
 {
@@ -505,6 +517,7 @@
 
 static struct rsnd_mod_ops rsnd_src_gen1_ops = {
 	.name	= SRC_NAME,
+	.dma_req = rsnd_src_dma_req,
 	.probe	= rsnd_src_probe_gen1,
 	.init	= rsnd_src_init_gen1,
 	.quit	= rsnd_src_quit,
@@ -607,13 +620,17 @@
 
 	if (rsnd_src_error_record_gen2(mod)) {
 		struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+		struct rsnd_src *src = rsnd_mod_to_src(mod);
 		struct device *dev = rsnd_priv_to_dev(priv);
 
-		_rsnd_src_stop_gen2(mod);
-		_rsnd_src_start_gen2(mod);
-
 		dev_dbg(dev, "%s[%d] restart\n",
 			rsnd_mod_name(mod), rsnd_mod_id(mod));
+
+		_rsnd_src_stop_gen2(mod);
+		if (src->err < 1024)
+			_rsnd_src_start_gen2(mod);
+		else
+			dev_warn(dev, "no more SRC restart\n");
 	}
 
 	return IRQ_HANDLED;
@@ -713,7 +730,6 @@
 
 	ret = rsnd_dma_init(priv,
 			    rsnd_mod_to_dma(mod),
-			    rsnd_info_is_playback(priv, src),
 			    src->info->dma_id);
 	if (ret)
 		goto rsnd_src_probe_gen2_fail;
@@ -733,7 +749,7 @@
 static int rsnd_src_remove_gen2(struct rsnd_mod *mod,
 				struct rsnd_priv *priv)
 {
-	rsnd_dma_quit(priv, rsnd_mod_to_dma(mod));
+	rsnd_dma_quit(rsnd_mod_to_dma(mod));
 
 	return 0;
 }
@@ -780,6 +796,7 @@
 
 static struct rsnd_mod_ops rsnd_src_gen2_ops = {
 	.name	= SRC_NAME,
+	.dma_req = rsnd_src_dma_req,
 	.probe	= rsnd_src_probe_gen2,
 	.remove	= rsnd_src_remove_gen2,
 	.init	= rsnd_src_init_gen2,
@@ -810,7 +827,7 @@
 	if (!of_data)
 		return;
 
-	src_node = of_get_child_by_name(dev->of_node, "rcar_sound,src");
+	src_node = rsnd_src_of_node(priv);
 	if (!src_node)
 		return;
 
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
index f7cb1fd..79dc7a3 100644
--- a/sound/soc/sh/rcar/ssi.c
+++ b/sound/soc/sh/rcar/ssi.c
@@ -80,13 +80,13 @@
 #define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod)
 #define rsnd_dma_to_ssi(dma)  rsnd_mod_to_ssi(rsnd_dma_to_mod(dma))
 #define rsnd_ssi_pio_available(ssi) ((ssi)->info->irq > 0)
-#define rsnd_ssi_dma_available(ssi) \
-	rsnd_dma_available(rsnd_mod_to_dma(&(ssi)->mod))
 #define rsnd_ssi_clk_from_parent(ssi) ((ssi)->parent)
 #define rsnd_ssi_mode_flags(p) ((p)->info->flags)
 #define rsnd_ssi_dai_id(ssi) ((ssi)->info->dai_id)
+#define rsnd_ssi_of_node(priv) \
+	of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ssi")
 
-static int rsnd_ssi_use_busif(struct rsnd_mod *mod)
+int rsnd_ssi_use_busif(struct rsnd_mod *mod)
 {
 	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
 	struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
@@ -416,11 +416,14 @@
 		/*
 		 * restart SSI
 		 */
-		rsnd_ssi_stop(mod, priv);
-		rsnd_ssi_start(mod, priv);
-
 		dev_dbg(dev, "%s[%d] restart\n",
 			rsnd_mod_name(mod), rsnd_mod_id(mod));
+
+		rsnd_ssi_stop(mod, priv);
+		if (ssi->err < 1024)
+			rsnd_ssi_start(mod, priv);
+		else
+			dev_warn(dev, "no more SSI restart\n");
 	}
 
 	rsnd_ssi_record_error(ssi, status);
@@ -478,7 +481,6 @@
 
 	ret = rsnd_dma_init(
 		priv, rsnd_mod_to_dma(mod),
-		rsnd_info_is_playback(priv, ssi),
 		dma_id);
 	if (ret)
 		goto rsnd_ssi_dma_probe_fail;
@@ -502,7 +504,7 @@
 	struct device *dev = rsnd_priv_to_dev(priv);
 	int irq = ssi->info->irq;
 
-	rsnd_dma_quit(priv, rsnd_mod_to_dma(mod));
+	rsnd_dma_quit(rsnd_mod_to_dma(mod));
 
 	/* PIO will request IRQ again */
 	devm_free_irq(dev, irq, ssi);
@@ -554,14 +556,25 @@
 	return 0;
 }
 
-static char *rsnd_ssi_dma_name(struct rsnd_mod *mod)
+static struct dma_chan *rsnd_ssi_dma_req(struct rsnd_mod *mod)
 {
-	return rsnd_ssi_use_busif(mod) ? "ssiu" : SSI_NAME;
+	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+	struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
+	int is_play = rsnd_io_is_play(io);
+	char *name;
+
+	if (rsnd_ssi_use_busif(mod))
+		name = is_play ? "rxu" : "txu";
+	else
+		name = is_play ? "rx" : "tx";
+
+	return rsnd_dma_request_channel(rsnd_ssi_of_node(priv),
+					mod, name);
 }
 
 static struct rsnd_mod_ops rsnd_ssi_dma_ops = {
 	.name	= SSI_NAME,
-	.dma_name = rsnd_ssi_dma_name,
+	.dma_req = rsnd_ssi_dma_req,
 	.probe	= rsnd_ssi_dma_probe,
 	.remove	= rsnd_ssi_dma_remove,
 	.init	= rsnd_ssi_init,
@@ -636,7 +649,7 @@
 	if (!of_data)
 		return;
 
-	node = of_get_child_by_name(dev->of_node, "rcar_sound,ssi");
+	node = rsnd_ssi_of_node(priv);
 	if (!node)
 		return;