diff options
Diffstat (limited to 'sound/soc/s3c24xx/s3c-i2s-v2.c')
-rw-r--r-- | sound/soc/s3c24xx/s3c-i2s-v2.c | 205 |
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 | ||
335 | static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream, | 307 | static 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); | 349 | static 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 | ||
550 | static 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 | |||
565 | struct 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 | } | ||
575 | EXPORT_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 */ |
557 | static unsigned int iis_fs_tab[] = { 256, 512, 384, 768 }; | 578 | static 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; |