Browse Source

Merge remote-tracking branch 'asoc/topic/rcar' into asoc-next

Mark Brown 11 years ago
parent
commit
2fd5373467

+ 9 - 0
Documentation/devicetree/bindings/sound/renesas,rsnd.txt

@@ -13,6 +13,9 @@ Required properties:
 - rcar_sound,src		: Should contain SRC feature.
 				  The number of SRC subnode should be same as HW.
 				  see below for detail.
+- rcar_sound,dvc		: Should contain DVC feature.
+				  The number of DVC subnode should be same as HW.
+				  see below for detail.
 - rcar_sound,dai		: DAI contents.
 				  The number of DAI subnode should be same as HW.
 				  see below for detail.
@@ -21,6 +24,7 @@ SSI subnode properties:
 - interrupts			: Should contain SSI interrupt for PIO transfer
 - shared-pin			: if shared clock pin
 - pio-transfer			: use PIO transfer mode
+- no-busif			: BUSIF is not ussed when [mem -> SSI] via DMA case
 
 SRC subnode properties:
 no properties at this point
@@ -39,6 +43,11 @@ rcar_sound: rcar_sound@0xffd90000 {
 		<0 0xec540000 0 0x1000>, /* SSIU */
 		<0 0xec541000 0 0x1280>; /* SSI */
 
+	rcar_sound,dvc {
+		dvc0: dvc@0 { };
+		dvc1: dvc@1 { };
+	};
+
 	rcar_sound,src {
 		src0: src@0 { };
 		src1: src@1 { };

+ 4 - 0
arch/arm/mach-shmobile/board-armadillo800eva.c

@@ -998,6 +998,8 @@ static struct platform_device fsi_wm8978_device = {
 	.id	= 0,
 	.dev	= {
 		.platform_data	= &fsi_wm8978_info,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+		.dma_mask = &fsi_wm8978_device.dev.coherent_dma_mask,
 	},
 };
 
@@ -1021,6 +1023,8 @@ static struct platform_device fsi_hdmi_device = {
 	.id	= 1,
 	.dev	= {
 		.platform_data	= &fsi2_hdmi_info,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+		.dma_mask = &fsi_hdmi_device.dev.coherent_dma_mask,
 	},
 };
 

+ 2 - 0
arch/arm/mach-shmobile/board-kzm9g.c

@@ -603,6 +603,8 @@ static struct platform_device fsi_ak4648_device = {
 	.name	= "asoc-simple-card",
 	.dev	= {
 		.platform_data	= &fsi2_ak4648_info,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+		.dma_mask = &fsi_ak4648_device.dev.coherent_dma_mask,
 	},
 };
 

+ 4 - 0
arch/arm/mach-shmobile/board-mackerel.c

@@ -523,6 +523,8 @@ static struct platform_device fsi_hdmi_device = {
 	.id	= 1,
 	.dev	= {
 		.platform_data	= &fsi2_hdmi_info,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+		.dma_mask = &fsi_hdmi_device.dev.coherent_dma_mask,
 	},
 };
 
@@ -919,6 +921,8 @@ static struct platform_device fsi_ak4643_device = {
 	.name	= "asoc-simple-card",
 	.dev	= {
 		.platform_data	= &fsi2_ak4643_info,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+		.dma_mask = &fsi_ak4643_device.dev.coherent_dma_mask,
 	},
 };
 

+ 2 - 0
arch/sh/boards/mach-ecovec24/setup.c

@@ -874,6 +874,8 @@ static struct platform_device fsi_da7210_device = {
 	.name	= "asoc-simple-card",
 	.dev	= {
 		.platform_data	= &fsi_da7210_info,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+		.dma_mask = &fsi_da7210_device.dev.coherent_dma_mask,
 	},
 };
 

+ 1 - 0
include/sound/rcar_snd.h

@@ -34,6 +34,7 @@
  * B : SSI direction
  */
 #define RSND_SSI_CLK_PIN_SHARE		(1 << 31)
+#define RSND_SSI_NO_BUSIF		(1 << 30) /* SSI+DMA without BUSIF */
 
 #define RSND_SSI(_dma_id, _pio_irq, _flags)		\
 { .dma_id = _dma_id, .pio_irq = _pio_irq, .flags = _flags }

+ 1 - 1
sound/soc/sh/Kconfig

@@ -37,7 +37,7 @@ config SND_SOC_SH4_SIU
 config SND_SOC_RCAR
 	tristate "R-Car series SRU/SCU/SSIU/SSI support"
 	select SND_SIMPLE_CARD
-	select REGMAP
+	select REGMAP_MMIO
 	help
 	  This option enables R-Car SUR/SCU/SSIU/SSI sound support
 

+ 52 - 137
sound/soc/sh/fsi.c

@@ -232,11 +232,7 @@ struct fsi_stream {
 	 * these are for DMAEngine
 	 */
 	struct dma_chan		*chan;
-	struct work_struct	work;
-	dma_addr_t		dma;
 	int			dma_id;
-	int			loop_cnt;
-	int			additional_pos;
 };
 
 struct fsi_clk {
@@ -1042,6 +1038,26 @@ static int fsi_clk_set_rate_cpg(struct device *dev,
 	return ret;
 }
 
+static void fsi_pointer_update(struct fsi_stream *io, int size)
+{
+	io->buff_sample_pos += size;
+
+	if (io->buff_sample_pos >=
+	    io->period_samples * (io->period_pos + 1)) {
+		struct snd_pcm_substream *substream = io->substream;
+		struct snd_pcm_runtime *runtime = substream->runtime;
+
+		io->period_pos++;
+
+		if (io->period_pos >= runtime->periods) {
+			io->buff_sample_pos = 0;
+			io->period_pos = 0;
+		}
+
+		snd_pcm_period_elapsed(substream);
+	}
+}
+
 /*
  *		pio data transfer handler
  */
@@ -1108,31 +1124,11 @@ static int fsi_pio_transfer(struct fsi_priv *fsi, struct fsi_stream *io,
 		void (*run32)(struct fsi_priv *fsi, u8 *buf, int samples),
 		int samples)
 {
-	struct snd_pcm_runtime *runtime;
-	struct snd_pcm_substream *substream;
 	u8 *buf;
-	int over_period;
 
 	if (!fsi_stream_is_working(fsi, io))
 		return -EINVAL;
 
-	over_period	= 0;
-	substream	= io->substream;
-	runtime		= substream->runtime;
-
-	/* FSI FIFO has limit.
-	 * So, this driver can not send periods data at a time
-	 */
-	if (io->buff_sample_pos >=
-	    io->period_samples * (io->period_pos + 1)) {
-
-		over_period = 1;
-		io->period_pos = (io->period_pos + 1) % runtime->periods;
-
-		if (0 == io->period_pos)
-			io->buff_sample_pos = 0;
-	}
-
 	buf = fsi_pio_get_area(fsi, io);
 
 	switch (io->sample_width) {
@@ -1146,11 +1142,7 @@ static int fsi_pio_transfer(struct fsi_priv *fsi, struct fsi_stream *io,
 		return -EINVAL;
 	}
 
-	/* update buff_sample_pos */
-	io->buff_sample_pos += samples;
-
-	if (over_period)
-		snd_pcm_period_elapsed(substream);
+	fsi_pointer_update(io, samples);
 
 	return 0;
 }
@@ -1279,11 +1271,6 @@ static irqreturn_t fsi_interrupt(int irq, void *data)
  */
 static int fsi_dma_init(struct fsi_priv *fsi, struct fsi_stream *io)
 {
-	struct snd_pcm_runtime *runtime = io->substream->runtime;
-	struct snd_soc_dai *dai = fsi_get_dai(io->substream);
-	enum dma_data_direction dir = fsi_stream_is_play(fsi, io) ?
-				DMA_TO_DEVICE : DMA_FROM_DEVICE;
-
 	/*
 	 * 24bit data : 24bit bus / package in back
 	 * 16bit data : 16bit bus / stream mode
@@ -1291,107 +1278,48 @@ static int fsi_dma_init(struct fsi_priv *fsi, struct fsi_stream *io)
 	io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) |
 			 BUSOP_SET(16, PACKAGE_16BITBUS_STREAM);
 
-	io->loop_cnt = 2; /* push 1st, 2nd period first, then 3rd, 4th... */
-	io->additional_pos = 0;
-	io->dma = dma_map_single(dai->dev, runtime->dma_area,
-				 snd_pcm_lib_buffer_bytes(io->substream), dir);
 	return 0;
 }
 
-static int fsi_dma_quit(struct fsi_priv *fsi, struct fsi_stream *io)
-{
-	struct snd_soc_dai *dai = fsi_get_dai(io->substream);
-	enum dma_data_direction dir = fsi_stream_is_play(fsi, io) ?
-		DMA_TO_DEVICE : DMA_FROM_DEVICE;
-
-	dma_unmap_single(dai->dev, io->dma,
-			 snd_pcm_lib_buffer_bytes(io->substream), dir);
-	return 0;
-}
-
-static dma_addr_t fsi_dma_get_area(struct fsi_stream *io, int additional)
-{
-	struct snd_pcm_runtime *runtime = io->substream->runtime;
-	int period = io->period_pos + additional;
-
-	if (period >= runtime->periods)
-		period = 0;
-
-	return io->dma + samples_to_bytes(runtime, period * io->period_samples);
-}
-
 static void fsi_dma_complete(void *data)
 {
 	struct fsi_stream *io = (struct fsi_stream *)data;
 	struct fsi_priv *fsi = fsi_stream_to_priv(io);
-	struct snd_pcm_runtime *runtime = io->substream->runtime;
-	struct snd_soc_dai *dai = fsi_get_dai(io->substream);
-	enum dma_data_direction dir = fsi_stream_is_play(fsi, io) ?
-		DMA_TO_DEVICE : DMA_FROM_DEVICE;
 
-	dma_sync_single_for_cpu(dai->dev, fsi_dma_get_area(io, 0),
-			samples_to_bytes(runtime, io->period_samples), dir);
-
-	io->buff_sample_pos += io->period_samples;
-	io->period_pos++;
-
-	if (io->period_pos >= runtime->periods) {
-		io->period_pos = 0;
-		io->buff_sample_pos = 0;
-	}
+	fsi_pointer_update(io, io->period_samples);
 
 	fsi_count_fifo_err(fsi);
-	fsi_stream_transfer(io);
-
-	snd_pcm_period_elapsed(io->substream);
 }
 
-static void fsi_dma_do_work(struct work_struct *work)
+static int fsi_dma_transfer(struct fsi_priv *fsi, struct fsi_stream *io)
 {
-	struct fsi_stream *io = container_of(work, struct fsi_stream, work);
-	struct fsi_priv *fsi = fsi_stream_to_priv(io);
-	struct snd_soc_dai *dai;
+	struct snd_soc_dai *dai = fsi_get_dai(io->substream);
+	struct snd_pcm_substream *substream = io->substream;
 	struct dma_async_tx_descriptor *desc;
-	struct snd_pcm_runtime *runtime;
-	enum dma_data_direction dir;
 	int is_play = fsi_stream_is_play(fsi, io);
-	int len, i;
-	dma_addr_t buf;
-
-	if (!fsi_stream_is_working(fsi, io))
-		return;
-
-	dai	= fsi_get_dai(io->substream);
-	runtime	= io->substream->runtime;
-	dir	= is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
-	len	= samples_to_bytes(runtime, io->period_samples);
-
-	for (i = 0; i < io->loop_cnt; i++) {
-		buf	= fsi_dma_get_area(io, io->additional_pos);
-
-		dma_sync_single_for_device(dai->dev, buf, len, dir);
-
-		desc = dmaengine_prep_slave_single(io->chan, buf, len, dir,
-					DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-		if (!desc) {
-			dev_err(dai->dev, "dmaengine_prep_slave_sg() fail\n");
-			return;
-		}
-
-		desc->callback		= fsi_dma_complete;
-		desc->callback_param	= io;
-
-		if (dmaengine_submit(desc) < 0) {
-			dev_err(dai->dev, "tx_submit() fail\n");
-			return;
-		}
+	enum dma_data_direction dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
+	int ret = -EIO;
+
+	desc = dmaengine_prep_dma_cyclic(io->chan,
+					 substream->runtime->dma_addr,
+					 snd_pcm_lib_buffer_bytes(substream),
+					 snd_pcm_lib_period_bytes(substream),
+					 dir,
+					 DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+	if (!desc) {
+		dev_err(dai->dev, "dmaengine_prep_dma_cyclic() fail\n");
+		goto fsi_dma_transfer_err;
+	}
 
-		dma_async_issue_pending(io->chan);
+	desc->callback		= fsi_dma_complete;
+	desc->callback_param	= io;
 
-		io->additional_pos = 1;
+	if (dmaengine_submit(desc) < 0) {
+		dev_err(dai->dev, "tx_submit() fail\n");
+		goto fsi_dma_transfer_err;
 	}
 
-	io->loop_cnt = 1;
+	dma_async_issue_pending(io->chan);
 
 	/*
 	 * FIXME
@@ -1408,13 +1336,11 @@ static void fsi_dma_do_work(struct work_struct *work)
 			fsi_reg_write(fsi, DIFF_ST, 0);
 		}
 	}
-}
 
-static int fsi_dma_transfer(struct fsi_priv *fsi, struct fsi_stream *io)
-{
-	schedule_work(&io->work);
+	ret = 0;
 
-	return 0;
+fsi_dma_transfer_err:
+	return ret;
 }
 
 static int fsi_dma_push_start_stop(struct fsi_priv *fsi, struct fsi_stream *io,
@@ -1475,15 +1401,11 @@ static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io, struct dev
 		return fsi_stream_probe(fsi, dev);
 	}
 
-	INIT_WORK(&io->work, fsi_dma_do_work);
-
 	return 0;
 }
 
 static int fsi_dma_remove(struct fsi_priv *fsi, struct fsi_stream *io)
 {
-	cancel_work_sync(&io->work);
-
 	fsi_stream_stop(fsi, io);
 
 	if (io->chan)
@@ -1495,7 +1417,6 @@ static int fsi_dma_remove(struct fsi_priv *fsi, struct fsi_stream *io)
 
 static struct fsi_stream_handler fsi_dma_push_handler = {
 	.init		= fsi_dma_init,
-	.quit		= fsi_dma_quit,
 	.probe		= fsi_dma_probe,
 	.transfer	= fsi_dma_transfer,
 	.remove		= fsi_dma_remove,
@@ -1657,9 +1578,9 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
 		if (!ret)
 			ret = fsi_hw_startup(fsi, io, dai->dev);
 		if (!ret)
-			ret = fsi_stream_transfer(io);
+			ret = fsi_stream_start(fsi, io);
 		if (!ret)
-			fsi_stream_start(fsi, io);
+			ret = fsi_stream_transfer(io);
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
 		if (!ret)
@@ -1850,16 +1771,10 @@ static void fsi_pcm_free(struct snd_pcm *pcm)
 
 static int fsi_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
-	struct snd_pcm *pcm = rtd->pcm;
-
-	/*
-	 * dont use SNDRV_DMA_TYPE_DEV, since it will oops the SH kernel
-	 * in MMAP mode (i.e. aplay -M)
-	 */
 	return snd_pcm_lib_preallocate_pages_for_all(
-		pcm,
-		SNDRV_DMA_TYPE_CONTINUOUS,
-		snd_dma_continuous_data(GFP_KERNEL),
+		rtd->pcm,
+		SNDRV_DMA_TYPE_DEV,
+		rtd->card->snd_card->dev,
 		PREALLOC_BUFFER, PREALLOC_BUFFER_MAX);
 }
 

+ 118 - 125
sound/soc/sh/rcar/core.c

@@ -138,6 +138,17 @@ char *rsnd_mod_name(struct rsnd_mod *mod)
 	return mod->ops->name;
 }
 
+char *rsnd_mod_dma_name(struct rsnd_mod *mod)
+{
+	if (!mod || !mod->ops)
+		return "unknown";
+
+	if (!mod->ops->dma_name)
+		return mod->ops->name;
+
+	return mod->ops->dma_name(mod);
+}
+
 void rsnd_mod_init(struct rsnd_priv *priv,
 		   struct rsnd_mod *mod,
 		   struct rsnd_mod_ops *ops,
@@ -153,26 +164,8 @@ void rsnd_mod_init(struct rsnd_priv *priv,
 /*
  *	rsnd_dma functions
  */
-static void __rsnd_dma_start(struct rsnd_dma *dma);
-static void rsnd_dma_continue(struct rsnd_dma *dma)
-{
-	/* push next A or B plane */
-	dma->submit_loop = 1;
-	schedule_work(&dma->work);
-}
-
-void rsnd_dma_start(struct rsnd_dma *dma)
-{
-	/* push both A and B plane*/
-	dma->offset = 0;
-	dma->submit_loop = 2;
-	__rsnd_dma_start(dma);
-}
-
 void rsnd_dma_stop(struct rsnd_dma *dma)
 {
-	dma->submit_loop = 0;
-	cancel_work_sync(&dma->work);
 	dmaengine_terminate_all(dma->chan);
 }
 
@@ -180,11 +173,7 @@ 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_priv *priv = rsnd_mod_to_priv(rsnd_dma_to_mod(dma));
 	struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
-	unsigned long flags;
-
-	rsnd_lock(priv, flags);
 
 	/*
 	 * Renesas sound Gen1 needs 1 DMAC,
@@ -197,57 +186,41 @@ static void rsnd_dma_complete(void *data)
 	 * rsnd_dai_pointer_update() will be called twice,
 	 * ant it will breaks io->byte_pos
 	 */
-	if (dma->submit_loop)
-		rsnd_dma_continue(dma);
-
-	rsnd_unlock(priv, flags);
 
 	rsnd_dai_pointer_update(io, io->byte_per_period);
 }
 
-static void __rsnd_dma_start(struct rsnd_dma *dma)
+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_runtime *runtime = rsnd_io_to_runtime(io);
+	struct snd_pcm_substream *substream = io->substream;
 	struct device *dev = rsnd_priv_to_dev(priv);
 	struct dma_async_tx_descriptor *desc;
-	dma_addr_t buf;
-	size_t len = io->byte_per_period;
-	int i;
 
-	for (i = 0; i < dma->submit_loop; i++) {
-
-		buf = runtime->dma_addr +
-			rsnd_dai_pointer_offset(io, dma->offset + len);
-		dma->offset = len;
-
-		desc = dmaengine_prep_slave_single(
-			dma->chan, buf, len, dma->dir,
-			DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-		if (!desc) {
-			dev_err(dev, "dmaengine_prep_slave_sg() fail\n");
-			return;
-		}
+	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);
 
-		desc->callback		= rsnd_dma_complete;
-		desc->callback_param	= dma;
+	if (!desc) {
+		dev_err(dev, "dmaengine_prep_slave_sg() fail\n");
+		return;
+	}
 
-		if (dmaengine_submit(desc) < 0) {
-			dev_err(dev, "dmaengine_submit() fail\n");
-			return;
-		}
+	desc->callback		= rsnd_dma_complete;
+	desc->callback_param	= dma;
 
-		dma_async_issue_pending(dma->chan);
+	if (dmaengine_submit(desc) < 0) {
+		dev_err(dev, "dmaengine_submit() fail\n");
+		return;
 	}
-}
-
-static void rsnd_dma_do_work(struct work_struct *work)
-{
-	struct rsnd_dma *dma = container_of(work, struct rsnd_dma, work);
 
-	__rsnd_dma_start(dma);
+	dma_async_issue_pending(dma->chan);
 }
 
 int rsnd_dma_available(struct rsnd_dma *dma)
@@ -261,14 +234,27 @@ 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_name(mod), rsnd_mod_id(mod));
+			 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_dma *dma,
-			     int is_play, char *dma_name)
+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);
@@ -276,7 +262,6 @@ static void rsnd_dma_of_name(struct rsnd_dma *dma,
 	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];
-	struct rsnd_mod *src_mod, *dst_mod;
 	int i, index;
 
 
@@ -301,7 +286,13 @@ static void rsnd_dma_of_name(struct rsnd_dma *dma,
 			mod[i] = src;
 			src = NULL;
 		} else {
-			mod[i] = dvc;
+			if ((!is_play) && (this == src))
+				this = dvc;
+
+			mod[i] = (is_play) ? src : dvc;
+			i++;
+			mod[i] = (is_play) ? dvc : src;
+			src = NULL;
 			dvc = NULL;
 		}
 
@@ -313,17 +304,12 @@ static void rsnd_dma_of_name(struct rsnd_dma *dma,
 	}
 
 	if (is_play) {
-		src_mod = mod[index - 1];
-		dst_mod = mod[index];
+		*mod_from = mod[index - 1];
+		*mod_to   = mod[index];
 	} else {
-		src_mod = mod[index];
-		dst_mod = mod[index - 1];
+		*mod_from = mod[index];
+		*mod_to   = mod[index - 1];
 	}
-
-	index = 0;
-	index = _rsnd_dma_of_name(dma_name + index, src_mod);
-	*(dma_name + index++) = '_';
-	index = _rsnd_dma_of_name(dma_name + index, dst_mod);
 }
 
 int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma,
@@ -331,6 +317,8 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma,
 {
 	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;
@@ -343,13 +331,18 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma,
 	dma_cap_zero(mask);
 	dma_cap_set(DMA_SLAVE, mask);
 
-	if (dev->of_node)
-		rsnd_dma_of_name(dma, is_play, dma_name);
-	else
-		snprintf(dma_name, DMA_NAME_SIZE,
-			 is_play ? "tx" : "rx");
+	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 name : %s\n", dma_name);
+	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,
@@ -359,14 +352,12 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma,
 		return -EIO;
 	}
 
-	rsnd_gen_dma_addr(priv, dma, &cfg, is_play, id);
-
 	ret = dmaengine_slave_config(dma->chan, &cfg);
 	if (ret < 0)
 		goto rsnd_dma_init_err;
 
-	dma->dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
-	INIT_WORK(&dma->work, rsnd_dma_do_work);
+	dma->addr = is_play ? cfg.src_addr : cfg.dst_addr;
+	dma->dir = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
 
 	return 0;
 
@@ -633,40 +624,41 @@ static int rsnd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 		return -EINVAL;
 	}
 
-	/* set clock inversion */
-	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
-	case SND_SOC_DAIFMT_NB_IF:
-		rdai->bit_clk_inv = 0;
-		rdai->frm_clk_inv = 1;
-		break;
-	case SND_SOC_DAIFMT_IB_NF:
-		rdai->bit_clk_inv = 1;
-		rdai->frm_clk_inv = 0;
-		break;
-	case SND_SOC_DAIFMT_IB_IF:
-		rdai->bit_clk_inv = 1;
-		rdai->frm_clk_inv = 1;
-		break;
-	case SND_SOC_DAIFMT_NB_NF:
-	default:
-		rdai->bit_clk_inv = 0;
-		rdai->frm_clk_inv = 0;
-		break;
-	}
-
 	/* set format */
 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 	case SND_SOC_DAIFMT_I2S:
 		rdai->sys_delay = 0;
 		rdai->data_alignment = 0;
+		rdai->frm_clk_inv = 0;
 		break;
 	case SND_SOC_DAIFMT_LEFT_J:
 		rdai->sys_delay = 1;
 		rdai->data_alignment = 0;
+		rdai->frm_clk_inv = 1;
 		break;
 	case SND_SOC_DAIFMT_RIGHT_J:
 		rdai->sys_delay = 1;
 		rdai->data_alignment = 1;
+		rdai->frm_clk_inv = 1;
+		break;
+	}
+
+	/* set clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_IF:
+		rdai->bit_clk_inv =  rdai->bit_clk_inv;
+		rdai->frm_clk_inv = !rdai->frm_clk_inv;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		rdai->bit_clk_inv = !rdai->bit_clk_inv;
+		rdai->frm_clk_inv =  rdai->frm_clk_inv;
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		rdai->bit_clk_inv = !rdai->bit_clk_inv;
+		rdai->frm_clk_inv = !rdai->frm_clk_inv;
+		break;
+	case SND_SOC_DAIFMT_NB_NF:
+	default:
 		break;
 	}
 
@@ -736,12 +728,13 @@ static void rsnd_of_parse_dai(struct platform_device *pdev,
 	struct device_node *dai_node,	*dai_np;
 	struct device_node *ssi_node,	*ssi_np;
 	struct device_node *src_node,	*src_np;
+	struct device_node *dvc_node,	*dvc_np;
 	struct device_node *playback, *capture;
 	struct rsnd_dai_platform_info *dai_info;
 	struct rcar_snd_info *info = rsnd_priv_to_info(priv);
 	struct device *dev = &pdev->dev;
 	int nr, i;
-	int dai_i, ssi_i, src_i;
+	int dai_i, ssi_i, src_i, dvc_i;
 
 	if (!of_data)
 		return;
@@ -767,6 +760,7 @@ static void rsnd_of_parse_dai(struct platform_device *pdev,
 
 	ssi_node = of_get_child_by_name(dev->of_node, "rcar_sound,ssi");
 	src_node = of_get_child_by_name(dev->of_node, "rcar_sound,src");
+	dvc_node = of_get_child_by_name(dev->of_node, "rcar_sound,dvc");
 
 #define mod_parse(name)							\
 if (name##_node) {							\
@@ -802,6 +796,7 @@ if (name##_node) {							\
 
 			mod_parse(ssi);
 			mod_parse(src);
+			mod_parse(dvc);
 
 			if (playback)
 				of_node_put(playback);
@@ -950,19 +945,17 @@ static struct snd_pcm_ops rsnd_pcm_ops = {
 
 static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
-	struct rsnd_priv *priv = snd_soc_dai_get_drvdata(rtd->cpu_dai);
-	struct rsnd_dai *rdai;
-	int i, ret;
+	struct snd_soc_dai *dai = rtd->cpu_dai;
+	struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
+	int ret;
 
-	for_each_rsnd_dai(rdai, priv, i) {
-		ret = rsnd_dai_call(pcm_new, &rdai->playback, rdai, rtd);
-		if (ret)
-			return ret;
+	ret = rsnd_dai_call(pcm_new, &rdai->playback, rdai, rtd);
+	if (ret)
+		return ret;
 
-		ret = rsnd_dai_call(pcm_new, &rdai->capture, rdai, rtd);
-		if (ret)
-			return ret;
-	}
+	ret = rsnd_dai_call(pcm_new, &rdai->capture, rdai, rtd);
+	if (ret)
+		return ret;
 
 	return snd_pcm_lib_preallocate_pages_for_all(
 		rtd->pcm,
@@ -1049,11 +1042,11 @@ static int rsnd_probe(struct platform_device *pdev)
 	for_each_rsnd_dai(rdai, priv, i) {
 		ret = rsnd_dai_call(probe, &rdai->playback, rdai);
 		if (ret)
-			return ret;
+			goto exit_snd_probe;
 
 		ret = rsnd_dai_call(probe, &rdai->capture, rdai);
 		if (ret)
-			return ret;
+			goto exit_snd_probe;
 	}
 
 	/*
@@ -1081,6 +1074,11 @@ static int rsnd_probe(struct platform_device *pdev)
 
 exit_snd_soc:
 	snd_soc_unregister_platform(dev);
+exit_snd_probe:
+	for_each_rsnd_dai(rdai, priv, i) {
+		rsnd_dai_call(remove, &rdai->playback, rdai);
+		rsnd_dai_call(remove, &rdai->capture, rdai);
+	}
 
 	return ret;
 }
@@ -1089,21 +1087,16 @@ static int rsnd_remove(struct platform_device *pdev)
 {
 	struct rsnd_priv *priv = dev_get_drvdata(&pdev->dev);
 	struct rsnd_dai *rdai;
-	int ret, i;
+	int ret = 0, i;
 
 	pm_runtime_disable(&pdev->dev);
 
 	for_each_rsnd_dai(rdai, priv, i) {
-		ret = rsnd_dai_call(remove, &rdai->playback, rdai);
-		if (ret)
-			return ret;
-
-		ret = rsnd_dai_call(remove, &rdai->capture, rdai);
-		if (ret)
-			return ret;
+		ret |= rsnd_dai_call(remove, &rdai->playback, rdai);
+		ret |= rsnd_dai_call(remove, &rdai->capture, rdai);
 	}
 
-	return 0;
+	return ret;
 }
 
 static struct platform_driver rsnd_driver = {

+ 101 - 34
sound/soc/sh/rcar/dvc.c

@@ -20,7 +20,8 @@ struct rsnd_dvc {
 	struct rsnd_dvc_platform_info *info; /* rcar_snd.h */
 	struct rsnd_mod mod;
 	struct clk *clk;
