diff options
| author | Mark Brown <[email protected]> | 2022-08-16 14:47:35 +0100 | 
|---|---|---|
| committer | Mark Brown <[email protected]> | 2022-08-16 14:47:35 +0100 | 
| commit | 2d7ea7635a1286d5954b155a47e862cbcd48fff5 (patch) | |
| tree | c6fb88a123276a07c284aed9893e4d6717ed4c54 /sound/soc/amd/acp/acp-i2s.c | |
| parent | 3b43a713f6b09ffbca468847000dabeaf92492df (diff) | |
| parent | 12229b7e50cfa95fda55b83a2617eafd6ac4c8c5 (diff) | |
Add support for linked list to store acp_stream and tdm support.
Merge series from Venkata Prasad Potturu <[email protected]>:
This patch is to add support for linked list to store acp_stream instead
static array and add tdm support for acp I2S stream.
Diffstat (limited to 'sound/soc/amd/acp/acp-i2s.c')
| -rw-r--r-- | sound/soc/amd/acp/acp-i2s.c | 80 | 
1 files changed, 79 insertions, 1 deletions
| diff --git a/sound/soc/amd/acp/acp-i2s.c b/sound/soc/amd/acp/acp-i2s.c index 393f729ef561..ac416572db0d 100644 --- a/sound/soc/amd/acp/acp-i2s.c +++ b/sound/soc/amd/acp/acp-i2s.c @@ -25,6 +25,65 @@  #define DRV_NAME "acp_i2s_playcap" +static int acp_i2s_set_fmt(struct snd_soc_dai *cpu_dai, +			   unsigned int fmt) +{ +	struct acp_dev_data *adata = snd_soc_dai_get_drvdata(cpu_dai); +	int mode; + +	mode = fmt & SND_SOC_DAIFMT_FORMAT_MASK; +	switch (mode) { +	case SND_SOC_DAIFMT_I2S: +		adata->tdm_mode = TDM_DISABLE; +		break; +	case SND_SOC_DAIFMT_DSP_A: +		adata->tdm_mode = TDM_ENABLE; +		break; +	default: +		return -EINVAL; +	} +	return 0; +} + +static int acp_i2s_set_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, u32 rx_mask, +				int slots, int slot_width) +{ +	struct device *dev = dai->component->dev; +	struct acp_dev_data *adata = snd_soc_dai_get_drvdata(dai); +	struct acp_stream *stream; +	int slot_len; + +	switch (slot_width) { +	case SLOT_WIDTH_8: +		slot_len = 8; +		break; +	case SLOT_WIDTH_16: +		slot_len = 16; +		break; +	case SLOT_WIDTH_24: +		slot_len = 24; +		break; +	case SLOT_WIDTH_32: +		slot_len = 0; +		break; +	default: +		dev_err(dev, "Unsupported bitdepth %d\n", slot_width); +		return -EINVAL; +	} + +	spin_lock_irq(&adata->acp_lock); +	list_for_each_entry(stream, &adata->stream_list, list) { +		if (tx_mask && stream->dir == SNDRV_PCM_STREAM_PLAYBACK) +			adata->tdm_tx_fmt[stream->dai_id - 1] = +					FRM_LEN | (slots << 15) | (slot_len << 18); +		else if (rx_mask && stream->dir == SNDRV_PCM_STREAM_CAPTURE) +			adata->tdm_rx_fmt[stream->dai_id - 1] = +					FRM_LEN | (slots << 15) | (slot_len << 18); +	} +	spin_unlock_irq(&adata->acp_lock); +	return 0; +} +  static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params,  			    struct snd_soc_dai *dai)  { @@ -33,7 +92,7 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_  	struct acp_resource *rsrc;  	u32 val;  	u32 xfer_resolution; -	u32 reg_val; +	u32 reg_val, fmt_reg, tdm_fmt;  	u32 lrclk_div_val, bclk_div_val;  	adata = snd_soc_dai_get_drvdata(dai); @@ -62,12 +121,15 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_  		switch (dai->driver->id) {  		case I2S_BT_INSTANCE:  			reg_val = ACP_BTTDM_ITER; +			fmt_reg = ACP_BTTDM_TXFRMT;  			break;  		case I2S_SP_INSTANCE:  			reg_val = ACP_I2STDM_ITER; +			fmt_reg = ACP_I2STDM_TXFRMT;  			break;  		case I2S_HS_INSTANCE:  			reg_val = ACP_HSTDM_ITER; +			fmt_reg = ACP_HSTDM_TXFRMT;  			break;  		default:  			dev_err(dev, "Invalid dai id %x\n", dai->driver->id); @@ -77,12 +139,15 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_  		switch (dai->driver->id) {  		case I2S_BT_INSTANCE:  			reg_val = ACP_BTTDM_IRER; +			fmt_reg = ACP_BTTDM_RXFRMT;  			break;  		case I2S_SP_INSTANCE:  			reg_val = ACP_I2STDM_IRER; +			fmt_reg = ACP_I2STDM_RXFRMT;  			break;  		case I2S_HS_INSTANCE:  			reg_val = ACP_HSTDM_IRER; +			fmt_reg = ACP_HSTDM_RXFRMT;  			break;  		default:  			dev_err(dev, "Invalid dai id %x\n", dai->driver->id); @@ -95,6 +160,16 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_  	val = val | (xfer_resolution  << 3);  	writel(val, adata->acp_base + reg_val); +	if (adata->tdm_mode) { +		val = readl(adata->acp_base + reg_val); +		writel(val | BIT(1), adata->acp_base + reg_val); +		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) +			tdm_fmt = adata->tdm_tx_fmt[dai->driver->id - 1]; +		else +			tdm_fmt = adata->tdm_rx_fmt[dai->driver->id - 1]; +		writel(tdm_fmt, adata->acp_base + fmt_reg); +	} +  	if (rsrc->soc_mclk) {  		switch (params_format(params)) {  		case SNDRV_PCM_FORMAT_S16_LE: @@ -443,6 +518,7 @@ static int acp_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_d  	stream->id = dai->driver->id + dir;  	stream->dai_id = dai->driver->id;  	stream->irq_bit = irq_bit; +	stream->dir = substream->stream;  	return 0;  } @@ -452,6 +528,8 @@ const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops = {  	.hw_params = acp_i2s_hwparams,  	.prepare = acp_i2s_prepare,  	.trigger = acp_i2s_trigger, +	.set_fmt = acp_i2s_set_fmt, +	.set_tdm_slot = acp_i2s_set_tdm_slot,  };  EXPORT_SYMBOL_NS_GPL(asoc_acp_cpu_dai_ops, SND_SOC_ACP_COMMON); |