aboutsummaryrefslogtreecommitdiff
path: root/sound/soc/davinci/davinci-mcasp.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/davinci/davinci-mcasp.c')
-rw-r--r--sound/soc/davinci/davinci-mcasp.c538
1 files changed, 313 insertions, 225 deletions
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c
index b7858bfa029..9afb14629a1 100644
--- a/sound/soc/davinci/davinci-mcasp.c
+++ b/sound/soc/davinci/davinci-mcasp.c
@@ -33,10 +33,23 @@
#include <sound/initval.h>
#include <sound/soc.h>
#include <sound/dmaengine_pcm.h>
+#include <sound/omap-pcm.h>
#include "davinci-pcm.h"
#include "davinci-mcasp.h"
+#define MCASP_MAX_AFIFO_DEPTH 64
+
+struct davinci_mcasp_context {
+ u32 txfmtctl;
+ u32 rxfmtctl;
+ u32 txfmt;
+ u32 rxfmt;
+ u32 aclkxctl;
+ u32 aclkrctl;
+ u32 pdir;
+};
+
struct davinci_mcasp {
struct davinci_pcm_dma_params dma_params[2];
struct snd_dmaengine_dai_dma_data dma_data[2];
@@ -53,6 +66,9 @@ struct davinci_mcasp {
u16 bclk_lrclk_ratio;
int streams;
+ int sysclk_freq;
+ bool bclk_master;
+
/* McASP FIFO related */
u8 txnumevt;
u8 rxnumevt;
@@ -60,15 +76,7 @@ struct davinci_mcasp {
bool dat_port;
#ifdef CONFIG_PM_SLEEP
- struct {
- u32 txfmtctl;
- u32 rxfmtctl;
- u32 txfmt;
- u32 rxfmt;
- u32 aclkxctl;
- u32 aclkrctl;
- u32 pdir;
- } context;
+ struct davinci_mcasp_context context;
#endif
};
@@ -263,24 +271,52 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
unsigned int fmt)
{
struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
+ int ret = 0;
+ u32 data_delay;
+ bool fs_pol_rising;
+ bool inv_fs = false;
+ pm_runtime_get_sync(mcasp->dev);
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_DSP_A:
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR);
+ /* 1st data bit occur one ACLK cycle after the frame sync */
+ data_delay = 1;
+ break;
case SND_SOC_DAIFMT_DSP_B:
case SND_SOC_DAIFMT_AC97:
mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR);
+ /* No delay after FS */
+ data_delay = 0;
break;
- default:
+ case SND_SOC_DAIFMT_I2S:
/* configure a full-word SYNC pulse (LRCLK) */
mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR);
-
- /* make 1st data bit occur one ACLK cycle after the frame sync */
- mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, FSXDLY(1));
- mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, FSRDLY(1));
+ /* 1st data bit occur one ACLK cycle after the frame sync */
+ data_delay = 1;
+ /* FS need to be inverted */
+ inv_fs = true;
break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ /* configure a full-word SYNC pulse (LRCLK) */
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR);
+ /* No delay after FS */
+ data_delay = 0;
+ break;
+ default:
+ ret = -EINVAL;
+ goto out;
}
+ mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, FSXDLY(data_delay),
+ FSXDLY(3));
+ mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, FSRDLY(data_delay),
+ FSRDLY(3));
+
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBS_CFS:
/* codec is clock and frame slave */
@@ -292,6 +328,7 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, ACLKX | ACLKR);
mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AFSX | AFSR);
+ mcasp->bclk_master = 1;
break;
case SND_SOC_DAIFMT_CBM_CFS:
/* codec is clock master and frame slave */
@@ -303,6 +340,7 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, ACLKX | ACLKR);
mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AFSX | AFSR);
+ mcasp->bclk_master = 0;
break;
case SND_SOC_DAIFMT_CBM_CFM:
/* codec is clock and frame master */
@@ -314,50 +352,52 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG,
ACLKX | AHCLKX | AFSX | ACLKR | AHCLKR | AFSR);
+ mcasp->bclk_master = 0;
break;
-
default:
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_IB_NF:
mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
- mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
-
- mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
- mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
+ fs_pol_rising = true;
break;
-
case SND_SOC_DAIFMT_NB_IF:
mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
- mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
-
- mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
- mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
+ fs_pol_rising = false;
break;
-
case SND_SOC_DAIFMT_IB_IF:
mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
- mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
-
- mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
- mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
+ fs_pol_rising = false;
break;
-
case SND_SOC_DAIFMT_NB_NF:
mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
- mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
-
mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
- mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
+ fs_pol_rising = true;
break;
-
default:
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
- return 0;
+ if (inv_fs)
+ fs_pol_rising = !fs_pol_rising;
+
+ if (fs_pol_rising) {
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
+ } else {
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
+ }
+out:
+ pm_runtime_put_sync(mcasp->dev);
+ return ret;
}
static int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div)
@@ -405,6 +445,8 @@ static int davinci_mcasp_set_sysclk(struct snd_soc_dai *dai, int clk_id,
mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AHCLKX);
}
+ mcasp->sysclk_freq = freq;
+
return 0;
}
@@ -448,18 +490,20 @@ static int davinci_config_channel_size(struct davinci_mcasp *mcasp,
return 0;
}
-static int davinci_hw_common_param(struct davinci_mcasp *mcasp, int stream,
- int channels)
+static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream,
+ int period_words, int channels)
{
+ struct davinci_pcm_dma_params *dma_params = &mcasp->dma_params[stream];
+ struct snd_dmaengine_dai_dma_data *dma_data = &mcasp->dma_data[stream];
int i;
u8 tx_ser = 0;
u8 rx_ser = 0;
- u8 ser;
u8 slots = mcasp->tdm_slots;
u8 max_active_serializers = (channels + slots - 1) / slots;
+ int active_serializers, numevt, n;
u32 reg;
/* Default configuration */
- if (mcasp->version != MCASP_VERSION_4)
+ if (mcasp->version < MCASP_VERSION_3)
mcasp_set_bits(mcasp, DAVINCI_MCASP_PWREMUMGT_REG, MCASP_SOFT);
/* All PINS as McASP */
@@ -490,46 +534,86 @@ static int davinci_hw_common_param(struct davinci_mcasp *mcasp, int stream,
}
}
- if (stream == SNDRV_PCM_STREAM_PLAYBACK)
- ser = tx_ser;
- else
- ser = rx_ser;
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ active_serializers = tx_ser;
+ numevt = mcasp->txnumevt;
+ reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
+ } else {
+ active_serializers = rx_ser;
+ numevt = mcasp->rxnumevt;
+ reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
+ }
- if (ser < max_active_serializers) {
+ if (active_serializers < max_active_serializers) {
dev_warn(mcasp->dev, "stream has more channels (%d) than are "
- "enabled in mcasp (%d)\n", channels, ser * slots);
+ "enabled in mcasp (%d)\n", channels,
+ active_serializers * slots);
return -EINVAL;
}
- if (mcasp->txnumevt && stream == SNDRV_PCM_STREAM_PLAYBACK) {
- if (mcasp->txnumevt * tx_ser > 64)
- mcasp->txnumevt = 1;
-
- reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
- mcasp_mod_bits(mcasp, reg, tx_ser, NUMDMA_MASK);
- mcasp_mod_bits(mcasp, reg, ((mcasp->txnumevt * tx_ser) << 8),
- NUMEVT_MASK);
+ /* AFIFO is not in use */
+ if (!numevt) {
+ /* Configure the burst size for platform drivers */
+ if (active_serializers > 1) {
+ /*
+ * If more than one serializers are in use we have one
+ * DMA request to provide data for all serializers.
+ * For example if three serializers are enabled the DMA
+ * need to transfer three words per DMA request.
+ */
+ dma_params->fifo_level = active_serializers;
+ dma_data->maxburst = active_serializers;
+ } else {
+ dma_params->fifo_level = 0;
+ dma_data->maxburst = 0;
+ }
+ return 0;
}
- if (mcasp->rxnumevt && stream == SNDRV_PCM_STREAM_CAPTURE) {
- if (mcasp->rxnumevt * rx_ser > 64)
- mcasp->rxnumevt = 1;
-
- reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
- mcasp_mod_bits(mcasp, reg, rx_ser, NUMDMA_MASK);
- mcasp_mod_bits(mcasp, reg, ((mcasp->rxnumevt * rx_ser) << 8),
- NUMEVT_MASK);
+ if (period_words % active_serializers) {
+ dev_err(mcasp->dev, "Invalid combination of period words and "
+ "active serializers: %d, %d\n", period_words,
+ active_serializers);
+ return -EINVAL;
}
+ /*
+ * Calculate the optimal AFIFO depth for platform side:
+ * The number of words for numevt need to be in steps of active
+ * serializers.
+ */
+ n = numevt % active_serializers;
+ if (n)
+ numevt += (active_serializers - n);
+ while (period_words % numevt && numevt > 0)
+ numevt -= active_serializers;
+ if (numevt <= 0)
+ numevt = active_serializers;
+
+ mcasp_mod_bits(mcasp, reg, active_serializers, NUMDMA_MASK);
+ mcasp_mod_bits(mcasp, reg, NUMEVT(numevt), NUMEVT_MASK);
+
+ /* Configure the burst size for platform drivers */
+ if (numevt == 1)
+ numevt = 0;
+ dma_params->fifo_level = numevt;
+ dma_data->maxburst = numevt;
+
return 0;
}
-static void davinci_hw_param(struct davinci_mcasp *mcasp, int stream)
+static int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream)
{
int i, active_slots;
u32 mask = 0;
u32 busel = 0;
+ if ((mcasp->tdm_slots < 2) || (mcasp->tdm_slots > 32)) {
+ dev_err(mcasp->dev, "tdm slot %d not supported\n",
+ mcasp->tdm_slots);
+ return -EINVAL;
+ }
+
active_slots = (mcasp->tdm_slots > 31) ? 32 : mcasp->tdm_slots;
for (i = 0; i < active_slots; i++)
mask |= (1 << i);
@@ -539,35 +623,21 @@ static void davinci_hw_param(struct davinci_mcasp *mcasp, int stream)
if (!mcasp->dat_port)
busel = TXSEL;
- if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
- /* bit stream is MSB first with no delay */
- /* DSP_B mode */
- mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, mask);
- mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, busel | TXORD);
-
- if ((mcasp->tdm_slots >= 2) && (mcasp->tdm_slots <= 32))
- mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG,
- FSXMOD(mcasp->tdm_slots), FSXMOD(0x1FF));
- else
- printk(KERN_ERR "playback tdm slot %d not supported\n",
- mcasp->tdm_slots);
- } else {
- /* bit stream is MSB first with no delay */
- /* DSP_B mode */
- mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, busel | RXORD);
- mcasp_set_reg(mcasp, DAVINCI_MCASP_RXTDM_REG, mask);
-
- if ((mcasp->tdm_slots >= 2) && (mcasp->tdm_slots <= 32))
- mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG,
- FSRMOD(mcasp->tdm_slots), FSRMOD(0x1FF));
- else
- printk(KERN_ERR "capture tdm slot %d not supported\n",
- mcasp->tdm_slots);
- }
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, mask);
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, busel | TXORD);
+ mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG,
+ FSXMOD(mcasp->tdm_slots), FSXMOD(0x1FF));
+
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_RXTDM_REG, mask);
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, busel | RXORD);
+ mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG,
+ FSRMOD(mcasp->tdm_slots), FSRMOD(0x1FF));
+
+ return 0;
}
/* S/PDIF */
-static void davinci_hw_dit_param(struct davinci_mcasp *mcasp)
+static int mcasp_dit_hw_param(struct davinci_mcasp *mcasp)
{
/* Set the TX format : 24 bit right rotation, 32 bit slot, Pad 0
and LSB first */
@@ -589,6 +659,8 @@ static void davinci_hw_dit_param(struct davinci_mcasp *mcasp)
/* Enable the DIT */
mcasp_set_bits(mcasp, DAVINCI_MCASP_TXDITCTL_REG, DITEN);
+
+ return 0;
}
static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
@@ -598,30 +670,34 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
struct davinci_pcm_dma_params *dma_params =
&mcasp->dma_params[substream->stream];
- struct snd_dmaengine_dai_dma_data *dma_data =
- &mcasp->dma_data[substream->stream];
int word_length;
- u8 fifo_level;
- u8 slots = mcasp->tdm_slots;
- u8 active_serializers;
- int channels;
- struct snd_interval *pcm_channels = hw_param_interval(params,
- SNDRV_PCM_HW_PARAM_CHANNELS);
- channels = pcm_channels->min;
+ int channels = params_channels(params);
+ int period_size = params_period_size(params);
+ int ret;
- active_serializers = (channels + slots - 1) / slots;
+ /* If mcasp is BCLK master we need to set BCLK divider */
+ if (mcasp->bclk_master) {
+ unsigned int bclk_freq = snd_soc_params_to_bclk(params);
+ if (mcasp->sysclk_freq % bclk_freq != 0) {
+ dev_err(mcasp->dev, "Can't produce required BCLK\n");
+ return -EINVAL;
+ }
+ davinci_mcasp_set_clkdiv(
+ cpu_dai, 1, mcasp->sysclk_freq / bclk_freq);
+ }
- if (davinci_hw_common_param(mcasp, substream->stream, channels) == -EINVAL)
- return -EINVAL;
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- fifo_level = mcasp->txnumevt * active_serializers;
- else
- fifo_level = mcasp->rxnumevt * active_serializers;
+ ret = mcasp_common_hw_param(mcasp, substream->stream,
+ period_size * channels, channels);
+ if (ret)
+ return ret;
if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE)
- davinci_hw_dit_param(mcasp);
+ ret = mcasp_dit_hw_param(mcasp);
else
- davinci_hw_param(mcasp, substream->stream);
+ ret = mcasp_i2s_hw_param(mcasp, substream->stream);
+
+ if (ret)
+ return ret;
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_U8:
@@ -655,14 +731,11 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
- if (mcasp->version == MCASP_VERSION_2 && !fifo_level)
+ if (mcasp->version == MCASP_VERSION_2 && !dma_params->fifo_level)
dma_params->acnt = 4;
else
dma_params->acnt = dma_params->data_type;
- dma_params->fifo_level = fifo_level;
- dma_data->maxburst = fifo_level;
-
davinci_config_channel_size(mcasp, word_length);
return 0;
@@ -678,19 +751,9 @@ static int davinci_mcasp_trigger(struct snd_pcm_substream *substream,
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- ret = pm_runtime_get_sync(mcasp->dev);
- if (IS_ERR_VALUE(ret))
- dev_err(mcasp->dev, "pm_runtime_get_sync() failed\n");
davinci_mcasp_start(mcasp, substream->stream);
break;
-
case SNDRV_PCM_TRIGGER_SUSPEND:
- davinci_mcasp_stop(mcasp, substream->stream);
- ret = pm_runtime_put_sync(mcasp->dev);
- if (IS_ERR_VALUE(ret))
- dev_err(mcasp->dev, "pm_runtime_put_sync() failed\n");
- break;
-
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
davinci_mcasp_stop(mcasp, substream->stream);
@@ -703,22 +766,7 @@ static int davinci_mcasp_trigger(struct snd_pcm_substream *substream,
return ret;
}
-static int davinci_mcasp_startup(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
-
- if (mcasp->version == MCASP_VERSION_4)
- snd_soc_dai_set_dma_data(dai, substream,
- &mcasp->dma_data[substream->stream]);
- else
- snd_soc_dai_set_dma_data(dai, substream, mcasp->dma_params);
-
- return 0;
-}
-
static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = {
- .startup = davinci_mcasp_startup,
.trigger = davinci_mcasp_trigger,
.hw_params = davinci_mcasp_hw_params,
.set_fmt = davinci_mcasp_set_dai_fmt,
@@ -726,6 +774,62 @@ static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = {
.set_sysclk = davinci_mcasp_set_sysclk,
};
+static int davinci_mcasp_dai_probe(struct snd_soc_dai *dai)
+{
+ struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
+
+ if (mcasp->version == MCASP_VERSION_4) {
+ /* Using dmaengine PCM */
+ dai->playback_dma_data =
+ &mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
+ dai->capture_dma_data =
+ &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE];
+ } else {
+ /* Using davinci-pcm */
+ dai->playback_dma_data = mcasp->dma_params;
+ dai->capture_dma_data = mcasp->dma_params;
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+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;
+
+ 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);
+
+ return 0;
+}
+
+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;
+
+ 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);
+
+ return 0;
+}
+#else
+#define davinci_mcasp_suspend NULL
+#define davinci_mcasp_resume NULL
+#endif
+
#define DAVINCI_MCASP_RATES SNDRV_PCM_RATE_8000_192000
#define DAVINCI_MCASP_PCM_FMTS (SNDRV_PCM_FMTBIT_S8 | \
@@ -742,6 +846,9 @@ static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = {
static struct snd_soc_dai_driver davinci_mcasp_dai[] = {
{
.name = "davinci-mcasp.0",
+ .probe = davinci_mcasp_dai_probe,
+ .suspend = davinci_mcasp_suspend,
+ .resume = davinci_mcasp_resume,
.playback = {
.channels_min = 2,
.channels_max = 32 * 16,
@@ -759,6 +866,7 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = {
},
{
.name = "davinci-mcasp.1",
+ .probe = davinci_mcasp_dai_probe,
.playback = {
.channels_min = 1,
.channels_max = 384,
@@ -775,28 +883,28 @@ static const struct snd_soc_component_driver davinci_mcasp_component = {
};
/* Some HW specific values and defaults. The rest is filled in from DT. */
-static struct snd_platform_data dm646x_mcasp_pdata = {
+static struct davinci_mcasp_pdata dm646x_mcasp_pdata = {
.tx_dma_offset = 0x400,
.rx_dma_offset = 0x400,
.asp_chan_q = EVENTQ_0,
.version = MCASP_VERSION_1,
};
-static struct snd_platform_data da830_mcasp_pdata = {
+static struct davinci_mcasp_pdata da830_mcasp_pdata = {
.tx_dma_offset = 0x2000,
.rx_dma_offset = 0x2000,
.asp_chan_q = EVENTQ_0,
.version = MCASP_VERSION_2,
};
-static struct snd_platform_data am33xx_mcasp_pdata = {
+static struct davinci_mcasp_pdata am33xx_mcasp_pdata = {
.tx_dma_offset = 0,
.rx_dma_offset = 0,
.asp_chan_q = EVENTQ_0,
.version = MCASP_VERSION_3,
};
-static struct snd_platform_data dra7_mcasp_pdata = {
+static struct davinci_mcasp_pdata dra7_mcasp_pdata = {
.tx_dma_offset = 0x200,
.rx_dma_offset = 0x284,
.asp_chan_q = EVENTQ_0,
@@ -864,11 +972,11 @@ err1:
return ret;
}
-static struct snd_platform_data *davinci_mcasp_set_pdata_from_of(
+static struct davinci_mcasp_pdata *davinci_mcasp_set_pdata_from_of(
struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
- struct snd_platform_data *pdata = NULL;
+ struct davinci_mcasp_pdata *pdata = NULL;
const struct of_device_id *match =
of_match_device(mcasp_dt_ids, &pdev->dev);
struct of_phandle_args dma_spec;
@@ -881,7 +989,7 @@ static struct snd_platform_data *davinci_mcasp_set_pdata_from_of(
pdata = pdev->dev.platform_data;
return pdata;
} else if (match) {
- pdata = (struct snd_platform_data *) match->data;
+ pdata = (struct davinci_mcasp_pdata*) match->data;
} else {
/* control shouldn't reach here. something is wrong */
ret = -EINVAL;
@@ -973,9 +1081,10 @@ nodata:
static int davinci_mcasp_probe(struct platform_device *pdev)
{
- struct davinci_pcm_dma_params *dma_data;
+ struct davinci_pcm_dma_params *dma_params;
+ struct snd_dmaengine_dai_dma_data *dma_data;
struct resource *mem, *ioarea, *res, *dat;
- struct snd_platform_data *pdata;
+ struct davinci_mcasp_pdata *pdata;
struct davinci_mcasp *mcasp;
int ret;
@@ -1025,7 +1134,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
if (!mcasp->base) {
dev_err(&pdev->dev, "ioremap failed\n");
ret = -ENOMEM;
- goto err_release_clk;
+ goto err;
}
mcasp->op_mode = pdata->op_mode;
@@ -1042,41 +1151,49 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
if (dat)
mcasp->dat_port = true;
- dma_data = &mcasp->dma_params[SNDRV_PCM_STREAM_PLAYBACK];
- dma_data->asp_chan_q = pdata->asp_chan_q;
- dma_data->ram_chan_q = pdata->ram_chan_q;
- dma_data->sram_pool = pdata->sram_pool;
- dma_data->sram_size = pdata->sram_size_playback;
+ dma_params = &mcasp->dma_params[SNDRV_PCM_STREAM_PLAYBACK];
+ dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
+ dma_params->asp_chan_q = pdata->asp_chan_q;
+ dma_params->ram_chan_q = pdata->ram_chan_q;
+ dma_params->sram_pool = pdata->sram_pool;
+ dma_params->sram_size = pdata->sram_size_playback;
if (dat)
- dma_data->dma_addr = dat->start;
+ dma_params->dma_addr = dat->start;
else
- dma_data->dma_addr = mem->start + pdata->tx_dma_offset;
+ dma_params->dma_addr = mem->start + pdata->tx_dma_offset;
/* Unconditional dmaengine stuff */
- mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr = dma_data->dma_addr;
+ dma_data->addr = dma_params->dma_addr;
res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
if (res)
- dma_data->channel = res->start;
+ dma_params->channel = res->start;
else
- dma_data->channel = pdata->tx_dma_channel;
+ dma_params->channel = pdata->tx_dma_channel;
- dma_data = &mcasp->dma_params[SNDRV_PCM_STREAM_CAPTURE];
- dma_data->asp_chan_q = pdata->asp_chan_q;
- dma_data->ram_chan_q = pdata->ram_chan_q;
- dma_data->sram_pool = pdata->sram_pool;
- dma_data->sram_size = pdata->sram_size_capture;
+ /* dmaengine filter data for DT and non-DT boot */
+ if (pdev->dev.of_node)
+ dma_data->filter_data = "tx";
+ else
+ dma_data->filter_data = &dma_params->channel;
+
+ dma_params = &mcasp->dma_params[SNDRV_PCM_STREAM_CAPTURE];
+ dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE];
+ dma_params->asp_chan_q = pdata->asp_chan_q;
+ dma_params->ram_chan_q = pdata->ram_chan_q;
+ dma_params->sram_pool = pdata->sram_pool;
+ dma_params->sram_size = pdata->sram_size_capture;
if (dat)
- dma_data->dma_addr = dat->start;
+ dma_params->dma_addr = dat->start;
else
- dma_data->dma_addr = mem->start + pdata->rx_dma_offset;
+ dma_params->dma_addr = mem->start + pdata->rx_dma_offset;
/* Unconditional dmaengine stuff */
- mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr = dma_data->dma_addr;
+ dma_data->addr = dma_params->dma_addr;
if (mcasp->version < MCASP_VERSION_3) {
mcasp->fifo_base = DAVINCI_MCASP_V2_AFIFO_BASE;
- /* dma_data->dma_addr is pointing to the data port address */
+ /* dma_params->dma_addr is pointing to the data port address */
mcasp->dat_port = true;
} else {
mcasp->fifo_base = DAVINCI_MCASP_V3_AFIFO_BASE;
@@ -1084,37 +1201,51 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
if (res)
- dma_data->channel = res->start;
+ dma_params->channel = res->start;
else
- dma_data->channel = pdata->rx_dma_channel;
+ dma_params->channel = pdata->rx_dma_channel;
- /* Unconditional dmaengine stuff */
- mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK].filter_data = "tx";
- mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE].filter_data = "rx";
+ /* dmaengine filter data for DT and non-DT boot */
+ if (pdev->dev.of_node)
+ dma_data->filter_data = "rx";
+ else
+ dma_data->filter_data = &dma_params->channel;
dev_set_drvdata(&pdev->dev, mcasp);
mcasp_reparent_fck(pdev);
- ret = snd_soc_register_component(&pdev->dev, &davinci_mcasp_component,
- &davinci_mcasp_dai[pdata->op_mode], 1);
+ ret = devm_snd_soc_register_component(&pdev->dev,
+ &davinci_mcasp_component,
+ &davinci_mcasp_dai[pdata->op_mode], 1);
if (ret != 0)
- goto err_release_clk;
+ goto err;
- if (mcasp->version != MCASP_VERSION_4) {
+ switch (mcasp->version) {
+ case MCASP_VERSION_1:
+ case MCASP_VERSION_2:
+ case MCASP_VERSION_3:
ret = davinci_soc_platform_register(&pdev->dev);
- if (ret) {
- dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
- goto err_unregister_component;
- }
+ break;
+ case MCASP_VERSION_4:
+ ret = omap_pcm_platform_register(&pdev->dev);
+ break;
+ default:
+ dev_err(&pdev->dev, "Invalid McASP version: %d\n",
+ mcasp->version);
+ ret = -EINVAL;
+ break;
+ }
+
+ if (ret) {
+ dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
+ goto err;
}
return 0;
-err_unregister_component:
- snd_soc_unregister_component(&pdev->dev);
-err_release_clk:
+err:
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
return ret;
@@ -1122,61 +1253,18 @@ err_release_clk:
static int davinci_mcasp_remove(struct platform_device *pdev)
{
- struct davinci_mcasp *mcasp = dev_get_drvdata(&pdev->dev);
-
- snd_soc_unregister_component(&pdev->dev);
- if (mcasp->version != MCASP_VERSION_4)
- davinci_soc_platform_unregister(&pdev->dev);
-
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
return 0;
}
-#ifdef CONFIG_PM_SLEEP
-static int davinci_mcasp_suspend(struct device *dev)
-{
- struct davinci_mcasp *mcasp = dev_get_drvdata(dev);
-
- mcasp->context.txfmtctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG);
- mcasp->context.rxfmtctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG);
- mcasp->context.txfmt = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXFMT_REG);
- mcasp->context.rxfmt = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMT_REG);
- mcasp->context.aclkxctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG);
- mcasp->context.aclkrctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKRCTL_REG);
- mcasp->context.pdir = mcasp_get_reg(mcasp, DAVINCI_MCASP_PDIR_REG);
-
- return 0;
-}
-
-static int davinci_mcasp_resume(struct device *dev)
-{
- struct davinci_mcasp *mcasp = dev_get_drvdata(dev);
-
- mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG, mcasp->context.txfmtctl);
- mcasp_set_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG, mcasp->context.rxfmtctl);
- mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMT_REG, mcasp->context.txfmt);
- mcasp_set_reg(mcasp, DAVINCI_MCASP_RXFMT_REG, mcasp->context.rxfmt);
- mcasp_set_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, mcasp->context.aclkxctl);
- mcasp_set_reg(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, mcasp->context.aclkrctl);
- mcasp_set_reg(mcasp, DAVINCI_MCASP_PDIR_REG, mcasp->context.pdir);
-
- return 0;
-}
-#endif
-
-SIMPLE_DEV_PM_OPS(davinci_mcasp_pm_ops,
- davinci_mcasp_suspend,
- davinci_mcasp_resume);
-
static struct platform_driver davinci_mcasp_driver = {
.probe = davinci_mcasp_probe,
.remove = davinci_mcasp_remove,
.driver = {
.name = "davinci-mcasp",
.owner = THIS_MODULE,
- .pm = &davinci_mcasp_pm_ops,
.of_match_table = mcasp_dt_ids,
},
};