|
@@ -98,6 +98,8 @@ struct dw_i2s_dev {
|
|
|
unsigned int i2s_reg_comp1;
|
|
|
unsigned int i2s_reg_comp2;
|
|
|
struct device *dev;
|
|
|
+ u32 ccr;
|
|
|
+ u32 xfer_resolution;
|
|
|
|
|
|
/* data related to DMA transfers b/w i2s and DMAC */
|
|
|
union dw_i2s_snd_dma_data play_dma_data;
|
|
@@ -217,31 +219,58 @@ static int dw_i2s_startup(struct snd_pcm_substream *substream,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static void dw_i2s_config(struct dw_i2s_dev *dev, int stream)
|
|
|
+{
|
|
|
+ u32 ch_reg, irq;
|
|
|
+ struct i2s_clk_config_data *config = &dev->config;
|
|
|
+
|
|
|
+
|
|
|
+ i2s_disable_channels(dev, stream);
|
|
|
+
|
|
|
+ for (ch_reg = 0; ch_reg < (config->chan_nr / 2); ch_reg++) {
|
|
|
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
|
|
+ i2s_write_reg(dev->i2s_base, TCR(ch_reg),
|
|
|
+ dev->xfer_resolution);
|
|
|
+ i2s_write_reg(dev->i2s_base, TFCR(ch_reg), 0x02);
|
|
|
+ irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg));
|
|
|
+ i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x30);
|
|
|
+ i2s_write_reg(dev->i2s_base, TER(ch_reg), 1);
|
|
|
+ } else {
|
|
|
+ i2s_write_reg(dev->i2s_base, RCR(ch_reg),
|
|
|
+ dev->xfer_resolution);
|
|
|
+ i2s_write_reg(dev->i2s_base, RFCR(ch_reg), 0x07);
|
|
|
+ irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg));
|
|
|
+ i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x03);
|
|
|
+ i2s_write_reg(dev->i2s_base, RER(ch_reg), 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static int dw_i2s_hw_params(struct snd_pcm_substream *substream,
|
|
|
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
|
|
|
{
|
|
|
struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
|
|
|
struct i2s_clk_config_data *config = &dev->config;
|
|
|
- u32 ccr, xfer_resolution, ch_reg, irq;
|
|
|
int ret;
|
|
|
|
|
|
switch (params_format(params)) {
|
|
|
case SNDRV_PCM_FORMAT_S16_LE:
|
|
|
config->data_width = 16;
|
|
|
- ccr = 0x00;
|
|
|
- xfer_resolution = 0x02;
|
|
|
+ dev->ccr = 0x00;
|
|
|
+ dev->xfer_resolution = 0x02;
|
|
|
break;
|
|
|
|
|
|
case SNDRV_PCM_FORMAT_S24_LE:
|
|
|
config->data_width = 24;
|
|
|
- ccr = 0x08;
|
|
|
- xfer_resolution = 0x04;
|
|
|
+ dev->ccr = 0x08;
|
|
|
+ dev->xfer_resolution = 0x04;
|
|
|
break;
|
|
|
|
|
|
case SNDRV_PCM_FORMAT_S32_LE:
|
|
|
config->data_width = 32;
|
|
|
- ccr = 0x10;
|
|
|
- xfer_resolution = 0x05;
|
|
|
+ dev->ccr = 0x10;
|
|
|
+ dev->xfer_resolution = 0x05;
|
|
|
break;
|
|
|
|
|
|
default:
|
|
@@ -262,27 +291,9 @@ static int dw_i2s_hw_params(struct snd_pcm_substream *substream,
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
- i2s_disable_channels(dev, substream->stream);
|
|
|
+ dw_i2s_config(dev, substream->stream);
|
|
|
|
|
|
- for (ch_reg = 0; ch_reg < (config->chan_nr / 2); ch_reg++) {
|
|
|
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
|
|
- i2s_write_reg(dev->i2s_base, TCR(ch_reg),
|
|
|
- xfer_resolution);
|
|
|
- i2s_write_reg(dev->i2s_base, TFCR(ch_reg), 0x02);
|
|
|
- irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg));
|
|
|
- i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x30);
|
|
|
- i2s_write_reg(dev->i2s_base, TER(ch_reg), 1);
|
|
|
- } else {
|
|
|
- i2s_write_reg(dev->i2s_base, RCR(ch_reg),
|
|
|
- xfer_resolution);
|
|
|
- i2s_write_reg(dev->i2s_base, RFCR(ch_reg), 0x07);
|
|
|
- irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg));
|
|
|
- i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x03);
|
|
|
- i2s_write_reg(dev->i2s_base, RER(ch_reg), 1);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- i2s_write_reg(dev->i2s_base, CCR, ccr);
|
|
|
+ i2s_write_reg(dev->i2s_base, CCR, dev->ccr);
|
|
|
|
|
|
config->sample_rate = params_rate(params);
|
|
|
|
|
@@ -431,6 +442,11 @@ static int dw_i2s_resume(struct snd_soc_dai *dai)
|
|
|
|
|
|
if (dev->capability & DW_I2S_MASTER)
|
|
|
clk_enable(dev->clk);
|
|
|
+
|
|
|
+ if (dai->playback_active)
|
|
|
+ dw_i2s_config(dev, SNDRV_PCM_STREAM_PLAYBACK);
|
|
|
+ if (dai->capture_active)
|
|
|
+ dw_i2s_config(dev, SNDRV_PCM_STREAM_CAPTURE);
|
|
|
return 0;
|
|
|
}
|
|
|
|