diff options
Diffstat (limited to 'sound/soc/sh/rz-ssi.c')
| -rw-r--r-- | sound/soc/sh/rz-ssi.c | 169 | 
1 files changed, 90 insertions, 79 deletions
diff --git a/sound/soc/sh/rz-ssi.c b/sound/soc/sh/rz-ssi.c index fa0cc08f70ec..5d6bae33ae34 100644 --- a/sound/soc/sh/rz-ssi.c +++ b/sound/soc/sh/rz-ssi.c @@ -28,8 +28,6 @@  /* SSI REGISTER BITS */  #define SSICR_DWL(x)		(((x) & 0x7) << 19)  #define SSICR_SWL(x)		(((x) & 0x7) << 16) -#define SSICR_MST		BIT(14) -#define SSICR_CKDV(x)		(((x) & 0xf) << 4)  #define SSICR_CKS		BIT(30)  #define SSICR_TUIEN		BIT(29) @@ -61,9 +59,7 @@  #define SSIFSR_RDC_MASK		0x3f  #define SSIFSR_RDC_SHIFT	8 -#define SSIFSR_TDC(x)		(((x) & 0x1f) << 24)  #define SSIFSR_TDE		BIT(16) -#define SSIFSR_RDC(x)		(((x) & 0x1f) << 8)  #define SSIFSR_RDF		BIT(0)  #define SSIOFR_LRCONT		BIT(8) @@ -188,26 +184,36 @@ static inline bool rz_ssi_is_dma_enabled(struct rz_ssi_priv *ssi)  	return (ssi->playback.dma_ch && (ssi->dma_rt || ssi->capture.dma_ch));  } -static int rz_ssi_stream_is_valid(struct rz_ssi_priv *ssi, -				  struct rz_ssi_stream *strm) +static void rz_ssi_set_substream(struct rz_ssi_stream *strm, +				 struct snd_pcm_substream *substream)  { +	struct rz_ssi_priv *ssi = strm->priv;  	unsigned long flags; -	int ret;  	spin_lock_irqsave(&ssi->lock, flags); -	ret = !!(strm->substream && strm->substream->runtime); +	strm->substream = substream; +	spin_unlock_irqrestore(&ssi->lock, flags); +} + +static bool rz_ssi_stream_is_valid(struct rz_ssi_priv *ssi, +				   struct rz_ssi_stream *strm) +{ +	unsigned long flags; +	bool ret; + +	spin_lock_irqsave(&ssi->lock, flags); +	ret = strm->substream && strm->substream->runtime;  	spin_unlock_irqrestore(&ssi->lock, flags);  	return ret;  } -static int rz_ssi_stream_init(struct rz_ssi_priv *ssi, -			      struct rz_ssi_stream *strm, -			      struct snd_pcm_substream *substream) +static void rz_ssi_stream_init(struct rz_ssi_stream *strm, +			       struct snd_pcm_substream *substream)  {  	struct snd_pcm_runtime *runtime = substream->runtime; -	strm->substream = substream; +	rz_ssi_set_substream(strm, substream);  	strm->sample_width = samples_to_bytes(runtime, 1);  	strm->dma_buffer_pos = 0;  	strm->period_counter = 0; @@ -219,19 +225,14 @@ static int rz_ssi_stream_init(struct rz_ssi_priv *ssi,  	/* fifo init */  	strm->fifo_sample_size = SSI_FIFO_DEPTH; - -	return 0;  }  static void rz_ssi_stream_quit(struct rz_ssi_priv *ssi,  			       struct rz_ssi_stream *strm)  {  	struct snd_soc_dai *dai = rz_ssi_get_dai(strm->substream); -	unsigned long flags; -	spin_lock_irqsave(&ssi->lock, flags); -	strm->substream = NULL; -	spin_unlock_irqrestore(&ssi->lock, flags); +	rz_ssi_set_substream(strm, NULL);  	if (strm->oerr_num > 0)  		dev_info(dai->dev, "overrun = %d\n", strm->oerr_num); @@ -414,51 +415,48 @@ static int rz_ssi_pio_recv(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm)  	u16 *buf;  	int fifo_samples;  	int frames_left; -	int samples = 0; +	int samples;  	int i;  	if (!rz_ssi_stream_is_valid(ssi, strm))  		return -EINVAL;  	runtime = substream->runtime; -	/* frames left in this period */ -	frames_left = runtime->period_size - (strm->buffer_pos % -					      runtime->period_size); -	if (frames_left == 0) -		frames_left = runtime->period_size; - -	/* Samples in RX FIFO */ -	fifo_samples = (rz_ssi_reg_readl(ssi, SSIFSR) >> -			SSIFSR_RDC_SHIFT) & SSIFSR_RDC_MASK; -	/* Only read full frames at a time */ -	while (frames_left && (fifo_samples >= runtime->channels)) { -		samples += runtime->channels; -		fifo_samples -= runtime->channels; -		frames_left--; -	} - -	/* not enough samples yet */ -	if (samples == 0) -		return 0; +	do { +		/* frames left in this period */ +		frames_left = runtime->period_size - +			      (strm->buffer_pos % runtime->period_size); +		if (!frames_left) +			frames_left = runtime->period_size; + +		/* Samples in RX FIFO */ +		fifo_samples = (rz_ssi_reg_readl(ssi, SSIFSR) >> +				SSIFSR_RDC_SHIFT) & SSIFSR_RDC_MASK; + +		/* Only read full frames at a time */ +		samples = 0; +		while (frames_left && (fifo_samples >= runtime->channels)) { +			samples += runtime->channels; +			fifo_samples -= runtime->channels; +			frames_left--; +		} -	/* calculate new buffer index */ -	buf = (u16 *)(runtime->dma_area); -	buf += strm->buffer_pos * runtime->channels; +		/* not enough samples yet */ +		if (!samples) +			break; -	/* Note, only supports 16-bit samples */ -	for (i = 0; i < samples; i++) -		*buf++ = (u16)(rz_ssi_reg_readl(ssi, SSIFRDR) >> 16); +		/* calculate new buffer index */ +		buf = (u16 *)runtime->dma_area; +		buf += strm->buffer_pos * runtime->channels; -	rz_ssi_reg_mask_setl(ssi, SSIFSR, SSIFSR_RDF, 0); -	rz_ssi_pointer_update(strm, samples / runtime->channels); +		/* Note, only supports 16-bit samples */ +		for (i = 0; i < samples; i++) +			*buf++ = (u16)(rz_ssi_reg_readl(ssi, SSIFRDR) >> 16); -	/* -	 * If we finished this period, but there are more samples in -	 * the RX FIFO, call this function again -	 */ -	if (frames_left == 0 && fifo_samples >= runtime->channels) -		rz_ssi_pio_recv(ssi, strm); +		rz_ssi_reg_mask_setl(ssi, SSIFSR, SSIFSR_RDF, 0); +		rz_ssi_pointer_update(strm, samples / runtime->channels); +	} while (!frames_left && fifo_samples >= runtime->channels);  	return 0;  } @@ -600,7 +598,7 @@ static int rz_ssi_dma_transfer(struct rz_ssi_priv *ssi,  		return -EINVAL;  	runtime = substream->runtime; -	if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) +	if (runtime->state == SNDRV_PCM_STATE_DRAINING)  		/*  		 * Stream is ending, so do not queue up any more DMA  		 * transfers otherwise we play partial sound clips @@ -726,9 +724,7 @@ static int rz_ssi_dai_trigger(struct snd_pcm_substream *substream, int cmd,  		rz_ssi_reg_mask_setl(ssi, SSIFCR, SSIFCR_SSIRST, 0);  		udelay(5); -		ret = rz_ssi_stream_init(ssi, strm, substream); -		if (ret) -			goto done; +		rz_ssi_stream_init(strm, substream);  		if (ssi->dma_rt) {  			bool is_playback; @@ -771,7 +767,7 @@ static int rz_ssi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)  	struct rz_ssi_priv *ssi = snd_soc_dai_get_drvdata(dai);  	switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { -	case SND_SOC_DAIFMT_CBC_CFC: +	case SND_SOC_DAIFMT_BP_FP:  		break;  	default:  		dev_err(ssi->dev, "Codec should be clk and frame consumer\n"); @@ -910,10 +906,11 @@ static struct snd_soc_dai_driver rz_ssi_soc_dai[] = {  };  static const struct snd_soc_component_driver rz_ssi_soc_component = { -	.name		= "rz-ssi", -	.open		= rz_ssi_pcm_open, -	.pointer	= rz_ssi_pcm_pointer, -	.pcm_construct	= rz_ssi_pcm_new, +	.name			= "rz-ssi", +	.open			= rz_ssi_pcm_open, +	.pointer		= rz_ssi_pcm_pointer, +	.pcm_construct		= rz_ssi_pcm_new, +	.legacy_dai_naming	= 1,  };  static int rz_ssi_probe(struct platform_device *pdev) @@ -975,24 +972,29 @@ static int rz_ssi_probe(struct platform_device *pdev)  	ssi->playback.priv = ssi;  	ssi->capture.priv = ssi; +	spin_lock_init(&ssi->lock); +	dev_set_drvdata(&pdev->dev, ssi); +  	/* Error Interrupt */  	ssi->irq_int = platform_get_irq_byname(pdev, "int_req"); -	if (ssi->irq_int < 0) -		return dev_err_probe(&pdev->dev, -ENODEV, -				     "Unable to get SSI int_req IRQ\n"); +	if (ssi->irq_int < 0) { +		rz_ssi_release_dma_channels(ssi); +		return ssi->irq_int; +	}  	ret = devm_request_irq(&pdev->dev, ssi->irq_int, &rz_ssi_interrupt,  			       0, dev_name(&pdev->dev), ssi); -	if (ret < 0) +	if (ret < 0) { +		rz_ssi_release_dma_channels(ssi);  		return dev_err_probe(&pdev->dev, ret,  				     "irq request error (int_req)\n"); +	}  	if (!rz_ssi_is_dma_enabled(ssi)) {  		/* Tx and Rx interrupts (pio only) */  		ssi->irq_tx = platform_get_irq_byname(pdev, "dma_tx");  		if (ssi->irq_tx < 0) -			return dev_err_probe(&pdev->dev, -ENODEV, -					     "Unable to get SSI dma_tx IRQ\n"); +			return ssi->irq_tx;  		ret = devm_request_irq(&pdev->dev, ssi->irq_tx,  				       &rz_ssi_interrupt, 0, @@ -1003,8 +1005,7 @@ static int rz_ssi_probe(struct platform_device *pdev)  		ssi->irq_rx = platform_get_irq_byname(pdev, "dma_rx");  		if (ssi->irq_rx < 0) -			return dev_err_probe(&pdev->dev, -ENODEV, -					     "Unable to get SSI dma_rx IRQ\n"); +			return ssi->irq_rx;  		ret = devm_request_irq(&pdev->dev, ssi->irq_rx,  				       &rz_ssi_interrupt, 0, @@ -1015,27 +1016,37 @@ static int rz_ssi_probe(struct platform_device *pdev)  	}  	ssi->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL); -	if (IS_ERR(ssi->rstc)) -		return PTR_ERR(ssi->rstc); +	if (IS_ERR(ssi->rstc)) { +		ret = PTR_ERR(ssi->rstc); +		goto err_reset; +	}  	reset_control_deassert(ssi->rstc);  	pm_runtime_enable(&pdev->dev); -	pm_runtime_resume_and_get(&pdev->dev); +	ret = pm_runtime_resume_and_get(&pdev->dev); +	if (ret < 0) { +		dev_err(&pdev->dev, "pm_runtime_resume_and_get failed\n"); +		goto err_pm; +	} -	spin_lock_init(&ssi->lock); -	dev_set_drvdata(&pdev->dev, ssi);  	ret = devm_snd_soc_register_component(&pdev->dev, &rz_ssi_soc_component,  					      rz_ssi_soc_dai,  					      ARRAY_SIZE(rz_ssi_soc_dai));  	if (ret < 0) { -		rz_ssi_release_dma_channels(ssi); - -		pm_runtime_put(ssi->dev); -		pm_runtime_disable(ssi->dev); -		reset_control_assert(ssi->rstc);  		dev_err(&pdev->dev, "failed to register snd component\n"); +		goto err_snd_soc;  	} +	return 0; + +err_snd_soc: +	pm_runtime_put(ssi->dev); +err_pm: +	pm_runtime_disable(ssi->dev); +	reset_control_assert(ssi->rstc); +err_reset: +	rz_ssi_release_dma_channels(ssi); +  	return ret;  }  | 