-	long volume[RSND_DVC_VOLUME_NUM];
+	u8 volume[RSND_DVC_VOLUME_NUM];
+	u8 mute[RSND_DVC_VOLUME_NUM];
 };
 
 #define rsnd_mod_to_dvc(_mod)	\
@@ -37,13 +38,18 @@ static void rsnd_dvc_volume_update(struct rsnd_mod *mod)
 	struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
 	u32 max = (0x00800000 - 1);
 	u32 vol[RSND_DVC_VOLUME_NUM];
+	u32 mute = 0;
 	int i;
 
-	for (i = 0; i < RSND_DVC_VOLUME_NUM; i++)
+	for (i = 0; i < RSND_DVC_VOLUME_NUM; i++) {
 		vol[i] = max / RSND_DVC_VOLUME_MAX * dvc->volume[i];
+		mute |= (!!dvc->mute[i]) << i;
+	}
 
 	rsnd_mod_write(mod, DVC_VOL0R, vol[0]);
 	rsnd_mod_write(mod, DVC_VOL1R, vol[1]);
+
+	rsnd_mod_write(mod, DVC_ZCMCR, mute);
 }
 
 static int rsnd_dvc_probe_gen2(struct rsnd_mod *mod,
@@ -96,8 +102,8 @@ static int rsnd_dvc_init(struct rsnd_mod *dvc_mod,
 
 	rsnd_mod_write(dvc_mod, DVC_ADINR, rsnd_get_adinr(dvc_mod));
 
-	/*  enable Volume  */
-	rsnd_mod_write(dvc_mod, DVC_DVUCR, 0x100);
+	/*  enable Volume / Mute */
+	rsnd_mod_write(dvc_mod, DVC_DVUCR, 0x101);
 
 	/* ch0/ch1 Volume */
 	rsnd_dvc_volume_update(dvc_mod);
@@ -140,10 +146,20 @@ static int rsnd_dvc_stop(struct rsnd_mod *mod,
 static int rsnd_dvc_volume_info(struct snd_kcontrol *kctrl,
 			       struct snd_ctl_elem_info *uinfo)
 {
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	struct rsnd_mod *mod = snd_kcontrol_chip(kctrl);
+	struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
+	u8 *val = (u8 *)kctrl->private_value;
+
 	uinfo->count = RSND_DVC_VOLUME_NUM;
 	uinfo->value.integer.min = 0;
-	uinfo->value.integer.max = RSND_DVC_VOLUME_MAX;
+
+	if (val == dvc->volume) {
+		uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+		uinfo->value.integer.max = RSND_DVC_VOLUME_MAX;
+	} else {
+		uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+		uinfo->value.integer.max = 1;
+	}
 
 	return 0;
 }
@@ -151,12 +167,11 @@ static int rsnd_dvc_volume_info(struct snd_kcontrol *kctrl,
 static int rsnd_dvc_volume_get(struct snd_kcontrol *kctrl,
 			      struct snd_ctl_elem_value *ucontrol)
 {
-	struct rsnd_mod *mod = snd_kcontrol_chip(kctrl);
-	struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
+	u8 *val = (u8 *)kctrl->private_value;
 	int i;
 
 	for (i = 0; i < RSND_DVC_VOLUME_NUM; i++)
-		ucontrol->value.integer.value[i] = dvc->volume[i];
+		ucontrol->value.integer.value[i] = val[i];
 
 	return 0;
 }
@@ -165,51 +180,38 @@ static int rsnd_dvc_volume_put(struct snd_kcontrol *kctrl,
 			      struct snd_ctl_elem_value *ucontrol)
 {
 	struct rsnd_mod *mod = snd_kcontrol_chip(kctrl);
-	struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
+	u8 *val = (u8 *)kctrl->private_value;
 	int i, change = 0;
 
 	for (i = 0; i < RSND_DVC_VOLUME_NUM; i++) {
-		if (ucontrol->value.integer.value[i] < 0 ||
-		    ucontrol->value.integer.value[i] > RSND_DVC_VOLUME_MAX)
-			return -EINVAL;
-
-		change |= (ucontrol->value.integer.value[i] != dvc->volume[i]);
+		change |= (ucontrol->value.integer.value[i] != val[i]);
+		val[i] = ucontrol->value.integer.value[i];
 	}
 
-	if (change) {
-		for (i = 0; i < RSND_DVC_VOLUME_NUM; i++)
-			dvc->volume[i] = ucontrol->value.integer.value[i];
-
+	if (change)
 		rsnd_dvc_volume_update(mod);
-	}
 
 	return change;
 }
 
-static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
-			    struct rsnd_dai *rdai,
-			    struct snd_soc_pcm_runtime *rtd)
+static int __rsnd_dvc_pcm_new(struct rsnd_mod *mod,
+			      struct rsnd_dai *rdai,
+			      struct snd_soc_pcm_runtime *rtd,
+			      const unsigned char *name,
+			      u8 *private)
 {
-	struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
-	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-	struct device *dev = rsnd_priv_to_dev(priv);
 	struct snd_card *card = rtd->card->snd_card;
 	struct snd_kcontrol *kctrl;
-	static struct snd_kcontrol_new knew = {
+	struct snd_kcontrol_new knew = {
 		.iface		= SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name		= "Playback Volume",
+		.name		= name,
 		.info		= rsnd_dvc_volume_info,
 		.get		= rsnd_dvc_volume_get,
 		.put		= rsnd_dvc_volume_put,
+		.private_value	= (unsigned long)private,
 	};
 	int ret;
 
-	if (!rsnd_dai_is_play(rdai, io)) {
-		dev_err(dev, "DVC%d is connected to Capture DAI\n",
-			rsnd_mod_id(mod));
-		return -EINVAL;
-	}
-
 	kctrl = snd_ctl_new1(&knew, mod);
 	if (!kctrl)
 		return -ENOMEM;
@@ -221,6 +223,33 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
 	return 0;
 }
 
+static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
+			    struct rsnd_dai *rdai,
+			    struct snd_soc_pcm_runtime *rtd)
+{
+	struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
+	struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
+	int ret;
+
+	/* Volume */
+	ret = __rsnd_dvc_pcm_new(mod, rdai, rtd,
+			rsnd_dai_is_play(rdai, io) ?
+			"DVC Out Playback Volume" : "DVC In Capture Volume",
+			dvc->volume);
+	if (ret < 0)
+		return ret;
+
+	/* Mute */
+	ret = __rsnd_dvc_pcm_new(mod, rdai, rtd,
+			rsnd_dai_is_play(rdai, io) ?
+			"DVC Out Mute Switch" : "DVC In Mute Switch",
+			dvc->mute);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
 static struct rsnd_mod_ops rsnd_dvc_ops = {
 	.name		= DVC_NAME,
 	.probe		= rsnd_dvc_probe_gen2,
@@ -239,6 +268,42 @@ struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id)
 	return &((struct rsnd_dvc *)(priv->dvc) + id)->mod;
 }
 
+static void rsnd_of_parse_dvc(struct platform_device *pdev,
+			      const struct rsnd_of_data *of_data,
+			      struct rsnd_priv *priv)
+{
+	struct device_node *node;
+	struct rsnd_dvc_platform_info *dvc_info;
+	struct rcar_snd_info *info = rsnd_priv_to_info(priv);
+	struct device *dev = &pdev->dev;
+	int nr;
+
+	if (!of_data)
+		return;
+
+	node = of_get_child_by_name(dev->of_node, "rcar_sound,dvc");
+	if (!node)
+		return;
+
+	nr = of_get_child_count(node);
+	if (!nr)
+		goto rsnd_of_parse_dvc_end;
+
+	dvc_info = devm_kzalloc(dev,
+				sizeof(struct rsnd_dvc_platform_info) * nr,
+				GFP_KERNEL);
+	if (!dvc_info) {
+		dev_err(dev, "dvc info allocation error\n");
+		goto rsnd_of_parse_dvc_end;
+	}
+
+	info->dvc_info		= dvc_info;
+	info->dvc_info_nr	= nr;
+
+rsnd_of_parse_dvc_end:
+	of_node_put(node);
+}
+
 int rsnd_dvc_probe(struct platform_device *pdev,
 		   const struct rsnd_of_data *of_data,
 		   struct rsnd_priv *priv)
@@ -250,6 +315,8 @@ int rsnd_dvc_probe(struct platform_device *pdev,
 	char name[RSND_DVC_NAME_SIZE];
 	int i, nr;
 
+	rsnd_of_parse_dvc(pdev, of_data, priv);
+
 	nr = info->dvc_info_nr;
 	if (!nr)
 		return 0;

+ 252 - 301
sound/soc/sh/rcar/gen.c

@@ -15,63 +15,35 @@ struct rsnd_gen {
 
 	struct rsnd_gen_ops *ops;
 
-	struct regmap *regmap;
+	struct regmap *regmap[RSND_BASE_MAX];
 	struct regmap_field *regs[RSND_REG_MAX];
 };
 
 #define rsnd_priv_to_gen(p)	((struct rsnd_gen *)(p)->gen)
 
-#define RSND_REG_SET(gen, id, reg_id, offset, _id_offset, _id_size)	\
-	[id] = {							\
-		.reg = (unsigned int)gen->base[reg_id] + offset,	\
-		.lsb = 0,						\
-		.msb = 31,						\
-		.id_size = _id_size,					\
-		.id_offset = _id_offset,				\
-	}
-
-/*
- *		basic function
- */
-static int rsnd_regmap_write32(void *context, const void *_data, size_t count)
-{
-	struct rsnd_priv *priv = context;
-	struct device *dev = rsnd_priv_to_dev(priv);
-	u32 *data = (u32 *)_data;
-	u32 val = data[1];
-	void __iomem *reg = (void *)data[0];
-
-	iowrite32(val, reg);
-
-	dev_dbg(dev, "w %p : %08x\n", reg, val);
-
-	return 0;
-}
-
-static int rsnd_regmap_read32(void *context,
-			      const void *_data, size_t reg_size,
-			      void *_val, size_t val_size)
-{
-	struct rsnd_priv *priv = context;
-	struct device *dev = rsnd_priv_to_dev(priv);
-	u32 *data = (u32 *)_data;
-	u32 *val = (u32 *)_val;
-	void __iomem *reg = (void *)data[0];
-
-	*val = ioread32(reg);
-
-	dev_dbg(dev, "r %p : %08x\n", reg, *val);
+struct rsnd_regmap_field_conf {
+	int idx;
+	unsigned int reg_offset;
+	unsigned int id_offset;
+};
 
-	return 0;
+#define RSND_REG_SET(id, offset, _id_offset)	\
+{						\
+	.idx = id,				\
+	.reg_offset = offset,			\
+	.id_offset = _id_offset,		\
 }
+/* single address mapping */
+#define RSND_GEN_S_REG(id, offset)	\
+	RSND_REG_SET(RSND_REG_##id, offset, 0)
 
-static struct regmap_bus rsnd_regmap_bus = {
-	.write				= rsnd_regmap_write32,
-	.read				= rsnd_regmap_read32,
-	.reg_format_endian_default	= REGMAP_ENDIAN_NATIVE,
-	.val_format_endian_default	= REGMAP_ENDIAN_NATIVE,
-};
+/* multi address mapping */
+#define RSND_GEN_M_REG(id, offset, _id_offset)	\
+	RSND_REG_SET(RSND_REG_##id, offset, _id_offset)
 
+/*
+ *		basic function
+ */
 static int rsnd_is_accessible_reg(struct rsnd_priv *priv,
 				  struct rsnd_gen *gen, enum rsnd_reg reg)
 {
@@ -88,6 +60,7 @@ static int rsnd_is_accessible_reg(struct rsnd_priv *priv,
 u32 rsnd_read(struct rsnd_priv *priv,
 	      struct rsnd_mod *mod, enum rsnd_reg reg)
 {
+	struct device *dev = rsnd_priv_to_dev(priv);
 	struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
 	u32 val;
 
@@ -96,6 +69,8 @@ u32 rsnd_read(struct rsnd_priv *priv,
 
 	regmap_fields_read(gen->regs[reg], rsnd_mod_id(mod), &val);
 
+	dev_dbg(dev, "r %s - 0x%04d : %08x\n", rsnd_mod_name(mod), reg, val);
+
 	return val;
 }
 
@@ -103,17 +78,21 @@ void rsnd_write(struct rsnd_priv *priv,
 		struct rsnd_mod *mod,
 		enum rsnd_reg reg, u32 data)
 {
+	struct device *dev = rsnd_priv_to_dev(priv);
 	struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
 
 	if (!rsnd_is_accessible_reg(priv, gen, reg))
 		return;
 
 	regmap_fields_write(gen->regs[reg], rsnd_mod_id(mod), data);
+
+	dev_dbg(dev, "w %s - 0x%04d : %08x\n", rsnd_mod_name(mod), reg, data);
 }
 
 void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod,
 	       enum rsnd_reg reg, u32 mask, u32 data)
 {
+	struct device *dev = rsnd_priv_to_dev(priv);
 	struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
 
 	if (!rsnd_is_accessible_reg(priv, gen, reg))
@@ -121,35 +100,63 @@ void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod,
 
 	regmap_fields_update_bits(gen->regs[reg], rsnd_mod_id(mod),
 				  mask, data);
+
+	dev_dbg(dev, "b %s - 0x%04d : %08x/%08x\n",
+		rsnd_mod_name(mod), reg, data, mask);
 }
 
-static int rsnd_gen_regmap_init(struct rsnd_priv *priv,
-				struct rsnd_gen  *gen,
-				struct reg_field *regf)
+#define rsnd_gen_regmap_init(priv, id_size, reg_id, conf)		\
+	_rsnd_gen_regmap_init(priv, id_size, reg_id, conf, ARRAY_SIZE(conf))
+static int _rsnd_gen_regmap_init(struct rsnd_priv *priv,
+				 int id_size,
+				 int reg_id,
+				 struct rsnd_regmap_field_conf *conf,
+				 int conf_size)
 {
-	int i;
+	struct platform_device *pdev = rsnd_priv_to_pdev(priv);
+	struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
 	struct device *dev = rsnd_priv_to_dev(priv);
+	struct resource *res;
 	struct regmap_config regc;
+	struct regmap_field *regs;
+	struct regmap *regmap;
+	struct reg_field regf;
+	void __iomem *base;
+	int i;
 
 	memset(&regc, 0, sizeof(regc));
 	regc.reg_bits = 32;
 	regc.val_bits = 32;
+	regc.reg_stride = 4;
 
-	gen->regmap = devm_regmap_init(dev, &rsnd_regmap_bus, priv, &regc);
-	if (IS_ERR(gen->regmap)) {
-		dev_err(dev, "regmap error %ld\n", PTR_ERR(gen->regmap));
-		return PTR_ERR(gen->regmap);
-	}
+	res = platform_get_resource(pdev, IORESOURCE_MEM, reg_id);
+	if (!res)
+		return -ENODEV;
+
+	base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	regmap = devm_regmap_init_mmio(dev, base, &regc);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	gen->base[reg_id] = base;
+	gen->regmap[reg_id] = regmap;
 
-	for (i = 0; i < RSND_REG_MAX; i++) {
-		gen->regs[i] = NULL;
-		if (!regf[i].reg)
-			continue;
+	for (i = 0; i < conf_size; i++) {
 
-		gen->regs[i] = devm_regmap_field_alloc(dev, gen->regmap, regf[i]);
-		if (IS_ERR(gen->regs[i]))
-			return PTR_ERR(gen->regs[i]);
+		regf.reg	= conf[i].reg_offset;
+		regf.id_offset	= conf[i].id_offset;
+		regf.lsb	= 0;
+		regf.msb	= 31;
+		regf.id_size	= id_size;
 
+		regs = devm_regmap_field_alloc(dev, regmap, regf);
+		if (IS_ERR(regs))
+			return PTR_ERR(regs);
+
+		gen->regs[conf[i].idx] = regs;
 	}
 
 	return 0;
@@ -165,15 +172,19 @@ static int rsnd_gen_regmap_init(struct rsnd_priv *priv,
  *
  *	ex) R-Car H2 case
  *	      mod        / DMAC in    / DMAC out   / DMAC PP in / DMAC pp out
- *	SSI : 0xec541000 / 0xec241008 / 0xec24100c / 0xec400000 / 0xec400000
+ *	SSI : 0xec541000 / 0xec241008 / 0xec24100c
+ *	SSIU: 0xec541000 / 0xec100000 / 0xec100000 / 0xec400000 / 0xec400000
  *	SCU : 0xec500000 / 0xec000000 / 0xec004000 / 0xec300000 / 0xec304000
- *	CMD : 0xec500000 / 0xec008000                             0xec308000
+ *	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_SSI_I_P(addr, i)	(addr ##_reg - 0x00141000 + (0x1000 * i))
-#define RDMA_SSI_O_P(addr, i)	(addr ##_reg - 0x00141000 + (0x1000 * i))
+#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))
@@ -184,14 +195,13 @@ static int rsnd_gen_regmap_init(struct rsnd_priv *priv,
 #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 void rsnd_gen2_dma_addr(struct rsnd_priv *priv,
-		       struct rsnd_dma *dma,
-		       struct dma_slave_config *cfg,
-		       int is_play, int slave_id)
+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_mod *mod = rsnd_dma_to_mod(dma);
 	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;
@@ -202,179 +212,152 @@ static void rsnd_gen2_dma_addr(struct rsnd_priv *priv,
 	int use_dvc = !!rsnd_io_to_mod_dvc(io);
 	int id = rsnd_mod_id(mod);
 	struct dma_addr {
-		dma_addr_t src_addr;
-		dma_addr_t dst_addr;
-	} dma_addrs[2][2][3] = {
-		{ /* SRC */
-			/* Capture */
-			{{ 0,				0 },
-			 { RDMA_SRC_O_N(src, id),	0 },
-			 { RDMA_CMD_O_N(src, id),	0 }},
-			/* Playback */
-			{{ 0,				0, },
-			 { 0,				RDMA_SRC_I_N(src, id) },
-			 { 0,				RDMA_SRC_I_N(src, id) }}
-		}, { /* SSI */
-			/* Capture */
-			{{ RDMA_SSI_O_N(ssi, id),	0 },
-			 { RDMA_SSI_O_P(ssi, id),	RDMA_SRC_I_P(src, id) },
-			 { RDMA_SSI_O_P(ssi, id),	RDMA_SRC_I_P(src, id) }},
-			/* Playback */
-			{{ 0,				RDMA_SSI_I_N(ssi, id) },
-			 { RDMA_SRC_O_P(src, id),	RDMA_SSI_I_P(ssi, id) },
-			 { RDMA_CMD_O_P(src, id),	RDMA_SSI_I_P(ssi, id) }}
-		}
+		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) {
+	if (use_dvc & !use_src)
 		dev_err(dev, "DVC is selected without SRC\n");
-		return;
-	}
 
-	cfg->src_addr = dma_addrs[is_ssi][is_play][use_src + use_dvc].src_addr;
-	cfg->dst_addr = dma_addrs[is_ssi][is_play][use_src + use_dvc].dst_addr;
+	/* use SSIU or SSI ? */
+	if (is_ssi && (0 == strcmp(rsnd_mod_dma_name(mod), "ssiu")))
+		is_ssi++;
 
-	dev_dbg(dev, "dma%d addr - src : %x / dst : %x\n",
-		id, cfg->src_addr, cfg->dst_addr);
+	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;
 }
 
-void rsnd_gen_dma_addr(struct rsnd_priv *priv,
-		       struct rsnd_dma *dma,
-		       struct dma_slave_config *cfg,
-		       int is_play, int slave_id)
+dma_addr_t rsnd_gen_dma_addr(struct rsnd_priv *priv,
+			     struct rsnd_mod *mod,
+			     int is_play, int is_from)
 {
-	cfg->slave_id   = slave_id;
-	cfg->src_addr   = 0;
-	cfg->dst_addr   = 0;
-	cfg->direction  = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
-
 	/*
 	 * gen1 uses default DMA addr
 	 */
 	if (rsnd_is_gen1(priv))
-		return;
+		return 0;
 
-	rsnd_gen2_dma_addr(priv, dma, cfg, is_play, slave_id);
-}
+	if (!mod)
+		return 0;
 
+	return rsnd_gen2_dma_addr(priv, mod, is_play, is_from);
+}
 
 /*
  *		Gen2
  */
-
-/* single address mapping */
-#define RSND_GEN2_S_REG(gen, reg, id, offset)				\
-	RSND_REG_SET(gen, RSND_REG_##id, RSND_GEN2_##reg, offset, 0, 10)
-
-/* multi address mapping */
-#define RSND_GEN2_M_REG(gen, reg, id, offset, _id_offset)		\
-	RSND_REG_SET(gen, RSND_REG_##id, RSND_GEN2_##reg, offset, _id_offset, 10)
-
-static int rsnd_gen2_regmap_init(struct rsnd_priv *priv, struct rsnd_gen *gen)
-{
-	struct reg_field regf[RSND_REG_MAX] = {
-		RSND_GEN2_S_REG(gen, SSIU,	SSI_MODE0,	0x800),
-		RSND_GEN2_S_REG(gen, SSIU,	SSI_MODE1,	0x804),
-		/* FIXME: it needs SSI_MODE2/3 in the future */
-		RSND_GEN2_M_REG(gen, SSIU,	SSI_BUSIF_MODE,	0x0,	0x80),
-		RSND_GEN2_M_REG(gen, SSIU,	SSI_BUSIF_ADINR,0x4,	0x80),
-		RSND_GEN2_M_REG(gen, SSIU,	SSI_CTRL,	0x10,	0x80),
-		RSND_GEN2_M_REG(gen, SSIU,	INT_ENABLE,	0x18,	0x80),
-
-		RSND_GEN2_M_REG(gen, SCU,	SRC_BUSIF_MODE,	0x0,	0x20),
-		RSND_GEN2_M_REG(gen, SCU,	SRC_ROUTE_MODE0,0xc,	0x20),
-		RSND_GEN2_M_REG(gen, SCU,	SRC_CTRL,	0x10,	0x20),
-		RSND_GEN2_M_REG(gen, SCU,	CMD_ROUTE_SLCT,	0x18c,	0x20),
-		RSND_GEN2_M_REG(gen, SCU,	CMD_CTRL,	0x190,	0x20),
-		RSND_GEN2_M_REG(gen, SCU,	SRC_SWRSR,	0x200,	0x40),
-		RSND_GEN2_M_REG(gen, SCU,	SRC_SRCIR,	0x204,	0x40),
-		RSND_GEN2_M_REG(gen, SCU,	SRC_ADINR,	0x214,	0x40),
-		RSND_GEN2_M_REG(gen, SCU,	SRC_IFSCR,	0x21c,	0x40),
-		RSND_GEN2_M_REG(gen, SCU,	SRC_IFSVR,	0x220,	0x40),
-		RSND_GEN2_M_REG(gen, SCU,	SRC_SRCCR,	0x224,	0x40),
-		RSND_GEN2_M_REG(gen, SCU,	SRC_BSDSR,	0x22c,	0x40),
-		RSND_GEN2_M_REG(gen, SCU,	SRC_BSISR,	0x238,	0x40),
-		RSND_GEN2_M_REG(gen, SCU,	DVC_SWRSR,	0xe00,	0x100),
-		RSND_GEN2_M_REG(gen, SCU,	DVC_DVUIR,	0xe04,	0x100),
-		RSND_GEN2_M_REG(gen, SCU,	DVC_ADINR,	0xe08,	0x100),
-		RSND_GEN2_M_REG(gen, SCU,	DVC_DVUCR,	0xe10,	0x100),
-		RSND_GEN2_M_REG(gen, SCU,	DVC_ZCMCR,	0xe14,	0x100),
-		RSND_GEN2_M_REG(gen, SCU,	DVC_VOL0R,	0xe28,	0x100),
-		RSND_GEN2_M_REG(gen, SCU,	DVC_VOL1R,	0xe2c,	0x100),
-		RSND_GEN2_M_REG(gen, SCU,	DVC_DVUER,	0xe48,	0x100),
-
-		RSND_GEN2_S_REG(gen, ADG,	BRRA,		0x00),
-		RSND_GEN2_S_REG(gen, ADG,	BRRB,		0x04),
-		RSND_GEN2_S_REG(gen, ADG,	SSICKR,		0x08),
-		RSND_GEN2_S_REG(gen, ADG,	AUDIO_CLK_SEL0,	0x0c),
-		RSND_GEN2_S_REG(gen, ADG,	AUDIO_CLK_SEL1,	0x10),
-		RSND_GEN2_S_REG(gen, ADG,	AUDIO_CLK_SEL2,	0x14),
-		RSND_GEN2_S_REG(gen, ADG,	DIV_EN,		0x30),
-		RSND_GEN2_S_REG(gen, ADG,	SRCIN_TIMSEL0,	0x34),
-		RSND_GEN2_S_REG(gen, ADG,	SRCIN_TIMSEL1,	0x38),
-		RSND_GEN2_S_REG(gen, ADG,	SRCIN_TIMSEL2,	0x3c),
-		RSND_GEN2_S_REG(gen, ADG,	SRCIN_TIMSEL3,	0x40),
-		RSND_GEN2_S_REG(gen, ADG,	SRCIN_TIMSEL4,	0x44),
-		RSND_GEN2_S_REG(gen, ADG,	SRCOUT_TIMSEL0,	0x48),
-		RSND_GEN2_S_REG(gen, ADG,	SRCOUT_TIMSEL1,	0x4c),
-		RSND_GEN2_S_REG(gen, ADG,	SRCOUT_TIMSEL2,	0x50),
-		RSND_GEN2_S_REG(gen, ADG,	SRCOUT_TIMSEL3,	0x54),
-		RSND_GEN2_S_REG(gen, ADG,	SRCOUT_TIMSEL4,	0x58),
-		RSND_GEN2_S_REG(gen, ADG,	CMDOUT_TIMSEL,	0x5c),
-
-		RSND_GEN2_M_REG(gen, SSI,	SSICR,		0x00,	0x40),
-		RSND_GEN2_M_REG(gen, SSI,	SSISR,		0x04,	0x40),
-		RSND_GEN2_M_REG(gen, SSI,	SSITDR,		0x08,	0x40),
-		RSND_GEN2_M_REG(gen, SSI,	SSIRDR,		0x0c,	0x40),
-		RSND_GEN2_M_REG(gen, SSI,	SSIWSR,		0x20,	0x40),
-	};
-
-	return rsnd_gen_regmap_init(priv, gen, regf);
-}
-
 static int rsnd_gen2_probe(struct platform_device *pdev,
 			   struct rsnd_priv *priv)
 {
 	struct device *dev = rsnd_priv_to_dev(priv);
-	struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
-	struct resource *scu_res;
-	struct resource *adg_res;
-	struct resource *ssiu_res;
-	struct resource *ssi_res;
-	int ret;
-
-	/*
-	 * map address
-	 */
-	scu_res  = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN2_SCU);
-	adg_res  = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN2_ADG);
-	ssiu_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN2_SSIU);
-	ssi_res  = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN2_SSI);
-
-	gen->base[RSND_GEN2_SCU]  = devm_ioremap_resource(dev, scu_res);
-	gen->base[RSND_GEN2_ADG]  = devm_ioremap_resource(dev, adg_res);
-	gen->base[RSND_GEN2_SSIU] = devm_ioremap_resource(dev, ssiu_res);
-	gen->base[RSND_GEN2_SSI]  = devm_ioremap_resource(dev, ssi_res);
-	if (IS_ERR(gen->base[RSND_GEN2_SCU])  ||
-	    IS_ERR(gen->base[RSND_GEN2_ADG])  ||
-	    IS_ERR(gen->base[RSND_GEN2_SSIU]) ||
-	    IS_ERR(gen->base[RSND_GEN2_SSI]))
-		return -ENODEV;
-
-	ret = rsnd_gen2_regmap_init(priv, gen);
-	if (ret < 0)
-		return ret;
-
-	dev_dbg(dev, "Gen2 device probed\n");
-	dev_dbg(dev, "SCU  : %pap => %p\n", &scu_res->start,
-		gen->base[RSND_GEN2_SCU]);
-	dev_dbg(dev, "ADG  : %pap => %p\n", &adg_res->start,
-		gen->base[RSND_GEN2_ADG]);
-	dev_dbg(dev, "SSIU : %pap => %p\n", &ssiu_res->start,
-		gen->base[RSND_GEN2_SSIU]);
-	dev_dbg(dev, "SSI  : %pap => %p\n", &ssi_res->start,
-		gen->base[RSND_GEN2_SSI]);
+	struct rsnd_regmap_field_conf conf_ssiu[] = {
+		RSND_GEN_S_REG(SSI_MODE0,	0x800),
+		RSND_GEN_S_REG(SSI_MODE1,	0x804),
+		/* FIXME: it needs SSI_MODE2/3 in the future */
+		RSND_GEN_M_REG(SSI_BUSIF_MODE,	0x0,	0x80),
+		RSND_GEN_M_REG(SSI_BUSIF_ADINR,	0x4,	0x80),
+		RSND_GEN_M_REG(BUSIF_DALIGN,	0x8,	0x80),
+		RSND_GEN_M_REG(SSI_CTRL,	0x10,	0x80),
+		RSND_GEN_M_REG(INT_ENABLE,	0x18,	0x80),
+	};
+	struct rsnd_regmap_field_conf conf_scu[] = {
+		RSND_GEN_M_REG(SRC_BUSIF_MODE,	0x0,	0x20),
+		RSND_GEN_M_REG(SRC_ROUTE_MODE0,	0xc,	0x20),
+		RSND_GEN_M_REG(SRC_CTRL,	0x10,	0x20),
+		RSND_GEN_M_REG(CMD_ROUTE_SLCT,	0x18c,	0x20),
+		RSND_GEN_M_REG(CMD_CTRL,	0x190,	0x20),
+		RSND_GEN_M_REG(SRC_SWRSR,	0x200,	0x40),
+		RSND_GEN_M_REG(SRC_SRCIR,	0x204,	0x40),
+		RSND_GEN_M_REG(SRC_ADINR,	0x214,	0x40),
+		RSND_GEN_M_REG(SRC_IFSCR,	0x21c,	0x40),
+		RSND_GEN_M_REG(SRC_IFSVR,	0x220,	0x40),
+		RSND_GEN_M_REG(SRC_SRCCR,	0x224,	0x40),
+		RSND_GEN_M_REG(SRC_BSDSR,	0x22c,	0x40),
+		RSND_GEN_M_REG(SRC_BSISR,	0x238,	0x40),
+		RSND_GEN_M_REG(DVC_SWRSR,	0xe00,	0x100),
+		RSND_GEN_M_REG(DVC_DVUIR,	0xe04,	0x100),
+		RSND_GEN_M_REG(DVC_ADINR,	0xe08,	0x100),
+		RSND_GEN_M_REG(DVC_DVUCR,	0xe10,	0x100),
+		RSND_GEN_M_REG(DVC_ZCMCR,	0xe14,	0x100),
+		RSND_GEN_M_REG(DVC_VOL0R,	0xe28,	0x100),
+		RSND_GEN_M_REG(DVC_VOL1R,	0xe2c,	0x100),
+		RSND_GEN_M_REG(DVC_DVUER,	0xe48,	0x100),
+	};
+	struct rsnd_regmap_field_conf conf_adg[] = {
+		RSND_GEN_S_REG(BRRA,		0x00),
+		RSND_GEN_S_REG(BRRB,		0x04),
+		RSND_GEN_S_REG(SSICKR,		0x08),
+		RSND_GEN_S_REG(AUDIO_CLK_SEL0,	0x0c),
+		RSND_GEN_S_REG(AUDIO_CLK_SEL1,	0x10),
+		RSND_GEN_S_REG(AUDIO_CLK_SEL2,	0x14),
+		RSND_GEN_S_REG(DIV_EN,		0x30),
+		RSND_GEN_S_REG(SRCIN_TIMSEL0,	0x34),
+		RSND_GEN_S_REG(SRCIN_TIMSEL1,	0x38),
+		RSND_GEN_S_REG(SRCIN_TIMSEL2,	0x3c),
+		RSND_GEN_S_REG(SRCIN_TIMSEL3,	0x40),
+		RSND_GEN_S_REG(SRCIN_TIMSEL4,	0x44),
+		RSND_GEN_S_REG(SRCOUT_TIMSEL0,	0x48),
+		RSND_GEN_S_REG(SRCOUT_TIMSEL1,	0x4c),
+		RSND_GEN_S_REG(SRCOUT_TIMSEL2,	0x50),
+		RSND_GEN_S_REG(SRCOUT_TIMSEL3,	0x54),
+		RSND_GEN_S_REG(SRCOUT_TIMSEL4,	0x58),
+		RSND_GEN_S_REG(CMDOUT_TIMSEL,	0x5c),
+	};
+	struct rsnd_regmap_field_conf conf_ssi[] = {
+		RSND_GEN_M_REG(SSICR,		0x00,	0x40),
+		RSND_GEN_M_REG(SSISR,		0x04,	0x40),
+		RSND_GEN_M_REG(SSITDR,		0x08,	0x40),
+		RSND_GEN_M_REG(SSIRDR,		0x0c,	0x40),
+		RSND_GEN_M_REG(SSIWSR,		0x20,	0x40),
+	};
+	int ret_ssiu;
+	int ret_scu;
+	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);
+	if (ret_ssiu < 0 ||
+	    ret_scu  < 0 ||
+	    ret_adg  < 0 ||
+	    ret_ssi  < 0)
+		return ret_ssiu | ret_scu | ret_adg | ret_ssi;
+
+	dev_dbg(dev, "Gen2 is probed\n");
 
 	return 0;
 }
@@ -383,92 +366,60 @@ static int rsnd_gen2_probe(struct platform_device *pdev,
  *		Gen1
  */
 
-/* single address mapping */
-#define RSND_GEN1_S_REG(gen, reg, id, offset)	\
-	RSND_REG_SET(gen, RSND_REG_##id, RSND_GEN1_##reg, offset, 0, 9)
-
-/* multi address mapping */
-#define RSND_GEN1_M_REG(gen, reg, id, offset, _id_offset)	\
-	RSND_REG_SET(gen, RSND_REG_##id, RSND_GEN1_##reg, offset, _id_offset, 9)
-
-static int rsnd_gen1_regmap_init(struct rsnd_priv *priv, struct rsnd_gen *gen)
-{
-	struct reg_field regf[RSND_REG_MAX] = {
-		RSND_GEN1_S_REG(gen, SRU,	SRC_ROUTE_SEL,	0x00),
-		RSND_GEN1_S_REG(gen, SRU,	SRC_TMG_SEL0,	0x08),
-		RSND_GEN1_S_REG(gen, SRU,	SRC_TMG_SEL1,	0x0c),
-		RSND_GEN1_S_REG(gen, SRU,	SRC_TMG_SEL2,	0x10),
-		RSND_GEN1_S_REG(gen, SRU,	SRC_ROUTE_CTRL,	0xc0),
-		RSND_GEN1_S_REG(gen, SRU,	SSI_MODE0,	0xD0),
-		RSND_GEN1_S_REG(gen, SRU,	SSI_MODE1,	0xD4),
-		RSND_GEN1_M_REG(gen, SRU,	SRC_BUSIF_MODE,	0x20,	0x4),
-		RSND_GEN1_M_REG(gen, SRU,	SRC_ROUTE_MODE0,0x50,	0x8),
-		RSND_GEN1_M_REG(gen, SRU,	SRC_SWRSR,	0x200,	0x40),
-		RSND_GEN1_M_REG(gen, SRU,	SRC_SRCIR,	0x204,	0x40),
-		RSND_GEN1_M_REG(gen, SRU,	SRC_ADINR,	0x214,	0x40),
-		RSND_GEN1_M_REG(gen, SRU,	SRC_IFSCR,	0x21c,	0x40),
-		RSND_GEN1_M_REG(gen, SRU,	SRC_IFSVR,	0x220,	0x40),
-		RSND_GEN1_M_REG(gen, SRU,	SRC_SRCCR,	0x224,	0x40),
-		RSND_GEN1_M_REG(gen, SRU,	SRC_MNFSR,	0x228,	0x40),
-
-		RSND_GEN1_S_REG(gen, ADG,	BRRA,		0x00),
-		RSND_GEN1_S_REG(gen, ADG,	BRRB,		0x04),
-		RSND_GEN1_S_REG(gen, ADG,	SSICKR,		0x08),
-		RSND_GEN1_S_REG(gen, ADG,	AUDIO_CLK_SEL0,	0x0c),
-		RSND_GEN1_S_REG(gen, ADG,	AUDIO_CLK_SEL1,	0x10),
-		RSND_GEN1_S_REG(gen, ADG,	AUDIO_CLK_SEL3,	0x18),
-		RSND_GEN1_S_REG(gen, ADG,	AUDIO_CLK_SEL4,	0x1c),
-		RSND_GEN1_S_REG(gen, ADG,	AUDIO_CLK_SEL5,	0x20),
-
-		RSND_GEN1_M_REG(gen, SSI,	SSICR,		0x00,	0x40),
-		RSND_GEN1_M_REG(gen, SSI,	SSISR,		0x04,	0x40),
-		RSND_GEN1_M_REG(gen, SSI,	SSITDR,		0x08,	0x40),
-		RSND_GEN1_M_REG(gen, SSI,	SSIRDR,		0x0c,	0x40),
-		RSND_GEN1_M_REG(gen, SSI,	SSIWSR,		0x20,	0x40),
-	};
-
-	return rsnd_gen_regmap_init(priv, gen, regf);
-}
-
 static int rsnd_gen1_probe(struct platform_device *pdev,
 			   struct rsnd_priv *priv)
 {
 	struct device *dev = rsnd_priv_to_dev(priv);
-	struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
-	struct resource *sru_res;
-	struct resource *adg_res;
-	struct resource *ssi_res;
-	int ret;
-
-	/*
-	 * map address
-	 */
-	sru_res	= platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_SRU);
-	adg_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_ADG);
-	ssi_res	= platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_SSI);
-
-	gen->base[RSND_GEN1_SRU] = devm_ioremap_resource(dev, sru_res);
-	gen->base[RSND_GEN1_ADG] = devm_ioremap_resource(dev, adg_res);
-	gen->base[RSND_GEN1_SSI] = devm_ioremap_resource(dev, ssi_res);
-	if (IS_ERR(gen->base[RSND_GEN1_SRU]) ||
-	    IS_ERR(gen->base[RSND_GEN1_ADG]) ||
-	    IS_ERR(gen->base[RSND_GEN1_SSI]))
-		return -ENODEV;
+	struct rsnd_regmap_field_conf conf_sru[] = {
+		RSND_GEN_S_REG(SRC_ROUTE_SEL,	0x00),
+		RSND_GEN_S_REG(SRC_TMG_SEL0,	0x08),
+		RSND_GEN_S_REG(SRC_TMG_SEL1,	0x0c),
+		RSND_GEN_S_REG(SRC_TMG_SEL2,	0x10),
+		RSND_GEN_S_REG(SRC_ROUTE_CTRL,	0xc0),
+		RSND_GEN_S_REG(SSI_MODE0,	0xD0),
+		RSND_GEN_S_REG(SSI_MODE1,	0xD4),
+		RSND_GEN_M_REG(SRC_BUSIF_MODE,	0x20,	0x4),
+		RSND_GEN_M_REG(SRC_ROUTE_MODE0,	0x50,	0x8),
+		RSND_GEN_M_REG(SRC_SWRSR,	0x200,	0x40),
+		RSND_GEN_M_REG(SRC_SRCIR,	0x204,	0x40),
+		RSND_GEN_M_REG(SRC_ADINR,	0x214,	0x40),
+		RSND_GEN_M_REG(SRC_IFSCR,	0x21c,	0x40),
+		RSND_GEN_M_REG(SRC_IFSVR,	0x220,	0x40),
+		RSND_GEN_M_REG(SRC_SRCCR,	0x224,	0x40),
+		RSND_GEN_M_REG(SRC_MNFSR,	0x228,	0x40),
+	};
+	struct rsnd_regmap_field_conf conf_adg[] = {
+		RSND_GEN_S_REG(BRRA,		0x00),
+		RSND_GEN_S_REG(BRRB,		0x04),
+		RSND_GEN_S_REG(SSICKR,		0x08),
+		RSND_GEN_S_REG(AUDIO_CLK_SEL0,	0x0c),
+		RSND_GEN_S_REG(AUDIO_CLK_SEL1,	0x10),
+		RSND_GEN_S_REG(AUDIO_CLK_SEL3,	0x18),
+		RSND_GEN_S_REG(AUDIO_CLK_SEL4,	0x1c),
+		RSND_GEN_S_REG(AUDIO_CLK_SEL5,	0x20),
+	};
+	struct rsnd_regmap_field_conf conf_ssi[] = {
+		RSND_GEN_M_REG(SSICR,		0x00,	0x40),
+		RSND_GEN_M_REG(SSISR,		0x04,	0x40),
+		RSND_GEN_M_REG(SSITDR,		0x08,	0x40),
+		RSND_GEN_M_REG(SSIRDR,		0x0c,	0x40),
+		RSND_GEN_M_REG(SSIWSR,		0x20,	0x40),
+	};
+	int ret_sru;
+	int ret_adg;
+	int ret_ssi;
 
-	ret = rsnd_gen1_regmap_init(priv, gen);
-	if (ret < 0)
-		return ret;
+	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);
+	if (ret_sru  < 0 ||
+	    ret_adg  < 0 ||
+	    ret_ssi  < 0)
+		return ret_sru | ret_adg | ret_ssi;
 
-	dev_dbg(dev, "Gen1 device probed\n");
-	dev_dbg(dev, "SRU : %pap => %p\n",	&sru_res->start,
-						gen->base[RSND_GEN1_SRU]);
-	dev_dbg(dev, "ADG : %pap => %p\n",	&adg_res->start,
-						gen->base[RSND_GEN1_ADG]);
-	dev_dbg(dev, "SSI : %pap => %p\n",	&ssi_res->start,
-						gen->base[RSND_GEN1_SSI]);
+	dev_dbg(dev, "Gen1 is probed\n");
 
 	return 0;
-
 }
 
 /*

+ 15 - 11
sound/soc/sh/rcar/rsnd.h

@@ -90,6 +90,7 @@ enum rsnd_reg {
 	RSND_REG_SHARE19,
 	RSND_REG_SHARE20,
 	RSND_REG_SHARE21,
+	RSND_REG_SHARE22,
 
 	RSND_REG_MAX,
 };
@@ -127,6 +128,7 @@ enum rsnd_reg {
 #define RSND_REG_AUDIO_CLK_SEL2		RSND_REG_SHARE19
 #define RSND_REG_CMD_CTRL		RSND_REG_SHARE20
 #define RSND_REG_CMDOUT_TIMSEL		RSND_REG_SHARE21
+#define RSND_REG_BUSIF_DALIGN		RSND_REG_SHARE22
 
 struct rsnd_of_data;
 struct rsnd_priv;
@@ -156,12 +158,9 @@ u32 rsnd_get_adinr(struct rsnd_mod *mod);
  */
 struct rsnd_dma {
 	struct sh_dmae_slave	slave;
-	struct work_struct	work;
 	struct dma_chan		*chan;
-	enum dma_data_direction dir;
-
-	int submit_loop;
-	int offset; /* it cares A/B plane */
+	enum dma_transfer_direction dir;
+	dma_addr_t		addr;
 };
 
 void rsnd_dma_start(struct rsnd_dma *dma);
@@ -185,6 +184,7 @@ enum rsnd_mod_type {
 
 struct rsnd_mod_ops {
 	char *name;
+	char* (*dma_name)(struct rsnd_mod *mod);
 	int (*probe)(struct rsnd_mod *mod,
 		     struct rsnd_dai *rdai);
 	int (*remove)(struct rsnd_mod *mod,
@@ -224,6 +224,7 @@ void rsnd_mod_init(struct rsnd_priv *priv,
 		   enum rsnd_mod_type type,
 		   int id);
 char *rsnd_mod_name(struct rsnd_mod *mod);
+char *rsnd_mod_dma_name(struct rsnd_mod *mod);
 
 /*
  *	R-Car sound DAI
@@ -281,10 +282,9 @@ int rsnd_gen_probe(struct platform_device *pdev,
 void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv,
 			       struct rsnd_mod *mod,
 			       enum rsnd_reg reg);
-void rsnd_gen_dma_addr(struct rsnd_priv *priv,
-		       struct rsnd_dma *dma,
-		       struct dma_slave_config *cfg,
-		       int is_play,  int slave_id);
+dma_addr_t rsnd_gen_dma_addr(struct rsnd_priv *priv,
+		       struct rsnd_mod *mod,
+		       int is_play,  int is_from);
 
 #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)
@@ -391,8 +391,12 @@ struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id);
 unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv,
 				   struct rsnd_dai_stream *io,
 				   struct snd_pcm_runtime *runtime);
-int rsnd_src_ssi_mode_init(struct rsnd_mod *ssi_mod,
-			   struct rsnd_dai *rdai);
+int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod,
+			struct rsnd_dai *rdai,
+			int use_busif);
+int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod,
+		       struct rsnd_dai *rdai,
+		       int use_busif);
 int rsnd_src_enable_ssi_irq(struct rsnd_mod *ssi_mod,
 			    struct rsnd_dai *rdai);
 

+ 76 - 10
sound/soc/sh/rcar/src.c

@@ -106,18 +106,19 @@ struct rsnd_src {
 /*
  *		Gen1/Gen2 common functions
  */
-int rsnd_src_ssi_mode_init(struct rsnd_mod *ssi_mod,
-			   struct rsnd_dai *rdai)
+int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod,
+			struct rsnd_dai *rdai,
+			int use_busif)
 {
 	struct rsnd_dai_stream *io = rsnd_mod_to_io(ssi_mod);
-	struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io);
+	struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
 	int ssi_id = rsnd_mod_id(ssi_mod);
 
 	/*
 	 * SSI_MODE0
 	 */
 	rsnd_mod_bset(ssi_mod, SSI_MODE0, (1 << ssi_id),
-		      src_mod ? 0 : (1 << ssi_id));
+		      !use_busif << ssi_id);
 
 	/*
 	 * SSI_MODE1
@@ -143,6 +144,46 @@ int rsnd_src_ssi_mode_init(struct rsnd_mod *ssi_mod,
 				      0x2 << shift : 0x1 << shift);
 	}
 
+	/*
+	 * DMA settings for SSIU
+	 */
+	if (use_busif) {
+		u32 val = 0x76543210;
+		u32 mask = ~0;
+
+		rsnd_mod_write(ssi_mod, SSI_BUSIF_ADINR,
+			       rsnd_get_adinr(ssi_mod));
+		rsnd_mod_write(ssi_mod, SSI_BUSIF_MODE,  1);
+		rsnd_mod_write(ssi_mod, SSI_CTRL, 0x1);
+
+		mask <<= runtime->channels * 4;
+		val = val & mask;
+
+		switch (runtime->sample_bits) {
+		case 16:
+			val |= 0x67452301 & ~mask;
+			break;
+		case 32:
+			val |= 0x76543210 & ~mask;
+			break;
+		}
+		rsnd_mod_write(ssi_mod, BUSIF_DALIGN, val);
+
+	}
+
+	return 0;
+}
+
+int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod,
+			struct rsnd_dai *rdai,
+			int use_busif)
+{
+	/*
+	 * DMA settings for SSIU
+	 */
+	if (use_busif)
+		rsnd_mod_write(ssi_mod, SSI_CTRL, 0);
+
 	return 0;
 }
 
@@ -461,18 +502,45 @@ static struct rsnd_mod_ops rsnd_src_gen1_ops = {
 static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod,
 					  struct rsnd_dai *rdai)
 {
+	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+	struct device *dev = rsnd_priv_to_dev(priv);
+	struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
+	struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+	struct rsnd_src *src = rsnd_mod_to_src(mod);
+	uint ratio;
 	int ret;
 
+	/* 6 - 1/6 are very enough ratio for SRC_BSDSR */
+	if (!rsnd_src_convert_rate(src))
+		ratio = 0;
+	else if (rsnd_src_convert_rate(src) > runtime->rate)
+		ratio = 100 * rsnd_src_convert_rate(src) / runtime->rate;
+	else
+		ratio = 100 * runtime->rate / rsnd_src_convert_rate(src);
+
+	if (ratio > 600) {
+		dev_err(dev, "FSO/FSI ratio error\n");
+		return -EINVAL;
+	}
+
 	ret = rsnd_src_set_convert_rate(mod, rdai);
 	if (ret < 0)
 		return ret;
 
-	rsnd_mod_write(mod, SSI_BUSIF_ADINR, rsnd_get_adinr(mod));
-	rsnd_mod_write(mod, SSI_BUSIF_MODE,  1);
-
 	rsnd_mod_write(mod, SRC_SRCCR, 0x00011110);
 
-	rsnd_mod_write(mod, SRC_BSDSR, 0x01800000);
+	switch (rsnd_mod_id(mod)) {
+	case 5:
+	case 6:
+	case 7:
+	case 8:
+		rsnd_mod_write(mod, SRC_BSDSR, 0x02400000);
+		break;
+	default:
+		rsnd_mod_write(mod, SRC_BSDSR, 0x01800000);
+		break;
+	}
+
 	rsnd_mod_write(mod, SRC_BSISR, 0x00100060);
 
 	return 0;
@@ -554,7 +622,6 @@ static int rsnd_src_start_gen2(struct rsnd_mod *mod,
 
 	rsnd_dma_start(rsnd_mod_to_dma(&src->mod));
 
-	rsnd_mod_write(mod, SSI_CTRL, 0x1);
 	rsnd_mod_write(mod, SRC_CTRL, val);
 
 	return rsnd_src_start(mod, rdai);
@@ -565,7 +632,6 @@ static int rsnd_src_stop_gen2(struct rsnd_mod *mod,
 {
 	struct rsnd_src *src = rsnd_mod_to_src(mod);
 
-	rsnd_mod_write(mod, SSI_CTRL, 0);
 	rsnd_mod_write(mod, SRC_CTRL, 0);
 
 	rsnd_dma_stop(rsnd_mod_to_dma(&src->mod));

+ 31 - 2
sound/soc/sh/rcar/ssi.c

@@ -90,6 +90,20 @@ struct rsnd_ssi {
 #define rsnd_ssi_mode_flags(p) ((p)->info->flags)
 #define rsnd_ssi_dai_id(ssi) ((ssi)->info->dai_id)
 
+static 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);
+	int use_busif = 0;
+
+	if (!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_NO_BUSIF))
+		use_busif = 1;
+	if (rsnd_io_to_mod_src(io))
+		use_busif = 1;
+
+	return use_busif;
+}
+
 static void rsnd_ssi_status_check(struct rsnd_mod *mod,
 				  u32 bit)
 {
@@ -289,8 +303,6 @@ static int rsnd_ssi_init(struct rsnd_mod *mod,
 	ssi->cr_own	= cr;
 	ssi->err	= -1; /* ignore 1st error */
 
-	rsnd_src_ssi_mode_init(mod, rdai);
-
 	return 0;
 }
 
@@ -389,6 +401,8 @@ static int rsnd_ssi_pio_start(struct rsnd_mod *mod,
 	/* enable PIO IRQ */
 	ssi->cr_etc = UIEN | OIEN | DIEN;
 
+	rsnd_src_ssiu_start(mod, rdai, 0);
+
 	rsnd_src_enable_ssi_irq(mod, rdai);
 
 	rsnd_ssi_hw_start(ssi, rdai, io);
@@ -405,6 +419,8 @@ static int rsnd_ssi_pio_stop(struct rsnd_mod *mod,
 
 	rsnd_ssi_hw_stop(ssi, rdai);
 
+	rsnd_src_ssiu_stop(mod, rdai, 0);
+
 	return 0;
 }
 
@@ -457,6 +473,8 @@ static int rsnd_ssi_dma_start(struct rsnd_mod *mod,
 	/* enable DMA transfer */
 	ssi->cr_etc = DMEN;
 
+	rsnd_src_ssiu_start(mod, rdai, rsnd_ssi_use_busif(mod));
+
 	rsnd_dma_start(dma);
 
 	rsnd_ssi_hw_start(ssi, ssi->rdai, io);
@@ -482,11 +500,19 @@ static int rsnd_ssi_dma_stop(struct rsnd_mod *mod,
 
 	rsnd_dma_stop(dma);
 
+	rsnd_src_ssiu_stop(mod, rdai, 1);
+
 	return 0;
 }
 
+static char *rsnd_ssi_dma_name(struct rsnd_mod *mod)
+{
+	return rsnd_ssi_use_busif(mod) ? "ssiu" : SSI_NAME;
+}
+
 static struct rsnd_mod_ops rsnd_ssi_dma_ops = {
 	.name	= SSI_NAME,
+	.dma_name = rsnd_ssi_dma_name,
 	.probe	= rsnd_ssi_dma_probe,
 	.remove	= rsnd_ssi_dma_remove,
 	.init	= rsnd_ssi_init,
@@ -595,6 +621,9 @@ static void rsnd_of_parse_ssi(struct platform_device *pdev,
 		 */
 		ssi_info->dma_id = of_get_property(np, "pio-transfer", NULL) ?
 			0 : 1;
+
+		if (of_get_property(np, "no-busif", NULL))
+			ssi_info->flags |= RSND_SSI_NO_BUSIF;
 	}
 
 rsnd_of_parse_ssi_end: