aboutsummaryrefslogtreecommitdiff
path: root/sound/soc/fsl
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2009-03-26 15:23:24 -0700
committerDavid S. Miller <davem@davemloft.net>2009-03-26 15:23:24 -0700
commit08abe18af1f78ee80c3c3a5ac47c3e0ae0beadf6 (patch)
tree2be39bf8942edca1bcec735145e144a682ca9cd3 /sound/soc/fsl
parentf0de70f8bb56952f6e016a65a8a8d006918f5bf6 (diff)
parent0384e2959127a56d0640505d004d8dd92f9c29f5 (diff)
Merge branch 'master' of /home/davem/src/GIT/linux-2.6/
Conflicts: drivers/net/wimax/i2400m/usb-notif.c
Diffstat (limited to 'sound/soc/fsl')
-rw-r--r--sound/soc/fsl/Kconfig17
-rw-r--r--sound/soc/fsl/Makefile7
-rw-r--r--sound/soc/fsl/fsl_dma.c181
-rw-r--r--sound/soc/fsl/fsl_ssi.c98
-rw-r--r--sound/soc/fsl/fsl_ssi.h2
-rw-r--r--sound/soc/fsl/mpc5200_psc_i2s.c20
-rw-r--r--sound/soc/fsl/mpc8610_hpcd.c5
7 files changed, 182 insertions, 148 deletions
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 95c12b26fe3..9fc90828337 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -1,17 +1,18 @@
config SND_SOC_OF_SIMPLE
tristate
+# ASoC platform support for the Freescale MPC8610 SOC. This compiles drivers
+# for the SSI and the Elo DMA controller. You will still need to select
+# a platform driver and a codec driver.
config SND_SOC_MPC8610
- bool "ALSA SoC support for the MPC8610 SOC"
- depends on MPC8610_HPCD
- default y if MPC8610
- help
- Say Y if you want to add support for codecs attached to the SSI
- device on an MPC8610.
+ tristate
+ depends on MPC8610
config SND_SOC_MPC8610_HPCD
- bool "ALSA SoC support for the Freescale MPC8610 HPCD board"
- depends on SND_SOC_MPC8610
+ tristate "ALSA SoC support for the Freescale MPC8610 HPCD board"
+ # I2C is necessary for the CS4270 driver
+ depends on MPC8610_HPCD && I2C
+ select SND_SOC_MPC8610
select SND_SOC_CS4270
select SND_SOC_CS4270_VD33_ERRATA
default y if MPC8610_HPCD
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index 035da4afec3..f85134c8638 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -2,10 +2,13 @@
obj-$(CONFIG_SND_SOC_OF_SIMPLE) += soc-of-simple.o
# MPC8610 HPCD Machine Support
-obj-$(CONFIG_SND_SOC_MPC8610_HPCD) += mpc8610_hpcd.o
+snd-soc-mpc8610-hpcd-objs := mpc8610_hpcd.o
+obj-$(CONFIG_SND_SOC_MPC8610_HPCD) += snd-soc-mpc8610-hpcd.o
# MPC8610 Platform Support
-obj-$(CONFIG_SND_SOC_MPC8610) += fsl_ssi.o fsl_dma.o
+snd-soc-fsl-ssi-objs := fsl_ssi.o
+snd-soc-fsl-dma-objs := fsl_dma.o
+obj-$(CONFIG_SND_SOC_MPC8610) += snd-soc-fsl-ssi.o snd-soc-fsl-dma.o
obj-$(CONFIG_SND_SOC_MPC5200_I2S) += mpc5200_psc_i2s.o
diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c
index 64993eda567..b3eb8570cd7 100644
--- a/sound/soc/fsl/fsl_dma.c
+++ b/sound/soc/fsl/fsl_dma.c
@@ -142,7 +142,8 @@ static const struct snd_pcm_hardware fsl_dma_hardware = {
.info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_JOINT_DUPLEX,
+ SNDRV_PCM_INFO_JOINT_DUPLEX |
+ SNDRV_PCM_INFO_PAUSE,
.formats = FSLDMA_PCM_FORMATS,
.rates = FSLDMA_PCM_RATES,
.rate_min = 5512,
@@ -464,11 +465,7 @@ static int fsl_dma_open(struct snd_pcm_substream *substream)
sizeof(struct fsl_dma_link_descriptor);
for (i = 0; i < NUM_DMA_LINKS; i++) {
- struct fsl_dma_link_descriptor *link = &dma_private->link[i];
-
- link->source_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP);
- link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP);
- link->next = cpu_to_be64(temp_link);
+ dma_private->link[i].next = cpu_to_be64(temp_link);
temp_link += sizeof(struct fsl_dma_link_descriptor);
}
@@ -525,79 +522,9 @@ static int fsl_dma_open(struct snd_pcm_substream *substream)
* This function obtains hardware parameters about the opened stream and
* programs the DMA controller accordingly.
*
- * Note that due to a quirk of the SSI's STX register, the target address
- * for the DMA operations depends on the sample size. So we don't program
- * the dest_addr (for playback -- source_addr for capture) fields in the
- * link descriptors here. We do that in fsl_dma_prepare()
- */
-static int fsl_dma_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *hw_params)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct fsl_dma_private *dma_private = runtime->private_data;
-
- dma_addr_t temp_addr; /* Pointer to next period */
-
- unsigned int i;
-
- /* Get all the parameters we need */
- size_t buffer_size = params_buffer_bytes(hw_params);
- size_t period_size = params_period_bytes(hw_params);
-
- /* Initialize our DMA tracking variables */
- dma_private->period_size = period_size;
- dma_private->num_periods = params_periods(hw_params);
- dma_private->dma_buf_end = dma_private->dma_buf_phys + buffer_size;
- dma_private->dma_buf_next = dma_private->dma_buf_phys +
- (NUM_DMA_LINKS * period_size);
- if (dma_private->dma_buf_next >= dma_private->dma_buf_end)
- dma_private->dma_buf_next = dma_private->dma_buf_phys;
-
- /*
- * The actual address in STX0 (destination for playback, source for
- * capture) is based on the sample size, but we don't know the sample
- * size in this function, so we'll have to adjust that later. See
- * comments in fsl_dma_prepare().
- *
- * The DMA controller does not have a cache, so the CPU does not
- * need to tell it to flush its cache. However, the DMA
- * controller does need to tell the CPU to flush its cache.
- * That's what the SNOOP bit does.
- *
- * Also, even though the DMA controller supports 36-bit addressing, for
- * simplicity we currently support only 32-bit addresses for the audio
- * buffer itself.
- */
- temp_addr = substream->dma_buffer.addr;
-
- for (i = 0; i < NUM_DMA_LINKS; i++) {
- struct fsl_dma_link_descriptor *link = &dma_private->link[i];
-
- link->count = cpu_to_be32(period_size);
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- link->source_addr = cpu_to_be32(temp_addr);
- else
- link->dest_addr = cpu_to_be32(temp_addr);
-
- temp_addr += period_size;
- }
-
- return 0;
-}
-
-/**
- * fsl_dma_prepare - prepare the DMA registers for playback.
- *
- * This function is called after the specifics of the audio data are known,
- * i.e. snd_pcm_runtime is initialized.
- *
- * In this function, we finish programming the registers of the DMA
- * controller that are dependent on the sample size.
- *
- * One of the drawbacks with big-endian is that when copying integers of
- * different sizes to a fixed-sized register, the address to which the
- * integer must be copied is dependent on the size of the integer.
+ * One drawback of big-endian is that when copying integers of different
+ * sizes to a fixed-sized register, the address to which the integer must be
+ * copied is dependent on the size of the integer.
*
* For example, if P is the address of a 32-bit register, and X is a 32-bit
* integer, then X should be copied to address P. However, if X is a 16-bit
@@ -613,22 +540,58 @@ static int fsl_dma_hw_params(struct snd_pcm_substream *substream,
* and 8 bytes at a time). So we do not support packed 24-bit samples.
* 24-bit data must be padded to 32 bits.
*/
-static int fsl_dma_prepare(struct snd_pcm_substream *substream)
+static int fsl_dma_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct fsl_dma_private *dma_private = runtime->private_data;
+
+ /* Number of bits per sample */
+ unsigned int sample_size =
+ snd_pcm_format_physical_width(params_format(hw_params));
+
+ /* Number of bytes per frame */
+ unsigned int frame_size = 2 * (sample_size / 8);
+
+ /* Bus address of SSI STX register */
+ dma_addr_t ssi_sxx_phys = dma_private->ssi_sxx_phys;
+
+ /* Size of the DMA buffer, in bytes */
+ size_t buffer_size = params_buffer_bytes(hw_params);
+
+ /* Number of bytes per period */
+ size_t period_size = params_period_bytes(hw_params);
+
+ /* Pointer to next period */
+ dma_addr_t temp_addr = substream->dma_buffer.addr;
+
+ /* Pointer to DMA controller */
struct ccsr_dma_channel __iomem *dma_channel = dma_private->dma_channel;
- u32 mr;
+
+ u32 mr; /* DMA Mode Register */
+
unsigned int i;
- dma_addr_t ssi_sxx_phys; /* Bus address of SSI STX register */
- unsigned int frame_size; /* Number of bytes per frame */
- ssi_sxx_phys = dma_private->ssi_sxx_phys;
+ /* Initialize our DMA tracking variables */
+ dma_private->period_size = period_size;
+ dma_private->num_periods = params_periods(hw_params);
+ dma_private->dma_buf_end = dma_private->dma_buf_phys + buffer_size;
+ dma_private->dma_buf_next = dma_private->dma_buf_phys +
+ (NUM_DMA_LINKS * period_size);
+
+ if (dma_private->dma_buf_next >= dma_private->dma_buf_end)
+ /* This happens if the number of periods == NUM_DMA_LINKS */
+ dma_private->dma_buf_next = dma_private->dma_buf_phys;
mr = in_be32(&dma_channel->mr) & ~(CCSR_DMA_MR_BWC_MASK |
CCSR_DMA_MR_SAHTS_MASK | CCSR_DMA_MR_DAHTS_MASK);
- switch (runtime->sample_bits) {
+ /* Due to a quirk of the SSI's STX register, the target address
+ * for the DMA operations depends on the sample size. So we calculate
+ * that offset here. While we're at it, also tell the DMA controller
+ * how much data to transfer per sample.
+ */
+ switch (sample_size) {
case 8:
mr |= CCSR_DMA_MR_DAHTS_1 | CCSR_DMA_MR_SAHTS_1;
ssi_sxx_phys += 3;
@@ -641,12 +604,12 @@ static int fsl_dma_prepare(struct snd_pcm_substream *substream)
mr |= CCSR_DMA_MR_DAHTS_4 | CCSR_DMA_MR_SAHTS_4;
break;
default:
+ /* We should never get here */
dev_err(substream->pcm->card->dev,
- "unsupported sample size %u\n", runtime->sample_bits);
+ "unsupported sample size %u\n", sample_size);
return -EINVAL;
}
- frame_size = runtime->frame_bits / 8;
/*
* BWC should always be a multiple of the frame size. BWC determines
* how many bytes are sent/received before the DMA controller checks the
@@ -655,7 +618,6 @@ static int fsl_dma_prepare(struct snd_pcm_substream *substream)
* capture, the receive FIFO is triggered when it contains one frame, so
* we want to receive one frame at a time.
*/
-
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
mr |= CCSR_DMA_MR_BWC(2 * frame_size);
else
@@ -663,16 +625,48 @@ static int fsl_dma_prepare(struct snd_pcm_substream *substream)
out_be32(&dma_channel->mr, mr);
- /*
- * Program the address of the DMA transfer to/from the SSI.
- */
for (i = 0; i < NUM_DMA_LINKS; i++) {
struct fsl_dma_link_descriptor *link = &dma_private->link[i];
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ link->count = cpu_to_be32(period_size);
+
+ /* Even though the DMA controller supports 36-bit addressing,
+ * for simplicity we allow only 32-bit addresses for the audio
+ * buffer itself. This was enforced in fsl_dma_new() with the
+ * DMA mask.
+ *
+ * The snoop bit tells the DMA controller whether it should tell
+ * the ECM to snoop during a read or write to an address. For
+ * audio, we use DMA to transfer data between memory and an I/O
+ * device (the SSI's STX0 or SRX0 register). Snooping is only
+ * needed if there is a cache, so we need to snoop memory
+ * addresses only. For playback, that means we snoop the source
+ * but not the destination. For capture, we snoop the
+ * destination but not the source.
+ *
+ * Note that failing to snoop properly is unlikely to cause
+ * cache incoherency if the period size is larger than the
+ * size of L1 cache. This is because filling in one period will
+ * flush out the data for the previous period. So if you
+ * increased period_bytes_min to a large enough size, you might
+ * get more performance by not snooping, and you'll still be
+ * okay.
+ */
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ link->source_addr = cpu_to_be32(temp_addr);
+ link->source_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP);
+
link->dest_addr = cpu_to_be32(ssi_sxx_phys);
- else
+ link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_NOSNOOP);
+ } else {
link->source_addr = cpu_to_be32(ssi_sxx_phys);
+ link->source_attr = cpu_to_be32(CCSR_DMA_ATR_NOSNOOP);
+
+ link->dest_addr = cpu_to_be32(temp_addr);
+ link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP);
+ }
+
+ temp_addr += period_size;
}
return 0;
@@ -808,7 +802,6 @@ static struct snd_pcm_ops fsl_dma_ops = {
.ioctl = snd_pcm_lib_ioctl,
.hw_params = fsl_dma_hw_params,
.hw_free = fsl_dma_hw_free,
- .prepare = fsl_dma_prepare,
.pointer = fsl_dma_pointer,
};
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index c6d6eb71dc1..169bca295b7 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -72,6 +72,7 @@
* @dev: struct device pointer
* @playback: the number of playback streams opened
* @capture: the number of capture streams opened
+ * @asynchronous: 0=synchronous mode, 1=asynchronous mode
* @cpu_dai: the CPU DAI for this device
* @dev_attr: the sysfs device attribute structure
* @stats: SSI statistics
@@ -86,6 +87,7 @@ struct fsl_ssi_private {
struct device *dev;
unsigned int playback;
unsigned int capture;
+ int asynchronous;
struct snd_soc_dai cpu_dai;
struct device_attribute dev_attr;
@@ -301,9 +303,10 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
*
* FIXME: Little-endian samples require a different shift dir
*/
- clrsetbits_be32(&ssi->scr, CCSR_SSI_SCR_I2S_MODE_MASK,
- CCSR_SSI_SCR_TFR_CLK_DIS |
- CCSR_SSI_SCR_I2S_MODE_SLAVE | CCSR_SSI_SCR_SYN);
+ clrsetbits_be32(&ssi->scr,
+ CCSR_SSI_SCR_I2S_MODE_MASK | CCSR_SSI_SCR_SYN,
+ CCSR_SSI_SCR_TFR_CLK_DIS | CCSR_SSI_SCR_I2S_MODE_SLAVE
+ | (ssi_private->asynchronous ? 0 : CCSR_SSI_SCR_SYN));
out_be32(&ssi->stcr,
CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFEN0 |
@@ -382,10 +385,15 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
SNDRV_PCM_HW_PARAM_RATE,
first_runtime->rate, first_runtime->rate);
- snd_pcm_hw_constraint_minmax(substream->runtime,
- SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
- first_runtime->sample_bits,
- first_runtime->sample_bits);
+ /* If we're in synchronous mode, then we need to constrain
+ * the sample size as well. We don't support independent sample
+ * rates in asynchronous mode.
+ */
+ if (!ssi_private->asynchronous)
+ snd_pcm_hw_constraint_minmax(substream->runtime,
+ SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
+ first_runtime->sample_bits,
+ first_runtime->sample_bits);
ssi_private->second_stream = substream;
}
@@ -400,7 +408,7 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
}
/**
- * fsl_ssi_prepare: prepare the SSI.
+ * fsl_ssi_hw_params - program the sample size
*
* Most of the SSI registers have been programmed in the startup function,
* but the word length must be programmed here. Unfortunately, programming
@@ -412,23 +420,27 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
* Note: The SxCCR.DC and SxCCR.PM bits are only used if the SSI is the
* clock master.
*/
-static int fsl_ssi_prepare(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
+static int fsl_ssi_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *cpu_dai)
{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data;
-
- struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
+ struct fsl_ssi_private *ssi_private = cpu_dai->private_data;
if (substream == ssi_private->first_stream) {
- u32 wl;
+ struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
+ unsigned int sample_size =
+ snd_pcm_format_width(params_format(hw_params));
+ u32 wl = CCSR_SSI_SxCCR_WL(sample_size);
/* The SSI should always be disabled at this points (SSIEN=0) */
- wl = CCSR_SSI_SxCCR_WL(snd_pcm_format_width(runtime->format));
/* In synchronous mode, the SSI uses STCCR for capture */
- clrsetbits_be32(&ssi->stccr, CCSR_SSI_SxCCR_WL_MASK, wl);
+ if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ||
+ !ssi_private->asynchronous)
+ clrsetbits_be32(&ssi->stccr,
+ CCSR_SSI_SxCCR_WL_MASK, wl);
+ else
+ clrsetbits_be32(&ssi->srccr,
+ CCSR_SSI_SxCCR_WL_MASK, wl);
}
return 0;
@@ -452,28 +464,33 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
- case SNDRV_PCM_TRIGGER_RESUME:
+ clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN);
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN);
setbits32(&ssi->scr,
CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_TE);
} else {
- clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN);
+ long timeout = jiffies + 10;
+
setbits32(&ssi->scr,
CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_RE);
- /*
- * I think we need this delay to allow time for the SSI
- * to put data into its FIFO. Without it, ALSA starts
- * to complain about overruns.
+ /* Wait until the SSI has filled its FIFO. Without this
+ * delay, ALSA complains about overruns. When the FIFO
+ * is full, the DMA controller initiates its first
+ * transfer. Until then, however, the DMA's DAR
+ * register is zero, which translates to an
+ * out-of-bounds pointer. This makes ALSA think an
+ * overrun has occurred.
*/
- mdelay(1);
+ while (!(in_be32(&ssi->sisr) & CCSR_SSI_SISR_RFF0) &&
+ (jiffies < timeout));
+ if (!(in_be32(&ssi->sisr) & CCSR_SSI_SISR_RFF0))
+ return -EIO;
}
break;
case SNDRV_PCM_TRIGGER_STOP:
- case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
clrbits32(&ssi->scr, CCSR_SSI_SCR_TE);
@@ -563,6 +580,15 @@ static int fsl_ssi_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format)
/**
* fsl_ssi_dai_template: template CPU DAI for the SSI
*/
+static struct snd_soc_dai_ops fsl_ssi_dai_ops = {
+ .startup = fsl_ssi_startup,
+ .hw_params = fsl_ssi_hw_params,
+ .shutdown = fsl_ssi_shutdown,
+ .trigger = fsl_ssi_trigger,
+ .set_sysclk = fsl_ssi_set_sysclk,
+ .set_fmt = fsl_ssi_set_fmt,
+};
+
static struct snd_soc_dai fsl_ssi_dai_template = {
.playback = {
/* The SSI does not support monaural audio. */
@@ -577,14 +603,7 @@ static struct snd_soc_dai fsl_ssi_dai_template = {
.rates = FSLSSI_I2S_RATES,
.formats = FSLSSI_I2S_FORMATS,
},
- .ops = {
- .startup = fsl_ssi_startup,
- .prepare = fsl_ssi_prepare,
- .shutdown = fsl_ssi_shutdown,
- .trigger = fsl_ssi_trigger,
- .set_sysclk = fsl_ssi_set_sysclk,
- .set_fmt = fsl_ssi_set_fmt,
- },
+ .ops = &fsl_ssi_dai_ops,
};
/**
@@ -654,6 +673,7 @@ struct snd_soc_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info)
ssi_private->ssi_phys = ssi_info->ssi_phys;
ssi_private->irq = ssi_info->irq;
ssi_private->dev = ssi_info->dev;
+ ssi_private->asynchronous = ssi_info->asynchronous;
ssi_private->dev->driver_data = fsl_ssi_dai;
@@ -704,6 +724,14 @@ void fsl_ssi_destroy_dai(struct snd_soc_dai *fsl_ssi_dai)
}
EXPORT_SYMBOL_GPL(fsl_ssi_destroy_dai);
+static int __init fsl_ssi_init(void)
+{
+ printk(KERN_INFO "Freescale Synchronous Serial Interface (SSI) ASoC Driver\n");
+
+ return 0;
+}
+module_init(fsl_ssi_init);
+
MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
MODULE_DESCRIPTION("Freescale Synchronous Serial Interface (SSI) ASoC Driver");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/fsl/fsl_ssi.h b/sound/soc/fsl/fsl_ssi.h
index 83b44d700e3..eade01feaab 100644
--- a/sound/soc/fsl/fsl_ssi.h
+++ b/sound/soc/fsl/fsl_ssi.h
@@ -208,6 +208,7 @@ struct ccsr_ssi {
* ssi_phys: physical address of the SSI registers
* irq: IRQ of this SSI
* dev: struct device, used to create the sysfs statistics file
+ * asynchronous: 0=synchronous mode, 1=asynchronous mode
*/
struct fsl_ssi_info {
unsigned int id;
@@ -215,6 +216,7 @@ struct fsl_ssi_info {
dma_addr_t ssi_phys;
unsigned int irq;
struct device *dev;
+ int asynchronous;
};
struct snd_soc_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info);
diff --git a/sound/soc/fsl/mpc5200_psc_i2s.c b/sound/soc/fsl/mpc5200_psc_i2s.c
index 9eb1ce185bd..3aa729df27b 100644
--- a/sound/soc/fsl/mpc5200_psc_i2s.c
+++ b/sound/soc/fsl/mpc5200_psc_i2s.c
@@ -468,6 +468,16 @@ static int psc_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format)
/**
* psc_i2s_dai_template: template CPU Digital Audio Interface
*/
+static struct snd_soc_dai_ops psc_i2s_dai_ops = {
+ .startup = psc_i2s_startup,
+ .hw_params = psc_i2s_hw_params,
+ .hw_free = psc_i2s_hw_free,
+ .shutdown = psc_i2s_shutdown,
+ .trigger = psc_i2s_trigger,
+ .set_sysclk = psc_i2s_set_sysclk,
+ .set_fmt = psc_i2s_set_fmt,
+};
+
static struct snd_soc_dai psc_i2s_dai_template = {
.playback = {
.channels_min = 2,
@@ -481,15 +491,7 @@ static struct snd_soc_dai psc_i2s_dai_template = {
.rates = PSC_I2S_RATES,
.formats = PSC_I2S_FORMATS,
},
- .ops = {
- .startup = psc_i2s_startup,
- .hw_params = psc_i2s_hw_params,
- .hw_free = psc_i2s_hw_free,
- .shutdown = psc_i2s_shutdown,
- .trigger = psc_i2s_trigger,
- .set_sysclk = psc_i2s_set_sysclk,
- .set_fmt = psc_i2s_set_fmt,
- },
+ .ops = &psc_i2s_dai_ops,
};
/* ---------------------------------------------------------------------
diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c
index acf39a646b2..ef67d1cdffe 100644
--- a/sound/soc/fsl/mpc8610_hpcd.c
+++ b/sound/soc/fsl/mpc8610_hpcd.c
@@ -353,6 +353,11 @@ static int mpc8610_hpcd_probe(struct of_device *ofdev,
}
ssi_info.irq = machine_data->ssi_irq;
+ /* Do we want to use asynchronous mode? */
+ ssi_info.asynchronous =
+ of_find_property(np, "fsl,ssi-asynchronous", NULL) ? 1 : 0;
+ if (ssi_info.asynchronous)
+ dev_info(&ofdev->dev, "using asynchronous mode\n");
/* Map the global utilities registers. */
guts_np = of_find_compatible_node(NULL, NULL, "fsl,mpc8610-guts");