aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/sound/soc-dapm.h3
-rw-r--r--sound/soc/fsl/fsl_dma.c7
-rw-r--r--sound/soc/fsl/fsl_ssi.c74
-rw-r--r--sound/soc/pxa/poodle.c8
-rw-r--r--sound/soc/pxa/tosa.c1
-rw-r--r--sound/soc/soc-dapm.c1
6 files changed, 76 insertions, 18 deletions
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index 3030fdc6981..c1b26fcc0b5 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -202,6 +202,9 @@ struct snd_soc_dapm_path;
struct snd_soc_dapm_pin;
struct snd_soc_dapm_route;
+int dapm_reg_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event);
+
/* dapm controls */
int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c
index da2bc590286..7ceea2bba1f 100644
--- a/sound/soc/fsl/fsl_dma.c
+++ b/sound/soc/fsl/fsl_dma.c
@@ -132,12 +132,17 @@ struct fsl_dma_private {
* Since each link descriptor has a 32-bit byte count field, we set
* period_bytes_max to the largest 32-bit number. We also have no maximum
* number of periods.
+ *
+ * Note that we specify SNDRV_PCM_INFO_JOINT_DUPLEX here, but only because a
+ * limitation in the SSI driver requires the sample rates for playback and
+ * capture to be the same.
*/
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_MMAP_VALID |
+ SNDRV_PCM_INFO_JOINT_DUPLEX,
.formats = FSLDMA_PCM_FORMATS,
.rates = FSLDMA_PCM_RATES,
.rate_min = 5512,
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index 71bff33f552..157a7895ffa 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -67,6 +67,8 @@
* @ssi: pointer to the SSI's registers
* @ssi_phys: physical address of the SSI registers
* @irq: IRQ of this SSI
+ * @first_stream: pointer to the stream that was opened first
+ * @second_stream: pointer to second stream
* @dev: struct device pointer
* @playback: the number of playback streams opened
* @capture: the number of capture streams opened
@@ -79,6 +81,8 @@ struct fsl_ssi_private {
struct ccsr_ssi __iomem *ssi;
dma_addr_t ssi_phys;
unsigned int irq;
+ struct snd_pcm_substream *first_stream;
+ struct snd_pcm_substream *second_stream;
struct device *dev;
unsigned int playback;
unsigned int capture;
@@ -342,6 +346,49 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream)
*/
}
+ if (!ssi_private->first_stream)
+ ssi_private->first_stream = substream;
+ else {
+ /* This is the second stream open, so we need to impose sample
+ * rate and maybe sample size constraints. Note that this can
+ * cause a race condition if the second stream is opened before
+ * the first stream is fully initialized.
+ *
+ * We provide some protection by checking to make sure the first
+ * stream is initialized, but it's not perfect. ALSA sometimes
+ * re-initializes the driver with a different sample rate or
+ * size. If the second stream is opened before the first stream
+ * has received its final parameters, then the second stream may
+ * be constrained to the wrong sample rate or size.
+ *
+ * FIXME: This code does not handle opening and closing streams
+ * repeatedly. If you open two streams and then close the first
+ * one, you may not be able to open another stream until you
+ * close the second one as well.
+ */
+ struct snd_pcm_runtime *first_runtime =
+ ssi_private->first_stream->runtime;
+
+ if (!first_runtime->rate || !first_runtime->sample_bits) {
+ dev_err(substream->pcm->card->dev,
+ "set sample rate and size in %s stream first\n",
+ substream->stream == SNDRV_PCM_STREAM_PLAYBACK
+ ? "capture" : "playback");
+ return -EAGAIN;
+ }
+
+ snd_pcm_hw_constraint_minmax(substream->runtime,
+ 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);
+
+ ssi_private->second_stream = substream;
+ }
+
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
ssi_private->playback++;
@@ -371,18 +418,16 @@ static int fsl_ssi_prepare(struct snd_pcm_substream *substream)
struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data;
struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
- u32 wl;
- wl = CCSR_SSI_SxCCR_WL(snd_pcm_format_width(runtime->format));
+ if (substream == ssi_private->first_stream) {
+ u32 wl;
- clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN);
+ /* The SSI should always be disabled at this points (SSIEN=0) */
+ wl = CCSR_SSI_SxCCR_WL(snd_pcm_format_width(runtime->format));
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ /* In synchronous mode, the SSI uses STCCR for capture */
clrsetbits_be32(&ssi->stccr, CCSR_SSI_SxCCR_WL_MASK, wl);
- else
- clrsetbits_be32(&ssi->srccr, CCSR_SSI_SxCCR_WL_MASK, wl);
-
- setbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN);
+ }
return 0;
}
@@ -407,9 +452,13 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd)
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- setbits32(&ssi->scr, CCSR_SSI_SCR_TE);
+ clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN);
+ setbits32(&ssi->scr,
+ CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_TE);
} else {
- setbits32(&ssi->scr, CCSR_SSI_SCR_RE);
+ clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN);
+ setbits32(&ssi->scr,
+ CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_RE);
/*
* I think we need this delay to allow time for the SSI
@@ -452,6 +501,11 @@ static void fsl_ssi_shutdown(struct snd_pcm_substream *substream)
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
ssi_private->capture--;
+ if (ssi_private->first_stream == substream)
+ ssi_private->first_stream = ssi_private->second_stream;
+
+ ssi_private->second_stream = NULL;
+
/*
* If this is the last active substream, disable the SSI and release
* the IRQ.
diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c
index 65a4e9a8c39..d968cf71b56 100644
--- a/sound/soc/pxa/poodle.c
+++ b/sound/soc/pxa/poodle.c
@@ -85,17 +85,13 @@ static int poodle_startup(struct snd_pcm_substream *substream)
}
/* we need to unmute the HP at shutdown as the mute burns power on poodle */
-static int poodle_shutdown(struct snd_pcm_substream *substream)
+static void poodle_shutdown(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->socdev->codec;
-
/* set = unmute headphone */
locomo_gpio_write(&poodle_locomo_device.dev,
POODLE_LOCOMO_GPIO_MUTE_L, 1);
locomo_gpio_write(&poodle_locomo_device.dev,
POODLE_LOCOMO_GPIO_MUTE_R, 1);
- return 0;
}
static int poodle_hw_params(struct snd_pcm_substream *substream,
@@ -232,7 +228,7 @@ static const struct soc_enum poodle_enum[] = {
SOC_ENUM_SINGLE_EXT(2, spk_function),
};
-static const snd_kcontrol_new_t wm8731_poodle_controls[] = {
+static const struct snd_kcontrol_new wm8731_poodle_controls[] = {
SOC_ENUM_EXT("Jack Function", poodle_enum[0], poodle_get_jack,
poodle_set_jack),
SOC_ENUM_EXT("Speaker Function", poodle_enum[1], poodle_get_spk,
diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c
index fe6cca9c9e7..22971a0f040 100644
--- a/sound/soc/pxa/tosa.c
+++ b/sound/soc/pxa/tosa.c
@@ -33,7 +33,6 @@
#include <asm/arch/pxa-regs.h>
#include <asm/arch/hardware.h>
#include <asm/arch/audio.h>
-#include <asm/arch/tosa.h>
#include "../codecs/wm9712.h"
#include "pxa2xx-pcm.h"
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 820347c9ae4..f9d100bc847 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -470,6 +470,7 @@ int dapm_reg_event(struct snd_soc_dapm_widget *w,
return 0;
}
+EXPORT_SYMBOL_GPL(dapm_reg_event);
/*
* Scan each dapm widget for complete audio path.