diff options
Diffstat (limited to 'sound/soc/sh/rcar/core.c')
| -rw-r--r-- | sound/soc/sh/rcar/core.c | 629 | 
1 files changed, 444 insertions, 185 deletions
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index a3570602851..4e86265f625 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -73,13 +73,13 @@   *   |  +- ssi[2]   *   |  ...   *   | - *   | ** these control scu + *   | ** these control src   *   | - *   +- scu + *   +- src   *      | - *      +- scu[0] - *      +- scu[1] - *      +- scu[2] + *      +- src[0] + *      +- src[1] + *      +- src[2]   *      ...   *   * @@ -94,62 +94,38 @@   *   */  #include <linux/pm_runtime.h> +#include <linux/shdma-base.h>  #include "rsnd.h"  #define RSND_RATES SNDRV_PCM_RATE_8000_96000  #define RSND_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE) +static struct rsnd_of_data rsnd_of_data_gen1 = { +	.flags = RSND_GEN1, +}; + +static struct rsnd_of_data rsnd_of_data_gen2 = { +	.flags = RSND_GEN2, +}; + +static 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 }, +	{}, +}; +MODULE_DEVICE_TABLE(of, rsnd_of_match); +  /*   *	rsnd_platform functions   */  #define rsnd_platform_call(priv, dai, func, param...)	\ -	(!(priv->info->func) ? -ENODEV :		\ +	(!(priv->info->func) ? 0 :		\  	 priv->info->func(param)) - -/* - *	basic function - */ -u32 rsnd_read(struct rsnd_priv *priv, -	      struct rsnd_mod *mod, enum rsnd_reg reg) -{ -	void __iomem *base = rsnd_gen_reg_get(priv, mod, reg); - -	BUG_ON(!base); - -	return ioread32(base); -} - -void rsnd_write(struct rsnd_priv *priv, -		struct rsnd_mod *mod, -		enum rsnd_reg reg, u32 data) -{ -	void __iomem *base = rsnd_gen_reg_get(priv, mod, reg); -	struct device *dev = rsnd_priv_to_dev(priv); - -	BUG_ON(!base); - -	dev_dbg(dev, "w %p : %08x\n", base, data); - -	iowrite32(data, base); -} - -void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, -	       enum rsnd_reg reg, u32 mask, u32 data) -{ -	void __iomem *base = rsnd_gen_reg_get(priv, mod, reg); -	struct device *dev = rsnd_priv_to_dev(priv); -	u32 val; - -	BUG_ON(!base); - -	val = ioread32(base); -	val &= ~mask; -	val |= data & mask; -	iowrite32(val, base); - -	dev_dbg(dev, "s %p : %08x\n", base, val); -} +#define rsnd_is_enable_path(io, name) \ +	((io)->info ? (io)->info->name : NULL) +#define rsnd_info_id(priv, io, name) \ +	((io)->info->name - priv->info->name##_info)  /*   *	rsnd_mod functions @@ -165,17 +141,19 @@ char *rsnd_mod_name(struct rsnd_mod *mod)  void rsnd_mod_init(struct rsnd_priv *priv,  		   struct rsnd_mod *mod,  		   struct rsnd_mod_ops *ops, +		   enum rsnd_mod_type type,  		   int id)  {  	mod->priv	= priv;  	mod->id		= id;  	mod->ops	= ops; -	INIT_LIST_HEAD(&mod->list); +	mod->type	= type;  }  /*   *	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 */ @@ -186,8 +164,9 @@ static void rsnd_dma_continue(struct rsnd_dma *dma)  void rsnd_dma_start(struct rsnd_dma *dma)  {  	/* push both A and B plane*/ +	dma->offset = 0;  	dma->submit_loop = 2; -	schedule_work(&dma->work); +	__rsnd_dma_start(dma);  }  void rsnd_dma_stop(struct rsnd_dma *dma) @@ -200,33 +179,49 @@ void rsnd_dma_stop(struct rsnd_dma *dma)  static void rsnd_dma_complete(void *data)  {  	struct rsnd_dma *dma = (struct rsnd_dma *)data; -	struct rsnd_priv *priv = dma->priv; +	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); -	dma->complete(dma); - +	/* +	 * 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 +	 */  	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_do_work(struct work_struct *work) +static void __rsnd_dma_start(struct rsnd_dma *dma)  { -	struct rsnd_dma *dma = container_of(work, struct rsnd_dma, work); -	struct rsnd_priv *priv = dma->priv; +	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 device *dev = rsnd_priv_to_dev(priv);  	struct dma_async_tx_descriptor *desc;  	dma_addr_t buf; -	size_t len; +	size_t len = io->byte_per_period;  	int i;  	for (i = 0; i < dma->submit_loop; i++) { -		if (dma->inquiry(dma, &buf, &len) < 0) -			return; +		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, @@ -244,9 +239,15 @@ static void rsnd_dma_do_work(struct work_struct *work)  			return;  		} +		dma_async_issue_pending(dma->chan);  	} +} + +static void rsnd_dma_do_work(struct work_struct *work) +{ +	struct rsnd_dma *dma = container_of(work, struct rsnd_dma, work); -	dma_async_issue_pending(dma->chan); +	__rsnd_dma_start(dma);  }  int rsnd_dma_available(struct rsnd_dma *dma) @@ -254,21 +255,83 @@ int rsnd_dma_available(struct rsnd_dma *dma)  	return !!dma->chan;  } -static bool rsnd_dma_filter(struct dma_chan *chan, void *param) +#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_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)  { -	chan->private = param; +	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]; +	struct rsnd_mod *src_mod, *dst_mod; +	int i, index; -	return true; + +	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; +			break; +		} else if (!dvc) { +			mod[i] = src; +			src = NULL; +		} else { +			mod[i] = dvc; +			dvc = NULL; +		} + +		if (mod[i] == this) +			index = i; +	} + +	if (is_play) { +		src_mod = mod[index - 1]; +		dst_mod = mod[index]; +	} else { +		src_mod = mod[index]; +		dst_mod = 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, -		  int is_play, int id, -		  int (*inquiry)(struct rsnd_dma *dma, -				  dma_addr_t *buf, int *len), -		  int (*complete)(struct rsnd_dma *dma)) +		  int is_play, int id)  {  	struct device *dev = rsnd_priv_to_dev(priv); +	struct dma_slave_config cfg; +	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"); @@ -278,22 +341,37 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma,  	dma_cap_zero(mask);  	dma_cap_set(DMA_SLAVE, mask); -	dma->slave.shdma_slave.slave_id = id; +	if (dev->of_node) +		rsnd_dma_of_name(dma, is_play, dma_name); +	else +		snprintf(dma_name, DMA_NAME_SIZE, +			 is_play ? "tx" : "rx"); + +	dev_dbg(dev, "dma name : %s\n", dma_name); -	dma->chan = dma_request_channel(mask, rsnd_dma_filter, -					&dma->slave.shdma_slave); +	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");  		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; -	dma->priv = priv; -	dma->inquiry = inquiry; -	dma->complete = complete;  	INIT_WORK(&dma->work, rsnd_dma_do_work);  	return 0; + +rsnd_dma_init_err: +	rsnd_dma_quit(priv, dma); + +	return ret;  }  void  rsnd_dma_quit(struct rsnd_priv *priv, @@ -306,47 +384,81 @@ void  rsnd_dma_quit(struct rsnd_priv *priv,  }  /* - *	rsnd_dai functions + *	settting function   */ -#define rsnd_dai_call(rdai, io, fn)			\ -({							\ -	struct rsnd_mod *mod, *n;			\ -	int ret = 0;					\ -	for_each_rsnd_mod(mod, n, io) {			\ -		ret = rsnd_mod_call(mod, fn, rdai, io);	\ -		if (ret < 0)				\ -			break;				\ -	}						\ -	ret;						\ -}) - -int rsnd_dai_connect(struct rsnd_dai *rdai, -		     struct rsnd_mod *mod, -		     struct rsnd_dai_stream *io) +u32 rsnd_get_adinr(struct rsnd_mod *mod)  {  	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 device *dev = rsnd_priv_to_dev(priv); +	u32 adinr = runtime->channels; -	if (!mod) { -		dev_err(dev, "NULL mod\n"); -		return -EIO; +	switch (runtime->sample_bits) { +	case 16: +		adinr |= (8 << 16); +		break; +	case 32: +		adinr |= (0 << 16); +		break; +	default: +		dev_warn(dev, "not supported sample bits\n"); +		return 0;  	} -	if (!list_empty(&mod->list)) { +	return adinr; +} + +/* + *	rsnd_dai functions + */ +#define __rsnd_mod_call(mod, func, rdai...)			\ +({								\ +	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);		\ +	struct device *dev = rsnd_priv_to_dev(priv);		\ +	dev_dbg(dev, "%s [%d] %s\n",				\ +		rsnd_mod_name(mod), rsnd_mod_id(mod), #func);	\ +	(mod)->ops->func(mod, rdai);				\ +}) + +#define rsnd_mod_call(mod, func, rdai...)	\ +	(!(mod) ? -ENODEV :			\ +	 !((mod)->ops->func) ? 0 :		\ +	 __rsnd_mod_call(mod, func, rdai)) + +#define rsnd_dai_call(fn, io, rdai...)				\ +({								\ +	struct rsnd_mod *mod;					\ +	int ret = 0, i;						\ +	for (i = 0; i < RSND_MOD_MAX; i++) {			\ +		mod = (io)->mod[i];				\ +		if (!mod)					\ +			continue;				\ +		ret = rsnd_mod_call(mod, fn, rdai);		\ +		if (ret < 0)					\ +			break;					\ +	}							\ +	ret;							\ +}) + +static int rsnd_dai_connect(struct rsnd_mod *mod, +			    struct rsnd_dai_stream *io) +{ +	if (!mod) +		return -EIO; + +	if (io->mod[mod->type]) { +		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",  			rsnd_mod_name(mod),  			rsnd_mod_id(mod));  		return -EIO;  	} -	list_add_tail(&mod->list, &io->head); - -	return 0; -} - -int rsnd_dai_disconnect(struct rsnd_mod *mod) -{ -	list_del_init(&mod->list); +	io->mod[mod->type] = mod; +	mod->io = io;  	return 0;  } @@ -355,7 +467,7 @@ int rsnd_dai_id(struct rsnd_priv *priv, struct rsnd_dai *rdai)  {  	int id = rdai - priv->rdai; -	if ((id < 0) || (id >= rsnd_dai_nr(priv))) +	if ((id < 0) || (id >= rsnd_rdai_nr(priv)))  		return -EINVAL;  	return id; @@ -363,6 +475,9 @@ int rsnd_dai_id(struct rsnd_priv *priv, struct rsnd_dai *rdai)  struct rsnd_dai *rsnd_dai_get(struct rsnd_priv *priv, int id)  { +	if ((id < 0) || (id >= rsnd_rdai_nr(priv))) +		return NULL; +  	return priv->rdai + id;  } @@ -418,10 +533,6 @@ static int rsnd_dai_stream_init(struct rsnd_dai_stream *io,  {  	struct snd_pcm_runtime *runtime = substream->runtime; -	if (!list_empty(&io->head)) -		return -EIO; - -	INIT_LIST_HEAD(&io->head);  	io->substream		= substream;  	io->byte_pos		= 0;  	io->period_pos		= 0; @@ -457,10 +568,7 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,  	struct rsnd_priv *priv = snd_soc_dai_get_drvdata(dai);  	struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);  	struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); -	struct rsnd_mod *mod = rsnd_ssi_mod_get_frm_dai(priv, -						rsnd_dai_id(priv, rdai), -						rsnd_dai_is_play(rdai, io)); -	int ssi_id = rsnd_mod_id(mod); +	int ssi_id = rsnd_mod_id(rsnd_io_to_mod_ssi(io));  	int ret;  	unsigned long flags; @@ -476,28 +584,20 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,  		if (ret < 0)  			goto dai_trigger_end; -		ret = rsnd_gen_path_init(priv, rdai, io); -		if (ret < 0) -			goto dai_trigger_end; - -		ret = rsnd_dai_call(rdai, io, init); +		ret = rsnd_dai_call(init, io, rdai);  		if (ret < 0)  			goto dai_trigger_end; -		ret = rsnd_dai_call(rdai, io, start); +		ret = rsnd_dai_call(start, io, rdai);  		if (ret < 0)  			goto dai_trigger_end;  		break;  	case SNDRV_PCM_TRIGGER_STOP: -		ret = rsnd_dai_call(rdai, io, stop); -		if (ret < 0) -			goto dai_trigger_end; - -		ret = rsnd_dai_call(rdai, io, quit); +		ret = rsnd_dai_call(stop, io, rdai);  		if (ret < 0)  			goto dai_trigger_end; -		ret = rsnd_gen_path_exit(priv, rdai, io); +		ret = rsnd_dai_call(quit, io, rdai);  		if (ret < 0)  			goto dai_trigger_end; @@ -522,10 +622,10 @@ static int rsnd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)  	/* set master/slave audio interface */  	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {  	case SND_SOC_DAIFMT_CBM_CFM: -		rdai->clk_master = 1; +		rdai->clk_master = 0;  		break;  	case SND_SOC_DAIFMT_CBS_CFS: -		rdai->clk_master = 0; +		rdai->clk_master = 1; /* codec is slave, cpu is master */  		break;  	default:  		return -EINVAL; @@ -576,26 +676,156 @@ static const struct snd_soc_dai_ops rsnd_soc_dai_ops = {  	.set_fmt	= rsnd_soc_dai_set_fmt,  }; +#define rsnd_path_parse(priv, io, type)				\ +({								\ +	struct rsnd_mod *mod;					\ +	int ret = 0;						\ +	int id = -1;						\ +								\ +	if (rsnd_is_enable_path(io, type)) {			\ +		id = rsnd_info_id(priv, io, type);		\ +		if (id >= 0) {					\ +			mod = rsnd_##type##_mod_get(priv, id);	\ +			ret = rsnd_dai_connect(mod, io);	\ +		}						\ +	}							\ +	ret;							\ +}) + +static int rsnd_path_init(struct rsnd_priv *priv, +			  struct rsnd_dai *rdai, +			  struct rsnd_dai_stream *io) +{ +	int ret; + +	/* +	 * Gen1 is created by SRU/SSI, and this SRU is base module of +	 * Gen2's SCU/SSIU/SSI. (Gen2 SCU/SSIU came from SRU) +	 * +	 * Easy image is.. +	 *	Gen1 SRU = Gen2 SCU + SSIU + etc +	 * +	 * Gen2 SCU path is very flexible, but, Gen1 SRU (SCU parts) is +	 * using fixed path. +	 */ + +	/* SRC */ +	ret = rsnd_path_parse(priv, io, src); +	if (ret < 0) +		return ret; + +	/* SSI */ +	ret = rsnd_path_parse(priv, io, ssi); +	if (ret < 0) +		return ret; + +	/* DVC */ +	ret = rsnd_path_parse(priv, io, dvc); +	if (ret < 0) +		return ret; + +	return ret; +} + +static void rsnd_of_parse_dai(struct platform_device *pdev, +			      const struct rsnd_of_data *of_data, +			      struct rsnd_priv *priv) +{ +	struct device_node *dai_node,	*dai_np; +	struct device_node *ssi_node,	*ssi_np; +	struct device_node *src_node,	*src_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; + +	if (!of_data) +		return; + +	dai_node = of_get_child_by_name(dev->of_node, "rcar_sound,dai"); +	if (!dai_node) +		return; + +	nr = of_get_child_count(dai_node); +	if (!nr) +		return; + +	dai_info = devm_kzalloc(dev, +				sizeof(struct rsnd_dai_platform_info) * nr, +				GFP_KERNEL); +	if (!dai_info) { +		dev_err(dev, "dai info allocation error\n"); +		return; +	} + +	info->dai_info_nr	= nr; +	info->dai_info		= dai_info; + +	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"); + +#define mod_parse(name)							\ +if (name##_node) {							\ +	struct rsnd_##name##_platform_info *name##_info;		\ +									\ +	name##_i = 0;							\ +	for_each_child_of_node(name##_node, name##_np) {		\ +		name##_info = info->name##_info + name##_i;		\ +									\ +		if (name##_np == playback)				\ +			dai_info->playback.name = name##_info;		\ +		if (name##_np == capture)				\ +			dai_info->capture.name = name##_info;		\ +									\ +		name##_i++;						\ +	}								\ +} + +	/* +	 * parse all dai +	 */ +	dai_i = 0; +	for_each_child_of_node(dai_node, dai_np) { +		dai_info = info->dai_info + dai_i; + +		for (i = 0;; i++) { + +			playback = of_parse_phandle(dai_np, "playback", i); +			capture  = of_parse_phandle(dai_np, "capture", i); + +			if (!playback && !capture) +				break; + +			mod_parse(ssi); +			mod_parse(src); + +			if (playback) +				of_node_put(playback); +			if (capture) +				of_node_put(capture); +		} + +		dai_i++; +	} +} +  static int rsnd_dai_probe(struct platform_device *pdev, -			  struct rcar_snd_info *info, +			  const struct rsnd_of_data *of_data,  			  struct rsnd_priv *priv)  {  	struct snd_soc_dai_driver *drv; +	struct rcar_snd_info *info = rsnd_priv_to_info(priv);  	struct rsnd_dai *rdai; -	struct rsnd_mod *pmod, *cmod; +	struct rsnd_ssi_platform_info *pmod, *cmod;  	struct device *dev = rsnd_priv_to_dev(priv);  	int dai_nr;  	int i; -	/* get max dai nr */ -	for (dai_nr = 0; dai_nr < 32; dai_nr++) { -		pmod = rsnd_ssi_mod_get_frm_dai(priv, dai_nr, 1); -		cmod = rsnd_ssi_mod_get_frm_dai(priv, dai_nr, 0); - -		if (!pmod && !cmod) -			break; -	} +	rsnd_of_parse_dai(pdev, of_data, priv); +	dai_nr = info->dai_info_nr;  	if (!dai_nr) {  		dev_err(dev, "no dai\n");  		return -EIO; @@ -608,17 +838,19 @@ static int rsnd_dai_probe(struct platform_device *pdev,  		return -ENOMEM;  	} +	priv->rdai_nr	= dai_nr; +	priv->daidrv	= drv; +	priv->rdai	= rdai; +  	for (i = 0; i < dai_nr; i++) { +		rdai[i].info = &info->dai_info[i]; -		pmod = rsnd_ssi_mod_get_frm_dai(priv, i, 1); -		cmod = rsnd_ssi_mod_get_frm_dai(priv, i, 0); +		pmod = rdai[i].info->playback.ssi; +		cmod = rdai[i].info->capture.ssi;  		/*  		 *	init rsnd_dai  		 */ -		INIT_LIST_HEAD(&rdai[i].playback.head); -		INIT_LIST_HEAD(&rdai[i].capture.head); -  		snprintf(rdai[i].name, RSND_DAI_NAME_SIZE, "rsnd-dai.%d", i);  		/* @@ -631,12 +863,18 @@ static int rsnd_dai_probe(struct platform_device *pdev,  			drv[i].playback.formats		= RSND_FMTS;  			drv[i].playback.channels_min	= 2;  			drv[i].playback.channels_max	= 2; + +			rdai[i].playback.info = &info->dai_info[i].playback; +			rsnd_path_init(priv, &rdai[i], &rdai[i].playback);  		}  		if (cmod) {  			drv[i].capture.rates		= RSND_RATES;  			drv[i].capture.formats		= RSND_FMTS;  			drv[i].capture.channels_min	= 2;  			drv[i].capture.channels_max	= 2; + +			rdai[i].capture.info = &info->dai_info[i].capture; +			rsnd_path_init(priv, &rdai[i], &rdai[i].capture);  		}  		dev_dbg(dev, "%s (%s/%s)\n", rdai[i].name, @@ -644,18 +882,9 @@ static int rsnd_dai_probe(struct platform_device *pdev,  			cmod ? "capture" : "  --   ");  	} -	priv->dai_nr	= dai_nr; -	priv->daidrv	= drv; -	priv->rdai	= rdai; -  	return 0;  } -static void rsnd_dai_remove(struct platform_device *pdev, -			  struct rsnd_priv *priv) -{ -} -  /*   *		pcm ops   */ @@ -664,12 +893,6 @@ static struct snd_pcm_hardware rsnd_pcm_hardware = {  			SNDRV_PCM_INFO_MMAP		|  			SNDRV_PCM_INFO_MMAP_VALID	|  			SNDRV_PCM_INFO_PAUSE, -	.formats		= RSND_FMTS, -	.rates			= RSND_RATES, -	.rate_min		= 8000, -	.rate_max		= 192000, -	.channels_min		= 2, -	.channels_max		= 2,  	.buffer_bytes_max	= 64 * 1024,  	.period_bytes_min	= 32,  	.period_bytes_max	= 8192, @@ -725,6 +948,20 @@ 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; + +	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->capture, rdai, rtd); +		if (ret) +			return ret; +	} +  	return snd_pcm_lib_preallocate_pages_for_all(  		rtd->pcm,  		SNDRV_DMA_TYPE_DEV, @@ -755,9 +992,31 @@ static int rsnd_probe(struct platform_device *pdev)  	struct rcar_snd_info *info;  	struct rsnd_priv *priv;  	struct device *dev = &pdev->dev; -	int ret; +	struct rsnd_dai *rdai; +	const struct of_device_id *of_id = of_match_device(rsnd_of_match, dev); +	const struct rsnd_of_data *of_data; +	int (*probe_func[])(struct platform_device *pdev, +			    const struct rsnd_of_data *of_data, +			    struct rsnd_priv *priv) = { +		rsnd_gen_probe, +		rsnd_ssi_probe, +		rsnd_src_probe, +		rsnd_dvc_probe, +		rsnd_adg_probe, +		rsnd_dai_probe, +	}; +	int ret, i; + +	info = NULL; +	of_data = NULL; +	if (of_id) { +		info = devm_kzalloc(&pdev->dev, +				    sizeof(struct rcar_snd_info), GFP_KERNEL); +		of_data = of_id->data; +	} else { +		info = pdev->dev.platform_data; +	} -	info = pdev->dev.platform_data;  	if (!info) {  		dev_err(dev, "driver needs R-Car sound information\n");  		return -ENODEV; @@ -772,32 +1031,28 @@ static int rsnd_probe(struct platform_device *pdev)  		return -ENODEV;  	} -	priv->dev	= dev; +	priv->pdev	= pdev;  	priv->info	= info;  	spin_lock_init(&priv->lock);  	/*  	 *	init each module  	 */ -	ret = rsnd_gen_probe(pdev, info, priv); -	if (ret < 0) -		return ret; - -	ret = rsnd_scu_probe(pdev, info, priv); -	if (ret < 0) -		return ret; - -	ret = rsnd_adg_probe(pdev, info, priv); -	if (ret < 0) -		return ret; +	for (i = 0; i < ARRAY_SIZE(probe_func); i++) { +		ret = probe_func[i](pdev, of_data, priv); +		if (ret) +			return ret; +	} -	ret = rsnd_ssi_probe(pdev, info, priv); -	if (ret < 0) -		return ret; +	for_each_rsnd_dai(rdai, priv, i) { +		ret = rsnd_dai_call(probe, &rdai->playback, rdai); +		if (ret) +			return ret; -	ret = rsnd_dai_probe(pdev, info, priv); -	if (ret < 0) -		return ret; +		ret = rsnd_dai_call(probe, &rdai->capture, rdai); +		if (ret) +			return ret; +	}  	/*  	 *	asoc register @@ -809,7 +1064,7 @@ static int rsnd_probe(struct platform_device *pdev)  	}  	ret = snd_soc_register_component(dev, &rsnd_soc_component, -					 priv->daidrv, rsnd_dai_nr(priv)); +					 priv->daidrv, rsnd_rdai_nr(priv));  	if (ret < 0) {  		dev_err(dev, "cannot snd dai register\n");  		goto exit_snd_soc; @@ -831,17 +1086,20 @@ exit_snd_soc:  static int rsnd_remove(struct platform_device *pdev)  {  	struct rsnd_priv *priv = dev_get_drvdata(&pdev->dev); +	struct rsnd_dai *rdai; +	int ret, i;  	pm_runtime_disable(&pdev->dev); -	/* -	 *	remove each module -	 */ -	rsnd_ssi_remove(pdev, priv); -	rsnd_adg_remove(pdev, priv); -	rsnd_scu_remove(pdev, priv); -	rsnd_dai_remove(pdev, priv); -	rsnd_gen_remove(pdev, priv); +	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; +	}  	return 0;  } @@ -849,6 +1107,7 @@ static int rsnd_remove(struct platform_device *pdev)  static struct platform_driver rsnd_driver = {  	.driver	= {  		.name	= "rcar_sound", +		.of_match_table = rsnd_of_match,  	},  	.probe		= rsnd_probe,  	.remove		= rsnd_remove,  | 
