aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/fsl
diff options
context:
space:
mode:
authorTimur Tabi <timur@freescale.com>2009-03-05 18:23:37 -0500
committerMark Brown <broonie@opensource.wolfsonmicro.com>2009-03-06 08:37:16 -0500
commita454dad19e78388d9f140ad0dfa6a849c57d385d (patch)
treef228d03393c681176fa031f04584a4119c7ad175 /sound/soc/fsl
parent499d8f4a528f1ebd0c19d89174fdc67130090c89 (diff)
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 @@
72 * @dev: struct device pointer 72 * @dev: struct device pointer
73 * @playback: the number of playback streams opened 73 * @playback: the number of playback streams opened
74 * @capture: the number of capture streams opened 74 * @capture: the number of capture streams opened
75 * @asynchronous: 0=synchronous mode, 1=asynchronous mode
75 * @cpu_dai: the CPU DAI for this device 76 * @cpu_dai: the CPU DAI for this device
76 * @dev_attr: the sysfs device attribute structure 77 * @dev_attr: the sysfs device attribute structure
77 * @stats: SSI statistics 78 * @stats: SSI statistics
@@ -86,6 +87,7 @@ struct fsl_ssi_private {
86 struct device *dev; 87 struct device *dev;
87 unsigned int playback; 88 unsigned int playback;
88 unsigned int capture; 89 unsigned int capture;
90 int asynchronous;
89 struct snd_soc_dai cpu_dai; 91 struct snd_soc_dai cpu_dai;
90 struct device_attribute dev_attr; 92 struct device_attribute dev_attr;
91 93
@@ -301,9 +303,10 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
301 * 303 *
302 * FIXME: Little-endian samples require a different shift dir 304 * FIXME: Little-endian samples require a different shift dir
303 */ 305 */
304 clrsetbits_be32(&ssi->scr, CCSR_SSI_SCR_I2S_MODE_MASK, 306 clrsetbits_be32(&ssi->scr,
305 CCSR_SSI_SCR_TFR_CLK_DIS | 307 CCSR_SSI_SCR_I2S_MODE_MASK | CCSR_SSI_SCR_SYN,
306 CCSR_SSI_SCR_I2S_MODE_SLAVE | CCSR_SSI_SCR_SYN); 308 CCSR_SSI_SCR_TFR_CLK_DIS | CCSR_SSI_SCR_I2S_MODE_SLAVE
309 | (ssi_private->asynchronous ? 0 : CCSR_SSI_SCR_SYN));
307 310
308 out_be32(&ssi->stcr, 311 out_be32(&ssi->stcr,
309 CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFEN0 | 312 CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFEN0 |
@@ -382,10 +385,15 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
382 SNDRV_PCM_HW_PARAM_RATE, 385 SNDRV_PCM_HW_PARAM_RATE,
383 first_runtime->rate, first_runtime->rate); 386 first_runtime->rate, first_runtime->rate);
384 387
385 snd_pcm_hw_constraint_minmax(substream->runtime, 388 /* If we're in synchronous mode, then we need to constrain
386 SNDRV_PCM_HW_PARAM_SAMPLE_BITS, 389 * the sample size as well. We don't support independent sample
387 first_runtime->sample_bits, 390 * rates in asynchronous mode.
388 first_runtime->sample_bits); 391 */
392 if (!ssi_private->asynchronous)
393 snd_pcm_hw_constraint_minmax(substream->runtime,
394 SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
395 first_runtime->sample_bits,
396 first_runtime->sample_bits);
389 397
390 ssi_private->second_stream = substream; 398 ssi_private->second_stream = substream;
391 } 399 }
@@ -421,13 +429,18 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream,
421 struct ccsr_ssi __iomem *ssi = ssi_private->ssi; 429 struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
422 unsigned int sample_size = 430 unsigned int sample_size =
423 snd_pcm_format_width(params_format(hw_params)); 431 snd_pcm_format_width(params_format(hw_params));
424 u32 wl; 432 u32 wl = CCSR_SSI_SxCCR_WL(sample_size);
425 433
426 /* The SSI should always be disabled at this points (SSIEN=0) */ 434 /* The SSI should always be disabled at this points (SSIEN=0) */
427 wl = CCSR_SSI_SxCCR_WL(sample_size);
428 435
429 /* In synchronous mode, the SSI uses STCCR for capture */ 436 /* In synchronous mode, the SSI uses STCCR for capture */
430 clrsetbits_be32(&ssi->stccr, CCSR_SSI_SxCCR_WL_MASK, wl); 437 if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ||
438 !ssi_private->asynchronous)
439 clrsetbits_be32(&ssi->stccr,
440 CCSR_SSI_SxCCR_WL_MASK, wl);
441 else
442 clrsetbits_be32(&ssi->srccr,
443 CCSR_SSI_SxCCR_WL_MASK, wl);
431 } 444 }
432 445
433 return 0; 446 return 0;
@@ -653,6 +666,7 @@ struct snd_soc_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info)
653 ssi_private->ssi_phys = ssi_info->ssi_phys; 666 ssi_private->ssi_phys = ssi_info->ssi_phys;
654 ssi_private->irq = ssi_info->irq; 667 ssi_private->irq = ssi_info->irq;
655 ssi_private->dev = ssi_info->dev; 668 ssi_private->dev = ssi_info->dev;
669 ssi_private->asynchronous = ssi_info->asynchronous;
656 670
657 ssi_private->dev->driver_data = fsl_ssi_dai; 671 ssi_private->dev->driver_data = fsl_ssi_dai;
658 672
@@ -703,6 +717,14 @@ void fsl_ssi_destroy_dai(struct snd_soc_dai *fsl_ssi_dai)
703} 717}
704EXPORT_SYMBOL_GPL(fsl_ssi_destroy_dai); 718EXPORT_SYMBOL_GPL(fsl_ssi_destroy_dai);
705 719
720static int __init fsl_ssi_init(void)
721{
722 printk(KERN_INFO "Freescale Synchronous Serial Interface (SSI) ASoC Driver\n");
723
724 return 0;
725}
726module_init(fsl_ssi_init);
727
706MODULE_AUTHOR("Timur Tabi <timur@freescale.com>"); 728MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
707MODULE_DESCRIPTION("Freescale Synchronous Serial Interface (SSI) ASoC Driver"); 729MODULE_DESCRIPTION("Freescale Synchronous Serial Interface (SSI) ASoC Driver");
708MODULE_LICENSE("GPL"); 730MODULE_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 {
208 * ssi_phys: physical address of the SSI registers 208 * ssi_phys: physical address of the SSI registers
209 * irq: IRQ of this SSI 209 * irq: IRQ of this SSI
210 * dev: struct device, used to create the sysfs statistics file 210 * dev: struct device, used to create the sysfs statistics file
211 * asynchronous: 0=synchronous mode, 1=asynchronous mode
211*/ 212*/
212struct fsl_ssi_info { 213struct fsl_ssi_info {
213 unsigned int id; 214 unsigned int id;
@@ -215,6 +216,7 @@ struct fsl_ssi_info {
215 dma_addr_t ssi_phys; 216 dma_addr_t ssi_phys;
216 unsigned int irq; 217 unsigned int irq;
217 struct device *dev; 218 struct device *dev;
219 int asynchronous;
218}; 220};
219 221
220struct snd_soc_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info); 222struct 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,
353 } 353 }
354 ssi_info.irq = machine_data->ssi_irq; 354 ssi_info.irq = machine_data->ssi_irq;
355 355
356 /* Do we want to use asynchronous mode? */
357 ssi_info.asynchronous =
358 of_find_property(np, "fsl,ssi-asynchronous", NULL) ? 1 : 0;
359 if (ssi_info.asynchronous)
360 dev_info(&ofdev->dev, "using asynchronous mode\n");
356 361
357 /* Map the global utilities registers. */ 362 /* Map the global utilities registers. */
358 guts_np = of_find_compatible_node(NULL, NULL, "fsl,mpc8610-guts"); 363 guts_np = of_find_compatible_node(NULL, NULL, "fsl,mpc8610-guts");