diff options
Diffstat (limited to 'sound/soc')
-rw-r--r-- | sound/soc/codecs/wm8960.c | 107 |
1 files changed, 84 insertions, 23 deletions
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index 804f4116912f..7cb0d07ca8a6 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c | |||
@@ -52,25 +52,72 @@ | |||
52 | * We can't read the WM8960 register space when we are | 52 | * We can't read the WM8960 register space when we are |
53 | * using 2 wire for device control, so we cache them instead. | 53 | * using 2 wire for device control, so we cache them instead. |
54 | */ | 54 | */ |
55 | static const u16 wm8960_reg[WM8960_CACHEREGNUM] = { | 55 | static const struct reg_default wm8960_reg_defaults[] = { |
56 | 0x0097, 0x0097, 0x0000, 0x0000, | 56 | { 0x0, 0x0097 }, |
57 | 0x0000, 0x0008, 0x0000, 0x000a, | 57 | { 0x1, 0x0097 }, |
58 | 0x01c0, 0x0000, 0x00ff, 0x00ff, | 58 | { 0x2, 0x0000 }, |
59 | 0x0000, 0x0000, 0x0000, 0x0000, | 59 | { 0x3, 0x0000 }, |
60 | 0x0000, 0x007b, 0x0100, 0x0032, | 60 | { 0x4, 0x0000 }, |
61 | 0x0000, 0x00c3, 0x00c3, 0x01c0, | 61 | { 0x5, 0x0008 }, |
62 | 0x0000, 0x0000, 0x0000, 0x0000, | 62 | { 0x6, 0x0000 }, |
63 | 0x0000, 0x0000, 0x0000, 0x0000, | 63 | { 0x7, 0x000a }, |
64 | 0x0100, 0x0100, 0x0050, 0x0050, | 64 | { 0x8, 0x01c0 }, |
65 | 0x0050, 0x0050, 0x0000, 0x0000, | 65 | { 0x9, 0x0000 }, |
66 | 0x0000, 0x0000, 0x0040, 0x0000, | 66 | { 0xa, 0x00ff }, |
67 | 0x0000, 0x0050, 0x0050, 0x0000, | 67 | { 0xb, 0x00ff }, |
68 | 0x0002, 0x0037, 0x004d, 0x0080, | 68 | |
69 | 0x0008, 0x0031, 0x0026, 0x00e9, | 69 | { 0x10, 0x0000 }, |
70 | { 0x11, 0x007b }, | ||
71 | { 0x12, 0x0100 }, | ||
72 | { 0x13, 0x0032 }, | ||
73 | { 0x14, 0x0000 }, | ||
74 | { 0x15, 0x00c3 }, | ||
75 | { 0x16, 0x00c3 }, | ||
76 | { 0x17, 0x01c0 }, | ||
77 | { 0x18, 0x0000 }, | ||
78 | { 0x19, 0x0000 }, | ||
79 | { 0x1a, 0x0000 }, | ||
80 | { 0x1b, 0x0000 }, | ||
81 | { 0x1c, 0x0000 }, | ||
82 | { 0x1d, 0x0000 }, | ||
83 | |||
84 | { 0x20, 0x0100 }, | ||
85 | { 0x21, 0x0100 }, | ||
86 | { 0x22, 0x0050 }, | ||
87 | |||
88 | { 0x25, 0x0050 }, | ||
89 | { 0x26, 0x0000 }, | ||
90 | { 0x27, 0x0000 }, | ||
91 | { 0x28, 0x0000 }, | ||
92 | { 0x29, 0x0000 }, | ||
93 | { 0x2a, 0x0040 }, | ||
94 | { 0x2b, 0x0000 }, | ||
95 | { 0x2c, 0x0000 }, | ||
96 | { 0x2d, 0x0050 }, | ||
97 | { 0x2e, 0x0050 }, | ||
98 | { 0x2f, 0x0000 }, | ||
99 | { 0x30, 0x0002 }, | ||
100 | { 0x31, 0x0037 }, | ||
101 | |||
102 | { 0x33, 0x0080 }, | ||
103 | { 0x34, 0x0008 }, | ||
104 | { 0x35, 0x0031 }, | ||
105 | { 0x36, 0x0026 }, | ||
106 | { 0x37, 0x00e9 }, | ||
70 | }; | 107 | }; |
71 | 108 | ||
109 | static bool wm8960_volatile(struct device *dev, unsigned int reg) | ||
110 | { | ||
111 | switch (reg) { | ||
112 | case WM8960_RESET: | ||
113 | return true; | ||
114 | default: | ||
115 | return false; | ||
116 | } | ||
117 | } | ||
118 | |||
72 | struct wm8960_priv { | 119 | struct wm8960_priv { |
73 | enum snd_soc_control_type control_type; | 120 | struct regmap *regmap; |
74 | int (*set_bias_level)(struct snd_soc_codec *, | 121 | int (*set_bias_level)(struct snd_soc_codec *, |
75 | enum snd_soc_bias_level level); | 122 | enum snd_soc_bias_level level); |
76 | struct snd_soc_dapm_widget *lout1; | 123 | struct snd_soc_dapm_widget *lout1; |
@@ -555,6 +602,8 @@ static int wm8960_mute(struct snd_soc_dai *dai, int mute) | |||
555 | static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec, | 602 | static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec, |
556 | enum snd_soc_bias_level level) | 603 | enum snd_soc_bias_level level) |
557 | { | 604 | { |
605 | struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); | ||
606 | |||
558 | switch (level) { | 607 | switch (level) { |
559 | case SND_SOC_BIAS_ON: | 608 | case SND_SOC_BIAS_ON: |
560 | break; | 609 | break; |
@@ -566,7 +615,7 @@ static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec, | |||
566 | 615 | ||
567 | case SND_SOC_BIAS_STANDBY: | 616 | case SND_SOC_BIAS_STANDBY: |
568 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 617 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { |
569 | snd_soc_cache_sync(codec); | 618 | regcache_sync(wm8960->regmap); |
570 | 619 | ||
571 | /* Enable anti-pop features */ | 620 | /* Enable anti-pop features */ |
572 | snd_soc_write(codec, WM8960_APOP1, | 621 | snd_soc_write(codec, WM8960_APOP1, |
@@ -667,7 +716,7 @@ static int wm8960_set_bias_level_capless(struct snd_soc_codec *codec, | |||
667 | break; | 716 | break; |
668 | 717 | ||
669 | case SND_SOC_BIAS_OFF: | 718 | case SND_SOC_BIAS_OFF: |
670 | snd_soc_cache_sync(codec); | 719 | regcache_sync(wm8960->regmap); |
671 | break; | 720 | break; |
672 | default: | 721 | default: |
673 | break; | 722 | break; |
@@ -915,7 +964,7 @@ static int wm8960_probe(struct snd_soc_codec *codec) | |||
915 | wm8960->set_bias_level = wm8960_set_bias_level_capless; | 964 | wm8960->set_bias_level = wm8960_set_bias_level_capless; |
916 | } | 965 | } |
917 | 966 | ||
918 | ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8960->control_type); | 967 | ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP); |
919 | if (ret < 0) { | 968 | if (ret < 0) { |
920 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | 969 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); |
921 | return ret; | 970 | return ret; |
@@ -963,9 +1012,18 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8960 = { | |||
963 | .suspend = wm8960_suspend, | 1012 | .suspend = wm8960_suspend, |
964 | .resume = wm8960_resume, | 1013 | .resume = wm8960_resume, |
965 | .set_bias_level = wm8960_set_bias_level, | 1014 | .set_bias_level = wm8960_set_bias_level, |
966 | .reg_cache_size = ARRAY_SIZE(wm8960_reg), | 1015 | }; |
967 | .reg_word_size = sizeof(u16), | 1016 | |
968 | .reg_cache_default = wm8960_reg, | 1017 | static const struct regmap_config wm8960_regmap = { |
1018 | .reg_bits = 7, | ||
1019 | .val_bits = 9, | ||
1020 | .max_register = WM8960_PLL4, | ||
1021 | |||
1022 | .reg_defaults = wm8960_reg_defaults, | ||
1023 | .num_reg_defaults = ARRAY_SIZE(wm8960_reg_defaults), | ||
1024 | .cache_type = REGCACHE_RBTREE, | ||
1025 | |||
1026 | .volatile_reg = wm8960_volatile, | ||
969 | }; | 1027 | }; |
970 | 1028 | ||
971 | static __devinit int wm8960_i2c_probe(struct i2c_client *i2c, | 1029 | static __devinit int wm8960_i2c_probe(struct i2c_client *i2c, |
@@ -979,8 +1037,11 @@ static __devinit int wm8960_i2c_probe(struct i2c_client *i2c, | |||
979 | if (wm8960 == NULL) | 1037 | if (wm8960 == NULL) |
980 | return -ENOMEM; | 1038 | return -ENOMEM; |
981 | 1039 | ||
1040 | wm8960->regmap = regmap_init_i2c(i2c, &wm8960_regmap); | ||
1041 | if (IS_ERR(wm8960->regmap)) | ||
1042 | return PTR_ERR(wm8960->regmap); | ||
1043 | |||
982 | i2c_set_clientdata(i2c, wm8960); | 1044 | i2c_set_clientdata(i2c, wm8960); |
983 | wm8960->control_type = SND_SOC_I2C; | ||
984 | 1045 | ||
985 | ret = snd_soc_register_codec(&i2c->dev, | 1046 | ret = snd_soc_register_codec(&i2c->dev, |
986 | &soc_codec_dev_wm8960, &wm8960_dai, 1); | 1047 | &soc_codec_dev_wm8960, &wm8960_dai, 1); |