aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/s3c24xx/s3c-i2s-v2.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/s3c24xx/s3c-i2s-v2.c')
-rw-r--r--sound/soc/s3c24xx/s3c-i2s-v2.c205
1 files changed, 116 insertions, 89 deletions
diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.c b/sound/soc/s3c24xx/s3c-i2s-v2.c
index 88515946b6c0..13311c8cf965 100644
--- a/sound/soc/s3c24xx/s3c-i2s-v2.c
+++ b/sound/soc/s3c24xx/s3c-i2s-v2.c
@@ -16,24 +16,17 @@
16 * option) any later version. 16 * option) any later version.
17 */ 17 */
18 18
19#include <linux/init.h>
20#include <linux/module.h>
21#include <linux/device.h>
22#include <linux/delay.h> 19#include <linux/delay.h>
23#include <linux/clk.h> 20#include <linux/clk.h>
24#include <linux/kernel.h>
25#include <linux/io.h> 21#include <linux/io.h>
26 22
27#include <sound/core.h>
28#include <sound/pcm.h> 23#include <sound/pcm.h>
29#include <sound/pcm_params.h> 24#include <sound/pcm_params.h>
30#include <sound/initval.h>
31#include <sound/soc.h> 25#include <sound/soc.h>
32 26
33#include <plat/regs-s3c2412-iis.h>
34
35#include <mach/dma.h> 27#include <mach/dma.h>
36 28
29#include "regs-i2s-v2.h"
37#include "s3c-i2s-v2.h" 30#include "s3c-i2s-v2.h"
38#include "s3c-dma.h" 31#include "s3c-dma.h"
39 32
@@ -272,35 +265,14 @@ static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
272 iismod = readl(i2s->regs + S3C2412_IISMOD); 265 iismod = readl(i2s->regs + S3C2412_IISMOD);
273 pr_debug("hw_params r: IISMOD: %x \n", iismod); 266 pr_debug("hw_params r: IISMOD: %x \n", iismod);
274 267
275#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413)
276#define IISMOD_MASTER_MASK S3C2412_IISMOD_MASTER_MASK
277#define IISMOD_SLAVE S3C2412_IISMOD_SLAVE
278#define IISMOD_MASTER S3C2412_IISMOD_MASTER_INTERNAL
279#endif
280
281#if defined(CONFIG_PLAT_S3C64XX)
282/* From Rev1.1 datasheet, we have two master and two slave modes:
283 * IMS[11:10]:
284 * 00 = master mode, fed from PCLK
285 * 01 = master mode, fed from CLKAUDIO
286 * 10 = slave mode, using PCLK
287 * 11 = slave mode, using I2SCLK
288 */
289#define IISMOD_MASTER_MASK (1 << 11)
290#define IISMOD_SLAVE (1 << 11)
291#define IISMOD_MASTER (0 << 11)
292#endif
293
294 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 268 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
295 case SND_SOC_DAIFMT_CBM_CFM: 269 case SND_SOC_DAIFMT_CBM_CFM:
296 i2s->master = 0; 270 i2s->master = 0;
297 iismod &= ~IISMOD_MASTER_MASK; 271 iismod |= S3C2412_IISMOD_SLAVE;
298 iismod |= IISMOD_SLAVE;
299 break; 272 break;
300 case SND_SOC_DAIFMT_CBS_CFS: 273 case SND_SOC_DAIFMT_CBS_CFS:
301 i2s->master = 1; 274 i2s->master = 1;
302 iismod &= ~IISMOD_MASTER_MASK; 275 iismod &= ~S3C2412_IISMOD_SLAVE;
303 iismod |= IISMOD_MASTER;
304 break; 276 break;
305 default: 277 default:
306 pr_err("unknwon master/slave format\n"); 278 pr_err("unknwon master/slave format\n");
@@ -332,7 +304,7 @@ static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
332 return 0; 304 return 0;
333} 305}
334 306
335static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream, 307static int s3c_i2sv2_hw_params(struct snd_pcm_substream *substream,
336 struct snd_pcm_hw_params *params, 308 struct snd_pcm_hw_params *params,
337 struct snd_soc_dai *socdai) 309 struct snd_soc_dai *socdai)
338{ 310{
@@ -355,37 +327,67 @@ static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream,
355 iismod = readl(i2s->regs + S3C2412_IISMOD); 327 iismod = readl(i2s->regs + S3C2412_IISMOD);
356 pr_debug("%s: r: IISMOD: %x\n", __func__, iismod); 328 pr_debug("%s: r: IISMOD: %x\n", __func__, iismod);
357 329
358#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413) 330 iismod &= ~S3C64XX_IISMOD_BLC_MASK;
331 /* Sample size */
359 switch (params_format(params)) { 332 switch (params_format(params)) {
360 case SNDRV_PCM_FORMAT_S8: 333 case SNDRV_PCM_FORMAT_S8:
361 iismod |= S3C2412_IISMOD_8BIT; 334 iismod |= S3C64XX_IISMOD_BLC_8BIT;
362 break; 335 break;
363 case SNDRV_PCM_FORMAT_S16_LE: 336 case SNDRV_PCM_FORMAT_S16_LE:
364 iismod &= ~S3C2412_IISMOD_8BIT; 337 break;
338 case SNDRV_PCM_FORMAT_S24_LE:
339 iismod |= S3C64XX_IISMOD_BLC_24BIT;
365 break; 340 break;
366 } 341 }
367#endif
368 342
369#ifdef CONFIG_PLAT_S3C64XX 343 writel(iismod, i2s->regs + S3C2412_IISMOD);
370 iismod &= ~(S3C64XX_IISMOD_BLC_MASK | S3C2412_IISMOD_BCLK_MASK); 344 pr_debug("%s: w: IISMOD: %x\n", __func__, iismod);
371 /* Sample size */ 345
372 switch (params_format(params)) { 346 return 0;
373 case SNDRV_PCM_FORMAT_S8: 347}
374 /* 8 bit sample, 16fs BCLK */ 348
375 iismod |= (S3C64XX_IISMOD_BLC_8BIT | S3C2412_IISMOD_BCLK_16FS); 349static int s3c_i2sv2_set_sysclk(struct snd_soc_dai *cpu_dai,
350 int clk_id, unsigned int freq, int dir)
351{
352 struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
353 u32 iismod = readl(i2s->regs + S3C2412_IISMOD);
354
355 pr_debug("Entered %s\n", __func__);
356 pr_debug("%s r: IISMOD: %x\n", __func__, iismod);
357
358 switch (clk_id) {
359 case S3C_I2SV2_CLKSRC_PCLK:
360 iismod &= ~S3C2412_IISMOD_IMS_SYSMUX;
376 break; 361 break;
377 case SNDRV_PCM_FORMAT_S16_LE: 362
378 /* 16 bit sample, 32fs BCLK */ 363 case S3C_I2SV2_CLKSRC_AUDIOBUS:
364 iismod |= S3C2412_IISMOD_IMS_SYSMUX;
379 break; 365 break;
380 case SNDRV_PCM_FORMAT_S24_LE: 366
381 /* 24 bit sample, 48fs BCLK */ 367 case S3C_I2SV2_CLKSRC_CDCLK:
382 iismod |= (S3C64XX_IISMOD_BLC_24BIT | S3C2412_IISMOD_BCLK_48FS); 368 /* Error if controller doesn't have the CDCLKCON bit */
369 if (!(i2s->feature & S3C_FEATURE_CDCLKCON))
370 return -EINVAL;
371
372 switch (dir) {
373 case SND_SOC_CLOCK_IN:
374 iismod |= S3C64XX_IISMOD_CDCLKCON;
375 break;
376 case SND_SOC_CLOCK_OUT:
377 iismod &= ~S3C64XX_IISMOD_CDCLKCON;
378 break;
379 default:
380 return -EINVAL;
381 }
383 break; 382 break;
383
384 default:
385 return -EINVAL;
384 } 386 }
385#endif
386 387
387 writel(iismod, i2s->regs + S3C2412_IISMOD); 388 writel(iismod, i2s->regs + S3C2412_IISMOD);
388 pr_debug("%s: w: IISMOD: %x\n", __func__, iismod); 389 pr_debug("%s w: IISMOD: %x\n", __func__, iismod);
390
389 return 0; 391 return 0;
390} 392}
391 393
@@ -472,29 +474,25 @@ static int s3c2412_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai,
472 474
473 switch (div_id) { 475 switch (div_id) {
474 case S3C_I2SV2_DIV_BCLK: 476 case S3C_I2SV2_DIV_BCLK:
475 if (div > 3) { 477 switch (div) {
476 /* convert value to bit field */ 478 case 16:
477 479 div = S3C2412_IISMOD_BCLK_16FS;
478 switch (div) { 480 break;
479 case 16:
480 div = S3C2412_IISMOD_BCLK_16FS;
481 break;
482 481
483 case 32: 482 case 32:
484 div = S3C2412_IISMOD_BCLK_32FS; 483 div = S3C2412_IISMOD_BCLK_32FS;
485 break; 484 break;
486 485
487 case 24: 486 case 24:
488 div = S3C2412_IISMOD_BCLK_24FS; 487 div = S3C2412_IISMOD_BCLK_24FS;
489 break; 488 break;
490 489
491 case 48: 490 case 48:
492 div = S3C2412_IISMOD_BCLK_48FS; 491 div = S3C2412_IISMOD_BCLK_48FS;
493 break; 492 break;
494 493
495 default: 494 default:
496 return -EINVAL; 495 return -EINVAL;
497 }
498 } 496 }
499 497
500 reg = readl(i2s->regs + S3C2412_IISMOD); 498 reg = readl(i2s->regs + S3C2412_IISMOD);
@@ -505,29 +503,25 @@ static int s3c2412_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai,
505 break; 503 break;
506 504
507 case S3C_I2SV2_DIV_RCLK: 505 case S3C_I2SV2_DIV_RCLK:
508 if (div > 3) { 506 switch (div) {
509 /* convert value to bit field */ 507 case 256:
510 508 div = S3C2412_IISMOD_RCLK_256FS;
511 switch (div) { 509 break;
512 case 256:
513 div = S3C2412_IISMOD_RCLK_256FS;
514 break;
515 510
516 case 384: 511 case 384:
517 div = S3C2412_IISMOD_RCLK_384FS; 512 div = S3C2412_IISMOD_RCLK_384FS;
518 break; 513 break;
519 514
520 case 512: 515 case 512:
521 div = S3C2412_IISMOD_RCLK_512FS; 516 div = S3C2412_IISMOD_RCLK_512FS;
522 break; 517 break;
523 518
524 case 768: 519 case 768:
525 div = S3C2412_IISMOD_RCLK_768FS; 520 div = S3C2412_IISMOD_RCLK_768FS;
526 break; 521 break;
527 522
528 default: 523 default:
529 return -EINVAL; 524 return -EINVAL;
530 }
531 } 525 }
532 526
533 reg = readl(i2s->regs + S3C2412_IISMOD); 527 reg = readl(i2s->regs + S3C2412_IISMOD);
@@ -553,6 +547,33 @@ static int s3c2412_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai,
553 return 0; 547 return 0;
554} 548}
555 549
550static snd_pcm_sframes_t s3c2412_i2s_delay(struct snd_pcm_substream *substream,
551 struct snd_soc_dai *dai)
552{
553 struct s3c_i2sv2_info *i2s = to_info(dai);
554 u32 reg = readl(i2s->regs + S3C2412_IISFIC);
555 snd_pcm_sframes_t delay;
556
557 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
558 delay = S3C2412_IISFIC_TXCOUNT(reg);
559 else
560 delay = S3C2412_IISFIC_RXCOUNT(reg);
561
562 return delay;
563}
564
565struct clk *s3c_i2sv2_get_clock(struct snd_soc_dai *cpu_dai)
566{
567 struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
568 u32 iismod = readl(i2s->regs + S3C2412_IISMOD);
569
570 if (iismod & S3C2412_IISMOD_IMS_SYSMUX)
571 return i2s->iis_cclk;
572 else
573 return i2s->iis_pclk;
574}
575EXPORT_SYMBOL_GPL(s3c_i2sv2_get_clock);
576
556/* default table of all avaialable root fs divisors */ 577/* default table of all avaialable root fs divisors */
557static unsigned int iis_fs_tab[] = { 256, 512, 384, 768 }; 578static unsigned int iis_fs_tab[] = { 256, 512, 384, 768 };
558 579
@@ -735,9 +756,15 @@ int s3c_i2sv2_register_dai(struct snd_soc_dai *dai)
735 struct snd_soc_dai_ops *ops = dai->ops; 756 struct snd_soc_dai_ops *ops = dai->ops;
736 757
737 ops->trigger = s3c2412_i2s_trigger; 758 ops->trigger = s3c2412_i2s_trigger;
738 ops->hw_params = s3c2412_i2s_hw_params; 759 if (!ops->hw_params)
760 ops->hw_params = s3c_i2sv2_hw_params;
739 ops->set_fmt = s3c2412_i2s_set_fmt; 761 ops->set_fmt = s3c2412_i2s_set_fmt;
740 ops->set_clkdiv = s3c2412_i2s_set_clkdiv; 762 ops->set_clkdiv = s3c2412_i2s_set_clkdiv;
763 ops->set_sysclk = s3c_i2sv2_set_sysclk;
764
765 /* Allow overriding by (for example) IISv4 */
766 if (!ops->delay)
767 ops->delay = s3c2412_i2s_delay;
741 768
742 dai->suspend = s3c2412_i2s_suspend; 769 dai->suspend = s3c2412_i2s_suspend;
743 dai->resume = s3c2412_i2s_resume; 770 dai->resume = s3c2412_i2s_resume;