summaryrefslogtreecommitdiffstats
path: root/sound/soc/fsl
diff options
context:
space:
mode:
authorTimur Tabi <timur@freescale.com>2009-03-06 00:23:37 +0100
committerMark Brown <broonie@opensource.wolfsonmicro.com>2009-03-06 14:37:16 +0100
commita454dad19e78388d9f140ad0dfa6a849c57d385d (patch)
treef228d03393c681176fa031f04584a4119c7ad175 /sound/soc/fsl
parentASoC: Update Kconfig for Samsung CPUs to reflect S3C64xx support (diff)
downloadlinux-a454dad19e78388d9f140ad0dfa6a849c57d385d.tar.xz
linux-a454dad19e78388d9f140ad0dfa6a849c57d385d.zip
ASoC: add support for SSI asynchronous mode to the Freescale SSI drivers
Add a new device tree property for the SSI node: "fsl,ssi-asynchronous". If defined, the SSI is programmed into asynchronous mode, otherwise it is programmed into synchronous mode. In asynchronous mode, pin SRCK must be connected to the same clock source as STFS, and pin SRFS must be connected to the same signal as STFS. Asynchronous mode allows playback and capture to use different sample sizes. It also technically allows different sample rates, but the driver does not support that. Signed-off-by: Timur Tabi <timur@freescale.com> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/fsl')
-rw-r--r--sound/soc/fsl/fsl_ssi.c42
-rw-r--r--sound/soc/fsl/fsl_ssi.h2
-rw-r--r--sound/soc/fsl/mpc8610_hpcd.c5
3 files changed, 39 insertions, 10 deletions
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index 6844009833db..8cb6bcf2c00f 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;
}
@@ -421,13 +429,18 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream,
struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
unsigned int sample_size =
snd_pcm_format_width(params_format(hw_params));
- u32 wl;
+ u32 wl = CCSR_SSI_SxCCR_WL(sample_size);
/* The SSI should always be disabled at this points (SSIEN=0) */
- wl = CCSR_SSI_SxCCR_WL(sample_size);
/* 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;
@@ -653,6 +666,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;
@@ -703,6 +717,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 83b44d700e33..eade01feaab6 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/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c
index acf39a646b2f..ef67d1cdffe7 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");