diff options
| -rw-r--r-- | sound/soc/codecs/Kconfig | 1 | ||||
| -rw-r--r-- | sound/soc/codecs/wm9712.c | 143 |
2 files changed, 79 insertions, 65 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index c67667bb970f..f472254a575d 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig | |||
| @@ -1057,6 +1057,7 @@ config SND_SOC_WM9705 | |||
| 1057 | 1057 | ||
| 1058 | config SND_SOC_WM9712 | 1058 | config SND_SOC_WM9712 |
| 1059 | tristate | 1059 | tristate |
| 1060 | select REGMAP_AC97 | ||
| 1060 | 1061 | ||
| 1061 | config SND_SOC_WM9713 | 1062 | config SND_SOC_WM9713 |
| 1062 | tristate | 1063 | tristate |
diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index 557709eac698..d2d0d2bb4412 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
| 16 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
| 17 | #include <linux/device.h> | 17 | #include <linux/device.h> |
| 18 | #include <linux/regmap.h> | ||
| 18 | #include <sound/core.h> | 19 | #include <sound/core.h> |
| 19 | #include <sound/pcm.h> | 20 | #include <sound/pcm.h> |
| 20 | #include <sound/ac97_codec.h> | 21 | #include <sound/ac97_codec.h> |
| @@ -32,31 +33,66 @@ struct wm9712_priv { | |||
| 32 | struct mutex lock; | 33 | struct mutex lock; |
| 33 | }; | 34 | }; |
| 34 | 35 | ||
| 35 | static unsigned int ac97_read(struct snd_soc_codec *codec, | 36 | static const struct reg_default wm9712_reg_defaults[] = { |
| 36 | unsigned int reg); | 37 | { 0x02, 0x8000 }, |
| 37 | static int ac97_write(struct snd_soc_codec *codec, | 38 | { 0x04, 0x8000 }, |
| 38 | unsigned int reg, unsigned int val); | 39 | { 0x06, 0x8000 }, |
| 40 | { 0x08, 0x0f0f }, | ||
| 41 | { 0x0a, 0xaaa0 }, | ||
| 42 | { 0x0c, 0xc008 }, | ||
| 43 | { 0x0e, 0x6808 }, | ||
| 44 | { 0x10, 0xe808 }, | ||
| 45 | { 0x12, 0xaaa0 }, | ||
| 46 | { 0x14, 0xad00 }, | ||
| 47 | { 0x16, 0x8000 }, | ||
| 48 | { 0x18, 0xe808 }, | ||
| 49 | { 0x1a, 0x3000 }, | ||
| 50 | { 0x1c, 0x8000 }, | ||
| 51 | { 0x20, 0x0000 }, | ||
| 52 | { 0x22, 0x0000 }, | ||
| 53 | { 0x26, 0x000f }, | ||
| 54 | { 0x28, 0x0605 }, | ||
| 55 | { 0x2a, 0x0410 }, | ||
| 56 | { 0x2c, 0xbb80 }, | ||
| 57 | { 0x2e, 0xbb80 }, | ||
| 58 | { 0x32, 0xbb80 }, | ||
| 59 | { 0x34, 0x2000 }, | ||
| 60 | { 0x4c, 0xf83e }, | ||
| 61 | { 0x4e, 0xffff }, | ||
| 62 | { 0x50, 0x0000 }, | ||
| 63 | { 0x52, 0x0000 }, | ||
| 64 | { 0x56, 0xf83e }, | ||
| 65 | { 0x58, 0x0008 }, | ||
| 66 | { 0x5c, 0x0000 }, | ||
| 67 | { 0x60, 0xb032 }, | ||
| 68 | { 0x62, 0x3e00 }, | ||
| 69 | { 0x64, 0x0000 }, | ||
| 70 | { 0x76, 0x0006 }, | ||
| 71 | { 0x78, 0x0001 }, | ||
| 72 | { 0x7a, 0x0000 }, | ||
| 73 | }; | ||
| 39 | 74 | ||
| 40 | /* | 75 | static bool wm9712_volatile_reg(struct device *dev, unsigned int reg) |
| 41 | * WM9712 register cache | 76 | { |
| 42 | */ | 77 | switch (reg) { |
| 43 | static const u16 wm9712_reg[] = { | 78 | case AC97_REC_GAIN: |
| 44 | 0x6174, 0x8000, 0x8000, 0x8000, /* 6 */ | 79 | return true; |
| 45 | 0x0f0f, 0xaaa0, 0xc008, 0x6808, /* e */ | 80 | default: |
| 46 | 0xe808, 0xaaa0, 0xad00, 0x8000, /* 16 */ | 81 | return regmap_ac97_default_volatile(dev, reg); |
| 47 | 0xe808, 0x3000, 0x8000, 0x0000, /* 1e */ | 82 | } |
| 48 | 0x0000, 0x0000, 0x0000, 0x000f, /* 26 */ | 83 | } |
| 49 | 0x0405, 0x0410, 0xbb80, 0xbb80, /* 2e */ | 84 | |
| 50 | 0x0000, 0xbb80, 0x0000, 0x0000, /* 36 */ | 85 | static const struct regmap_config wm9712_regmap_config = { |
| 51 | 0x0000, 0x2000, 0x0000, 0x0000, /* 3e */ | 86 | .reg_bits = 16, |
| 52 | 0x0000, 0x0000, 0x0000, 0x0000, /* 46 */ | 87 | .reg_stride = 2, |
| 53 | 0x0000, 0x0000, 0xf83e, 0xffff, /* 4e */ | 88 | .val_bits = 16, |
| 54 | 0x0000, 0x0000, 0x0000, 0xf83e, /* 56 */ | 89 | .max_register = 0x7e, |
| 55 | 0x0008, 0x0000, 0x0000, 0x0000, /* 5e */ | 90 | .cache_type = REGCACHE_RBTREE, |
| 56 | 0xb032, 0x3e00, 0x0000, 0x0000, /* 66 */ | 91 | |
| 57 | 0x0000, 0x0000, 0x0000, 0x0000, /* 6e */ | 92 | .volatile_reg = wm9712_volatile_reg, |
| 58 | 0x0000, 0x0000, 0x0000, 0x0006, /* 76 */ | 93 | |
| 59 | 0x0001, 0x0000, 0x574d, 0x4c12, /* 7e */ | 94 | .reg_defaults = wm9712_reg_defaults, |
| 95 | .num_reg_defaults = ARRAY_SIZE(wm9712_reg_defaults), | ||
| 60 | }; | 96 | }; |
| 61 | 97 | ||
| 62 | #define HPL_MIXER 0x0 | 98 | #define HPL_MIXER 0x0 |
| @@ -488,35 +524,13 @@ static const struct snd_soc_dapm_route wm9712_audio_map[] = { | |||
| 488 | static unsigned int ac97_read(struct snd_soc_codec *codec, | 524 | static unsigned int ac97_read(struct snd_soc_codec *codec, |
| 489 | unsigned int reg) | 525 | unsigned int reg) |
| 490 | { | 526 | { |
| 491 | struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec); | 527 | return snd_soc_read(codec, reg); |
| 492 | u16 *cache = codec->reg_cache; | ||
| 493 | |||
| 494 | if (reg == AC97_RESET || reg == AC97_GPIO_STATUS || | ||
| 495 | reg == AC97_VENDOR_ID1 || reg == AC97_VENDOR_ID2 || | ||
| 496 | reg == AC97_REC_GAIN) | ||
| 497 | return soc_ac97_ops->read(wm9712->ac97, reg); | ||
| 498 | else { | ||
| 499 | reg = reg >> 1; | ||
| 500 | |||
| 501 | if (reg >= (ARRAY_SIZE(wm9712_reg))) | ||
| 502 | return -EIO; | ||
| 503 | |||
| 504 | return cache[reg]; | ||
| 505 | } | ||
| 506 | } | 528 | } |
| 507 | 529 | ||
| 508 | static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, | 530 | static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, |
| 509 | unsigned int val) | 531 | unsigned int val) |
| 510 | { | 532 | { |
| 511 | struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec); | 533 | return snd_soc_write(codec, reg, val); |
| 512 | u16 *cache = codec->reg_cache; | ||
| 513 | |||
| 514 | soc_ac97_ops->write(wm9712->ac97, reg, val); | ||
| 515 | reg = reg >> 1; | ||
| 516 | if (reg < (ARRAY_SIZE(wm9712_reg))) | ||
| 517 | cache[reg] = val; | ||
| 518 | |||
| 519 | return 0; | ||
| 520 | } | 534 | } |
| 521 | 535 | ||
| 522 | static int ac97_prepare(struct snd_pcm_substream *substream, | 536 | static int ac97_prepare(struct snd_pcm_substream *substream, |
| @@ -619,8 +633,7 @@ static int wm9712_set_bias_level(struct snd_soc_codec *codec, | |||
| 619 | static int wm9712_soc_resume(struct snd_soc_codec *codec) | 633 | static int wm9712_soc_resume(struct snd_soc_codec *codec) |
| 620 | { | 634 | { |
| 621 | struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec); | 635 | struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec); |
| 622 | int i, ret; | 636 | int ret; |
| 623 | u16 *cache = codec->reg_cache; | ||
| 624 | 637 | ||
| 625 | ret = snd_ac97_reset(wm9712->ac97, true, WM9712_VENDOR_ID, | 638 | ret = snd_ac97_reset(wm9712->ac97, true, WM9712_VENDOR_ID, |
| 626 | WM9712_VENDOR_ID_MASK); | 639 | WM9712_VENDOR_ID_MASK); |
| @@ -629,15 +642,8 @@ static int wm9712_soc_resume(struct snd_soc_codec *codec) | |||
| 629 | 642 | ||
| 630 | snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY); | 643 | snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY); |
| 631 | 644 | ||
| 632 | if (ret == 0) { | 645 | if (ret == 0) |
| 633 | /* Sync reg_cache with the hardware after cold reset */ | 646 | regcache_sync(codec->component.regmap); |
| 634 | for (i = 2; i < ARRAY_SIZE(wm9712_reg) << 1; i += 2) { | ||
| 635 | if (i == AC97_INT_PAGING || i == AC97_POWERDOWN || | ||
| 636 | (i > 0x58 && i != 0x5c)) | ||
| 637 | continue; | ||
| 638 | soc_ac97_ops->write(wm9712->ac97, i, cache[i>>1]); | ||
| 639 | } | ||
| 640 | } | ||
| 641 | 647 | ||
| 642 | return ret; | 648 | return ret; |
| 643 | } | 649 | } |
| @@ -645,6 +651,7 @@ static int wm9712_soc_resume(struct snd_soc_codec *codec) | |||
| 645 | static int wm9712_soc_probe(struct snd_soc_codec *codec) | 651 | static int wm9712_soc_probe(struct snd_soc_codec *codec) |
| 646 | { | 652 | { |
| 647 | struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec); | 653 | struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec); |
| 654 | struct regmap *regmap; | ||
| 648 | int ret; | 655 | int ret; |
| 649 | 656 | ||
| 650 | wm9712->ac97 = snd_soc_new_ac97_codec(codec, WM9712_VENDOR_ID, | 657 | wm9712->ac97 = snd_soc_new_ac97_codec(codec, WM9712_VENDOR_ID, |
| @@ -655,16 +662,28 @@ static int wm9712_soc_probe(struct snd_soc_codec *codec) | |||
| 655 | return ret; | 662 | return ret; |
| 656 | } | 663 | } |
| 657 | 664 | ||
| 665 | regmap = regmap_init_ac97(wm9712->ac97, &wm9712_regmap_config); | ||
| 666 | if (IS_ERR(regmap)) { | ||
| 667 | ret = PTR_ERR(regmap); | ||
| 668 | goto err_free_ac97_codec; | ||
| 669 | } | ||
| 670 | |||
| 671 | snd_soc_codec_init_regmap(codec, regmap); | ||
| 672 | |||
| 658 | /* set alc mux to none */ | 673 | /* set alc mux to none */ |
| 659 | ac97_write(codec, AC97_VIDEO, ac97_read(codec, AC97_VIDEO) | 0x3000); | 674 | ac97_write(codec, AC97_VIDEO, ac97_read(codec, AC97_VIDEO) | 0x3000); |
| 660 | 675 | ||
| 661 | return 0; | 676 | return 0; |
| 677 | err_free_ac97_codec: | ||
| 678 | snd_soc_free_ac97_codec(wm9712->ac97); | ||
| 679 | return ret; | ||
| 662 | } | 680 | } |
| 663 | 681 | ||
| 664 | static int wm9712_soc_remove(struct snd_soc_codec *codec) | 682 | static int wm9712_soc_remove(struct snd_soc_codec *codec) |
| 665 | { | 683 | { |
| 666 | struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec); | 684 | struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec); |
| 667 | 685 | ||
| 686 | snd_soc_codec_exit_regmap(codec); | ||
| 668 | snd_soc_free_ac97_codec(wm9712->ac97); | 687 | snd_soc_free_ac97_codec(wm9712->ac97); |
| 669 | return 0; | 688 | return 0; |
| 670 | } | 689 | } |
| @@ -673,14 +692,8 @@ static const struct snd_soc_codec_driver soc_codec_dev_wm9712 = { | |||
| 673 | .probe = wm9712_soc_probe, | 692 | .probe = wm9712_soc_probe, |
| 674 | .remove = wm9712_soc_remove, | 693 | .remove = wm9712_soc_remove, |
| 675 | .resume = wm9712_soc_resume, | 694 | .resume = wm9712_soc_resume, |
| 676 | .read = ac97_read, | ||
| 677 | .write = ac97_write, | ||
| 678 | .set_bias_level = wm9712_set_bias_level, | 695 | .set_bias_level = wm9712_set_bias_level, |
| 679 | .suspend_bias_off = true, | 696 | .suspend_bias_off = true, |
| 680 | .reg_cache_size = ARRAY_SIZE(wm9712_reg), | ||
| 681 | .reg_word_size = sizeof(u16), | ||
| 682 | .reg_cache_step = 2, | ||
| 683 | .reg_cache_default = wm9712_reg, | ||
| 684 | 697 | ||
| 685 | .component_driver = { | 698 | .component_driver = { |
| 686 | .controls = wm9712_snd_ac97_controls, | 699 | .controls = wm9712_snd_ac97_controls, |
