diff options
Diffstat (limited to 'sound/soc/davinci/davinci-mcasp.c')
| -rw-r--r-- | sound/soc/davinci/davinci-mcasp.c | 104 | 
1 files changed, 79 insertions, 25 deletions
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index c28508da34cf..0eed9b1b24e1 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -42,14 +42,26 @@  #define MCASP_MAX_AFIFO_DEPTH	64 +static u32 context_regs[] = { +	DAVINCI_MCASP_TXFMCTL_REG, +	DAVINCI_MCASP_RXFMCTL_REG, +	DAVINCI_MCASP_TXFMT_REG, +	DAVINCI_MCASP_RXFMT_REG, +	DAVINCI_MCASP_ACLKXCTL_REG, +	DAVINCI_MCASP_ACLKRCTL_REG, +	DAVINCI_MCASP_AHCLKXCTL_REG, +	DAVINCI_MCASP_AHCLKRCTL_REG, +	DAVINCI_MCASP_PDIR_REG, +	DAVINCI_MCASP_RXMASK_REG, +	DAVINCI_MCASP_TXMASK_REG, +	DAVINCI_MCASP_RXTDM_REG, +	DAVINCI_MCASP_TXTDM_REG, +}; +  struct davinci_mcasp_context { -	u32	txfmtctl; -	u32	rxfmtctl; -	u32	txfmt; -	u32	rxfmt; -	u32	aclkxctl; -	u32	aclkrctl; -	u32	pdir; +	u32	config_regs[ARRAY_SIZE(context_regs)]; +	u32	afifo_regs[2]; /* for read/write fifo control registers */ +	u32	*xrsr_regs; /* for serializer configuration */  };  struct davinci_mcasp { @@ -403,7 +415,8 @@ out:  	return ret;  } -static int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div) +static int __davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, +				      int div, bool explicit)  {  	struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); @@ -420,7 +433,8 @@ static int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div  			       ACLKXDIV(div - 1), ACLKXDIV_MASK);  		mcasp_mod_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG,  			       ACLKRDIV(div - 1), ACLKRDIV_MASK); -		mcasp->bclk_div = div; +		if (explicit) +			mcasp->bclk_div = div;  		break;  	case 2:		/* BCLK/LRCLK ratio */ @@ -434,6 +448,12 @@ static int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div  	return 0;  } +static int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, +				    int div) +{ +	return __davinci_mcasp_set_clkdiv(dai, div_id, div, 1); +} +  static int davinci_mcasp_set_sysclk(struct snd_soc_dai *dai, int clk_id,  				    unsigned int freq, int dir)  { @@ -459,8 +479,17 @@ static int davinci_config_channel_size(struct davinci_mcasp *mcasp,  {  	u32 fmt;  	u32 tx_rotate = (word_length / 4) & 0x7; -	u32 rx_rotate = (32 - word_length) / 4;  	u32 mask = (1ULL << word_length) - 1; +	/* +	 * For captured data we should not rotate, inversion and masking is +	 * enoguh to get the data to the right position: +	 * Format	  data from bus		after reverse (XRBUF) +	 * S16_LE:	|LSB|MSB|xxx|xxx|	|xxx|xxx|MSB|LSB| +	 * S24_3LE:	|LSB|DAT|MSB|xxx|	|xxx|MSB|DAT|LSB| +	 * S24_LE:	|LSB|DAT|MSB|xxx|	|xxx|MSB|DAT|LSB| +	 * S32_LE:	|LSB|DAT|DAT|MSB|	|MSB|DAT|DAT|LSB| +	 */ +	u32 rx_rotate = 0;  	/*  	 * if s BCLK-to-LRCLK ratio has been configured via the set_clkdiv() @@ -738,7 +767,7 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,  				 "Inaccurate BCLK: %u Hz / %u != %u Hz\n",  				 mcasp->sysclk_freq, div, bclk_freq);  		} -		davinci_mcasp_set_clkdiv(cpu_dai, 1, div); +		__davinci_mcasp_set_clkdiv(cpu_dai, 1, div, 0);  	}  	ret = mcasp_common_hw_param(mcasp, substream->stream, @@ -857,14 +886,24 @@ static int davinci_mcasp_suspend(struct snd_soc_dai *dai)  {  	struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);  	struct davinci_mcasp_context *context = &mcasp->context; +	u32 reg; +	int i; -	context->txfmtctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG); -	context->rxfmtctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG); -	context->txfmt = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXFMT_REG); -	context->rxfmt = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMT_REG); -	context->aclkxctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG); -	context->aclkrctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKRCTL_REG); -	context->pdir = mcasp_get_reg(mcasp, DAVINCI_MCASP_PDIR_REG); +	for (i = 0; i < ARRAY_SIZE(context_regs); i++) +		context->config_regs[i] = mcasp_get_reg(mcasp, context_regs[i]); + +	if (mcasp->txnumevt) { +		reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET; +		context->afifo_regs[0] = mcasp_get_reg(mcasp, reg); +	} +	if (mcasp->rxnumevt) { +		reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET; +		context->afifo_regs[1] = mcasp_get_reg(mcasp, reg); +	} + +	for (i = 0; i < mcasp->num_serializer; i++) +		context->xrsr_regs[i] = mcasp_get_reg(mcasp, +						DAVINCI_MCASP_XRSRCTL_REG(i));  	return 0;  } @@ -873,14 +912,24 @@ static int davinci_mcasp_resume(struct snd_soc_dai *dai)  {  	struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);  	struct davinci_mcasp_context *context = &mcasp->context; +	u32 reg; +	int i; + +	for (i = 0; i < ARRAY_SIZE(context_regs); i++) +		mcasp_set_reg(mcasp, context_regs[i], context->config_regs[i]); + +	if (mcasp->txnumevt) { +		reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET; +		mcasp_set_reg(mcasp, reg, context->afifo_regs[0]); +	} +	if (mcasp->rxnumevt) { +		reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET; +		mcasp_set_reg(mcasp, reg, context->afifo_regs[1]); +	} -	mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG, context->txfmtctl); -	mcasp_set_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG, context->rxfmtctl); -	mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMT_REG, context->txfmt); -	mcasp_set_reg(mcasp, DAVINCI_MCASP_RXFMT_REG, context->rxfmt); -	mcasp_set_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, context->aclkxctl); -	mcasp_set_reg(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, context->aclkrctl); -	mcasp_set_reg(mcasp, DAVINCI_MCASP_PDIR_REG, context->pdir); +	for (i = 0; i < mcasp->num_serializer; i++) +		mcasp_set_reg(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i), +			      context->xrsr_regs[i]);  	return 0;  } @@ -1199,6 +1248,11 @@ static int davinci_mcasp_probe(struct platform_device *pdev)  	mcasp->op_mode = pdata->op_mode;  	mcasp->tdm_slots = pdata->tdm_slots;  	mcasp->num_serializer = pdata->num_serializer; +#ifdef CONFIG_PM_SLEEP +	mcasp->context.xrsr_regs = devm_kzalloc(&pdev->dev, +					sizeof(u32) * mcasp->num_serializer, +					GFP_KERNEL); +#endif  	mcasp->serial_dir = pdata->serial_dir;  	mcasp->version = pdata->version;  	mcasp->txnumevt = pdata->txnumevt;  |