diff options
Diffstat (limited to 'sound/soc/codecs/wm8960.c')
-rw-r--r-- | sound/soc/codecs/wm8960.c | 194 |
1 files changed, 72 insertions, 122 deletions
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index d1769e6c0c44..c529ffcfe5d8 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c | |||
@@ -69,61 +69,7 @@ struct wm8960_priv { | |||
69 | struct snd_soc_codec codec; | 69 | struct snd_soc_codec codec; |
70 | }; | 70 | }; |
71 | 71 | ||
72 | /* | 72 | #define wm8960_reset(c) snd_soc_write(c, WM8960_RESET, 0) |
73 | * read wm8960 register cache | ||
74 | */ | ||
75 | static inline unsigned int wm8960_read_reg_cache(struct snd_soc_codec *codec, | ||
76 | unsigned int reg) | ||
77 | { | ||
78 | u16 *cache = codec->reg_cache; | ||
79 | if (reg == WM8960_RESET) | ||
80 | return 0; | ||
81 | if (reg >= WM8960_CACHEREGNUM) | ||
82 | return -1; | ||
83 | return cache[reg]; | ||
84 | } | ||
85 | |||
86 | /* | ||
87 | * write wm8960 register cache | ||
88 | */ | ||
89 | static inline void wm8960_write_reg_cache(struct snd_soc_codec *codec, | ||
90 | u16 reg, unsigned int value) | ||
91 | { | ||
92 | u16 *cache = codec->reg_cache; | ||
93 | if (reg >= WM8960_CACHEREGNUM) | ||
94 | return; | ||
95 | cache[reg] = value; | ||
96 | } | ||
97 | |||
98 | static inline unsigned int wm8960_read(struct snd_soc_codec *codec, | ||
99 | unsigned int reg) | ||
100 | { | ||
101 | return wm8960_read_reg_cache(codec, reg); | ||
102 | } | ||
103 | |||
104 | /* | ||
105 | * write to the WM8960 register space | ||
106 | */ | ||
107 | static int wm8960_write(struct snd_soc_codec *codec, unsigned int reg, | ||
108 | unsigned int value) | ||
109 | { | ||
110 | u8 data[2]; | ||
111 | |||
112 | /* data is | ||
113 | * D15..D9 WM8960 register offset | ||
114 | * D8...D0 register data | ||
115 | */ | ||
116 | data[0] = (reg << 1) | ((value >> 8) & 0x0001); | ||
117 | data[1] = value & 0x00ff; | ||
118 | |||
119 | wm8960_write_reg_cache(codec, reg, value); | ||
120 | if (codec->hw_write(codec->control_data, data, 2) == 2) | ||
121 | return 0; | ||
122 | else | ||
123 | return -EIO; | ||
124 | } | ||
125 | |||
126 | #define wm8960_reset(c) wm8960_write(c, WM8960_RESET, 0) | ||
127 | 73 | ||
128 | /* enumerated controls */ | 74 | /* enumerated controls */ |
129 | static const char *wm8960_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"}; | 75 | static const char *wm8960_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"}; |
@@ -420,7 +366,7 @@ static int wm8960_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
420 | } | 366 | } |
421 | 367 | ||
422 | /* set iface */ | 368 | /* set iface */ |
423 | wm8960_write(codec, WM8960_IFACE1, iface); | 369 | snd_soc_write(codec, WM8960_IFACE1, iface); |
424 | return 0; | 370 | return 0; |
425 | } | 371 | } |
426 | 372 | ||
@@ -431,7 +377,7 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream, | |||
431 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 377 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
432 | struct snd_soc_device *socdev = rtd->socdev; | 378 | struct snd_soc_device *socdev = rtd->socdev; |
433 | struct snd_soc_codec *codec = socdev->card->codec; | 379 | struct snd_soc_codec *codec = socdev->card->codec; |
434 | u16 iface = wm8960_read(codec, WM8960_IFACE1) & 0xfff3; | 380 | u16 iface = snd_soc_read(codec, WM8960_IFACE1) & 0xfff3; |
435 | 381 | ||
436 | /* bit size */ | 382 | /* bit size */ |
437 | switch (params_format(params)) { | 383 | switch (params_format(params)) { |
@@ -446,19 +392,19 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream, | |||
446 | } | 392 | } |
447 | 393 | ||
448 | /* set iface */ | 394 | /* set iface */ |
449 | wm8960_write(codec, WM8960_IFACE1, iface); | 395 | snd_soc_write(codec, WM8960_IFACE1, iface); |
450 | return 0; | 396 | return 0; |
451 | } | 397 | } |
452 | 398 | ||
453 | static int wm8960_mute(struct snd_soc_dai *dai, int mute) | 399 | static int wm8960_mute(struct snd_soc_dai *dai, int mute) |
454 | { | 400 | { |
455 | struct snd_soc_codec *codec = dai->codec; | 401 | struct snd_soc_codec *codec = dai->codec; |
456 | u16 mute_reg = wm8960_read(codec, WM8960_DACCTL1) & 0xfff7; | 402 | u16 mute_reg = snd_soc_read(codec, WM8960_DACCTL1) & 0xfff7; |
457 | 403 | ||
458 | if (mute) | 404 | if (mute) |
459 | wm8960_write(codec, WM8960_DACCTL1, mute_reg | 0x8); | 405 | snd_soc_write(codec, WM8960_DACCTL1, mute_reg | 0x8); |
460 | else | 406 | else |
461 | wm8960_write(codec, WM8960_DACCTL1, mute_reg); | 407 | snd_soc_write(codec, WM8960_DACCTL1, mute_reg); |
462 | return 0; | 408 | return 0; |
463 | } | 409 | } |
464 | 410 | ||
@@ -474,16 +420,16 @@ static int wm8960_set_bias_level(struct snd_soc_codec *codec, | |||
474 | 420 | ||
475 | case SND_SOC_BIAS_PREPARE: | 421 | case SND_SOC_BIAS_PREPARE: |
476 | /* Set VMID to 2x50k */ | 422 | /* Set VMID to 2x50k */ |
477 | reg = wm8960_read(codec, WM8960_POWER1); | 423 | reg = snd_soc_read(codec, WM8960_POWER1); |
478 | reg &= ~0x180; | 424 | reg &= ~0x180; |
479 | reg |= 0x80; | 425 | reg |= 0x80; |
480 | wm8960_write(codec, WM8960_POWER1, reg); | 426 | snd_soc_write(codec, WM8960_POWER1, reg); |
481 | break; | 427 | break; |
482 | 428 | ||
483 | case SND_SOC_BIAS_STANDBY: | 429 | case SND_SOC_BIAS_STANDBY: |
484 | if (codec->bias_level == SND_SOC_BIAS_OFF) { | 430 | if (codec->bias_level == SND_SOC_BIAS_OFF) { |
485 | /* Enable anti-pop features */ | 431 | /* Enable anti-pop features */ |
486 | wm8960_write(codec, WM8960_APOP1, | 432 | snd_soc_write(codec, WM8960_APOP1, |
487 | WM8960_POBCTRL | WM8960_SOFT_ST | | 433 | WM8960_POBCTRL | WM8960_SOFT_ST | |
488 | WM8960_BUFDCOPEN | WM8960_BUFIOEN); | 434 | WM8960_BUFDCOPEN | WM8960_BUFIOEN); |
489 | 435 | ||
@@ -491,43 +437,43 @@ static int wm8960_set_bias_level(struct snd_soc_codec *codec, | |||
491 | reg = WM8960_DISOP; | 437 | reg = WM8960_DISOP; |
492 | if (pdata) | 438 | if (pdata) |
493 | reg |= pdata->dres << 4; | 439 | reg |= pdata->dres << 4; |
494 | wm8960_write(codec, WM8960_APOP2, reg); | 440 | snd_soc_write(codec, WM8960_APOP2, reg); |
495 | 441 | ||
496 | msleep(400); | 442 | msleep(400); |
497 | 443 | ||
498 | wm8960_write(codec, WM8960_APOP2, 0); | 444 | snd_soc_write(codec, WM8960_APOP2, 0); |
499 | 445 | ||
500 | /* Enable & ramp VMID at 2x50k */ | 446 | /* Enable & ramp VMID at 2x50k */ |
501 | reg = wm8960_read(codec, WM8960_POWER1); | 447 | reg = snd_soc_read(codec, WM8960_POWER1); |
502 | reg |= 0x80; | 448 | reg |= 0x80; |
503 | wm8960_write(codec, WM8960_POWER1, reg); | 449 | snd_soc_write(codec, WM8960_POWER1, reg); |
504 | msleep(100); | 450 | msleep(100); |
505 | 451 | ||
506 | /* Enable VREF */ | 452 | /* Enable VREF */ |
507 | wm8960_write(codec, WM8960_POWER1, reg | WM8960_VREF); | 453 | snd_soc_write(codec, WM8960_POWER1, reg | WM8960_VREF); |
508 | 454 | ||
509 | /* Disable anti-pop features */ | 455 | /* Disable anti-pop features */ |
510 | wm8960_write(codec, WM8960_APOP1, WM8960_BUFIOEN); | 456 | snd_soc_write(codec, WM8960_APOP1, WM8960_BUFIOEN); |
511 | } | 457 | } |
512 | 458 | ||
513 | /* Set VMID to 2x250k */ | 459 | /* Set VMID to 2x250k */ |
514 | reg = wm8960_read(codec, WM8960_POWER1); | 460 | reg = snd_soc_read(codec, WM8960_POWER1); |
515 | reg &= ~0x180; | 461 | reg &= ~0x180; |
516 | reg |= 0x100; | 462 | reg |= 0x100; |
517 | wm8960_write(codec, WM8960_POWER1, reg); | 463 | snd_soc_write(codec, WM8960_POWER1, reg); |
518 | break; | 464 | break; |
519 | 465 | ||
520 | case SND_SOC_BIAS_OFF: | 466 | case SND_SOC_BIAS_OFF: |
521 | /* Enable anti-pop features */ | 467 | /* Enable anti-pop features */ |
522 | wm8960_write(codec, WM8960_APOP1, | 468 | snd_soc_write(codec, WM8960_APOP1, |
523 | WM8960_POBCTRL | WM8960_SOFT_ST | | 469 | WM8960_POBCTRL | WM8960_SOFT_ST | |
524 | WM8960_BUFDCOPEN | WM8960_BUFIOEN); | 470 | WM8960_BUFDCOPEN | WM8960_BUFIOEN); |
525 | 471 | ||
526 | /* Disable VMID and VREF, let them discharge */ | 472 | /* Disable VMID and VREF, let them discharge */ |
527 | wm8960_write(codec, WM8960_POWER1, 0); | 473 | snd_soc_write(codec, WM8960_POWER1, 0); |
528 | msleep(600); | 474 | msleep(600); |
529 | 475 | ||
530 | wm8960_write(codec, WM8960_APOP1, 0); | 476 | snd_soc_write(codec, WM8960_APOP1, 0); |
531 | break; | 477 | break; |
532 | } | 478 | } |
533 | 479 | ||
@@ -610,33 +556,33 @@ static int wm8960_set_dai_pll(struct snd_soc_dai *codec_dai, | |||
610 | 556 | ||
611 | /* Disable the PLL: even if we are changing the frequency the | 557 | /* Disable the PLL: even if we are changing the frequency the |
612 | * PLL needs to be disabled while we do so. */ | 558 | * PLL needs to be disabled while we do so. */ |
613 | wm8960_write(codec, WM8960_CLOCK1, | 559 | snd_soc_write(codec, WM8960_CLOCK1, |
614 | wm8960_read(codec, WM8960_CLOCK1) & ~1); | 560 | snd_soc_read(codec, WM8960_CLOCK1) & ~1); |
615 | wm8960_write(codec, WM8960_POWER2, | 561 | snd_soc_write(codec, WM8960_POWER2, |
616 | wm8960_read(codec, WM8960_POWER2) & ~1); | 562 | snd_soc_read(codec, WM8960_POWER2) & ~1); |
617 | 563 | ||
618 | if (!freq_in || !freq_out) | 564 | if (!freq_in || !freq_out) |
619 | return 0; | 565 | return 0; |
620 | 566 | ||
621 | reg = wm8960_read(codec, WM8960_PLL1) & ~0x3f; | 567 | reg = snd_soc_read(codec, WM8960_PLL1) & ~0x3f; |
622 | reg |= pll_div.pre_div << 4; | 568 | reg |= pll_div.pre_div << 4; |
623 | reg |= pll_div.n; | 569 | reg |= pll_div.n; |
624 | 570 | ||
625 | if (pll_div.k) { | 571 | if (pll_div.k) { |
626 | reg |= 0x20; | 572 | reg |= 0x20; |
627 | 573 | ||
628 | wm8960_write(codec, WM8960_PLL2, (pll_div.k >> 18) & 0x3f); | 574 | snd_soc_write(codec, WM8960_PLL2, (pll_div.k >> 18) & 0x3f); |
629 | wm8960_write(codec, WM8960_PLL3, (pll_div.k >> 9) & 0x1ff); | 575 | snd_soc_write(codec, WM8960_PLL3, (pll_div.k >> 9) & 0x1ff); |
630 | wm8960_write(codec, WM8960_PLL4, pll_div.k & 0x1ff); | 576 | snd_soc_write(codec, WM8960_PLL4, pll_div.k & 0x1ff); |
631 | } | 577 | } |
632 | wm8960_write(codec, WM8960_PLL1, reg); | 578 | snd_soc_write(codec, WM8960_PLL1, reg); |
633 | 579 | ||
634 | /* Turn it on */ | 580 | /* Turn it on */ |
635 | wm8960_write(codec, WM8960_POWER2, | 581 | snd_soc_write(codec, WM8960_POWER2, |
636 | wm8960_read(codec, WM8960_POWER2) | 1); | 582 | snd_soc_read(codec, WM8960_POWER2) | 1); |
637 | msleep(250); | 583 | msleep(250); |
638 | wm8960_write(codec, WM8960_CLOCK1, | 584 | snd_soc_write(codec, WM8960_CLOCK1, |
639 | wm8960_read(codec, WM8960_CLOCK1) | 1); | 585 | snd_soc_read(codec, WM8960_CLOCK1) | 1); |
640 | 586 | ||
641 | return 0; | 587 | return 0; |
642 | } | 588 | } |
@@ -649,28 +595,28 @@ static int wm8960_set_dai_clkdiv(struct snd_soc_dai *codec_dai, | |||
649 | 595 | ||
650 | switch (div_id) { | 596 | switch (div_id) { |
651 | case WM8960_SYSCLKSEL: | 597 | case WM8960_SYSCLKSEL: |
652 | reg = wm8960_read(codec, WM8960_CLOCK1) & 0x1fe; | 598 | reg = snd_soc_read(codec, WM8960_CLOCK1) & 0x1fe; |
653 | wm8960_write(codec, WM8960_CLOCK1, reg | div); | 599 | snd_soc_write(codec, WM8960_CLOCK1, reg | div); |
654 | break; | 600 | break; |
655 | case WM8960_SYSCLKDIV: | 601 | case WM8960_SYSCLKDIV: |
656 | reg = wm8960_read(codec, WM8960_CLOCK1) & 0x1f9; | 602 | reg = snd_soc_read(codec, WM8960_CLOCK1) & 0x1f9; |
657 | wm8960_write(codec, WM8960_CLOCK1, reg | div); | 603 | snd_soc_write(codec, WM8960_CLOCK1, reg | div); |
658 | break; | 604 | break; |
659 | case WM8960_DACDIV: | 605 | case WM8960_DACDIV: |
660 | reg = wm8960_read(codec, WM8960_CLOCK1) & 0x1c7; | 606 | reg = snd_soc_read(codec, WM8960_CLOCK1) & 0x1c7; |
661 | wm8960_write(codec, WM8960_CLOCK1, reg | div); | 607 | snd_soc_write(codec, WM8960_CLOCK1, reg | div); |
662 | break; | 608 | break; |
663 | case WM8960_OPCLKDIV: | 609 | case WM8960_OPCLKDIV: |
664 | reg = wm8960_read(codec, WM8960_PLL1) & 0x03f; | 610 | reg = snd_soc_read(codec, WM8960_PLL1) & 0x03f; |
665 | wm8960_write(codec, WM8960_PLL1, reg | div); | 611 | snd_soc_write(codec, WM8960_PLL1, reg | div); |
666 | break; | 612 | break; |
667 | case WM8960_DCLKDIV: | 613 | case WM8960_DCLKDIV: |
668 | reg = wm8960_read(codec, WM8960_CLOCK2) & 0x03f; | 614 | reg = snd_soc_read(codec, WM8960_CLOCK2) & 0x03f; |
669 | wm8960_write(codec, WM8960_CLOCK2, reg | div); | 615 | snd_soc_write(codec, WM8960_CLOCK2, reg | div); |
670 | break; | 616 | break; |
671 | case WM8960_TOCLKSEL: | 617 | case WM8960_TOCLKSEL: |
672 | reg = wm8960_read(codec, WM8960_ADDCTL1) & 0x1fd; | 618 | reg = snd_soc_read(codec, WM8960_ADDCTL1) & 0x1fd; |
673 | wm8960_write(codec, WM8960_ADDCTL1, reg | div); | 619 | snd_soc_write(codec, WM8960_ADDCTL1, reg | div); |
674 | break; | 620 | break; |
675 | default: | 621 | default: |
676 | return -EINVAL; | 622 | return -EINVAL; |
@@ -830,8 +776,6 @@ static int wm8960_register(struct wm8960_priv *wm8960) | |||
830 | codec->private_data = wm8960; | 776 | codec->private_data = wm8960; |
831 | codec->name = "WM8960"; | 777 | codec->name = "WM8960"; |
832 | codec->owner = THIS_MODULE; | 778 | codec->owner = THIS_MODULE; |
833 | codec->read = wm8960_read_reg_cache; | ||
834 | codec->write = wm8960_write; | ||
835 | codec->bias_level = SND_SOC_BIAS_OFF; | 779 | codec->bias_level = SND_SOC_BIAS_OFF; |
836 | codec->set_bias_level = wm8960_set_bias_level; | 780 | codec->set_bias_level = wm8960_set_bias_level; |
837 | codec->dai = &wm8960_dai; | 781 | codec->dai = &wm8960_dai; |
@@ -841,6 +785,12 @@ static int wm8960_register(struct wm8960_priv *wm8960) | |||
841 | 785 | ||
842 | memcpy(codec->reg_cache, wm8960_reg, sizeof(wm8960_reg)); | 786 | memcpy(codec->reg_cache, wm8960_reg, sizeof(wm8960_reg)); |
843 | 787 | ||
788 | ret = snd_soc_codec_set_cache_io(codec, 7, 9); | ||
789 | if (ret < 0) { | ||
790 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | ||
791 | goto err; | ||
792 | } | ||
793 | |||
844 | ret = wm8960_reset(codec); | 794 | ret = wm8960_reset(codec); |
845 | if (ret < 0) { | 795 | if (ret < 0) { |
846 | dev_err(codec->dev, "Failed to issue reset\n"); | 796 | dev_err(codec->dev, "Failed to issue reset\n"); |
@@ -852,26 +802,26 @@ static int wm8960_register(struct wm8960_priv *wm8960) | |||
852 | wm8960_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 802 | wm8960_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
853 | 803 | ||
854 | /* Latch the update bits */ | 804 | /* Latch the update bits */ |
855 | reg = wm8960_read(codec, WM8960_LINVOL); | 805 | reg = snd_soc_read(codec, WM8960_LINVOL); |
856 | wm8960_write(codec, WM8960_LINVOL, reg | 0x100); | 806 | snd_soc_write(codec, WM8960_LINVOL, reg | 0x100); |
857 | reg = wm8960_read(codec, WM8960_RINVOL); | 807 | reg = snd_soc_read(codec, WM8960_RINVOL); |
858 | wm8960_write(codec, WM8960_RINVOL, reg | 0x100); | 808 | snd_soc_write(codec, WM8960_RINVOL, reg | 0x100); |
859 | reg = wm8960_read(codec, WM8960_LADC); | 809 | reg = snd_soc_read(codec, WM8960_LADC); |
860 | wm8960_write(codec, WM8960_LADC, reg | 0x100); | 810 | snd_soc_write(codec, WM8960_LADC, reg | 0x100); |
861 | reg = wm8960_read(codec, WM8960_RADC); | 811 | reg = snd_soc_read(codec, WM8960_RADC); |
862 | wm8960_write(codec, WM8960_RADC, reg | 0x100); | 812 | snd_soc_write(codec, WM8960_RADC, reg | 0x100); |
863 | reg = wm8960_read(codec, WM8960_LDAC); | 813 | reg = snd_soc_read(codec, WM8960_LDAC); |
864 | wm8960_write(codec, WM8960_LDAC, reg | 0x100); | 814 | snd_soc_write(codec, WM8960_LDAC, reg | 0x100); |
865 | reg = wm8960_read(codec, WM8960_RDAC); | 815 | reg = snd_soc_read(codec, WM8960_RDAC); |
866 | wm8960_write(codec, WM8960_RDAC, reg | 0x100); | 816 | snd_soc_write(codec, WM8960_RDAC, reg | 0x100); |
867 | reg = wm8960_read(codec, WM8960_LOUT1); | 817 | reg = snd_soc_read(codec, WM8960_LOUT1); |
868 | wm8960_write(codec, WM8960_LOUT1, reg | 0x100); | 818 | snd_soc_write(codec, WM8960_LOUT1, reg | 0x100); |
869 | reg = wm8960_read(codec, WM8960_ROUT1); | 819 | reg = snd_soc_read(codec, WM8960_ROUT1); |
870 | wm8960_write(codec, WM8960_ROUT1, reg | 0x100); | 820 | snd_soc_write(codec, WM8960_ROUT1, reg | 0x100); |
871 | reg = wm8960_read(codec, WM8960_LOUT2); | 821 | reg = snd_soc_read(codec, WM8960_LOUT2); |
872 | wm8960_write(codec, WM8960_LOUT2, reg | 0x100); | 822 | snd_soc_write(codec, WM8960_LOUT2, reg | 0x100); |
873 | reg = wm8960_read(codec, WM8960_ROUT2); | 823 | reg = snd_soc_read(codec, WM8960_ROUT2); |
874 | wm8960_write(codec, WM8960_ROUT2, reg | 0x100); | 824 | snd_soc_write(codec, WM8960_ROUT2, reg | 0x100); |
875 | 825 | ||
876 | wm8960_codec = codec; | 826 | wm8960_codec = codec; |
877 | 827 | ||