diff options
Diffstat (limited to 'sound/soc/codecs')
-rw-r--r-- | sound/soc/codecs/Kconfig | 22 | ||||
-rw-r--r-- | sound/soc/codecs/Makefile | 8 | ||||
-rw-r--r-- | sound/soc/codecs/ac97.c | 31 | ||||
-rw-r--r-- | sound/soc/codecs/ac97.h | 2 | ||||
-rw-r--r-- | sound/soc/codecs/ak4535.c | 696 | ||||
-rw-r--r-- | sound/soc/codecs/ak4535.h | 46 | ||||
-rw-r--r-- | sound/soc/codecs/cs4270.c | 8 | ||||
-rw-r--r-- | sound/soc/codecs/cs4270.h | 2 | ||||
-rw-r--r-- | sound/soc/codecs/tlv320aic3x.c | 384 | ||||
-rw-r--r-- | sound/soc/codecs/tlv320aic3x.h | 55 | ||||
-rw-r--r-- | sound/soc/codecs/uda1380.c | 852 | ||||
-rw-r--r-- | sound/soc/codecs/uda1380.h | 89 | ||||
-rw-r--r-- | sound/soc/codecs/wm8510.c | 817 | ||||
-rw-r--r-- | sound/soc/codecs/wm8510.h | 103 | ||||
-rw-r--r-- | sound/soc/codecs/wm8731.c | 79 | ||||
-rw-r--r-- | sound/soc/codecs/wm8731.h | 2 | ||||
-rw-r--r-- | sound/soc/codecs/wm8750.c | 87 | ||||
-rw-r--r-- | sound/soc/codecs/wm8750.h | 2 | ||||
-rw-r--r-- | sound/soc/codecs/wm8753.c | 183 | ||||
-rw-r--r-- | sound/soc/codecs/wm8753.h | 2 | ||||
-rw-r--r-- | sound/soc/codecs/wm8990.c | 1626 | ||||
-rw-r--r-- | sound/soc/codecs/wm8990.h | 832 | ||||
-rw-r--r-- | sound/soc/codecs/wm9712.c | 53 | ||||
-rw-r--r-- | sound/soc/codecs/wm9712.h | 2 | ||||
-rw-r--r-- | sound/soc/codecs/wm9713.c | 79 | ||||
-rw-r--r-- | sound/soc/codecs/wm9713.h | 2 |
26 files changed, 5596 insertions, 468 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 3903ab7dfa4a..1db04a28a53d 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig | |||
@@ -1,31 +1,37 @@ | |||
1 | config SND_SOC_AC97_CODEC | 1 | config SND_SOC_AC97_CODEC |
2 | tristate | 2 | tristate |
3 | depends on SND_SOC | 3 | select SND_AC97_CODEC |
4 | |||
5 | config SND_SOC_AK4535 | ||
6 | tristate | ||
7 | |||
8 | config SND_SOC_UDA1380 | ||
9 | tristate | ||
10 | |||
11 | config SND_SOC_WM8510 | ||
12 | tristate | ||
4 | 13 | ||
5 | config SND_SOC_WM8731 | 14 | config SND_SOC_WM8731 |
6 | tristate | 15 | tristate |
7 | depends on SND_SOC | ||
8 | 16 | ||
9 | config SND_SOC_WM8750 | 17 | config SND_SOC_WM8750 |
10 | tristate | 18 | tristate |
11 | depends on SND_SOC | ||
12 | 19 | ||
13 | config SND_SOC_WM8753 | 20 | config SND_SOC_WM8753 |
14 | tristate | 21 | tristate |
15 | depends on SND_SOC | 22 | |
23 | config SND_SOC_WM8990 | ||
24 | tristate | ||
16 | 25 | ||
17 | config SND_SOC_WM9712 | 26 | config SND_SOC_WM9712 |
18 | tristate | 27 | tristate |
19 | depends on SND_SOC | ||
20 | 28 | ||
21 | config SND_SOC_WM9713 | 29 | config SND_SOC_WM9713 |
22 | tristate | 30 | tristate |
23 | depends on SND_SOC | ||
24 | 31 | ||
25 | # Cirrus Logic CS4270 Codec | 32 | # Cirrus Logic CS4270 Codec |
26 | config SND_SOC_CS4270 | 33 | config SND_SOC_CS4270 |
27 | tristate | 34 | tristate |
28 | depends on SND_SOC | ||
29 | 35 | ||
30 | # Cirrus Logic CS4270 Codec Hardware Mute Support | 36 | # Cirrus Logic CS4270 Codec Hardware Mute Support |
31 | # Select if you have external muting circuitry attached to your CS4270. | 37 | # Select if you have external muting circuitry attached to your CS4270. |
@@ -43,4 +49,4 @@ config SND_SOC_CS4270_VD33_ERRATA | |||
43 | 49 | ||
44 | config SND_SOC_TLV320AIC3X | 50 | config SND_SOC_TLV320AIC3X |
45 | tristate | 51 | tristate |
46 | depends on SND_SOC && I2C | 52 | depends on I2C |
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 4e1314c9d3ec..d7b97abcf729 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile | |||
@@ -1,16 +1,24 @@ | |||
1 | snd-soc-ac97-objs := ac97.o | 1 | snd-soc-ac97-objs := ac97.o |
2 | snd-soc-ak4535-objs := ak4535.o | ||
3 | snd-soc-uda1380-objs := uda1380.o | ||
4 | snd-soc-wm8510-objs := wm8510.o | ||
2 | snd-soc-wm8731-objs := wm8731.o | 5 | snd-soc-wm8731-objs := wm8731.o |
3 | snd-soc-wm8750-objs := wm8750.o | 6 | snd-soc-wm8750-objs := wm8750.o |
4 | snd-soc-wm8753-objs := wm8753.o | 7 | snd-soc-wm8753-objs := wm8753.o |
8 | snd-soc-wm8990-objs := wm8990.o | ||
5 | snd-soc-wm9712-objs := wm9712.o | 9 | snd-soc-wm9712-objs := wm9712.o |
6 | snd-soc-wm9713-objs := wm9713.o | 10 | snd-soc-wm9713-objs := wm9713.o |
7 | snd-soc-cs4270-objs := cs4270.o | 11 | snd-soc-cs4270-objs := cs4270.o |
8 | snd-soc-tlv320aic3x-objs := tlv320aic3x.o | 12 | snd-soc-tlv320aic3x-objs := tlv320aic3x.o |
9 | 13 | ||
10 | obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o | 14 | obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o |
15 | obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o | ||
16 | obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o | ||
17 | obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o | ||
11 | obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o | 18 | obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o |
12 | obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o | 19 | obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o |
13 | obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o | 20 | obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o |
21 | obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o | ||
14 | obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o | 22 | obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o |
15 | obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o | 23 | obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o |
16 | obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o | 24 | obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o |
diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c index 2a1ffe396908..61fd96ca7bc7 100644 --- a/sound/soc/codecs/ac97.c +++ b/sound/soc/codecs/ac97.c | |||
@@ -10,9 +10,6 @@ | |||
10 | * Free Software Foundation; either version 2 of the License, or (at your | 10 | * Free Software Foundation; either version 2 of the License, or (at your |
11 | * option) any later version. | 11 | * option) any later version. |
12 | * | 12 | * |
13 | * Revision history | ||
14 | * 17th Oct 2005 Initial version. | ||
15 | * | ||
16 | * Generic AC97 support. | 13 | * Generic AC97 support. |
17 | */ | 14 | */ |
18 | 15 | ||
@@ -24,6 +21,7 @@ | |||
24 | #include <sound/ac97_codec.h> | 21 | #include <sound/ac97_codec.h> |
25 | #include <sound/initval.h> | 22 | #include <sound/initval.h> |
26 | #include <sound/soc.h> | 23 | #include <sound/soc.h> |
24 | #include "ac97.h" | ||
27 | 25 | ||
28 | #define AC97_VERSION "0.6" | 26 | #define AC97_VERSION "0.6" |
29 | 27 | ||
@@ -43,7 +41,7 @@ static int ac97_prepare(struct snd_pcm_substream *substream) | |||
43 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 |\ | 41 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 |\ |
44 | SNDRV_PCM_RATE_48000) | 42 | SNDRV_PCM_RATE_48000) |
45 | 43 | ||
46 | struct snd_soc_codec_dai ac97_dai = { | 44 | struct snd_soc_dai ac97_dai = { |
47 | .name = "AC97 HiFi", | 45 | .name = "AC97 HiFi", |
48 | .type = SND_SOC_DAI_AC97, | 46 | .type = SND_SOC_DAI_AC97, |
49 | .playback = { | 47 | .playback = { |
@@ -146,9 +144,34 @@ static int ac97_soc_remove(struct platform_device *pdev) | |||
146 | return 0; | 144 | return 0; |
147 | } | 145 | } |
148 | 146 | ||
147 | #ifdef CONFIG_PM | ||
148 | static int ac97_soc_suspend(struct platform_device *pdev, pm_message_t msg) | ||
149 | { | ||
150 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
151 | |||
152 | snd_ac97_suspend(socdev->codec->ac97); | ||
153 | |||
154 | return 0; | ||
155 | } | ||
156 | |||
157 | static int ac97_soc_resume(struct platform_device *pdev) | ||
158 | { | ||
159 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
160 | |||
161 | snd_ac97_resume(socdev->codec->ac97); | ||
162 | |||
163 | return 0; | ||
164 | } | ||
165 | #else | ||
166 | #define ac97_soc_suspend NULL | ||
167 | #define ac97_soc_resume NULL | ||
168 | #endif | ||
169 | |||
149 | struct snd_soc_codec_device soc_codec_dev_ac97 = { | 170 | struct snd_soc_codec_device soc_codec_dev_ac97 = { |
150 | .probe = ac97_soc_probe, | 171 | .probe = ac97_soc_probe, |
151 | .remove = ac97_soc_remove, | 172 | .remove = ac97_soc_remove, |
173 | .suspend = ac97_soc_suspend, | ||
174 | .resume = ac97_soc_resume, | ||
152 | }; | 175 | }; |
153 | EXPORT_SYMBOL_GPL(soc_codec_dev_ac97); | 176 | EXPORT_SYMBOL_GPL(soc_codec_dev_ac97); |
154 | 177 | ||
diff --git a/sound/soc/codecs/ac97.h b/sound/soc/codecs/ac97.h index 2bf6d69fd069..281aa42e2bbb 100644 --- a/sound/soc/codecs/ac97.h +++ b/sound/soc/codecs/ac97.h | |||
@@ -14,6 +14,6 @@ | |||
14 | #define __LINUX_SND_SOC_AC97_H | 14 | #define __LINUX_SND_SOC_AC97_H |
15 | 15 | ||
16 | extern struct snd_soc_codec_device soc_codec_dev_ac97; | 16 | extern struct snd_soc_codec_device soc_codec_dev_ac97; |
17 | extern struct snd_soc_codec_dai ac97_dai; | 17 | extern struct snd_soc_dai ac97_dai; |
18 | 18 | ||
19 | #endif | 19 | #endif |
diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c new file mode 100644 index 000000000000..b26003c4f3e8 --- /dev/null +++ b/sound/soc/codecs/ak4535.c | |||
@@ -0,0 +1,696 @@ | |||
1 | /* | ||
2 | * ak4535.c -- AK4535 ALSA Soc Audio driver | ||
3 | * | ||
4 | * Copyright 2005 Openedhand Ltd. | ||
5 | * | ||
6 | * Author: Richard Purdie <richard@openedhand.com> | ||
7 | * | ||
8 | * Based on wm8753.c by Liam Girdwood | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #include <linux/module.h> | ||
16 | #include <linux/moduleparam.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/delay.h> | ||
19 | #include <linux/pm.h> | ||
20 | #include <linux/i2c.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | #include <sound/core.h> | ||
23 | #include <sound/pcm.h> | ||
24 | #include <sound/pcm_params.h> | ||
25 | #include <sound/soc.h> | ||
26 | #include <sound/soc-dapm.h> | ||
27 | #include <sound/initval.h> | ||
28 | |||
29 | #include "ak4535.h" | ||
30 | |||
31 | #define AUDIO_NAME "ak4535" | ||
32 | #define AK4535_VERSION "0.3" | ||
33 | |||
34 | struct snd_soc_codec_device soc_codec_dev_ak4535; | ||
35 | |||
36 | /* codec private data */ | ||
37 | struct ak4535_priv { | ||
38 | unsigned int sysclk; | ||
39 | }; | ||
40 | |||
41 | /* | ||
42 | * ak4535 register cache | ||
43 | */ | ||
44 | static const u16 ak4535_reg[AK4535_CACHEREGNUM] = { | ||
45 | 0x0000, 0x0080, 0x0000, 0x0003, | ||
46 | 0x0002, 0x0000, 0x0011, 0x0001, | ||
47 | 0x0000, 0x0040, 0x0036, 0x0010, | ||
48 | 0x0000, 0x0000, 0x0057, 0x0000, | ||
49 | }; | ||
50 | |||
51 | /* | ||
52 | * read ak4535 register cache | ||
53 | */ | ||
54 | static inline unsigned int ak4535_read_reg_cache(struct snd_soc_codec *codec, | ||
55 | unsigned int reg) | ||
56 | { | ||
57 | u16 *cache = codec->reg_cache; | ||
58 | if (reg >= AK4535_CACHEREGNUM) | ||
59 | return -1; | ||
60 | return cache[reg]; | ||
61 | } | ||
62 | |||
63 | static inline unsigned int ak4535_read(struct snd_soc_codec *codec, | ||
64 | unsigned int reg) | ||
65 | { | ||
66 | u8 data; | ||
67 | data = reg; | ||
68 | |||
69 | if (codec->hw_write(codec->control_data, &data, 1) != 1) | ||
70 | return -EIO; | ||
71 | |||
72 | if (codec->hw_read(codec->control_data, &data, 1) != 1) | ||
73 | return -EIO; | ||
74 | |||
75 | return data; | ||
76 | }; | ||
77 | |||
78 | /* | ||
79 | * write ak4535 register cache | ||
80 | */ | ||
81 | static inline void ak4535_write_reg_cache(struct snd_soc_codec *codec, | ||
82 | u16 reg, unsigned int value) | ||
83 | { | ||
84 | u16 *cache = codec->reg_cache; | ||
85 | if (reg >= AK4535_CACHEREGNUM) | ||
86 | return; | ||
87 | cache[reg] = value; | ||
88 | } | ||
89 | |||
90 | /* | ||
91 | * write to the AK4535 register space | ||
92 | */ | ||
93 | static int ak4535_write(struct snd_soc_codec *codec, unsigned int reg, | ||
94 | unsigned int value) | ||
95 | { | ||
96 | u8 data[2]; | ||
97 | |||
98 | /* data is | ||
99 | * D15..D8 AK4535 register offset | ||
100 | * D7...D0 register data | ||
101 | */ | ||
102 | data[0] = reg & 0xff; | ||
103 | data[1] = value & 0xff; | ||
104 | |||
105 | ak4535_write_reg_cache(codec, reg, value); | ||
106 | if (codec->hw_write(codec->control_data, data, 2) == 2) | ||
107 | return 0; | ||
108 | else | ||
109 | return -EIO; | ||
110 | } | ||
111 | |||
112 | static int ak4535_sync(struct snd_soc_codec *codec) | ||
113 | { | ||
114 | u16 *cache = codec->reg_cache; | ||
115 | int i, r = 0; | ||
116 | |||
117 | for (i = 0; i < AK4535_CACHEREGNUM; i++) | ||
118 | r |= ak4535_write(codec, i, cache[i]); | ||
119 | |||
120 | return r; | ||
121 | }; | ||
122 | |||
123 | static const char *ak4535_mono_gain[] = {"+6dB", "-17dB"}; | ||
124 | static const char *ak4535_mono_out[] = {"(L + R)/2", "Hi-Z"}; | ||
125 | static const char *ak4535_hp_out[] = {"Stereo", "Mono"}; | ||
126 | static const char *ak4535_deemp[] = {"44.1kHz", "Off", "48kHz", "32kHz"}; | ||
127 | static const char *ak4535_mic_select[] = {"Internal", "External"}; | ||
128 | |||
129 | static const struct soc_enum ak4535_enum[] = { | ||
130 | SOC_ENUM_SINGLE(AK4535_SIG1, 7, 2, ak4535_mono_gain), | ||
131 | SOC_ENUM_SINGLE(AK4535_SIG1, 6, 2, ak4535_mono_out), | ||
132 | SOC_ENUM_SINGLE(AK4535_MODE2, 2, 2, ak4535_hp_out), | ||
133 | SOC_ENUM_SINGLE(AK4535_DAC, 0, 4, ak4535_deemp), | ||
134 | SOC_ENUM_SINGLE(AK4535_MIC, 1, 2, ak4535_mic_select), | ||
135 | }; | ||
136 | |||
137 | static const struct snd_kcontrol_new ak4535_snd_controls[] = { | ||
138 | SOC_SINGLE("ALC2 Switch", AK4535_SIG1, 1, 1, 0), | ||
139 | SOC_ENUM("Mono 1 Output", ak4535_enum[1]), | ||
140 | SOC_ENUM("Mono 1 Gain", ak4535_enum[0]), | ||
141 | SOC_ENUM("Headphone Output", ak4535_enum[2]), | ||
142 | SOC_ENUM("Playback Deemphasis", ak4535_enum[3]), | ||
143 | SOC_SINGLE("Bass Volume", AK4535_DAC, 2, 3, 0), | ||
144 | SOC_SINGLE("Mic Boost (+20dB) Switch", AK4535_MIC, 0, 1, 0), | ||
145 | SOC_ENUM("Mic Select", ak4535_enum[4]), | ||
146 | SOC_SINGLE("ALC Operation Time", AK4535_TIMER, 0, 3, 0), | ||
147 | SOC_SINGLE("ALC Recovery Time", AK4535_TIMER, 2, 3, 0), | ||
148 | SOC_SINGLE("ALC ZC Time", AK4535_TIMER, 4, 3, 0), | ||
149 | SOC_SINGLE("ALC 1 Switch", AK4535_ALC1, 5, 1, 0), | ||
150 | SOC_SINGLE("ALC 2 Switch", AK4535_ALC1, 6, 1, 0), | ||
151 | SOC_SINGLE("ALC Volume", AK4535_ALC2, 0, 127, 0), | ||
152 | SOC_SINGLE("Capture Volume", AK4535_PGA, 0, 127, 0), | ||
153 | SOC_SINGLE("Left Playback Volume", AK4535_LATT, 0, 127, 1), | ||
154 | SOC_SINGLE("Right Playback Volume", AK4535_RATT, 0, 127, 1), | ||
155 | SOC_SINGLE("AUX Bypass Volume", AK4535_VOL, 0, 15, 0), | ||
156 | SOC_SINGLE("Mic Sidetone Volume", AK4535_VOL, 4, 7, 0), | ||
157 | }; | ||
158 | |||
159 | /* add non dapm controls */ | ||
160 | static int ak4535_add_controls(struct snd_soc_codec *codec) | ||
161 | { | ||
162 | int err, i; | ||
163 | |||
164 | for (i = 0; i < ARRAY_SIZE(ak4535_snd_controls); i++) { | ||
165 | err = snd_ctl_add(codec->card, | ||
166 | snd_soc_cnew(&ak4535_snd_controls[i], codec, NULL)); | ||
167 | if (err < 0) | ||
168 | return err; | ||
169 | } | ||
170 | |||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | /* Mono 1 Mixer */ | ||
175 | static const struct snd_kcontrol_new ak4535_mono1_mixer_controls[] = { | ||
176 | SOC_DAPM_SINGLE("Mic Sidetone Switch", AK4535_SIG1, 4, 1, 0), | ||
177 | SOC_DAPM_SINGLE("Mono Playback Switch", AK4535_SIG1, 5, 1, 0), | ||
178 | }; | ||
179 | |||
180 | /* Stereo Mixer */ | ||
181 | static const struct snd_kcontrol_new ak4535_stereo_mixer_controls[] = { | ||
182 | SOC_DAPM_SINGLE("Mic Sidetone Switch", AK4535_SIG2, 4, 1, 0), | ||
183 | SOC_DAPM_SINGLE("Playback Switch", AK4535_SIG2, 7, 1, 0), | ||
184 | SOC_DAPM_SINGLE("Aux Bypass Switch", AK4535_SIG2, 5, 1, 0), | ||
185 | }; | ||
186 | |||
187 | /* Input Mixer */ | ||
188 | static const struct snd_kcontrol_new ak4535_input_mixer_controls[] = { | ||
189 | SOC_DAPM_SINGLE("Mic Capture Switch", AK4535_MIC, 2, 1, 0), | ||
190 | SOC_DAPM_SINGLE("Aux Capture Switch", AK4535_MIC, 5, 1, 0), | ||
191 | }; | ||
192 | |||
193 | /* Input mux */ | ||
194 | static const struct snd_kcontrol_new ak4535_input_mux_control = | ||
195 | SOC_DAPM_ENUM("Input Select", ak4535_enum[4]); | ||
196 | |||
197 | /* HP L switch */ | ||
198 | static const struct snd_kcontrol_new ak4535_hpl_control = | ||
199 | SOC_DAPM_SINGLE("Switch", AK4535_SIG2, 1, 1, 1); | ||
200 | |||
201 | /* HP R switch */ | ||
202 | static const struct snd_kcontrol_new ak4535_hpr_control = | ||
203 | SOC_DAPM_SINGLE("Switch", AK4535_SIG2, 0, 1, 1); | ||
204 | |||
205 | /* mono 2 switch */ | ||
206 | static const struct snd_kcontrol_new ak4535_mono2_control = | ||
207 | SOC_DAPM_SINGLE("Switch", AK4535_SIG1, 0, 1, 0); | ||
208 | |||
209 | /* Line out switch */ | ||
210 | static const struct snd_kcontrol_new ak4535_line_control = | ||
211 | SOC_DAPM_SINGLE("Switch", AK4535_SIG2, 6, 1, 0); | ||
212 | |||
213 | /* ak4535 dapm widgets */ | ||
214 | static const struct snd_soc_dapm_widget ak4535_dapm_widgets[] = { | ||
215 | SND_SOC_DAPM_MIXER("Stereo Mixer", SND_SOC_NOPM, 0, 0, | ||
216 | &ak4535_stereo_mixer_controls[0], | ||
217 | ARRAY_SIZE(ak4535_stereo_mixer_controls)), | ||
218 | SND_SOC_DAPM_MIXER("Mono1 Mixer", SND_SOC_NOPM, 0, 0, | ||
219 | &ak4535_mono1_mixer_controls[0], | ||
220 | ARRAY_SIZE(ak4535_mono1_mixer_controls)), | ||
221 | SND_SOC_DAPM_MIXER("Input Mixer", SND_SOC_NOPM, 0, 0, | ||
222 | &ak4535_input_mixer_controls[0], | ||
223 | ARRAY_SIZE(ak4535_input_mixer_controls)), | ||
224 | SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, | ||
225 | &ak4535_input_mux_control), | ||
226 | SND_SOC_DAPM_DAC("DAC", "Playback", AK4535_PM2, 0, 0), | ||
227 | SND_SOC_DAPM_SWITCH("Mono 2 Enable", SND_SOC_NOPM, 0, 0, | ||
228 | &ak4535_mono2_control), | ||
229 | /* speaker powersave bit */ | ||
230 | SND_SOC_DAPM_PGA("Speaker Enable", AK4535_MODE2, 0, 0, NULL, 0), | ||
231 | SND_SOC_DAPM_SWITCH("Line Out Enable", SND_SOC_NOPM, 0, 0, | ||
232 | &ak4535_line_control), | ||
233 | SND_SOC_DAPM_SWITCH("Left HP Enable", SND_SOC_NOPM, 0, 0, | ||
234 | &ak4535_hpl_control), | ||
235 | SND_SOC_DAPM_SWITCH("Right HP Enable", SND_SOC_NOPM, 0, 0, | ||
236 | &ak4535_hpr_control), | ||
237 | SND_SOC_DAPM_OUTPUT("LOUT"), | ||
238 | SND_SOC_DAPM_OUTPUT("HPL"), | ||
239 | SND_SOC_DAPM_OUTPUT("ROUT"), | ||
240 | SND_SOC_DAPM_OUTPUT("HPR"), | ||
241 | SND_SOC_DAPM_OUTPUT("SPP"), | ||
242 | SND_SOC_DAPM_OUTPUT("SPN"), | ||
243 | SND_SOC_DAPM_OUTPUT("MOUT1"), | ||
244 | SND_SOC_DAPM_OUTPUT("MOUT2"), | ||
245 | SND_SOC_DAPM_OUTPUT("MICOUT"), | ||
246 | SND_SOC_DAPM_ADC("ADC", "Capture", AK4535_PM1, 0, 0), | ||
247 | SND_SOC_DAPM_PGA("Spk Amp", AK4535_PM2, 3, 0, NULL, 0), | ||
248 | SND_SOC_DAPM_PGA("HP R Amp", AK4535_PM2, 1, 0, NULL, 0), | ||
249 | SND_SOC_DAPM_PGA("HP L Amp", AK4535_PM2, 2, 0, NULL, 0), | ||
250 | SND_SOC_DAPM_PGA("Mic", AK4535_PM1, 1, 0, NULL, 0), | ||
251 | SND_SOC_DAPM_PGA("Line Out", AK4535_PM1, 4, 0, NULL, 0), | ||
252 | SND_SOC_DAPM_PGA("Mono Out", AK4535_PM1, 3, 0, NULL, 0), | ||
253 | SND_SOC_DAPM_PGA("AUX In", AK4535_PM1, 2, 0, NULL, 0), | ||
254 | |||
255 | SND_SOC_DAPM_MICBIAS("Mic Int Bias", AK4535_MIC, 3, 0), | ||
256 | SND_SOC_DAPM_MICBIAS("Mic Ext Bias", AK4535_MIC, 4, 0), | ||
257 | SND_SOC_DAPM_INPUT("MICIN"), | ||
258 | SND_SOC_DAPM_INPUT("MICEXT"), | ||
259 | SND_SOC_DAPM_INPUT("AUX"), | ||
260 | SND_SOC_DAPM_INPUT("MIN"), | ||
261 | SND_SOC_DAPM_INPUT("AIN"), | ||
262 | }; | ||
263 | |||
264 | static const struct snd_soc_dapm_route audio_map[] = { | ||
265 | /*stereo mixer */ | ||
266 | {"Stereo Mixer", "Playback Switch", "DAC"}, | ||
267 | {"Stereo Mixer", "Mic Sidetone Switch", "Mic"}, | ||
268 | {"Stereo Mixer", "Aux Bypass Switch", "AUX In"}, | ||
269 | |||
270 | /* mono1 mixer */ | ||
271 | {"Mono1 Mixer", "Mic Sidetone Switch", "Mic"}, | ||
272 | {"Mono1 Mixer", "Mono Playback Switch", "DAC"}, | ||
273 | |||
274 | /* Mic */ | ||
275 | {"Mic", NULL, "AIN"}, | ||
276 | {"Input Mux", "Internal", "Mic Int Bias"}, | ||
277 | {"Input Mux", "External", "Mic Ext Bias"}, | ||
278 | {"Mic Int Bias", NULL, "MICIN"}, | ||
279 | {"Mic Ext Bias", NULL, "MICEXT"}, | ||
280 | {"MICOUT", NULL, "Input Mux"}, | ||
281 | |||
282 | /* line out */ | ||
283 | {"LOUT", NULL, "Line Out Enable"}, | ||
284 | {"ROUT", NULL, "Line Out Enable"}, | ||
285 | {"Line Out Enable", "Switch", "Line Out"}, | ||
286 | {"Line Out", NULL, "Stereo Mixer"}, | ||
287 | |||
288 | /* mono1 out */ | ||
289 | {"MOUT1", NULL, "Mono Out"}, | ||
290 | {"Mono Out", NULL, "Mono1 Mixer"}, | ||
291 | |||
292 | /* left HP */ | ||
293 | {"HPL", NULL, "Left HP Enable"}, | ||
294 | {"Left HP Enable", "Switch", "HP L Amp"}, | ||
295 | {"HP L Amp", NULL, "Stereo Mixer"}, | ||
296 | |||
297 | /* right HP */ | ||
298 | {"HPR", NULL, "Right HP Enable"}, | ||
299 | {"Right HP Enable", "Switch", "HP R Amp"}, | ||
300 | {"HP R Amp", NULL, "Stereo Mixer"}, | ||
301 | |||
302 | /* speaker */ | ||
303 | {"SPP", NULL, "Speaker Enable"}, | ||
304 | {"SPN", NULL, "Speaker Enable"}, | ||
305 | {"Speaker Enable", "Switch", "Spk Amp"}, | ||
306 | {"Spk Amp", NULL, "MIN"}, | ||
307 | |||
308 | /* mono 2 */ | ||
309 | {"MOUT2", NULL, "Mono 2 Enable"}, | ||
310 | {"Mono 2 Enable", "Switch", "Stereo Mixer"}, | ||
311 | |||
312 | /* Aux In */ | ||
313 | {"Aux In", NULL, "AUX"}, | ||
314 | |||
315 | /* ADC */ | ||
316 | {"ADC", NULL, "Input Mixer"}, | ||
317 | {"Input Mixer", "Mic Capture Switch", "Mic"}, | ||
318 | {"Input Mixer", "Aux Capture Switch", "Aux In"}, | ||
319 | }; | ||
320 | |||
321 | static int ak4535_add_widgets(struct snd_soc_codec *codec) | ||
322 | { | ||
323 | snd_soc_dapm_new_controls(codec, ak4535_dapm_widgets, | ||
324 | ARRAY_SIZE(ak4535_dapm_widgets)); | ||
325 | |||
326 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | ||
327 | |||
328 | snd_soc_dapm_new_widgets(codec); | ||
329 | return 0; | ||
330 | } | ||
331 | |||
332 | static int ak4535_set_dai_sysclk(struct snd_soc_dai *codec_dai, | ||
333 | int clk_id, unsigned int freq, int dir) | ||
334 | { | ||
335 | struct snd_soc_codec *codec = codec_dai->codec; | ||
336 | struct ak4535_priv *ak4535 = codec->private_data; | ||
337 | |||
338 | ak4535->sysclk = freq; | ||
339 | return 0; | ||
340 | } | ||
341 | |||
342 | static int ak4535_hw_params(struct snd_pcm_substream *substream, | ||
343 | struct snd_pcm_hw_params *params) | ||
344 | { | ||
345 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
346 | struct snd_soc_device *socdev = rtd->socdev; | ||
347 | struct snd_soc_codec *codec = socdev->codec; | ||
348 | struct ak4535_priv *ak4535 = codec->private_data; | ||
349 | u8 mode2 = ak4535_read_reg_cache(codec, AK4535_MODE2) & ~(0x3 << 5); | ||
350 | int rate = params_rate(params), fs = 256; | ||
351 | |||
352 | if (rate) | ||
353 | fs = ak4535->sysclk / rate; | ||
354 | |||
355 | /* set fs */ | ||
356 | switch (fs) { | ||
357 | case 1024: | ||
358 | mode2 |= (0x2 << 5); | ||
359 | break; | ||
360 | case 512: | ||
361 | mode2 |= (0x1 << 5); | ||
362 | break; | ||
363 | case 256: | ||
364 | break; | ||
365 | } | ||
366 | |||
367 | /* set rate */ | ||
368 | ak4535_write(codec, AK4535_MODE2, mode2); | ||
369 | return 0; | ||
370 | } | ||
371 | |||
372 | static int ak4535_set_dai_fmt(struct snd_soc_dai *codec_dai, | ||
373 | unsigned int fmt) | ||
374 | { | ||
375 | struct snd_soc_codec *codec = codec_dai->codec; | ||
376 | u8 mode1 = 0; | ||
377 | |||
378 | /* interface format */ | ||
379 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
380 | case SND_SOC_DAIFMT_I2S: | ||
381 | mode1 = 0x0002; | ||
382 | break; | ||
383 | case SND_SOC_DAIFMT_LEFT_J: | ||
384 | mode1 = 0x0001; | ||
385 | break; | ||
386 | default: | ||
387 | return -EINVAL; | ||
388 | } | ||
389 | |||
390 | /* use 32 fs for BCLK to save power */ | ||
391 | mode1 |= 0x4; | ||
392 | |||
393 | ak4535_write(codec, AK4535_MODE1, mode1); | ||
394 | return 0; | ||
395 | } | ||
396 | |||
397 | static int ak4535_mute(struct snd_soc_dai *dai, int mute) | ||
398 | { | ||
399 | struct snd_soc_codec *codec = dai->codec; | ||
400 | u16 mute_reg = ak4535_read_reg_cache(codec, AK4535_DAC) & 0xffdf; | ||
401 | if (!mute) | ||
402 | ak4535_write(codec, AK4535_DAC, mute_reg); | ||
403 | else | ||
404 | ak4535_write(codec, AK4535_DAC, mute_reg | 0x20); | ||
405 | return 0; | ||
406 | } | ||
407 | |||
408 | static int ak4535_set_bias_level(struct snd_soc_codec *codec, | ||
409 | enum snd_soc_bias_level level) | ||
410 | { | ||
411 | u16 i; | ||
412 | |||
413 | switch (level) { | ||
414 | case SND_SOC_BIAS_ON: | ||
415 | ak4535_mute(codec->dai, 0); | ||
416 | break; | ||
417 | case SND_SOC_BIAS_PREPARE: | ||
418 | ak4535_mute(codec->dai, 1); | ||
419 | break; | ||
420 | case SND_SOC_BIAS_STANDBY: | ||
421 | i = ak4535_read_reg_cache(codec, AK4535_PM1); | ||
422 | ak4535_write(codec, AK4535_PM1, i | 0x80); | ||
423 | i = ak4535_read_reg_cache(codec, AK4535_PM2); | ||
424 | ak4535_write(codec, AK4535_PM2, i & (~0x80)); | ||
425 | break; | ||
426 | case SND_SOC_BIAS_OFF: | ||
427 | i = ak4535_read_reg_cache(codec, AK4535_PM1); | ||
428 | ak4535_write(codec, AK4535_PM1, i & (~0x80)); | ||
429 | break; | ||
430 | } | ||
431 | codec->bias_level = level; | ||
432 | return 0; | ||
433 | } | ||
434 | |||
435 | #define AK4535_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | ||
436 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ | ||
437 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) | ||
438 | |||
439 | struct snd_soc_dai ak4535_dai = { | ||
440 | .name = "AK4535", | ||
441 | .playback = { | ||
442 | .stream_name = "Playback", | ||
443 | .channels_min = 1, | ||
444 | .channels_max = 2, | ||
445 | .rates = AK4535_RATES, | ||
446 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | ||
447 | .capture = { | ||
448 | .stream_name = "Capture", | ||
449 | .channels_min = 1, | ||
450 | .channels_max = 2, | ||
451 | .rates = AK4535_RATES, | ||
452 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | ||
453 | .ops = { | ||
454 | .hw_params = ak4535_hw_params, | ||
455 | }, | ||
456 | .dai_ops = { | ||
457 | .set_fmt = ak4535_set_dai_fmt, | ||
458 | .digital_mute = ak4535_mute, | ||
459 | .set_sysclk = ak4535_set_dai_sysclk, | ||
460 | }, | ||
461 | }; | ||
462 | EXPORT_SYMBOL_GPL(ak4535_dai); | ||
463 | |||
464 | static int ak4535_suspend(struct platform_device *pdev, pm_message_t state) | ||
465 | { | ||
466 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
467 | struct snd_soc_codec *codec = socdev->codec; | ||
468 | |||
469 | ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
470 | return 0; | ||
471 | } | ||
472 | |||
473 | static int ak4535_resume(struct platform_device *pdev) | ||
474 | { | ||
475 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
476 | struct snd_soc_codec *codec = socdev->codec; | ||
477 | ak4535_sync(codec); | ||
478 | ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
479 | ak4535_set_bias_level(codec, codec->suspend_bias_level); | ||
480 | return 0; | ||
481 | } | ||
482 | |||
483 | /* | ||
484 | * initialise the AK4535 driver | ||
485 | * register the mixer and dsp interfaces with the kernel | ||
486 | */ | ||
487 | static int ak4535_init(struct snd_soc_device *socdev) | ||
488 | { | ||
489 | struct snd_soc_codec *codec = socdev->codec; | ||
490 | int ret = 0; | ||
491 | |||
492 | codec->name = "AK4535"; | ||
493 | codec->owner = THIS_MODULE; | ||
494 | codec->read = ak4535_read_reg_cache; | ||
495 | codec->write = ak4535_write; | ||
496 | codec->set_bias_level = ak4535_set_bias_level; | ||
497 | codec->dai = &ak4535_dai; | ||
498 | codec->num_dai = 1; | ||
499 | codec->reg_cache_size = ARRAY_SIZE(ak4535_reg); | ||
500 | codec->reg_cache = kmemdup(ak4535_reg, sizeof(ak4535_reg), GFP_KERNEL); | ||
501 | |||
502 | if (codec->reg_cache == NULL) | ||
503 | return -ENOMEM; | ||
504 | |||
505 | /* register pcms */ | ||
506 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
507 | if (ret < 0) { | ||
508 | printk(KERN_ERR "ak4535: failed to create pcms\n"); | ||
509 | goto pcm_err; | ||
510 | } | ||
511 | |||
512 | /* power on device */ | ||
513 | ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
514 | |||
515 | ak4535_add_controls(codec); | ||
516 | ak4535_add_widgets(codec); | ||
517 | ret = snd_soc_register_card(socdev); | ||
518 | if (ret < 0) { | ||
519 | printk(KERN_ERR "ak4535: failed to register card\n"); | ||
520 | goto card_err; | ||
521 | } | ||
522 | |||
523 | return ret; | ||
524 | |||
525 | card_err: | ||
526 | snd_soc_free_pcms(socdev); | ||
527 | snd_soc_dapm_free(socdev); | ||
528 | pcm_err: | ||
529 | kfree(codec->reg_cache); | ||
530 | |||
531 | return ret; | ||
532 | } | ||
533 | |||
534 | static struct snd_soc_device *ak4535_socdev; | ||
535 | |||
536 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
537 | |||
538 | #define I2C_DRIVERID_AK4535 0xfefe /* liam - need a proper id */ | ||
539 | |||
540 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | ||
541 | |||
542 | /* Magic definition of all other variables and things */ | ||
543 | I2C_CLIENT_INSMOD; | ||
544 | |||
545 | static struct i2c_driver ak4535_i2c_driver; | ||
546 | static struct i2c_client client_template; | ||
547 | |||
548 | /* If the i2c layer weren't so broken, we could pass this kind of data | ||
549 | around */ | ||
550 | static int ak4535_codec_probe(struct i2c_adapter *adap, int addr, int kind) | ||
551 | { | ||
552 | struct snd_soc_device *socdev = ak4535_socdev; | ||
553 | struct ak4535_setup_data *setup = socdev->codec_data; | ||
554 | struct snd_soc_codec *codec = socdev->codec; | ||
555 | struct i2c_client *i2c; | ||
556 | int ret; | ||
557 | |||
558 | if (addr != setup->i2c_address) | ||
559 | return -ENODEV; | ||
560 | |||
561 | client_template.adapter = adap; | ||
562 | client_template.addr = addr; | ||
563 | |||
564 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | ||
565 | if (i2c == NULL) { | ||
566 | kfree(codec); | ||
567 | return -ENOMEM; | ||
568 | } | ||
569 | i2c_set_clientdata(i2c, codec); | ||
570 | codec->control_data = i2c; | ||
571 | |||
572 | ret = i2c_attach_client(i2c); | ||
573 | if (ret < 0) { | ||
574 | printk(KERN_ERR "failed to attach codec at addr %x\n", addr); | ||
575 | goto err; | ||
576 | } | ||
577 | |||
578 | ret = ak4535_init(socdev); | ||
579 | if (ret < 0) { | ||
580 | printk(KERN_ERR "failed to initialise AK4535\n"); | ||
581 | goto err; | ||
582 | } | ||
583 | return ret; | ||
584 | |||
585 | err: | ||
586 | kfree(codec); | ||
587 | kfree(i2c); | ||
588 | return ret; | ||
589 | } | ||
590 | |||
591 | static int ak4535_i2c_detach(struct i2c_client *client) | ||
592 | { | ||
593 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | ||
594 | i2c_detach_client(client); | ||
595 | kfree(codec->reg_cache); | ||
596 | kfree(client); | ||
597 | return 0; | ||
598 | } | ||
599 | |||
600 | static int ak4535_i2c_attach(struct i2c_adapter *adap) | ||
601 | { | ||
602 | return i2c_probe(adap, &addr_data, ak4535_codec_probe); | ||
603 | } | ||
604 | |||
605 | /* corgi i2c codec control layer */ | ||
606 | static struct i2c_driver ak4535_i2c_driver = { | ||
607 | .driver = { | ||
608 | .name = "AK4535 I2C Codec", | ||
609 | .owner = THIS_MODULE, | ||
610 | }, | ||
611 | .id = I2C_DRIVERID_AK4535, | ||
612 | .attach_adapter = ak4535_i2c_attach, | ||
613 | .detach_client = ak4535_i2c_detach, | ||
614 | .command = NULL, | ||
615 | }; | ||
616 | |||
617 | static struct i2c_client client_template = { | ||
618 | .name = "AK4535", | ||
619 | .driver = &ak4535_i2c_driver, | ||
620 | }; | ||
621 | #endif | ||
622 | |||
623 | static int ak4535_probe(struct platform_device *pdev) | ||
624 | { | ||
625 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
626 | struct ak4535_setup_data *setup; | ||
627 | struct snd_soc_codec *codec; | ||
628 | struct ak4535_priv *ak4535; | ||
629 | int ret = 0; | ||
630 | |||
631 | printk(KERN_INFO "AK4535 Audio Codec %s", AK4535_VERSION); | ||
632 | |||
633 | setup = socdev->codec_data; | ||
634 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
635 | if (codec == NULL) | ||
636 | return -ENOMEM; | ||
637 | |||
638 | ak4535 = kzalloc(sizeof(struct ak4535_priv), GFP_KERNEL); | ||
639 | if (ak4535 == NULL) { | ||
640 | kfree(codec); | ||
641 | return -ENOMEM; | ||
642 | } | ||
643 | |||
644 | codec->private_data = ak4535; | ||
645 | socdev->codec = codec; | ||
646 | mutex_init(&codec->mutex); | ||
647 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
648 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
649 | |||
650 | ak4535_socdev = socdev; | ||
651 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
652 | if (setup->i2c_address) { | ||
653 | normal_i2c[0] = setup->i2c_address; | ||
654 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
655 | codec->hw_read = (hw_read_t)i2c_master_recv; | ||
656 | ret = i2c_add_driver(&ak4535_i2c_driver); | ||
657 | if (ret != 0) | ||
658 | printk(KERN_ERR "can't add i2c driver"); | ||
659 | } | ||
660 | #else | ||
661 | /* Add other interfaces here */ | ||
662 | #endif | ||
663 | return ret; | ||
664 | } | ||
665 | |||
666 | /* power down chip */ | ||
667 | static int ak4535_remove(struct platform_device *pdev) | ||
668 | { | ||
669 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
670 | struct snd_soc_codec *codec = socdev->codec; | ||
671 | |||
672 | if (codec->control_data) | ||
673 | ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
674 | |||
675 | snd_soc_free_pcms(socdev); | ||
676 | snd_soc_dapm_free(socdev); | ||
677 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
678 | i2c_del_driver(&ak4535_i2c_driver); | ||
679 | #endif | ||
680 | kfree(codec->private_data); | ||
681 | kfree(codec); | ||
682 | |||
683 | return 0; | ||
684 | } | ||
685 | |||
686 | struct snd_soc_codec_device soc_codec_dev_ak4535 = { | ||
687 | .probe = ak4535_probe, | ||
688 | .remove = ak4535_remove, | ||
689 | .suspend = ak4535_suspend, | ||
690 | .resume = ak4535_resume, | ||
691 | }; | ||
692 | EXPORT_SYMBOL_GPL(soc_codec_dev_ak4535); | ||
693 | |||
694 | MODULE_DESCRIPTION("Soc AK4535 driver"); | ||
695 | MODULE_AUTHOR("Richard Purdie"); | ||
696 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/ak4535.h b/sound/soc/codecs/ak4535.h new file mode 100644 index 000000000000..e9fe30e2c056 --- /dev/null +++ b/sound/soc/codecs/ak4535.h | |||
@@ -0,0 +1,46 @@ | |||
1 | /* | ||
2 | * ak4535.h -- AK4535 Soc Audio driver | ||
3 | * | ||
4 | * Copyright 2005 Openedhand Ltd. | ||
5 | * | ||
6 | * Author: Richard Purdie <richard@openedhand.com> | ||
7 | * | ||
8 | * Based on wm8753.h | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #ifndef _AK4535_H | ||
16 | #define _AK4535_H | ||
17 | |||
18 | /* AK4535 register space */ | ||
19 | |||
20 | #define AK4535_PM1 0x0 | ||
21 | #define AK4535_PM2 0x1 | ||
22 | #define AK4535_SIG1 0x2 | ||
23 | #define AK4535_SIG2 0x3 | ||
24 | #define AK4535_MODE1 0x4 | ||
25 | #define AK4535_MODE2 0x5 | ||
26 | #define AK4535_DAC 0x6 | ||
27 | #define AK4535_MIC 0x7 | ||
28 | #define AK4535_TIMER 0x8 | ||
29 | #define AK4535_ALC1 0x9 | ||
30 | #define AK4535_ALC2 0xa | ||
31 | #define AK4535_PGA 0xb | ||
32 | #define AK4535_LATT 0xc | ||
33 | #define AK4535_RATT 0xd | ||
34 | #define AK4535_VOL 0xe | ||
35 | #define AK4535_STATUS 0xf | ||
36 | |||
37 | #define AK4535_CACHEREGNUM 0x10 | ||
38 | |||
39 | struct ak4535_setup_data { | ||
40 | unsigned short i2c_address; | ||
41 | }; | ||
42 | |||
43 | extern struct snd_soc_dai ak4535_dai; | ||
44 | extern struct snd_soc_codec_device soc_codec_dev_ak4535; | ||
45 | |||
46 | #endif | ||
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index e73fcfd9f5cd..9deb8c74fdfd 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c | |||
@@ -201,7 +201,7 @@ static struct { | |||
201 | * driver what the input settings can be. This would need to be implemented | 201 | * driver what the input settings can be. This would need to be implemented |
202 | * for stand-alone mode to work. | 202 | * for stand-alone mode to work. |
203 | */ | 203 | */ |
204 | static int cs4270_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai, | 204 | static int cs4270_set_dai_sysclk(struct snd_soc_dai *codec_dai, |
205 | int clk_id, unsigned int freq, int dir) | 205 | int clk_id, unsigned int freq, int dir) |
206 | { | 206 | { |
207 | struct snd_soc_codec *codec = codec_dai->codec; | 207 | struct snd_soc_codec *codec = codec_dai->codec; |
@@ -251,7 +251,7 @@ static int cs4270_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai, | |||
251 | * data for playback only, but ASoC currently does not support different | 251 | * data for playback only, but ASoC currently does not support different |
252 | * formats for playback vs. record. | 252 | * formats for playback vs. record. |
253 | */ | 253 | */ |
254 | static int cs4270_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | 254 | static int cs4270_set_dai_fmt(struct snd_soc_dai *codec_dai, |
255 | unsigned int format) | 255 | unsigned int format) |
256 | { | 256 | { |
257 | struct snd_soc_codec *codec = codec_dai->codec; | 257 | struct snd_soc_codec *codec = codec_dai->codec; |
@@ -471,7 +471,7 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream, | |||
471 | * board does not have the MUTEA or MUTEB pins connected to such circuitry, | 471 | * board does not have the MUTEA or MUTEB pins connected to such circuitry, |
472 | * then this function will do nothing. | 472 | * then this function will do nothing. |
473 | */ | 473 | */ |
474 | static int cs4270_mute(struct snd_soc_codec_dai *dai, int mute) | 474 | static int cs4270_mute(struct snd_soc_dai *dai, int mute) |
475 | { | 475 | { |
476 | struct snd_soc_codec *codec = dai->codec; | 476 | struct snd_soc_codec *codec = dai->codec; |
477 | int reg6; | 477 | int reg6; |
@@ -667,7 +667,7 @@ error: | |||
667 | 667 | ||
668 | #endif /* USE_I2C*/ | 668 | #endif /* USE_I2C*/ |
669 | 669 | ||
670 | struct snd_soc_codec_dai cs4270_dai = { | 670 | struct snd_soc_dai cs4270_dai = { |
671 | .name = "CS4270", | 671 | .name = "CS4270", |
672 | .playback = { | 672 | .playback = { |
673 | .stream_name = "Playback", | 673 | .stream_name = "Playback", |
diff --git a/sound/soc/codecs/cs4270.h b/sound/soc/codecs/cs4270.h index 0ced49b7804d..adc6cd9667d4 100644 --- a/sound/soc/codecs/cs4270.h +++ b/sound/soc/codecs/cs4270.h | |||
@@ -16,7 +16,7 @@ | |||
16 | * The ASoC codec DAI structure for the CS4270. Assign this structure to | 16 | * The ASoC codec DAI structure for the CS4270. Assign this structure to |
17 | * the .codec_dai field of your machine driver's snd_soc_dai_link structure. | 17 | * the .codec_dai field of your machine driver's snd_soc_dai_link structure. |
18 | */ | 18 | */ |
19 | extern struct snd_soc_codec_dai cs4270_dai; | 19 | extern struct snd_soc_dai cs4270_dai; |
20 | 20 | ||
21 | /* | 21 | /* |
22 | * The ASoC codec device structure for the CS4270. Assign this structure | 22 | * The ASoC codec device structure for the CS4270. Assign this structure |
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 09b1661b8a3a..b1dce5f459db 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c | |||
@@ -29,7 +29,7 @@ | |||
29 | * --------------------------------------- | 29 | * --------------------------------------- |
30 | * | 30 | * |
31 | * Hence the machine layer should disable unsupported inputs/outputs by | 31 | * Hence the machine layer should disable unsupported inputs/outputs by |
32 | * snd_soc_dapm_set_endpoint(codec, "MONO_LOUT", 0), etc. | 32 | * snd_soc_dapm_disable_pin(codec, "MONO_LOUT"), etc. |
33 | */ | 33 | */ |
34 | 34 | ||
35 | #include <linux/module.h> | 35 | #include <linux/module.h> |
@@ -49,7 +49,7 @@ | |||
49 | #include "tlv320aic3x.h" | 49 | #include "tlv320aic3x.h" |
50 | 50 | ||
51 | #define AUDIO_NAME "aic3x" | 51 | #define AUDIO_NAME "aic3x" |
52 | #define AIC3X_VERSION "0.1" | 52 | #define AIC3X_VERSION "0.2" |
53 | 53 | ||
54 | /* codec private data */ | 54 | /* codec private data */ |
55 | struct aic3x_priv { | 55 | struct aic3x_priv { |
@@ -138,6 +138,20 @@ static int aic3x_write(struct snd_soc_codec *codec, unsigned int reg, | |||
138 | return -EIO; | 138 | return -EIO; |
139 | } | 139 | } |
140 | 140 | ||
141 | /* | ||
142 | * read from the aic3x register space | ||
143 | */ | ||
144 | static int aic3x_read(struct snd_soc_codec *codec, unsigned int reg, | ||
145 | u8 *value) | ||
146 | { | ||
147 | *value = reg & 0xff; | ||
148 | if (codec->hw_read(codec->control_data, value, 1) != 1) | ||
149 | return -EIO; | ||
150 | |||
151 | aic3x_write_reg_cache(codec, reg, *value); | ||
152 | return 0; | ||
153 | } | ||
154 | |||
141 | #define SOC_DAPM_SINGLE_AIC3X(xname, reg, shift, mask, invert) \ | 155 | #define SOC_DAPM_SINGLE_AIC3X(xname, reg, shift, mask, invert) \ |
142 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 156 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
143 | .info = snd_soc_info_volsw, \ | 157 | .info = snd_soc_info_volsw, \ |
@@ -192,7 +206,7 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol, | |||
192 | } | 206 | } |
193 | 207 | ||
194 | if (found) | 208 | if (found) |
195 | snd_soc_dapm_sync_endpoints(widget->codec); | 209 | snd_soc_dapm_sync(widget->codec); |
196 | } | 210 | } |
197 | 211 | ||
198 | ret = snd_soc_update_bits(widget->codec, reg, val_mask, val); | 212 | ret = snd_soc_update_bits(widget->codec, reg, val_mask, val); |
@@ -209,6 +223,8 @@ static const char *aic3x_right_hpcom_mux[] = | |||
209 | { "differential of HPROUT", "constant VCM", "single-ended", | 223 | { "differential of HPROUT", "constant VCM", "single-ended", |
210 | "differential of HPLCOM", "external feedback" }; | 224 | "differential of HPLCOM", "external feedback" }; |
211 | static const char *aic3x_linein_mode_mux[] = { "single-ended", "differential" }; | 225 | static const char *aic3x_linein_mode_mux[] = { "single-ended", "differential" }; |
226 | static const char *aic3x_adc_hpf[] = | ||
227 | { "Disabled", "0.0045xFs", "0.0125xFs", "0.025xFs" }; | ||
212 | 228 | ||
213 | #define LDAC_ENUM 0 | 229 | #define LDAC_ENUM 0 |
214 | #define RDAC_ENUM 1 | 230 | #define RDAC_ENUM 1 |
@@ -218,6 +234,7 @@ static const char *aic3x_linein_mode_mux[] = { "single-ended", "differential" }; | |||
218 | #define LINE1R_ENUM 5 | 234 | #define LINE1R_ENUM 5 |
219 | #define LINE2L_ENUM 6 | 235 | #define LINE2L_ENUM 6 |
220 | #define LINE2R_ENUM 7 | 236 | #define LINE2R_ENUM 7 |
237 | #define ADC_HPF_ENUM 8 | ||
221 | 238 | ||
222 | static const struct soc_enum aic3x_enum[] = { | 239 | static const struct soc_enum aic3x_enum[] = { |
223 | SOC_ENUM_SINGLE(DAC_LINE_MUX, 6, 3, aic3x_left_dac_mux), | 240 | SOC_ENUM_SINGLE(DAC_LINE_MUX, 6, 3, aic3x_left_dac_mux), |
@@ -228,6 +245,7 @@ static const struct soc_enum aic3x_enum[] = { | |||
228 | SOC_ENUM_SINGLE(LINE1R_2_RADC_CTRL, 7, 2, aic3x_linein_mode_mux), | 245 | SOC_ENUM_SINGLE(LINE1R_2_RADC_CTRL, 7, 2, aic3x_linein_mode_mux), |
229 | SOC_ENUM_SINGLE(LINE2L_2_LADC_CTRL, 7, 2, aic3x_linein_mode_mux), | 246 | SOC_ENUM_SINGLE(LINE2L_2_LADC_CTRL, 7, 2, aic3x_linein_mode_mux), |
230 | SOC_ENUM_SINGLE(LINE2R_2_RADC_CTRL, 7, 2, aic3x_linein_mode_mux), | 247 | SOC_ENUM_SINGLE(LINE2R_2_RADC_CTRL, 7, 2, aic3x_linein_mode_mux), |
248 | SOC_ENUM_DOUBLE(AIC3X_CODEC_DFILT_CTRL, 6, 4, 4, aic3x_adc_hpf), | ||
231 | }; | 249 | }; |
232 | 250 | ||
233 | static const struct snd_kcontrol_new aic3x_snd_controls[] = { | 251 | static const struct snd_kcontrol_new aic3x_snd_controls[] = { |
@@ -278,6 +296,8 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = { | |||
278 | /* Input */ | 296 | /* Input */ |
279 | SOC_DOUBLE_R("PGA Capture Volume", LADC_VOL, RADC_VOL, 0, 0x7f, 0), | 297 | SOC_DOUBLE_R("PGA Capture Volume", LADC_VOL, RADC_VOL, 0, 0x7f, 0), |
280 | SOC_DOUBLE_R("PGA Capture Switch", LADC_VOL, RADC_VOL, 7, 0x01, 1), | 298 | SOC_DOUBLE_R("PGA Capture Switch", LADC_VOL, RADC_VOL, 7, 0x01, 1), |
299 | |||
300 | SOC_ENUM("ADC HPF Cut-off", aic3x_enum[ADC_HPF_ENUM]), | ||
281 | }; | 301 | }; |
282 | 302 | ||
283 | /* add non dapm controls */ | 303 | /* add non dapm controls */ |
@@ -441,11 +461,34 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { | |||
441 | SND_SOC_DAPM_MUX("Right Line2R Mux", SND_SOC_NOPM, 0, 0, | 461 | SND_SOC_DAPM_MUX("Right Line2R Mux", SND_SOC_NOPM, 0, 0, |
442 | &aic3x_right_line2_mux_controls), | 462 | &aic3x_right_line2_mux_controls), |
443 | 463 | ||
464 | /* | ||
465 | * Not a real mic bias widget but similar function. This is for dynamic | ||
466 | * control of GPIO1 digital mic modulator clock output function when | ||
467 | * using digital mic. | ||
468 | */ | ||
469 | SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "GPIO1 dmic modclk", | ||
470 | AIC3X_GPIO1_REG, 4, 0xf, | ||
471 | AIC3X_GPIO1_FUNC_DIGITAL_MIC_MODCLK, | ||
472 | AIC3X_GPIO1_FUNC_DISABLED), | ||
473 | |||
474 | /* | ||
475 | * Also similar function like mic bias. Selects digital mic with | ||
476 | * configurable oversampling rate instead of ADC converter. | ||
477 | */ | ||
478 | SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "DMic Rate 128", | ||
479 | AIC3X_ASD_INTF_CTRLA, 0, 3, 1, 0), | ||
480 | SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "DMic Rate 64", | ||
481 | AIC3X_ASD_INTF_CTRLA, 0, 3, 2, 0), | ||
482 | SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "DMic Rate 32", | ||
483 | AIC3X_ASD_INTF_CTRLA, 0, 3, 3, 0), | ||
484 | |||
444 | /* Mic Bias */ | 485 | /* Mic Bias */ |
445 | SND_SOC_DAPM_MICBIAS("Mic Bias 2V", MICBIAS_CTRL, 6, 0), | 486 | SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias 2V", |
446 | SND_SOC_DAPM_MICBIAS("Mic Bias 2.5V", MICBIAS_CTRL, 7, 0), | 487 | MICBIAS_CTRL, 6, 3, 1, 0), |
447 | SND_SOC_DAPM_MICBIAS("Mic Bias AVDD", MICBIAS_CTRL, 6, 0), | 488 | SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias 2.5V", |
448 | SND_SOC_DAPM_MICBIAS("Mic Bias AVDD", MICBIAS_CTRL, 7, 0), | 489 | MICBIAS_CTRL, 6, 3, 2, 0), |
490 | SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias AVDD", | ||
491 | MICBIAS_CTRL, 6, 3, 3, 0), | ||
449 | 492 | ||
450 | /* Left PGA to Left Output bypass */ | 493 | /* Left PGA to Left Output bypass */ |
451 | SND_SOC_DAPM_MIXER("Left PGA Bypass Mixer", SND_SOC_NOPM, 0, 0, | 494 | SND_SOC_DAPM_MIXER("Left PGA Bypass Mixer", SND_SOC_NOPM, 0, 0, |
@@ -483,7 +526,7 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { | |||
483 | SND_SOC_DAPM_INPUT("LINE2R"), | 526 | SND_SOC_DAPM_INPUT("LINE2R"), |
484 | }; | 527 | }; |
485 | 528 | ||
486 | static const char *intercon[][3] = { | 529 | static const struct snd_soc_dapm_route intercon[] = { |
487 | /* Left Output */ | 530 | /* Left Output */ |
488 | {"Left DAC Mux", "DAC_L1", "Left DAC"}, | 531 | {"Left DAC Mux", "DAC_L1", "Left DAC"}, |
489 | {"Left DAC Mux", "DAC_L2", "Left DAC"}, | 532 | {"Left DAC Mux", "DAC_L2", "Left DAC"}, |
@@ -554,6 +597,7 @@ static const char *intercon[][3] = { | |||
554 | {"Left PGA Mixer", "Mic3L Switch", "MIC3L"}, | 597 | {"Left PGA Mixer", "Mic3L Switch", "MIC3L"}, |
555 | 598 | ||
556 | {"Left ADC", NULL, "Left PGA Mixer"}, | 599 | {"Left ADC", NULL, "Left PGA Mixer"}, |
600 | {"Left ADC", NULL, "GPIO1 dmic modclk"}, | ||
557 | 601 | ||
558 | /* Right Input */ | 602 | /* Right Input */ |
559 | {"Right Line1R Mux", "single-ended", "LINE1R"}, | 603 | {"Right Line1R Mux", "single-ended", "LINE1R"}, |
@@ -567,6 +611,7 @@ static const char *intercon[][3] = { | |||
567 | {"Right PGA Mixer", "Mic3R Switch", "MIC3R"}, | 611 | {"Right PGA Mixer", "Mic3R Switch", "MIC3R"}, |
568 | 612 | ||
569 | {"Right ADC", NULL, "Right PGA Mixer"}, | 613 | {"Right ADC", NULL, "Right PGA Mixer"}, |
614 | {"Right ADC", NULL, "GPIO1 dmic modclk"}, | ||
570 | 615 | ||
571 | /* Left PGA Bypass */ | 616 | /* Left PGA Bypass */ |
572 | {"Left PGA Bypass Mixer", "Line Switch", "Left PGA Mixer"}, | 617 | {"Left PGA Bypass Mixer", "Line Switch", "Left PGA Mixer"}, |
@@ -628,101 +673,27 @@ static const char *intercon[][3] = { | |||
628 | {"Mono Out", NULL, "Right Line2 Bypass Mixer"}, | 673 | {"Mono Out", NULL, "Right Line2 Bypass Mixer"}, |
629 | {"Right HP Out", NULL, "Right Line2 Bypass Mixer"}, | 674 | {"Right HP Out", NULL, "Right Line2 Bypass Mixer"}, |
630 | 675 | ||
631 | /* terminator */ | 676 | /* |
632 | {NULL, NULL, NULL}, | 677 | * Logical path between digital mic enable and GPIO1 modulator clock |
678 | * output function | ||
679 | */ | ||
680 | {"GPIO1 dmic modclk", NULL, "DMic Rate 128"}, | ||
681 | {"GPIO1 dmic modclk", NULL, "DMic Rate 64"}, | ||
682 | {"GPIO1 dmic modclk", NULL, "DMic Rate 32"}, | ||
633 | }; | 683 | }; |
634 | 684 | ||
635 | static int aic3x_add_widgets(struct snd_soc_codec *codec) | 685 | static int aic3x_add_widgets(struct snd_soc_codec *codec) |
636 | { | 686 | { |
637 | int i; | 687 | snd_soc_dapm_new_controls(codec, aic3x_dapm_widgets, |
638 | 688 | ARRAY_SIZE(aic3x_dapm_widgets)); | |
639 | for (i = 0; i < ARRAY_SIZE(aic3x_dapm_widgets); i++) | ||
640 | snd_soc_dapm_new_control(codec, &aic3x_dapm_widgets[i]); | ||
641 | 689 | ||
642 | /* set up audio path interconnects */ | 690 | /* set up audio path interconnects */ |
643 | for (i = 0; intercon[i][0] != NULL; i++) | 691 | snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); |
644 | snd_soc_dapm_connect_input(codec, intercon[i][0], | ||
645 | intercon[i][1], intercon[i][2]); | ||
646 | 692 | ||
647 | snd_soc_dapm_new_widgets(codec); | 693 | snd_soc_dapm_new_widgets(codec); |
648 | return 0; | 694 | return 0; |
649 | } | 695 | } |
650 | 696 | ||
651 | struct aic3x_rate_divs { | ||
652 | u32 mclk; | ||
653 | u32 rate; | ||
654 | u32 fsref_reg; | ||
655 | u8 sr_reg:4; | ||
656 | u8 pllj_reg; | ||
657 | u16 plld_reg; | ||
658 | }; | ||
659 | |||
660 | /* AIC3X codec mclk clock divider coefficients */ | ||
661 | static const struct aic3x_rate_divs aic3x_divs[] = { | ||
662 | /* 8k */ | ||
663 | {12000000, 8000, 48000, 0xa, 16, 3840}, | ||
664 | {19200000, 8000, 48000, 0xa, 10, 2400}, | ||
665 | {22579200, 8000, 48000, 0xa, 8, 7075}, | ||
666 | {33868800, 8000, 48000, 0xa, 5, 8049}, | ||
667 | /* 11.025k */ | ||
668 | {12000000, 11025, 44100, 0x6, 15, 528}, | ||
669 | {19200000, 11025, 44100, 0x6, 9, 4080}, | ||
670 | {22579200, 11025, 44100, 0x6, 8, 0}, | ||
671 | {33868800, 11025, 44100, 0x6, 5, 3333}, | ||
672 | /* 16k */ | ||
673 | {12000000, 16000, 48000, 0x4, 16, 3840}, | ||
674 | {19200000, 16000, 48000, 0x4, 10, 2400}, | ||
675 | {22579200, 16000, 48000, 0x4, 8, 7075}, | ||
676 | {33868800, 16000, 48000, 0x4, 5, 8049}, | ||
677 | /* 22.05k */ | ||
678 | {12000000, 22050, 44100, 0x2, 15, 528}, | ||
679 | {19200000, 22050, 44100, 0x2, 9, 4080}, | ||
680 | {22579200, 22050, 44100, 0x2, 8, 0}, | ||
681 | {33868800, 22050, 44100, 0x2, 5, 3333}, | ||
682 | /* 32k */ | ||
683 | {12000000, 32000, 48000, 0x1, 16, 3840}, | ||
684 | {19200000, 32000, 48000, 0x1, 10, 2400}, | ||
685 | {22579200, 32000, 48000, 0x1, 8, 7075}, | ||
686 | {33868800, 32000, 48000, 0x1, 5, 8049}, | ||
687 | /* 44.1k */ | ||
688 | {12000000, 44100, 44100, 0x0, 15, 528}, | ||
689 | {19200000, 44100, 44100, 0x0, 9, 4080}, | ||
690 | {22579200, 44100, 44100, 0x0, 8, 0}, | ||
691 | {33868800, 44100, 44100, 0x0, 5, 3333}, | ||
692 | /* 48k */ | ||
693 | {12000000, 48000, 48000, 0x0, 16, 3840}, | ||
694 | {19200000, 48000, 48000, 0x0, 10, 2400}, | ||
695 | {22579200, 48000, 48000, 0x0, 8, 7075}, | ||
696 | {33868800, 48000, 48000, 0x0, 5, 8049}, | ||
697 | /* 64k */ | ||
698 | {12000000, 64000, 96000, 0x1, 16, 3840}, | ||
699 | {19200000, 64000, 96000, 0x1, 10, 2400}, | ||
700 | {22579200, 64000, 96000, 0x1, 8, 7075}, | ||
701 | {33868800, 64000, 96000, 0x1, 5, 8049}, | ||
702 | /* 88.2k */ | ||
703 | {12000000, 88200, 88200, 0x0, 15, 528}, | ||
704 | {19200000, 88200, 88200, 0x0, 9, 4080}, | ||
705 | {22579200, 88200, 88200, 0x0, 8, 0}, | ||
706 | {33868800, 88200, 88200, 0x0, 5, 3333}, | ||
707 | /* 96k */ | ||
708 | {12000000, 96000, 96000, 0x0, 16, 3840}, | ||
709 | {19200000, 96000, 96000, 0x0, 10, 2400}, | ||
710 | {22579200, 96000, 96000, 0x0, 8, 7075}, | ||
711 | {33868800, 96000, 96000, 0x0, 5, 8049}, | ||
712 | }; | ||
713 | |||
714 | static inline int aic3x_get_divs(int mclk, int rate) | ||
715 | { | ||
716 | int i; | ||
717 | |||
718 | for (i = 0; i < ARRAY_SIZE(aic3x_divs); i++) { | ||
719 | if (aic3x_divs[i].rate == rate && aic3x_divs[i].mclk == mclk) | ||
720 | return i; | ||
721 | } | ||
722 | |||
723 | return 0; | ||
724 | } | ||
725 | |||
726 | static int aic3x_hw_params(struct snd_pcm_substream *substream, | 697 | static int aic3x_hw_params(struct snd_pcm_substream *substream, |
727 | struct snd_pcm_hw_params *params) | 698 | struct snd_pcm_hw_params *params) |
728 | { | 699 | { |
@@ -730,49 +701,107 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, | |||
730 | struct snd_soc_device *socdev = rtd->socdev; | 701 | struct snd_soc_device *socdev = rtd->socdev; |
731 | struct snd_soc_codec *codec = socdev->codec; | 702 | struct snd_soc_codec *codec = socdev->codec; |
732 | struct aic3x_priv *aic3x = codec->private_data; | 703 | struct aic3x_priv *aic3x = codec->private_data; |
733 | int i; | 704 | int codec_clk = 0, bypass_pll = 0, fsref, last_clk = 0; |
734 | u8 data, pll_p, pll_r, pll_j; | 705 | u8 data, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1; |
735 | u16 pll_d; | 706 | u16 pll_d = 1; |
736 | |||
737 | i = aic3x_get_divs(aic3x->sysclk, params_rate(params)); | ||
738 | 707 | ||
739 | /* Route Left DAC to left channel input and | 708 | /* select data word length */ |
740 | * right DAC to right channel input */ | 709 | data = |
741 | data = (LDAC2LCH | RDAC2RCH); | 710 | aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLB) & (~(0x3 << 4)); |
742 | switch (aic3x_divs[i].fsref_reg) { | 711 | switch (params_format(params)) { |
743 | case 44100: | 712 | case SNDRV_PCM_FORMAT_S16_LE: |
744 | data |= FSREF_44100; | ||
745 | break; | 713 | break; |
746 | case 48000: | 714 | case SNDRV_PCM_FORMAT_S20_3LE: |
747 | data |= FSREF_48000; | 715 | data |= (0x01 << 4); |
748 | break; | 716 | break; |
749 | case 88200: | 717 | case SNDRV_PCM_FORMAT_S24_LE: |
750 | data |= FSREF_44100 | DUAL_RATE_MODE; | 718 | data |= (0x02 << 4); |
751 | break; | 719 | break; |
752 | case 96000: | 720 | case SNDRV_PCM_FORMAT_S32_LE: |
753 | data |= FSREF_48000 | DUAL_RATE_MODE; | 721 | data |= (0x03 << 4); |
754 | break; | 722 | break; |
755 | } | 723 | } |
724 | aic3x_write(codec, AIC3X_ASD_INTF_CTRLB, data); | ||
725 | |||
726 | /* Fsref can be 44100 or 48000 */ | ||
727 | fsref = (params_rate(params) % 11025 == 0) ? 44100 : 48000; | ||
728 | |||
729 | /* Try to find a value for Q which allows us to bypass the PLL and | ||
730 | * generate CODEC_CLK directly. */ | ||
731 | for (pll_q = 2; pll_q < 18; pll_q++) | ||
732 | if (aic3x->sysclk / (128 * pll_q) == fsref) { | ||
733 | bypass_pll = 1; | ||
734 | break; | ||
735 | } | ||
736 | |||
737 | if (bypass_pll) { | ||
738 | pll_q &= 0xf; | ||
739 | aic3x_write(codec, AIC3X_PLL_PROGA_REG, pll_q << PLLQ_SHIFT); | ||
740 | aic3x_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_CLKDIV); | ||
741 | } else | ||
742 | aic3x_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_PLLDIV); | ||
743 | |||
744 | /* Route Left DAC to left channel input and | ||
745 | * right DAC to right channel input */ | ||
746 | data = (LDAC2LCH | RDAC2RCH); | ||
747 | data |= (fsref == 44100) ? FSREF_44100 : FSREF_48000; | ||
748 | if (params_rate(params) >= 64000) | ||
749 | data |= DUAL_RATE_MODE; | ||
756 | aic3x_write(codec, AIC3X_CODEC_DATAPATH_REG, data); | 750 | aic3x_write(codec, AIC3X_CODEC_DATAPATH_REG, data); |
757 | 751 | ||
758 | /* codec sample rate select */ | 752 | /* codec sample rate select */ |
759 | data = aic3x_divs[i].sr_reg; | 753 | data = (fsref * 20) / params_rate(params); |
754 | if (params_rate(params) < 64000) | ||
755 | data /= 2; | ||
756 | data /= 5; | ||
757 | data -= 2; | ||
760 | data |= (data << 4); | 758 | data |= (data << 4); |
761 | aic3x_write(codec, AIC3X_SAMPLE_RATE_SEL_REG, data); | 759 | aic3x_write(codec, AIC3X_SAMPLE_RATE_SEL_REG, data); |
762 | 760 | ||
763 | /* Use PLL for generation Fsref by equation: | 761 | if (bypass_pll) |
764 | * Fsref = (MCLK * K * R)/(2048 * P); | 762 | return 0; |
765 | * Fix P = 2 and R = 1 and calculate K, if | 763 | |
766 | * K = J.D, i.e. J - an interger portion of K and D is the fractional | 764 | /* Use PLL |
767 | * one with 4 digits of precision; | 765 | * find an apropriate setup for j, d, r and p by iterating over |
768 | * Example: | 766 | * p and r - j and d are calculated for each fraction. |
769 | * For MCLK = 22.5792 MHz and Fsref = 48kHz: | 767 | * Up to 128 values are probed, the closest one wins the game. |
770 | * Select P = 2, R= 1, K = 8.7074, which results in J = 8, D = 7074 | 768 | * The sysclk is divided by 1000 to prevent integer overflows. |
771 | */ | 769 | */ |
772 | pll_p = 2; | 770 | codec_clk = (2048 * fsref) / (aic3x->sysclk / 1000); |
773 | pll_r = 1; | 771 | |
774 | pll_j = aic3x_divs[i].pllj_reg; | 772 | for (r = 1; r <= 16; r++) |
775 | pll_d = aic3x_divs[i].plld_reg; | 773 | for (p = 1; p <= 8; p++) { |
774 | int clk, tmp = (codec_clk * pll_r * 10) / pll_p; | ||
775 | u8 j = tmp / 10000; | ||
776 | u16 d = tmp % 10000; | ||
777 | |||
778 | if (j > 63) | ||
779 | continue; | ||
780 | |||
781 | if (d != 0 && aic3x->sysclk < 10000000) | ||
782 | continue; | ||
783 | |||
784 | /* This is actually 1000 * ((j + (d/10000)) * r) / p | ||
785 | * The term had to be converted to get rid of the | ||
786 | * division by 10000 */ | ||
787 | clk = ((10000 * j * r) + (d * r)) / (10 * p); | ||
788 | |||
789 | /* check whether this values get closer than the best | ||
790 | * ones we had before */ | ||
791 | if (abs(codec_clk - clk) < abs(codec_clk - last_clk)) { | ||
792 | pll_j = j; pll_d = d; pll_r = r; pll_p = p; | ||
793 | last_clk = clk; | ||
794 | } | ||
795 | |||
796 | /* Early exit for exact matches */ | ||
797 | if (clk == codec_clk) | ||
798 | break; | ||
799 | } | ||
800 | |||
801 | if (last_clk == 0) { | ||
802 | printk(KERN_ERR "%s(): unable to setup PLL\n", __func__); | ||
803 | return -EINVAL; | ||
804 | } | ||
776 | 805 | ||
777 | data = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); | 806 | data = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); |
778 | aic3x_write(codec, AIC3X_PLL_PROGA_REG, data | (pll_p << PLLP_SHIFT)); | 807 | aic3x_write(codec, AIC3X_PLL_PROGA_REG, data | (pll_p << PLLP_SHIFT)); |
@@ -782,28 +811,10 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, | |||
782 | aic3x_write(codec, AIC3X_PLL_PROGD_REG, | 811 | aic3x_write(codec, AIC3X_PLL_PROGD_REG, |
783 | (pll_d & 0x3F) << PLLD_LSB_SHIFT); | 812 | (pll_d & 0x3F) << PLLD_LSB_SHIFT); |
784 | 813 | ||
785 | /* select data word length */ | ||
786 | data = | ||
787 | aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLB) & (~(0x3 << 4)); | ||
788 | switch (params_format(params)) { | ||
789 | case SNDRV_PCM_FORMAT_S16_LE: | ||
790 | break; | ||
791 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
792 | data |= (0x01 << 4); | ||
793 | break; | ||
794 | case SNDRV_PCM_FORMAT_S24_LE: | ||
795 | data |= (0x02 << 4); | ||
796 | break; | ||
797 | case SNDRV_PCM_FORMAT_S32_LE: | ||
798 | data |= (0x03 << 4); | ||
799 | break; | ||
800 | } | ||
801 | aic3x_write(codec, AIC3X_ASD_INTF_CTRLB, data); | ||
802 | |||
803 | return 0; | 814 | return 0; |
804 | } | 815 | } |
805 | 816 | ||
806 | static int aic3x_mute(struct snd_soc_codec_dai *dai, int mute) | 817 | static int aic3x_mute(struct snd_soc_dai *dai, int mute) |
807 | { | 818 | { |
808 | struct snd_soc_codec *codec = dai->codec; | 819 | struct snd_soc_codec *codec = dai->codec; |
809 | u8 ldac_reg = aic3x_read_reg_cache(codec, LDAC_VOL) & ~MUTE_ON; | 820 | u8 ldac_reg = aic3x_read_reg_cache(codec, LDAC_VOL) & ~MUTE_ON; |
@@ -820,31 +831,25 @@ static int aic3x_mute(struct snd_soc_codec_dai *dai, int mute) | |||
820 | return 0; | 831 | return 0; |
821 | } | 832 | } |
822 | 833 | ||
823 | static int aic3x_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai, | 834 | static int aic3x_set_dai_sysclk(struct snd_soc_dai *codec_dai, |
824 | int clk_id, unsigned int freq, int dir) | 835 | int clk_id, unsigned int freq, int dir) |
825 | { | 836 | { |
826 | struct snd_soc_codec *codec = codec_dai->codec; | 837 | struct snd_soc_codec *codec = codec_dai->codec; |
827 | struct aic3x_priv *aic3x = codec->private_data; | 838 | struct aic3x_priv *aic3x = codec->private_data; |
828 | 839 | ||
829 | switch (freq) { | 840 | aic3x->sysclk = freq; |
830 | case 12000000: | 841 | return 0; |
831 | case 19200000: | ||
832 | case 22579200: | ||
833 | case 33868800: | ||
834 | aic3x->sysclk = freq; | ||
835 | return 0; | ||
836 | } | ||
837 | |||
838 | return -EINVAL; | ||
839 | } | 842 | } |
840 | 843 | ||
841 | static int aic3x_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | 844 | static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai, |
842 | unsigned int fmt) | 845 | unsigned int fmt) |
843 | { | 846 | { |
844 | struct snd_soc_codec *codec = codec_dai->codec; | 847 | struct snd_soc_codec *codec = codec_dai->codec; |
845 | struct aic3x_priv *aic3x = codec->private_data; | 848 | struct aic3x_priv *aic3x = codec->private_data; |
846 | u8 iface_areg = 0; | 849 | u8 iface_areg, iface_breg; |
847 | u8 iface_breg = 0; | 850 | |
851 | iface_areg = aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLA) & 0x3f; | ||
852 | iface_breg = aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLB) & 0x3f; | ||
848 | 853 | ||
849 | /* set master/slave audio interface */ | 854 | /* set master/slave audio interface */ |
850 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | 855 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
@@ -883,13 +888,14 @@ static int aic3x_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | |||
883 | return 0; | 888 | return 0; |
884 | } | 889 | } |
885 | 890 | ||
886 | static int aic3x_dapm_event(struct snd_soc_codec *codec, int event) | 891 | static int aic3x_set_bias_level(struct snd_soc_codec *codec, |
892 | enum snd_soc_bias_level level) | ||
887 | { | 893 | { |
888 | struct aic3x_priv *aic3x = codec->private_data; | 894 | struct aic3x_priv *aic3x = codec->private_data; |
889 | u8 reg; | 895 | u8 reg; |
890 | 896 | ||
891 | switch (event) { | 897 | switch (level) { |
892 | case SNDRV_CTL_POWER_D0: | 898 | case SND_SOC_BIAS_ON: |
893 | /* all power is driven by DAPM system */ | 899 | /* all power is driven by DAPM system */ |
894 | if (aic3x->master) { | 900 | if (aic3x->master) { |
895 | /* enable pll */ | 901 | /* enable pll */ |
@@ -898,10 +904,9 @@ static int aic3x_dapm_event(struct snd_soc_codec *codec, int event) | |||
898 | reg | PLL_ENABLE); | 904 | reg | PLL_ENABLE); |
899 | } | 905 | } |
900 | break; | 906 | break; |
901 | case SNDRV_CTL_POWER_D1: | 907 | case SND_SOC_BIAS_PREPARE: |
902 | case SNDRV_CTL_POWER_D2: | ||
903 | break; | 908 | break; |
904 | case SNDRV_CTL_POWER_D3hot: | 909 | case SND_SOC_BIAS_STANDBY: |
905 | /* | 910 | /* |
906 | * all power is driven by DAPM system, | 911 | * all power is driven by DAPM system, |
907 | * so output power is safe if bypass was set | 912 | * so output power is safe if bypass was set |
@@ -913,7 +918,7 @@ static int aic3x_dapm_event(struct snd_soc_codec *codec, int event) | |||
913 | reg & ~PLL_ENABLE); | 918 | reg & ~PLL_ENABLE); |
914 | } | 919 | } |
915 | break; | 920 | break; |
916 | case SNDRV_CTL_POWER_D3cold: | 921 | case SND_SOC_BIAS_OFF: |
917 | /* force all power off */ | 922 | /* force all power off */ |
918 | reg = aic3x_read_reg_cache(codec, LINE1L_2_LADC_CTRL); | 923 | reg = aic3x_read_reg_cache(codec, LINE1L_2_LADC_CTRL); |
919 | aic3x_write(codec, LINE1L_2_LADC_CTRL, reg & ~LADC_PWR_ON); | 924 | aic3x_write(codec, LINE1L_2_LADC_CTRL, reg & ~LADC_PWR_ON); |
@@ -949,16 +954,43 @@ static int aic3x_dapm_event(struct snd_soc_codec *codec, int event) | |||
949 | } | 954 | } |
950 | break; | 955 | break; |
951 | } | 956 | } |
952 | codec->dapm_state = event; | 957 | codec->bias_level = level; |
953 | 958 | ||
954 | return 0; | 959 | return 0; |
955 | } | 960 | } |
956 | 961 | ||
962 | void aic3x_set_gpio(struct snd_soc_codec *codec, int gpio, int state) | ||
963 | { | ||
964 | u8 reg = gpio ? AIC3X_GPIO2_REG : AIC3X_GPIO1_REG; | ||
965 | u8 bit = gpio ? 3: 0; | ||
966 | u8 val = aic3x_read_reg_cache(codec, reg) & ~(1 << bit); | ||
967 | aic3x_write(codec, reg, val | (!!state << bit)); | ||
968 | } | ||
969 | EXPORT_SYMBOL_GPL(aic3x_set_gpio); | ||
970 | |||
971 | int aic3x_get_gpio(struct snd_soc_codec *codec, int gpio) | ||
972 | { | ||
973 | u8 reg = gpio ? AIC3X_GPIO2_REG : AIC3X_GPIO1_REG; | ||
974 | u8 val, bit = gpio ? 2: 1; | ||
975 | |||
976 | aic3x_read(codec, reg, &val); | ||
977 | return (val >> bit) & 1; | ||
978 | } | ||
979 | EXPORT_SYMBOL_GPL(aic3x_get_gpio); | ||
980 | |||
981 | int aic3x_headset_detected(struct snd_soc_codec *codec) | ||
982 | { | ||
983 | u8 val; | ||
984 | aic3x_read(codec, AIC3X_RT_IRQ_FLAGS_REG, &val); | ||
985 | return (val >> 2) & 1; | ||
986 | } | ||
987 | EXPORT_SYMBOL_GPL(aic3x_headset_detected); | ||
988 | |||
957 | #define AIC3X_RATES SNDRV_PCM_RATE_8000_96000 | 989 | #define AIC3X_RATES SNDRV_PCM_RATE_8000_96000 |
958 | #define AIC3X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ | 990 | #define AIC3X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ |
959 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) | 991 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) |
960 | 992 | ||
961 | struct snd_soc_codec_dai aic3x_dai = { | 993 | struct snd_soc_dai aic3x_dai = { |
962 | .name = "aic3x", | 994 | .name = "aic3x", |
963 | .playback = { | 995 | .playback = { |
964 | .stream_name = "Playback", | 996 | .stream_name = "Playback", |
@@ -988,7 +1020,7 @@ static int aic3x_suspend(struct platform_device *pdev, pm_message_t state) | |||
988 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1020 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
989 | struct snd_soc_codec *codec = socdev->codec; | 1021 | struct snd_soc_codec *codec = socdev->codec; |
990 | 1022 | ||
991 | aic3x_dapm_event(codec, SNDRV_CTL_POWER_D3cold); | 1023 | aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF); |
992 | 1024 | ||
993 | return 0; | 1025 | return 0; |
994 | } | 1026 | } |
@@ -1008,7 +1040,7 @@ static int aic3x_resume(struct platform_device *pdev) | |||
1008 | codec->hw_write(codec->control_data, data, 2); | 1040 | codec->hw_write(codec->control_data, data, 2); |
1009 | } | 1041 | } |
1010 | 1042 | ||
1011 | aic3x_dapm_event(codec, codec->suspend_dapm_state); | 1043 | aic3x_set_bias_level(codec, codec->suspend_bias_level); |
1012 | 1044 | ||
1013 | return 0; | 1045 | return 0; |
1014 | } | 1046 | } |
@@ -1020,16 +1052,17 @@ static int aic3x_resume(struct platform_device *pdev) | |||
1020 | static int aic3x_init(struct snd_soc_device *socdev) | 1052 | static int aic3x_init(struct snd_soc_device *socdev) |
1021 | { | 1053 | { |
1022 | struct snd_soc_codec *codec = socdev->codec; | 1054 | struct snd_soc_codec *codec = socdev->codec; |
1055 | struct aic3x_setup_data *setup = socdev->codec_data; | ||
1023 | int reg, ret = 0; | 1056 | int reg, ret = 0; |
1024 | 1057 | ||
1025 | codec->name = "aic3x"; | 1058 | codec->name = "aic3x"; |
1026 | codec->owner = THIS_MODULE; | 1059 | codec->owner = THIS_MODULE; |
1027 | codec->read = aic3x_read_reg_cache; | 1060 | codec->read = aic3x_read_reg_cache; |
1028 | codec->write = aic3x_write; | 1061 | codec->write = aic3x_write; |
1029 | codec->dapm_event = aic3x_dapm_event; | 1062 | codec->set_bias_level = aic3x_set_bias_level; |
1030 | codec->dai = &aic3x_dai; | 1063 | codec->dai = &aic3x_dai; |
1031 | codec->num_dai = 1; | 1064 | codec->num_dai = 1; |
1032 | codec->reg_cache_size = sizeof(aic3x_reg); | 1065 | codec->reg_cache_size = ARRAY_SIZE(aic3x_reg); |
1033 | codec->reg_cache = kmemdup(aic3x_reg, sizeof(aic3x_reg), GFP_KERNEL); | 1066 | codec->reg_cache = kmemdup(aic3x_reg, sizeof(aic3x_reg), GFP_KERNEL); |
1034 | if (codec->reg_cache == NULL) | 1067 | if (codec->reg_cache == NULL) |
1035 | return -ENOMEM; | 1068 | return -ENOMEM; |
@@ -1108,7 +1141,11 @@ static int aic3x_init(struct snd_soc_device *socdev) | |||
1108 | aic3x_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL); | 1141 | aic3x_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL); |
1109 | 1142 | ||
1110 | /* off, with power on */ | 1143 | /* off, with power on */ |
1111 | aic3x_dapm_event(codec, SNDRV_CTL_POWER_D3hot); | 1144 | aic3x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
1145 | |||
1146 | /* setup GPIO functions */ | ||
1147 | aic3x_write(codec, AIC3X_GPIO1_REG, (setup->gpio_func[0] & 0xf) << 4); | ||
1148 | aic3x_write(codec, AIC3X_GPIO2_REG, (setup->gpio_func[1] & 0xf) << 4); | ||
1112 | 1149 | ||
1113 | aic3x_add_controls(codec); | 1150 | aic3x_add_controls(codec); |
1114 | aic3x_add_widgets(codec); | 1151 | aic3x_add_widgets(codec); |
@@ -1217,6 +1254,12 @@ static struct i2c_client client_template = { | |||
1217 | .name = "AIC3X", | 1254 | .name = "AIC3X", |
1218 | .driver = &aic3x_i2c_driver, | 1255 | .driver = &aic3x_i2c_driver, |
1219 | }; | 1256 | }; |
1257 | |||
1258 | static int aic3x_i2c_read(struct i2c_client *client, u8 *value, int len) | ||
1259 | { | ||
1260 | value[0] = i2c_smbus_read_byte_data(client, value[0]); | ||
1261 | return (len == 1); | ||
1262 | } | ||
1220 | #endif | 1263 | #endif |
1221 | 1264 | ||
1222 | static int aic3x_probe(struct platform_device *pdev) | 1265 | static int aic3x_probe(struct platform_device *pdev) |
@@ -1251,6 +1294,7 @@ static int aic3x_probe(struct platform_device *pdev) | |||
1251 | if (setup->i2c_address) { | 1294 | if (setup->i2c_address) { |
1252 | normal_i2c[0] = setup->i2c_address; | 1295 | normal_i2c[0] = setup->i2c_address; |
1253 | codec->hw_write = (hw_write_t) i2c_master_send; | 1296 | codec->hw_write = (hw_write_t) i2c_master_send; |
1297 | codec->hw_read = (hw_read_t) aic3x_i2c_read; | ||
1254 | ret = i2c_add_driver(&aic3x_i2c_driver); | 1298 | ret = i2c_add_driver(&aic3x_i2c_driver); |
1255 | if (ret != 0) | 1299 | if (ret != 0) |
1256 | printk(KERN_ERR "can't add i2c driver"); | 1300 | printk(KERN_ERR "can't add i2c driver"); |
@@ -1268,7 +1312,7 @@ static int aic3x_remove(struct platform_device *pdev) | |||
1268 | 1312 | ||
1269 | /* power down chip */ | 1313 | /* power down chip */ |
1270 | if (codec->control_data) | 1314 | if (codec->control_data) |
1271 | aic3x_dapm_event(codec, SNDRV_CTL_POWER_D3); | 1315 | aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF); |
1272 | 1316 | ||
1273 | snd_soc_free_pcms(socdev); | 1317 | snd_soc_free_pcms(socdev); |
1274 | snd_soc_dapm_free(socdev); | 1318 | snd_soc_dapm_free(socdev); |
diff --git a/sound/soc/codecs/tlv320aic3x.h b/sound/soc/codecs/tlv320aic3x.h index d0cdeeb629de..d76c079b86e7 100644 --- a/sound/soc/codecs/tlv320aic3x.h +++ b/sound/soc/codecs/tlv320aic3x.h | |||
@@ -37,6 +37,8 @@ | |||
37 | #define AIC3X_ASD_INTF_CTRLB 9 | 37 | #define AIC3X_ASD_INTF_CTRLB 9 |
38 | /* Audio overflow status and PLL R value programming register */ | 38 | /* Audio overflow status and PLL R value programming register */ |
39 | #define AIC3X_OVRF_STATUS_AND_PLLR_REG 11 | 39 | #define AIC3X_OVRF_STATUS_AND_PLLR_REG 11 |
40 | /* Audio codec digital filter control register */ | ||
41 | #define AIC3X_CODEC_DFILT_CTRL 12 | ||
40 | 42 | ||
41 | /* ADC PGA Gain control registers */ | 43 | /* ADC PGA Gain control registers */ |
42 | #define LADC_VOL 15 | 44 | #define LADC_VOL 15 |
@@ -108,6 +110,13 @@ | |||
108 | #define DACR1_2_RLOPM_VOL 92 | 110 | #define DACR1_2_RLOPM_VOL 92 |
109 | #define LLOPM_CTRL 86 | 111 | #define LLOPM_CTRL 86 |
110 | #define RLOPM_CTRL 93 | 112 | #define RLOPM_CTRL 93 |
113 | /* GPIO/IRQ registers */ | ||
114 | #define AIC3X_STICKY_IRQ_FLAGS_REG 96 | ||
115 | #define AIC3X_RT_IRQ_FLAGS_REG 97 | ||
116 | #define AIC3X_GPIO1_REG 98 | ||
117 | #define AIC3X_GPIO2_REG 99 | ||
118 | #define AIC3X_GPIOA_REG 100 | ||
119 | #define AIC3X_GPIOB_REG 101 | ||
111 | /* Clock generation control register */ | 120 | /* Clock generation control register */ |
112 | #define AIC3X_CLKGEN_CTRL_REG 102 | 121 | #define AIC3X_CLKGEN_CTRL_REG 102 |
113 | 122 | ||
@@ -128,12 +137,15 @@ | |||
128 | 137 | ||
129 | /* PLL registers bitfields */ | 138 | /* PLL registers bitfields */ |
130 | #define PLLP_SHIFT 0 | 139 | #define PLLP_SHIFT 0 |
140 | #define PLLQ_SHIFT 3 | ||
131 | #define PLLR_SHIFT 0 | 141 | #define PLLR_SHIFT 0 |
132 | #define PLLJ_SHIFT 2 | 142 | #define PLLJ_SHIFT 2 |
133 | #define PLLD_MSB_SHIFT 0 | 143 | #define PLLD_MSB_SHIFT 0 |
134 | #define PLLD_LSB_SHIFT 2 | 144 | #define PLLD_LSB_SHIFT 2 |
135 | 145 | ||
136 | /* Clock generation register bits */ | 146 | /* Clock generation register bits */ |
147 | #define CODEC_CLKIN_PLLDIV 0 | ||
148 | #define CODEC_CLKIN_CLKDIV 1 | ||
137 | #define PLL_CLKIN_SHIFT 4 | 149 | #define PLL_CLKIN_SHIFT 4 |
138 | #define MCLK_SOURCE 0x0 | 150 | #define MCLK_SOURCE 0x0 |
139 | #define PLL_CLKDIV_SHIFT 0 | 151 | #define PLL_CLKDIV_SHIFT 0 |
@@ -171,11 +183,52 @@ | |||
171 | /* Default input volume */ | 183 | /* Default input volume */ |
172 | #define DEFAULT_GAIN 0x20 | 184 | #define DEFAULT_GAIN 0x20 |
173 | 185 | ||
186 | /* GPIO API */ | ||
187 | enum { | ||
188 | AIC3X_GPIO1_FUNC_DISABLED = 0, | ||
189 | AIC3X_GPIO1_FUNC_AUDIO_WORDCLK_ADC = 1, | ||
190 | AIC3X_GPIO1_FUNC_CLOCK_MUX = 2, | ||
191 | AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV2 = 3, | ||
192 | AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV4 = 4, | ||
193 | AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV8 = 5, | ||
194 | AIC3X_GPIO1_FUNC_SHORT_CIRCUIT_IRQ = 6, | ||
195 | AIC3X_GPIO1_FUNC_AGC_NOISE_IRQ = 7, | ||
196 | AIC3X_GPIO1_FUNC_INPUT = 8, | ||
197 | AIC3X_GPIO1_FUNC_OUTPUT = 9, | ||
198 | AIC3X_GPIO1_FUNC_DIGITAL_MIC_MODCLK = 10, | ||
199 | AIC3X_GPIO1_FUNC_AUDIO_WORDCLK = 11, | ||
200 | AIC3X_GPIO1_FUNC_BUTTON_IRQ = 12, | ||
201 | AIC3X_GPIO1_FUNC_HEADSET_DETECT_IRQ = 13, | ||
202 | AIC3X_GPIO1_FUNC_HEADSET_DETECT_OR_BUTTON_IRQ = 14, | ||
203 | AIC3X_GPIO1_FUNC_ALL_IRQ = 16 | ||
204 | }; | ||
205 | |||
206 | enum { | ||
207 | AIC3X_GPIO2_FUNC_DISABLED = 0, | ||
208 | AIC3X_GPIO2_FUNC_HEADSET_DETECT_IRQ = 2, | ||
209 | AIC3X_GPIO2_FUNC_INPUT = 3, | ||
210 | AIC3X_GPIO2_FUNC_OUTPUT = 4, | ||
211 | AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT = 5, | ||
212 | AIC3X_GPIO2_FUNC_AUDIO_BITCLK = 8, | ||
213 | AIC3X_GPIO2_FUNC_HEADSET_DETECT_OR_BUTTON_IRQ = 9, | ||
214 | AIC3X_GPIO2_FUNC_ALL_IRQ = 10, | ||
215 | AIC3X_GPIO2_FUNC_SHORT_CIRCUIT_OR_AGC_IRQ = 11, | ||
216 | AIC3X_GPIO2_FUNC_HEADSET_OR_BUTTON_PRESS_OR_SHORT_CIRCUIT_IRQ = 12, | ||
217 | AIC3X_GPIO2_FUNC_SHORT_CIRCUIT_IRQ = 13, | ||
218 | AIC3X_GPIO2_FUNC_AGC_NOISE_IRQ = 14, | ||
219 | AIC3X_GPIO2_FUNC_BUTTON_PRESS_IRQ = 15 | ||
220 | }; | ||
221 | |||
222 | void aic3x_set_gpio(struct snd_soc_codec *codec, int gpio, int state); | ||
223 | int aic3x_get_gpio(struct snd_soc_codec *codec, int gpio); | ||
224 | int aic3x_headset_detected(struct snd_soc_codec *codec); | ||
225 | |||
174 | struct aic3x_setup_data { | 226 | struct aic3x_setup_data { |
175 | unsigned short i2c_address; | 227 | unsigned short i2c_address; |
228 | unsigned int gpio_func[2]; | ||
176 | }; | 229 | }; |
177 | 230 | ||
178 | extern struct snd_soc_codec_dai aic3x_dai; | 231 | extern struct snd_soc_dai aic3x_dai; |
179 | extern struct snd_soc_codec_device soc_codec_dev_aic3x; | 232 | extern struct snd_soc_codec_device soc_codec_dev_aic3x; |
180 | 233 | ||
181 | #endif /* _AIC3X_H */ | 234 | #endif /* _AIC3X_H */ |
diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c new file mode 100644 index 000000000000..a52d6d9e007a --- /dev/null +++ b/sound/soc/codecs/uda1380.c | |||
@@ -0,0 +1,852 @@ | |||
1 | /* | ||
2 | * uda1380.c - Philips UDA1380 ALSA SoC audio driver | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * Copyright (c) 2007 Philipp Zabel <philipp.zabel@gmail.com> | ||
9 | * Improved support for DAPM and audio routing/mixing capabilities, | ||
10 | * added TLV support. | ||
11 | * | ||
12 | * Modified by Richard Purdie <richard@openedhand.com> to fit into SoC | ||
13 | * codec model. | ||
14 | * | ||
15 | * Copyright (c) 2005 Giorgio Padrin <giorgio@mandarinlogiq.org> | ||
16 | * Copyright 2005 Openedhand Ltd. | ||
17 | */ | ||
18 | |||
19 | #include <linux/module.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/types.h> | ||
22 | #include <linux/string.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/errno.h> | ||
25 | #include <linux/ioctl.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <linux/i2c.h> | ||
28 | #include <sound/core.h> | ||
29 | #include <sound/control.h> | ||
30 | #include <sound/initval.h> | ||
31 | #include <sound/info.h> | ||
32 | #include <sound/soc.h> | ||
33 | #include <sound/soc-dapm.h> | ||
34 | #include <sound/tlv.h> | ||
35 | |||
36 | #include "uda1380.h" | ||
37 | |||
38 | #define UDA1380_VERSION "0.6" | ||
39 | #define AUDIO_NAME "uda1380" | ||
40 | |||
41 | /* | ||
42 | * uda1380 register cache | ||
43 | */ | ||
44 | static const u16 uda1380_reg[UDA1380_CACHEREGNUM] = { | ||
45 | 0x0502, 0x0000, 0x0000, 0x3f3f, | ||
46 | 0x0202, 0x0000, 0x0000, 0x0000, | ||
47 | 0x0000, 0x0000, 0x0000, 0x0000, | ||
48 | 0x0000, 0x0000, 0x0000, 0x0000, | ||
49 | 0x0000, 0xff00, 0x0000, 0x4800, | ||
50 | 0x0000, 0x0000, 0x0000, 0x0000, | ||
51 | 0x0000, 0x0000, 0x0000, 0x0000, | ||
52 | 0x0000, 0x0000, 0x0000, 0x0000, | ||
53 | 0x0000, 0x8000, 0x0002, 0x0000, | ||
54 | }; | ||
55 | |||
56 | /* | ||
57 | * read uda1380 register cache | ||
58 | */ | ||
59 | static inline unsigned int uda1380_read_reg_cache(struct snd_soc_codec *codec, | ||
60 | unsigned int reg) | ||
61 | { | ||
62 | u16 *cache = codec->reg_cache; | ||
63 | if (reg == UDA1380_RESET) | ||
64 | return 0; | ||
65 | if (reg >= UDA1380_CACHEREGNUM) | ||
66 | return -1; | ||
67 | return cache[reg]; | ||
68 | } | ||
69 | |||
70 | /* | ||
71 | * write uda1380 register cache | ||
72 | */ | ||
73 | static inline void uda1380_write_reg_cache(struct snd_soc_codec *codec, | ||
74 | u16 reg, unsigned int value) | ||
75 | { | ||
76 | u16 *cache = codec->reg_cache; | ||
77 | if (reg >= UDA1380_CACHEREGNUM) | ||
78 | return; | ||
79 | cache[reg] = value; | ||
80 | } | ||
81 | |||
82 | /* | ||
83 | * write to the UDA1380 register space | ||
84 | */ | ||
85 | static int uda1380_write(struct snd_soc_codec *codec, unsigned int reg, | ||
86 | unsigned int value) | ||
87 | { | ||
88 | u8 data[3]; | ||
89 | |||
90 | /* data is | ||
91 | * data[0] is register offset | ||
92 | * data[1] is MS byte | ||
93 | * data[2] is LS byte | ||
94 | */ | ||
95 | data[0] = reg; | ||
96 | data[1] = (value & 0xff00) >> 8; | ||
97 | data[2] = value & 0x00ff; | ||
98 | |||
99 | uda1380_write_reg_cache(codec, reg, value); | ||
100 | |||
101 | /* the interpolator & decimator regs must only be written when the | ||
102 | * codec DAI is active. | ||
103 | */ | ||
104 | if (!codec->active && (reg >= UDA1380_MVOL)) | ||
105 | return 0; | ||
106 | pr_debug("uda1380: hw write %x val %x\n", reg, value); | ||
107 | if (codec->hw_write(codec->control_data, data, 3) == 3) { | ||
108 | unsigned int val; | ||
109 | i2c_master_send(codec->control_data, data, 1); | ||
110 | i2c_master_recv(codec->control_data, data, 2); | ||
111 | val = (data[0]<<8) | data[1]; | ||
112 | if (val != value) { | ||
113 | pr_debug("uda1380: READ BACK VAL %x\n", | ||
114 | (data[0]<<8) | data[1]); | ||
115 | return -EIO; | ||
116 | } | ||
117 | return 0; | ||
118 | } else | ||
119 | return -EIO; | ||
120 | } | ||
121 | |||
122 | #define uda1380_reset(c) uda1380_write(c, UDA1380_RESET, 0) | ||
123 | |||
124 | /* declarations of ALSA reg_elem_REAL controls */ | ||
125 | static const char *uda1380_deemp[] = { | ||
126 | "None", | ||
127 | "32kHz", | ||
128 | "44.1kHz", | ||
129 | "48kHz", | ||
130 | "96kHz", | ||
131 | }; | ||
132 | static const char *uda1380_input_sel[] = { | ||
133 | "Line", | ||
134 | "Mic + Line R", | ||
135 | "Line L", | ||
136 | "Mic", | ||
137 | }; | ||
138 | static const char *uda1380_output_sel[] = { | ||
139 | "DAC", | ||
140 | "Analog Mixer", | ||
141 | }; | ||
142 | static const char *uda1380_spf_mode[] = { | ||
143 | "Flat", | ||
144 | "Minimum1", | ||
145 | "Minimum2", | ||
146 | "Maximum" | ||
147 | }; | ||
148 | static const char *uda1380_capture_sel[] = { | ||
149 | "ADC", | ||
150 | "Digital Mixer" | ||
151 | }; | ||
152 | static const char *uda1380_sel_ns[] = { | ||
153 | "3rd-order", | ||
154 | "5th-order" | ||
155 | }; | ||
156 | static const char *uda1380_mix_control[] = { | ||
157 | "off", | ||
158 | "PCM only", | ||
159 | "before sound processing", | ||
160 | "after sound processing" | ||
161 | }; | ||
162 | static const char *uda1380_sdet_setting[] = { | ||
163 | "3200", | ||
164 | "4800", | ||
165 | "9600", | ||
166 | "19200" | ||
167 | }; | ||
168 | static const char *uda1380_os_setting[] = { | ||
169 | "single-speed", | ||
170 | "double-speed (no mixing)", | ||
171 | "quad-speed (no mixing)" | ||
172 | }; | ||
173 | |||
174 | static const struct soc_enum uda1380_deemp_enum[] = { | ||
175 | SOC_ENUM_SINGLE(UDA1380_DEEMP, 8, 5, uda1380_deemp), | ||
176 | SOC_ENUM_SINGLE(UDA1380_DEEMP, 0, 5, uda1380_deemp), | ||
177 | }; | ||
178 | static const struct soc_enum uda1380_input_sel_enum = | ||
179 | SOC_ENUM_SINGLE(UDA1380_ADC, 2, 4, uda1380_input_sel); /* SEL_MIC, SEL_LNA */ | ||
180 | static const struct soc_enum uda1380_output_sel_enum = | ||
181 | SOC_ENUM_SINGLE(UDA1380_PM, 7, 2, uda1380_output_sel); /* R02_EN_AVC */ | ||
182 | static const struct soc_enum uda1380_spf_enum = | ||
183 | SOC_ENUM_SINGLE(UDA1380_MODE, 14, 4, uda1380_spf_mode); /* M */ | ||
184 | static const struct soc_enum uda1380_capture_sel_enum = | ||
185 | SOC_ENUM_SINGLE(UDA1380_IFACE, 6, 2, uda1380_capture_sel); /* SEL_SOURCE */ | ||
186 | static const struct soc_enum uda1380_sel_ns_enum = | ||
187 | SOC_ENUM_SINGLE(UDA1380_MIXER, 14, 2, uda1380_sel_ns); /* SEL_NS */ | ||
188 | static const struct soc_enum uda1380_mix_enum = | ||
189 | SOC_ENUM_SINGLE(UDA1380_MIXER, 12, 4, uda1380_mix_control); /* MIX, MIX_POS */ | ||
190 | static const struct soc_enum uda1380_sdet_enum = | ||
191 | SOC_ENUM_SINGLE(UDA1380_MIXER, 4, 4, uda1380_sdet_setting); /* SD_VALUE */ | ||
192 | static const struct soc_enum uda1380_os_enum = | ||
193 | SOC_ENUM_SINGLE(UDA1380_MIXER, 0, 3, uda1380_os_setting); /* OS */ | ||
194 | |||
195 | /* | ||
196 | * from -48 dB in 1.5 dB steps (mute instead of -49.5 dB) | ||
197 | */ | ||
198 | static DECLARE_TLV_DB_SCALE(amix_tlv, -4950, 150, 1); | ||
199 | |||
200 | /* | ||
201 | * from -78 dB in 1 dB steps (3 dB steps, really. LSB are ignored), | ||
202 | * from -66 dB in 0.5 dB steps (2 dB steps, really) and | ||
203 | * from -52 dB in 0.25 dB steps | ||
204 | */ | ||
205 | static const unsigned int mvol_tlv[] = { | ||
206 | TLV_DB_RANGE_HEAD(3), | ||
207 | 0, 15, TLV_DB_SCALE_ITEM(-8200, 100, 1), | ||
208 | 16, 43, TLV_DB_SCALE_ITEM(-6600, 50, 0), | ||
209 | 44, 252, TLV_DB_SCALE_ITEM(-5200, 25, 0), | ||
210 | }; | ||
211 | |||
212 | /* | ||
213 | * from -72 dB in 1.5 dB steps (6 dB steps really), | ||
214 | * from -66 dB in 0.75 dB steps (3 dB steps really), | ||
215 | * from -60 dB in 0.5 dB steps (2 dB steps really) and | ||
216 | * from -46 dB in 0.25 dB steps | ||
217 | */ | ||
218 | static const unsigned int vc_tlv[] = { | ||
219 | TLV_DB_RANGE_HEAD(4), | ||
220 | 0, 7, TLV_DB_SCALE_ITEM(-7800, 150, 1), | ||
221 | 8, 15, TLV_DB_SCALE_ITEM(-6600, 75, 0), | ||
222 | 16, 43, TLV_DB_SCALE_ITEM(-6000, 50, 0), | ||
223 | 44, 228, TLV_DB_SCALE_ITEM(-4600, 25, 0), | ||
224 | }; | ||
225 | |||
226 | /* from 0 to 6 dB in 2 dB steps if SPF mode != flat */ | ||
227 | static DECLARE_TLV_DB_SCALE(tr_tlv, 0, 200, 0); | ||
228 | |||
229 | /* from 0 to 24 dB in 2 dB steps, if SPF mode == maximum, otherwise cuts | ||
230 | * off at 18 dB max) */ | ||
231 | static DECLARE_TLV_DB_SCALE(bb_tlv, 0, 200, 0); | ||
232 | |||
233 | /* from -63 to 24 dB in 0.5 dB steps (-128...48) */ | ||
234 | static DECLARE_TLV_DB_SCALE(dec_tlv, -6400, 50, 1); | ||
235 | |||
236 | /* from 0 to 24 dB in 3 dB steps */ | ||
237 | static DECLARE_TLV_DB_SCALE(pga_tlv, 0, 300, 0); | ||
238 | |||
239 | /* from 0 to 30 dB in 2 dB steps */ | ||
240 | static DECLARE_TLV_DB_SCALE(vga_tlv, 0, 200, 0); | ||
241 | |||
242 | static const struct snd_kcontrol_new uda1380_snd_controls[] = { | ||
243 | SOC_DOUBLE_TLV("Analog Mixer Volume", UDA1380_AMIX, 0, 8, 44, 1, amix_tlv), /* AVCR, AVCL */ | ||
244 | SOC_DOUBLE_TLV("Master Playback Volume", UDA1380_MVOL, 0, 8, 252, 1, mvol_tlv), /* MVCL, MVCR */ | ||
245 | SOC_SINGLE_TLV("ADC Playback Volume", UDA1380_MIXVOL, 8, 228, 1, vc_tlv), /* VC2 */ | ||
246 | SOC_SINGLE_TLV("PCM Playback Volume", UDA1380_MIXVOL, 0, 228, 1, vc_tlv), /* VC1 */ | ||
247 | SOC_ENUM("Sound Processing Filter", uda1380_spf_enum), /* M */ | ||
248 | SOC_DOUBLE_TLV("Tone Control - Treble", UDA1380_MODE, 4, 12, 3, 0, tr_tlv), /* TRL, TRR */ | ||
249 | SOC_DOUBLE_TLV("Tone Control - Bass", UDA1380_MODE, 0, 8, 15, 0, bb_tlv), /* BBL, BBR */ | ||
250 | /**/ SOC_SINGLE("Master Playback Switch", UDA1380_DEEMP, 14, 1, 1), /* MTM */ | ||
251 | SOC_SINGLE("ADC Playback Switch", UDA1380_DEEMP, 11, 1, 1), /* MT2 from decimation filter */ | ||
252 | SOC_ENUM("ADC Playback De-emphasis", uda1380_deemp_enum[0]), /* DE2 */ | ||
253 | SOC_SINGLE("PCM Playback Switch", UDA1380_DEEMP, 3, 1, 1), /* MT1, from digital data input */ | ||
254 | SOC_ENUM("PCM Playback De-emphasis", uda1380_deemp_enum[1]), /* DE1 */ | ||
255 | SOC_SINGLE("DAC Polarity inverting Switch", UDA1380_MIXER, 15, 1, 0), /* DA_POL_INV */ | ||
256 | SOC_ENUM("Noise Shaper", uda1380_sel_ns_enum), /* SEL_NS */ | ||
257 | SOC_ENUM("Digital Mixer Signal Control", uda1380_mix_enum), /* MIX_POS, MIX */ | ||
258 | SOC_SINGLE("Silence Switch", UDA1380_MIXER, 7, 1, 0), /* SILENCE, force DAC output to silence */ | ||
259 | SOC_SINGLE("Silence Detector Switch", UDA1380_MIXER, 6, 1, 0), /* SDET_ON */ | ||
260 | SOC_ENUM("Silence Detector Setting", uda1380_sdet_enum), /* SD_VALUE */ | ||
261 | SOC_ENUM("Oversampling Input", uda1380_os_enum), /* OS */ | ||
262 | SOC_DOUBLE_S8_TLV("ADC Capture Volume", UDA1380_DEC, -128, 48, dec_tlv), /* ML_DEC, MR_DEC */ | ||
263 | /**/ SOC_SINGLE("ADC Capture Switch", UDA1380_PGA, 15, 1, 1), /* MT_ADC */ | ||
264 | SOC_DOUBLE_TLV("Line Capture Volume", UDA1380_PGA, 0, 8, 8, 0, pga_tlv), /* PGA_GAINCTRLL, PGA_GAINCTRLR */ | ||
265 | SOC_SINGLE("ADC Polarity inverting Switch", UDA1380_ADC, 12, 1, 0), /* ADCPOL_INV */ | ||
266 | SOC_SINGLE_TLV("Mic Capture Volume", UDA1380_ADC, 8, 15, 0, vga_tlv), /* VGA_CTRL */ | ||
267 | SOC_SINGLE("DC Filter Bypass Switch", UDA1380_ADC, 1, 1, 0), /* SKIP_DCFIL (before decimator) */ | ||
268 | SOC_SINGLE("DC Filter Enable Switch", UDA1380_ADC, 0, 1, 0), /* EN_DCFIL (at output of decimator) */ | ||
269 | SOC_SINGLE("AGC Timing", UDA1380_AGC, 8, 7, 0), /* TODO: enum, see table 62 */ | ||
270 | SOC_SINGLE("AGC Target level", UDA1380_AGC, 2, 3, 1), /* AGC_LEVEL */ | ||
271 | /* -5.5, -8, -11.5, -14 dBFS */ | ||
272 | SOC_SINGLE("AGC Switch", UDA1380_AGC, 0, 1, 0), | ||
273 | }; | ||
274 | |||
275 | /* add non dapm controls */ | ||
276 | static int uda1380_add_controls(struct snd_soc_codec *codec) | ||
277 | { | ||
278 | int err, i; | ||
279 | |||
280 | for (i = 0; i < ARRAY_SIZE(uda1380_snd_controls); i++) { | ||
281 | err = snd_ctl_add(codec->card, | ||
282 | snd_soc_cnew(&uda1380_snd_controls[i], codec, NULL)); | ||
283 | if (err < 0) | ||
284 | return err; | ||
285 | } | ||
286 | |||
287 | return 0; | ||
288 | } | ||
289 | |||
290 | /* Input mux */ | ||
291 | static const struct snd_kcontrol_new uda1380_input_mux_control = | ||
292 | SOC_DAPM_ENUM("Route", uda1380_input_sel_enum); | ||
293 | |||
294 | /* Output mux */ | ||
295 | static const struct snd_kcontrol_new uda1380_output_mux_control = | ||
296 | SOC_DAPM_ENUM("Route", uda1380_output_sel_enum); | ||
297 | |||
298 | /* Capture mux */ | ||
299 | static const struct snd_kcontrol_new uda1380_capture_mux_control = | ||
300 | SOC_DAPM_ENUM("Route", uda1380_capture_sel_enum); | ||
301 | |||
302 | |||
303 | static const struct snd_soc_dapm_widget uda1380_dapm_widgets[] = { | ||
304 | SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, | ||
305 | &uda1380_input_mux_control), | ||
306 | SND_SOC_DAPM_MUX("Output Mux", SND_SOC_NOPM, 0, 0, | ||
307 | &uda1380_output_mux_control), | ||
308 | SND_SOC_DAPM_MUX("Capture Mux", SND_SOC_NOPM, 0, 0, | ||
309 | &uda1380_capture_mux_control), | ||
310 | SND_SOC_DAPM_PGA("Left PGA", UDA1380_PM, 3, 0, NULL, 0), | ||
311 | SND_SOC_DAPM_PGA("Right PGA", UDA1380_PM, 1, 0, NULL, 0), | ||
312 | SND_SOC_DAPM_PGA("Mic LNA", UDA1380_PM, 4, 0, NULL, 0), | ||
313 | SND_SOC_DAPM_ADC("Left ADC", "Left Capture", UDA1380_PM, 2, 0), | ||
314 | SND_SOC_DAPM_ADC("Right ADC", "Right Capture", UDA1380_PM, 0, 0), | ||
315 | SND_SOC_DAPM_INPUT("VINM"), | ||
316 | SND_SOC_DAPM_INPUT("VINL"), | ||
317 | SND_SOC_DAPM_INPUT("VINR"), | ||
318 | SND_SOC_DAPM_MIXER("Analog Mixer", UDA1380_PM, 6, 0, NULL, 0), | ||
319 | SND_SOC_DAPM_OUTPUT("VOUTLHP"), | ||
320 | SND_SOC_DAPM_OUTPUT("VOUTRHP"), | ||
321 | SND_SOC_DAPM_OUTPUT("VOUTL"), | ||
322 | SND_SOC_DAPM_OUTPUT("VOUTR"), | ||
323 | SND_SOC_DAPM_DAC("DAC", "Playback", UDA1380_PM, 10, 0), | ||
324 | SND_SOC_DAPM_PGA("HeadPhone Driver", UDA1380_PM, 13, 0, NULL, 0), | ||
325 | }; | ||
326 | |||
327 | static const struct snd_soc_dapm_route audio_map[] = { | ||
328 | |||
329 | /* output mux */ | ||
330 | {"HeadPhone Driver", NULL, "Output Mux"}, | ||
331 | {"VOUTR", NULL, "Output Mux"}, | ||
332 | {"VOUTL", NULL, "Output Mux"}, | ||
333 | |||
334 | {"Analog Mixer", NULL, "VINR"}, | ||
335 | {"Analog Mixer", NULL, "VINL"}, | ||
336 | {"Analog Mixer", NULL, "DAC"}, | ||
337 | |||
338 | {"Output Mux", "DAC", "DAC"}, | ||
339 | {"Output Mux", "Analog Mixer", "Analog Mixer"}, | ||
340 | |||
341 | /* {"DAC", "Digital Mixer", "I2S" } */ | ||
342 | |||
343 | /* headphone driver */ | ||
344 | {"VOUTLHP", NULL, "HeadPhone Driver"}, | ||
345 | {"VOUTRHP", NULL, "HeadPhone Driver"}, | ||
346 | |||
347 | /* input mux */ | ||
348 | {"Left ADC", NULL, "Input Mux"}, | ||
349 | {"Input Mux", "Mic", "Mic LNA"}, | ||
350 | {"Input Mux", "Mic + Line R", "Mic LNA"}, | ||
351 | {"Input Mux", "Line L", "Left PGA"}, | ||
352 | {"Input Mux", "Line", "Left PGA"}, | ||
353 | |||
354 | /* right input */ | ||
355 | {"Right ADC", "Mic + Line R", "Right PGA"}, | ||
356 | {"Right ADC", "Line", "Right PGA"}, | ||
357 | |||
358 | /* inputs */ | ||
359 | {"Mic LNA", NULL, "VINM"}, | ||
360 | {"Left PGA", NULL, "VINL"}, | ||
361 | {"Right PGA", NULL, "VINR"}, | ||
362 | }; | ||
363 | |||
364 | static int uda1380_add_widgets(struct snd_soc_codec *codec) | ||
365 | { | ||
366 | snd_soc_dapm_new_controls(codec, uda1380_dapm_widgets, | ||
367 | ARRAY_SIZE(uda1380_dapm_widgets)); | ||
368 | |||
369 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | ||
370 | |||
371 | snd_soc_dapm_new_widgets(codec); | ||
372 | return 0; | ||
373 | } | ||
374 | |||
375 | static int uda1380_set_dai_fmt(struct snd_soc_dai *codec_dai, | ||
376 | unsigned int fmt) | ||
377 | { | ||
378 | struct snd_soc_codec *codec = codec_dai->codec; | ||
379 | int iface; | ||
380 | |||
381 | /* set up DAI based upon fmt */ | ||
382 | iface = uda1380_read_reg_cache(codec, UDA1380_IFACE); | ||
383 | iface &= ~(R01_SFORI_MASK | R01_SIM | R01_SFORO_MASK); | ||
384 | |||
385 | /* FIXME: how to select I2S for DATAO and MSB for DATAI correctly? */ | ||
386 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
387 | case SND_SOC_DAIFMT_I2S: | ||
388 | iface |= R01_SFORI_I2S | R01_SFORO_I2S; | ||
389 | break; | ||
390 | case SND_SOC_DAIFMT_LSB: | ||
391 | iface |= R01_SFORI_LSB16 | R01_SFORO_I2S; | ||
392 | break; | ||
393 | case SND_SOC_DAIFMT_MSB: | ||
394 | iface |= R01_SFORI_MSB | R01_SFORO_I2S; | ||
395 | } | ||
396 | |||
397 | if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM) | ||
398 | iface |= R01_SIM; | ||
399 | |||
400 | uda1380_write(codec, UDA1380_IFACE, iface); | ||
401 | |||
402 | return 0; | ||
403 | } | ||
404 | |||
405 | /* | ||
406 | * Flush reg cache | ||
407 | * We can only write the interpolator and decimator registers | ||
408 | * when the DAI is being clocked by the CPU DAI. It's up to the | ||
409 | * machine and cpu DAI driver to do this before we are called. | ||
410 | */ | ||
411 | static int uda1380_pcm_prepare(struct snd_pcm_substream *substream) | ||
412 | { | ||
413 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
414 | struct snd_soc_device *socdev = rtd->socdev; | ||
415 | struct snd_soc_codec *codec = socdev->codec; | ||
416 | int reg, reg_start, reg_end, clk; | ||
417 | |||
418 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
419 | reg_start = UDA1380_MVOL; | ||
420 | reg_end = UDA1380_MIXER; | ||
421 | } else { | ||
422 | reg_start = UDA1380_DEC; | ||
423 | reg_end = UDA1380_AGC; | ||
424 | } | ||
425 | |||
426 | /* FIXME disable DAC_CLK */ | ||
427 | clk = uda1380_read_reg_cache(codec, UDA1380_CLK); | ||
428 | uda1380_write(codec, UDA1380_CLK, clk & ~R00_DAC_CLK); | ||
429 | |||
430 | for (reg = reg_start; reg <= reg_end; reg++) { | ||
431 | pr_debug("uda1380: flush reg %x val %x:", reg, | ||
432 | uda1380_read_reg_cache(codec, reg)); | ||
433 | uda1380_write(codec, reg, uda1380_read_reg_cache(codec, reg)); | ||
434 | } | ||
435 | |||
436 | /* FIXME enable DAC_CLK */ | ||
437 | uda1380_write(codec, UDA1380_CLK, clk | R00_DAC_CLK); | ||
438 | |||
439 | return 0; | ||
440 | } | ||
441 | |||
442 | static int uda1380_pcm_hw_params(struct snd_pcm_substream *substream, | ||
443 | struct snd_pcm_hw_params *params) | ||
444 | { | ||
445 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
446 | struct snd_soc_device *socdev = rtd->socdev; | ||
447 | struct snd_soc_codec *codec = socdev->codec; | ||
448 | u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK); | ||
449 | |||
450 | /* set WSPLL power and divider if running from this clock */ | ||
451 | if (clk & R00_DAC_CLK) { | ||
452 | int rate = params_rate(params); | ||
453 | u16 pm = uda1380_read_reg_cache(codec, UDA1380_PM); | ||
454 | clk &= ~0x3; /* clear SEL_LOOP_DIV */ | ||
455 | switch (rate) { | ||
456 | case 6250 ... 12500: | ||
457 | clk |= 0x0; | ||
458 | break; | ||
459 | case 12501 ... 25000: | ||
460 | clk |= 0x1; | ||
461 | break; | ||
462 | case 25001 ... 50000: | ||
463 | clk |= 0x2; | ||
464 | break; | ||
465 | case 50001 ... 100000: | ||
466 | clk |= 0x3; | ||
467 | break; | ||
468 | } | ||
469 | uda1380_write(codec, UDA1380_PM, R02_PON_PLL | pm); | ||
470 | } | ||
471 | |||
472 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
473 | clk |= R00_EN_DAC | R00_EN_INT; | ||
474 | else | ||
475 | clk |= R00_EN_ADC | R00_EN_DEC; | ||
476 | |||
477 | uda1380_write(codec, UDA1380_CLK, clk); | ||
478 | return 0; | ||
479 | } | ||
480 | |||
481 | static void uda1380_pcm_shutdown(struct snd_pcm_substream *substream) | ||
482 | { | ||
483 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
484 | struct snd_soc_device *socdev = rtd->socdev; | ||
485 | struct snd_soc_codec *codec = socdev->codec; | ||
486 | u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK); | ||
487 | |||
488 | /* shut down WSPLL power if running from this clock */ | ||
489 | if (clk & R00_DAC_CLK) { | ||
490 | u16 pm = uda1380_read_reg_cache(codec, UDA1380_PM); | ||
491 | uda1380_write(codec, UDA1380_PM, ~R02_PON_PLL & pm); | ||
492 | } | ||
493 | |||
494 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
495 | clk &= ~(R00_EN_DAC | R00_EN_INT); | ||
496 | else | ||
497 | clk &= ~(R00_EN_ADC | R00_EN_DEC); | ||
498 | |||
499 | uda1380_write(codec, UDA1380_CLK, clk); | ||
500 | } | ||
501 | |||
502 | static int uda1380_mute(struct snd_soc_dai *codec_dai, int mute) | ||
503 | { | ||
504 | struct snd_soc_codec *codec = codec_dai->codec; | ||
505 | u16 mute_reg = uda1380_read_reg_cache(codec, UDA1380_DEEMP) & ~R13_MTM; | ||
506 | |||
507 | /* FIXME: mute(codec,0) is called when the magician clock is already | ||
508 | * set to WSPLL, but for some unknown reason writing to interpolator | ||
509 | * registers works only when clocked by SYSCLK */ | ||
510 | u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK); | ||
511 | uda1380_write(codec, UDA1380_CLK, ~R00_DAC_CLK & clk); | ||
512 | if (mute) | ||
513 | uda1380_write(codec, UDA1380_DEEMP, mute_reg | R13_MTM); | ||
514 | else | ||
515 | uda1380_write(codec, UDA1380_DEEMP, mute_reg); | ||
516 | uda1380_write(codec, UDA1380_CLK, clk); | ||
517 | return 0; | ||
518 | } | ||
519 | |||
520 | static int uda1380_set_bias_level(struct snd_soc_codec *codec, | ||
521 | enum snd_soc_bias_level level) | ||
522 | { | ||
523 | int pm = uda1380_read_reg_cache(codec, UDA1380_PM); | ||
524 | |||
525 | switch (level) { | ||
526 | case SND_SOC_BIAS_ON: | ||
527 | case SND_SOC_BIAS_PREPARE: | ||
528 | uda1380_write(codec, UDA1380_PM, R02_PON_BIAS | pm); | ||
529 | break; | ||
530 | case SND_SOC_BIAS_STANDBY: | ||
531 | uda1380_write(codec, UDA1380_PM, R02_PON_BIAS); | ||
532 | break; | ||
533 | case SND_SOC_BIAS_OFF: | ||
534 | uda1380_write(codec, UDA1380_PM, 0x0); | ||
535 | break; | ||
536 | } | ||
537 | codec->bias_level = level; | ||
538 | return 0; | ||
539 | } | ||
540 | |||
541 | #define UDA1380_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | ||
542 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ | ||
543 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) | ||
544 | |||
545 | struct snd_soc_dai uda1380_dai[] = { | ||
546 | { | ||
547 | .name = "UDA1380", | ||
548 | .playback = { | ||
549 | .stream_name = "Playback", | ||
550 | .channels_min = 1, | ||
551 | .channels_max = 2, | ||
552 | .rates = UDA1380_RATES, | ||
553 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | ||
554 | .capture = { | ||
555 | .stream_name = "Capture", | ||
556 | .channels_min = 1, | ||
557 | .channels_max = 2, | ||
558 | .rates = UDA1380_RATES, | ||
559 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | ||
560 | .ops = { | ||
561 | .hw_params = uda1380_pcm_hw_params, | ||
562 | .shutdown = uda1380_pcm_shutdown, | ||
563 | .prepare = uda1380_pcm_prepare, | ||
564 | }, | ||
565 | .dai_ops = { | ||
566 | .digital_mute = uda1380_mute, | ||
567 | .set_fmt = uda1380_set_dai_fmt, | ||
568 | }, | ||
569 | }, | ||
570 | { /* playback only - dual interface */ | ||
571 | .name = "UDA1380", | ||
572 | .playback = { | ||
573 | .stream_name = "Playback", | ||
574 | .channels_min = 1, | ||
575 | .channels_max = 2, | ||
576 | .rates = UDA1380_RATES, | ||
577 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
578 | }, | ||
579 | .ops = { | ||
580 | .hw_params = uda1380_pcm_hw_params, | ||
581 | .shutdown = uda1380_pcm_shutdown, | ||
582 | .prepare = uda1380_pcm_prepare, | ||
583 | }, | ||
584 | .dai_ops = { | ||
585 | .digital_mute = uda1380_mute, | ||
586 | .set_fmt = uda1380_set_dai_fmt, | ||
587 | }, | ||
588 | }, | ||
589 | { /* capture only - dual interface*/ | ||
590 | .name = "UDA1380", | ||
591 | .capture = { | ||
592 | .stream_name = "Capture", | ||
593 | .channels_min = 1, | ||
594 | .channels_max = 2, | ||
595 | .rates = UDA1380_RATES, | ||
596 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
597 | }, | ||
598 | .ops = { | ||
599 | .hw_params = uda1380_pcm_hw_params, | ||
600 | .shutdown = uda1380_pcm_shutdown, | ||
601 | .prepare = uda1380_pcm_prepare, | ||
602 | }, | ||
603 | .dai_ops = { | ||
604 | .set_fmt = uda1380_set_dai_fmt, | ||
605 | }, | ||
606 | }, | ||
607 | }; | ||
608 | EXPORT_SYMBOL_GPL(uda1380_dai); | ||
609 | |||
610 | static int uda1380_suspend(struct platform_device *pdev, pm_message_t state) | ||
611 | { | ||
612 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
613 | struct snd_soc_codec *codec = socdev->codec; | ||
614 | |||
615 | uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
616 | return 0; | ||
617 | } | ||
618 | |||
619 | static int uda1380_resume(struct platform_device *pdev) | ||
620 | { | ||
621 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
622 | struct snd_soc_codec *codec = socdev->codec; | ||
623 | int i; | ||
624 | u8 data[2]; | ||
625 | u16 *cache = codec->reg_cache; | ||
626 | |||
627 | /* Sync reg_cache with the hardware */ | ||
628 | for (i = 0; i < ARRAY_SIZE(uda1380_reg); i++) { | ||
629 | data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); | ||
630 | data[1] = cache[i] & 0x00ff; | ||
631 | codec->hw_write(codec->control_data, data, 2); | ||
632 | } | ||
633 | uda1380_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
634 | uda1380_set_bias_level(codec, codec->suspend_bias_level); | ||
635 | return 0; | ||
636 | } | ||
637 | |||
638 | /* | ||
639 | * initialise the UDA1380 driver | ||
640 | * register mixer and dsp interfaces with the kernel | ||
641 | */ | ||
642 | static int uda1380_init(struct snd_soc_device *socdev, int dac_clk) | ||
643 | { | ||
644 | struct snd_soc_codec *codec = socdev->codec; | ||
645 | int ret = 0; | ||
646 | |||
647 | codec->name = "UDA1380"; | ||
648 | codec->owner = THIS_MODULE; | ||
649 | codec->read = uda1380_read_reg_cache; | ||
650 | codec->write = uda1380_write; | ||
651 | codec->set_bias_level = uda1380_set_bias_level; | ||
652 | codec->dai = uda1380_dai; | ||
653 | codec->num_dai = ARRAY_SIZE(uda1380_dai); | ||
654 | codec->reg_cache = kmemdup(uda1380_reg, sizeof(uda1380_reg), | ||
655 | GFP_KERNEL); | ||
656 | if (codec->reg_cache == NULL) | ||
657 | return -ENOMEM; | ||
658 | codec->reg_cache_size = ARRAY_SIZE(uda1380_reg); | ||
659 | codec->reg_cache_step = 1; | ||
660 | uda1380_reset(codec); | ||
661 | |||
662 | /* register pcms */ | ||
663 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
664 | if (ret < 0) { | ||
665 | pr_err("uda1380: failed to create pcms\n"); | ||
666 | goto pcm_err; | ||
667 | } | ||
668 | |||
669 | /* power on device */ | ||
670 | uda1380_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
671 | /* set clock input */ | ||
672 | switch (dac_clk) { | ||
673 | case UDA1380_DAC_CLK_SYSCLK: | ||
674 | uda1380_write(codec, UDA1380_CLK, 0); | ||
675 | break; | ||
676 | case UDA1380_DAC_CLK_WSPLL: | ||
677 | uda1380_write(codec, UDA1380_CLK, R00_DAC_CLK); | ||
678 | break; | ||
679 | } | ||
680 | |||
681 | /* uda1380 init */ | ||
682 | uda1380_add_controls(codec); | ||
683 | uda1380_add_widgets(codec); | ||
684 | ret = snd_soc_register_card(socdev); | ||
685 | if (ret < 0) { | ||
686 | pr_err("uda1380: failed to register card\n"); | ||
687 | goto card_err; | ||
688 | } | ||
689 | |||
690 | return ret; | ||
691 | |||
692 | card_err: | ||
693 | snd_soc_free_pcms(socdev); | ||
694 | snd_soc_dapm_free(socdev); | ||
695 | pcm_err: | ||
696 | kfree(codec->reg_cache); | ||
697 | return ret; | ||
698 | } | ||
699 | |||
700 | static struct snd_soc_device *uda1380_socdev; | ||
701 | |||
702 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
703 | |||
704 | #define I2C_DRIVERID_UDA1380 0xfefe /* liam - need a proper id */ | ||
705 | |||
706 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | ||
707 | |||
708 | /* Magic definition of all other variables and things */ | ||
709 | I2C_CLIENT_INSMOD; | ||
710 | |||
711 | static struct i2c_driver uda1380_i2c_driver; | ||
712 | static struct i2c_client client_template; | ||
713 | |||
714 | /* If the i2c layer weren't so broken, we could pass this kind of data | ||
715 | around */ | ||
716 | |||
717 | static int uda1380_codec_probe(struct i2c_adapter *adap, int addr, int kind) | ||
718 | { | ||
719 | struct snd_soc_device *socdev = uda1380_socdev; | ||
720 | struct uda1380_setup_data *setup = socdev->codec_data; | ||
721 | struct snd_soc_codec *codec = socdev->codec; | ||
722 | struct i2c_client *i2c; | ||
723 | int ret; | ||
724 | |||
725 | if (addr != setup->i2c_address) | ||
726 | return -ENODEV; | ||
727 | |||
728 | client_template.adapter = adap; | ||
729 | client_template.addr = addr; | ||
730 | |||
731 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | ||
732 | if (i2c == NULL) { | ||
733 | kfree(codec); | ||
734 | return -ENOMEM; | ||
735 | } | ||
736 | i2c_set_clientdata(i2c, codec); | ||
737 | codec->control_data = i2c; | ||
738 | |||
739 | ret = i2c_attach_client(i2c); | ||
740 | if (ret < 0) { | ||
741 | pr_err("uda1380: failed to attach codec at addr %x\n", addr); | ||
742 | goto err; | ||
743 | } | ||
744 | |||
745 | ret = uda1380_init(socdev, setup->dac_clk); | ||
746 | if (ret < 0) { | ||
747 | pr_err("uda1380: failed to initialise UDA1380\n"); | ||
748 | goto err; | ||
749 | } | ||
750 | return ret; | ||
751 | |||
752 | err: | ||
753 | kfree(codec); | ||
754 | kfree(i2c); | ||
755 | return ret; | ||
756 | } | ||
757 | |||
758 | static int uda1380_i2c_detach(struct i2c_client *client) | ||
759 | { | ||
760 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | ||
761 | i2c_detach_client(client); | ||
762 | kfree(codec->reg_cache); | ||
763 | kfree(client); | ||
764 | return 0; | ||
765 | } | ||
766 | |||
767 | static int uda1380_i2c_attach(struct i2c_adapter *adap) | ||
768 | { | ||
769 | return i2c_probe(adap, &addr_data, uda1380_codec_probe); | ||
770 | } | ||
771 | |||
772 | static struct i2c_driver uda1380_i2c_driver = { | ||
773 | .driver = { | ||
774 | .name = "UDA1380 I2C Codec", | ||
775 | .owner = THIS_MODULE, | ||
776 | }, | ||
777 | .id = I2C_DRIVERID_UDA1380, | ||
778 | .attach_adapter = uda1380_i2c_attach, | ||
779 | .detach_client = uda1380_i2c_detach, | ||
780 | .command = NULL, | ||
781 | }; | ||
782 | |||
783 | static struct i2c_client client_template = { | ||
784 | .name = "UDA1380", | ||
785 | .driver = &uda1380_i2c_driver, | ||
786 | }; | ||
787 | #endif | ||
788 | |||
789 | static int uda1380_probe(struct platform_device *pdev) | ||
790 | { | ||
791 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
792 | struct uda1380_setup_data *setup; | ||
793 | struct snd_soc_codec *codec; | ||
794 | int ret = 0; | ||
795 | |||
796 | pr_info("UDA1380 Audio Codec %s", UDA1380_VERSION); | ||
797 | |||
798 | setup = socdev->codec_data; | ||
799 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
800 | if (codec == NULL) | ||
801 | return -ENOMEM; | ||
802 | |||
803 | socdev->codec = codec; | ||
804 | mutex_init(&codec->mutex); | ||
805 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
806 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
807 | |||
808 | uda1380_socdev = socdev; | ||
809 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
810 | if (setup->i2c_address) { | ||
811 | normal_i2c[0] = setup->i2c_address; | ||
812 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
813 | ret = i2c_add_driver(&uda1380_i2c_driver); | ||
814 | if (ret != 0) | ||
815 | printk(KERN_ERR "can't add i2c driver"); | ||
816 | } | ||
817 | #else | ||
818 | /* Add other interfaces here */ | ||
819 | #endif | ||
820 | return ret; | ||
821 | } | ||
822 | |||
823 | /* power down chip */ | ||
824 | static int uda1380_remove(struct platform_device *pdev) | ||
825 | { | ||
826 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
827 | struct snd_soc_codec *codec = socdev->codec; | ||
828 | |||
829 | if (codec->control_data) | ||
830 | uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
831 | |||
832 | snd_soc_free_pcms(socdev); | ||
833 | snd_soc_dapm_free(socdev); | ||
834 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
835 | i2c_del_driver(&uda1380_i2c_driver); | ||
836 | #endif | ||
837 | kfree(codec); | ||
838 | |||
839 | return 0; | ||
840 | } | ||
841 | |||
842 | struct snd_soc_codec_device soc_codec_dev_uda1380 = { | ||
843 | .probe = uda1380_probe, | ||
844 | .remove = uda1380_remove, | ||
845 | .suspend = uda1380_suspend, | ||
846 | .resume = uda1380_resume, | ||
847 | }; | ||
848 | EXPORT_SYMBOL_GPL(soc_codec_dev_uda1380); | ||
849 | |||
850 | MODULE_AUTHOR("Giorgio Padrin"); | ||
851 | MODULE_DESCRIPTION("Audio support for codec Philips UDA1380"); | ||
852 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/uda1380.h b/sound/soc/codecs/uda1380.h new file mode 100644 index 000000000000..50c603e2c9f2 --- /dev/null +++ b/sound/soc/codecs/uda1380.h | |||
@@ -0,0 +1,89 @@ | |||
1 | /* | ||
2 | * Audio support for Philips UDA1380 | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * Copyright (c) 2005 Giorgio Padrin <giorgio@mandarinlogiq.org> | ||
9 | */ | ||
10 | |||
11 | #ifndef _UDA1380_H | ||
12 | #define _UDA1380_H | ||
13 | |||
14 | #define UDA1380_CLK 0x00 | ||
15 | #define UDA1380_IFACE 0x01 | ||
16 | #define UDA1380_PM 0x02 | ||
17 | #define UDA1380_AMIX 0x03 | ||
18 | #define UDA1380_HP 0x04 | ||
19 | #define UDA1380_MVOL 0x10 | ||
20 | #define UDA1380_MIXVOL 0x11 | ||
21 | #define UDA1380_MODE 0x12 | ||
22 | #define UDA1380_DEEMP 0x13 | ||
23 | #define UDA1380_MIXER 0x14 | ||
24 | #define UDA1380_INTSTAT 0x18 | ||
25 | #define UDA1380_DEC 0x20 | ||
26 | #define UDA1380_PGA 0x21 | ||
27 | #define UDA1380_ADC 0x22 | ||
28 | #define UDA1380_AGC 0x23 | ||
29 | #define UDA1380_DECSTAT 0x28 | ||
30 | #define UDA1380_RESET 0x7f | ||
31 | |||
32 | #define UDA1380_CACHEREGNUM 0x24 | ||
33 | |||
34 | /* Register flags */ | ||
35 | #define R00_EN_ADC 0x0800 | ||
36 | #define R00_EN_DEC 0x0400 | ||
37 | #define R00_EN_DAC 0x0200 | ||
38 | #define R00_EN_INT 0x0100 | ||
39 | #define R00_DAC_CLK 0x0010 | ||
40 | #define R01_SFORI_I2S 0x0000 | ||
41 | #define R01_SFORI_LSB16 0x0100 | ||
42 | #define R01_SFORI_LSB18 0x0200 | ||
43 | #define R01_SFORI_LSB20 0x0300 | ||
44 | #define R01_SFORI_MSB 0x0500 | ||
45 | #define R01_SFORI_MASK 0x0700 | ||
46 | #define R01_SFORO_I2S 0x0000 | ||
47 | #define R01_SFORO_LSB16 0x0001 | ||
48 | #define R01_SFORO_LSB18 0x0002 | ||
49 | #define R01_SFORO_LSB20 0x0003 | ||
50 | #define R01_SFORO_LSB24 0x0004 | ||
51 | #define R01_SFORO_MSB 0x0005 | ||
52 | #define R01_SFORO_MASK 0x0007 | ||
53 | #define R01_SEL_SOURCE 0x0040 | ||
54 | #define R01_SIM 0x0010 | ||
55 | #define R02_PON_PLL 0x8000 | ||
56 | #define R02_PON_HP 0x2000 | ||
57 | #define R02_PON_DAC 0x0400 | ||
58 | #define R02_PON_BIAS 0x0100 | ||
59 | #define R02_EN_AVC 0x0080 | ||
60 | #define R02_PON_AVC 0x0040 | ||
61 | #define R02_PON_LNA 0x0010 | ||
62 | #define R02_PON_PGAL 0x0008 | ||
63 | #define R02_PON_ADCL 0x0004 | ||
64 | #define R02_PON_PGAR 0x0002 | ||
65 | #define R02_PON_ADCR 0x0001 | ||
66 | #define R13_MTM 0x4000 | ||
67 | #define R14_SILENCE 0x0080 | ||
68 | #define R14_SDET_ON 0x0040 | ||
69 | #define R21_MT_ADC 0x8000 | ||
70 | #define R22_SEL_LNA 0x0008 | ||
71 | #define R22_SEL_MIC 0x0004 | ||
72 | #define R22_SKIP_DCFIL 0x0002 | ||
73 | #define R23_AGC_EN 0x0001 | ||
74 | |||
75 | struct uda1380_setup_data { | ||
76 | unsigned short i2c_address; | ||
77 | int dac_clk; | ||
78 | #define UDA1380_DAC_CLK_SYSCLK 0 | ||
79 | #define UDA1380_DAC_CLK_WSPLL 1 | ||
80 | }; | ||
81 | |||
82 | #define UDA1380_DAI_DUPLEX 0 /* playback and capture on single DAI */ | ||
83 | #define UDA1380_DAI_PLAYBACK 1 /* playback DAI */ | ||
84 | #define UDA1380_DAI_CAPTURE 2 /* capture DAI */ | ||
85 | |||
86 | extern struct snd_soc_dai uda1380_dai[3]; | ||
87 | extern struct snd_soc_codec_device soc_codec_dev_uda1380; | ||
88 | |||
89 | #endif /* _UDA1380_H */ | ||
diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c new file mode 100644 index 000000000000..67325fd95447 --- /dev/null +++ b/sound/soc/codecs/wm8510.c | |||
@@ -0,0 +1,817 @@ | |||
1 | /* | ||
2 | * wm8510.c -- WM8510 ALSA Soc Audio driver | ||
3 | * | ||
4 | * Copyright 2006 Wolfson Microelectronics PLC. | ||
5 | * | ||
6 | * Author: Liam Girdwood <liam.girdwood@wolfsonmicro.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/moduleparam.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/delay.h> | ||
18 | #include <linux/pm.h> | ||
19 | #include <linux/i2c.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <sound/core.h> | ||
22 | #include <sound/pcm.h> | ||
23 | #include <sound/pcm_params.h> | ||
24 | #include <sound/soc.h> | ||
25 | #include <sound/soc-dapm.h> | ||
26 | #include <sound/initval.h> | ||
27 | |||
28 | #include "wm8510.h" | ||
29 | |||
30 | #define AUDIO_NAME "wm8510" | ||
31 | #define WM8510_VERSION "0.6" | ||
32 | |||
33 | struct snd_soc_codec_device soc_codec_dev_wm8510; | ||
34 | |||
35 | /* | ||
36 | * wm8510 register cache | ||
37 | * We can't read the WM8510 register space when we are | ||
38 | * using 2 wire for device control, so we cache them instead. | ||
39 | */ | ||
40 | static const u16 wm8510_reg[WM8510_CACHEREGNUM] = { | ||
41 | 0x0000, 0x0000, 0x0000, 0x0000, | ||
42 | 0x0050, 0x0000, 0x0140, 0x0000, | ||
43 | 0x0000, 0x0000, 0x0000, 0x00ff, | ||
44 | 0x0000, 0x0000, 0x0100, 0x00ff, | ||
45 | 0x0000, 0x0000, 0x012c, 0x002c, | ||
46 | 0x002c, 0x002c, 0x002c, 0x0000, | ||
47 | 0x0032, 0x0000, 0x0000, 0x0000, | ||
48 | 0x0000, 0x0000, 0x0000, 0x0000, | ||
49 | 0x0038, 0x000b, 0x0032, 0x0000, | ||
50 | 0x0008, 0x000c, 0x0093, 0x00e9, | ||
51 | 0x0000, 0x0000, 0x0000, 0x0000, | ||
52 | 0x0003, 0x0010, 0x0000, 0x0000, | ||
53 | 0x0000, 0x0002, 0x0001, 0x0000, | ||
54 | 0x0000, 0x0000, 0x0039, 0x0000, | ||
55 | 0x0001, | ||
56 | }; | ||
57 | |||
58 | /* | ||
59 | * read wm8510 register cache | ||
60 | */ | ||
61 | static inline unsigned int wm8510_read_reg_cache(struct snd_soc_codec *codec, | ||
62 | unsigned int reg) | ||
63 | { | ||
64 | u16 *cache = codec->reg_cache; | ||
65 | if (reg == WM8510_RESET) | ||
66 | return 0; | ||
67 | if (reg >= WM8510_CACHEREGNUM) | ||
68 | return -1; | ||
69 | return cache[reg]; | ||
70 | } | ||
71 | |||
72 | /* | ||
73 | * write wm8510 register cache | ||
74 | */ | ||
75 | static inline void wm8510_write_reg_cache(struct snd_soc_codec *codec, | ||
76 | u16 reg, unsigned int value) | ||
77 | { | ||
78 | u16 *cache = codec->reg_cache; | ||
79 | if (reg >= WM8510_CACHEREGNUM) | ||
80 | return; | ||
81 | cache[reg] = value; | ||
82 | } | ||
83 | |||
84 | /* | ||
85 | * write to the WM8510 register space | ||
86 | */ | ||
87 | static int wm8510_write(struct snd_soc_codec *codec, unsigned int reg, | ||
88 | unsigned int value) | ||
89 | { | ||
90 | u8 data[2]; | ||
91 | |||
92 | /* data is | ||
93 | * D15..D9 WM8510 register offset | ||
94 | * D8...D0 register data | ||
95 | */ | ||
96 | data[0] = (reg << 1) | ((value >> 8) & 0x0001); | ||
97 | data[1] = value & 0x00ff; | ||
98 | |||
99 | wm8510_write_reg_cache(codec, reg, value); | ||
100 | if (codec->hw_write(codec->control_data, data, 2) == 2) | ||
101 | return 0; | ||
102 | else | ||
103 | return -EIO; | ||
104 | } | ||
105 | |||
106 | #define wm8510_reset(c) wm8510_write(c, WM8510_RESET, 0) | ||
107 | |||
108 | static const char *wm8510_companding[] = { "Off", "NC", "u-law", "A-law" }; | ||
109 | static const char *wm8510_deemp[] = { "None", "32kHz", "44.1kHz", "48kHz" }; | ||
110 | static const char *wm8510_alc[] = { "ALC", "Limiter" }; | ||
111 | |||
112 | static const struct soc_enum wm8510_enum[] = { | ||
113 | SOC_ENUM_SINGLE(WM8510_COMP, 1, 4, wm8510_companding), /* adc */ | ||
114 | SOC_ENUM_SINGLE(WM8510_COMP, 3, 4, wm8510_companding), /* dac */ | ||
115 | SOC_ENUM_SINGLE(WM8510_DAC, 4, 4, wm8510_deemp), | ||
116 | SOC_ENUM_SINGLE(WM8510_ALC3, 8, 2, wm8510_alc), | ||
117 | }; | ||
118 | |||
119 | static const struct snd_kcontrol_new wm8510_snd_controls[] = { | ||
120 | |||
121 | SOC_SINGLE("Digital Loopback Switch", WM8510_COMP, 0, 1, 0), | ||
122 | |||
123 | SOC_ENUM("DAC Companding", wm8510_enum[1]), | ||
124 | SOC_ENUM("ADC Companding", wm8510_enum[0]), | ||
125 | |||
126 | SOC_ENUM("Playback De-emphasis", wm8510_enum[2]), | ||
127 | SOC_SINGLE("DAC Inversion Switch", WM8510_DAC, 0, 1, 0), | ||
128 | |||
129 | SOC_SINGLE("Master Playback Volume", WM8510_DACVOL, 0, 127, 0), | ||
130 | |||
131 | SOC_SINGLE("High Pass Filter Switch", WM8510_ADC, 8, 1, 0), | ||
132 | SOC_SINGLE("High Pass Cut Off", WM8510_ADC, 4, 7, 0), | ||
133 | SOC_SINGLE("ADC Inversion Switch", WM8510_COMP, 0, 1, 0), | ||
134 | |||
135 | SOC_SINGLE("Capture Volume", WM8510_ADCVOL, 0, 127, 0), | ||
136 | |||
137 | SOC_SINGLE("DAC Playback Limiter Switch", WM8510_DACLIM1, 8, 1, 0), | ||
138 | SOC_SINGLE("DAC Playback Limiter Decay", WM8510_DACLIM1, 4, 15, 0), | ||
139 | SOC_SINGLE("DAC Playback Limiter Attack", WM8510_DACLIM1, 0, 15, 0), | ||
140 | |||
141 | SOC_SINGLE("DAC Playback Limiter Threshold", WM8510_DACLIM2, 4, 7, 0), | ||
142 | SOC_SINGLE("DAC Playback Limiter Boost", WM8510_DACLIM2, 0, 15, 0), | ||
143 | |||
144 | SOC_SINGLE("ALC Enable Switch", WM8510_ALC1, 8, 1, 0), | ||
145 | SOC_SINGLE("ALC Capture Max Gain", WM8510_ALC1, 3, 7, 0), | ||
146 | SOC_SINGLE("ALC Capture Min Gain", WM8510_ALC1, 0, 7, 0), | ||
147 | |||
148 | SOC_SINGLE("ALC Capture ZC Switch", WM8510_ALC2, 8, 1, 0), | ||
149 | SOC_SINGLE("ALC Capture Hold", WM8510_ALC2, 4, 7, 0), | ||
150 | SOC_SINGLE("ALC Capture Target", WM8510_ALC2, 0, 15, 0), | ||
151 | |||
152 | SOC_ENUM("ALC Capture Mode", wm8510_enum[3]), | ||
153 | SOC_SINGLE("ALC Capture Decay", WM8510_ALC3, 4, 15, 0), | ||
154 | SOC_SINGLE("ALC Capture Attack", WM8510_ALC3, 0, 15, 0), | ||
155 | |||
156 | SOC_SINGLE("ALC Capture Noise Gate Switch", WM8510_NGATE, 3, 1, 0), | ||
157 | SOC_SINGLE("ALC Capture Noise Gate Threshold", WM8510_NGATE, 0, 7, 0), | ||
158 | |||
159 | SOC_SINGLE("Capture PGA ZC Switch", WM8510_INPPGA, 7, 1, 0), | ||
160 | SOC_SINGLE("Capture PGA Volume", WM8510_INPPGA, 0, 63, 0), | ||
161 | |||
162 | SOC_SINGLE("Speaker Playback ZC Switch", WM8510_SPKVOL, 7, 1, 0), | ||
163 | SOC_SINGLE("Speaker Playback Switch", WM8510_SPKVOL, 6, 1, 1), | ||
164 | SOC_SINGLE("Speaker Playback Volume", WM8510_SPKVOL, 0, 63, 0), | ||
165 | SOC_SINGLE("Speaker Boost", WM8510_OUTPUT, 2, 1, 0), | ||
166 | |||
167 | SOC_SINGLE("Capture Boost(+20dB)", WM8510_ADCBOOST, 8, 1, 0), | ||
168 | SOC_SINGLE("Mono Playback Switch", WM8510_MONOMIX, 6, 1, 1), | ||
169 | }; | ||
170 | |||
171 | /* add non dapm controls */ | ||
172 | static int wm8510_add_controls(struct snd_soc_codec *codec) | ||
173 | { | ||
174 | int err, i; | ||
175 | |||
176 | for (i = 0; i < ARRAY_SIZE(wm8510_snd_controls); i++) { | ||
177 | err = snd_ctl_add(codec->card, | ||
178 | snd_soc_cnew(&wm8510_snd_controls[i], codec, | ||
179 | NULL)); | ||
180 | if (err < 0) | ||
181 | return err; | ||
182 | } | ||
183 | |||
184 | return 0; | ||
185 | } | ||
186 | |||
187 | /* Speaker Output Mixer */ | ||
188 | static const struct snd_kcontrol_new wm8510_speaker_mixer_controls[] = { | ||
189 | SOC_DAPM_SINGLE("Line Bypass Switch", WM8510_SPKMIX, 1, 1, 0), | ||
190 | SOC_DAPM_SINGLE("Aux Playback Switch", WM8510_SPKMIX, 5, 1, 0), | ||
191 | SOC_DAPM_SINGLE("PCM Playback Switch", WM8510_SPKMIX, 0, 1, 0), | ||
192 | }; | ||
193 | |||
194 | /* Mono Output Mixer */ | ||
195 | static const struct snd_kcontrol_new wm8510_mono_mixer_controls[] = { | ||
196 | SOC_DAPM_SINGLE("Line Bypass Switch", WM8510_MONOMIX, 1, 1, 0), | ||
197 | SOC_DAPM_SINGLE("Aux Playback Switch", WM8510_MONOMIX, 2, 1, 0), | ||
198 | SOC_DAPM_SINGLE("PCM Playback Switch", WM8510_MONOMIX, 0, 1, 0), | ||
199 | }; | ||
200 | |||
201 | static const struct snd_kcontrol_new wm8510_boost_controls[] = { | ||
202 | SOC_DAPM_SINGLE("Mic PGA Switch", WM8510_INPPGA, 6, 1, 0), | ||
203 | SOC_DAPM_SINGLE("Aux Volume", WM8510_ADCBOOST, 0, 7, 0), | ||
204 | SOC_DAPM_SINGLE("Mic Volume", WM8510_ADCBOOST, 4, 7, 0), | ||
205 | }; | ||
206 | |||
207 | static const struct snd_kcontrol_new wm8510_micpga_controls[] = { | ||
208 | SOC_DAPM_SINGLE("MICP Switch", WM8510_INPUT, 0, 1, 0), | ||
209 | SOC_DAPM_SINGLE("MICN Switch", WM8510_INPUT, 1, 1, 0), | ||
210 | SOC_DAPM_SINGLE("AUX Switch", WM8510_INPUT, 2, 1, 0), | ||
211 | }; | ||
212 | |||
213 | static const struct snd_soc_dapm_widget wm8510_dapm_widgets[] = { | ||
214 | SND_SOC_DAPM_MIXER("Speaker Mixer", WM8510_POWER3, 2, 0, | ||
215 | &wm8510_speaker_mixer_controls[0], | ||
216 | ARRAY_SIZE(wm8510_speaker_mixer_controls)), | ||
217 | SND_SOC_DAPM_MIXER("Mono Mixer", WM8510_POWER3, 3, 0, | ||
218 | &wm8510_mono_mixer_controls[0], | ||
219 | ARRAY_SIZE(wm8510_mono_mixer_controls)), | ||
220 | SND_SOC_DAPM_DAC("DAC", "HiFi Playback", WM8510_POWER3, 0, 0), | ||
221 | SND_SOC_DAPM_ADC("ADC", "HiFi Capture", WM8510_POWER2, 0, 0), | ||
222 | SND_SOC_DAPM_PGA("Aux Input", WM8510_POWER1, 6, 0, NULL, 0), | ||
223 | SND_SOC_DAPM_PGA("SpkN Out", WM8510_POWER3, 5, 0, NULL, 0), | ||
224 | SND_SOC_DAPM_PGA("SpkP Out", WM8510_POWER3, 6, 0, NULL, 0), | ||
225 | SND_SOC_DAPM_PGA("Mono Out", WM8510_POWER3, 7, 0, NULL, 0), | ||
226 | |||
227 | SND_SOC_DAPM_PGA("Mic PGA", WM8510_POWER2, 2, 0, | ||
228 | &wm8510_micpga_controls[0], | ||
229 | ARRAY_SIZE(wm8510_micpga_controls)), | ||
230 | SND_SOC_DAPM_MIXER("Boost Mixer", WM8510_POWER2, 4, 0, | ||
231 | &wm8510_boost_controls[0], | ||
232 | ARRAY_SIZE(wm8510_boost_controls)), | ||
233 | |||
234 | SND_SOC_DAPM_MICBIAS("Mic Bias", WM8510_POWER1, 4, 0), | ||
235 | |||
236 | SND_SOC_DAPM_INPUT("MICN"), | ||
237 | SND_SOC_DAPM_INPUT("MICP"), | ||
238 | SND_SOC_DAPM_INPUT("AUX"), | ||
239 | SND_SOC_DAPM_OUTPUT("MONOOUT"), | ||
240 | SND_SOC_DAPM_OUTPUT("SPKOUTP"), | ||
241 | SND_SOC_DAPM_OUTPUT("SPKOUTN"), | ||
242 | }; | ||
243 | |||
244 | static const struct snd_soc_dapm_route audio_map[] = { | ||
245 | /* Mono output mixer */ | ||
246 | {"Mono Mixer", "PCM Playback Switch", "DAC"}, | ||
247 | {"Mono Mixer", "Aux Playback Switch", "Aux Input"}, | ||
248 | {"Mono Mixer", "Line Bypass Switch", "Boost Mixer"}, | ||
249 | |||
250 | /* Speaker output mixer */ | ||
251 | {"Speaker Mixer", "PCM Playback Switch", "DAC"}, | ||
252 | {"Speaker Mixer", "Aux Playback Switch", "Aux Input"}, | ||
253 | {"Speaker Mixer", "Line Bypass Switch", "Boost Mixer"}, | ||
254 | |||
255 | /* Outputs */ | ||
256 | {"Mono Out", NULL, "Mono Mixer"}, | ||
257 | {"MONOOUT", NULL, "Mono Out"}, | ||
258 | {"SpkN Out", NULL, "Speaker Mixer"}, | ||
259 | {"SpkP Out", NULL, "Speaker Mixer"}, | ||
260 | {"SPKOUTN", NULL, "SpkN Out"}, | ||
261 | {"SPKOUTP", NULL, "SpkP Out"}, | ||
262 | |||
263 | /* Microphone PGA */ | ||
264 | {"Mic PGA", "MICN Switch", "MICN"}, | ||
265 | {"Mic PGA", "MICP Switch", "MICP"}, | ||
266 | { "Mic PGA", "AUX Switch", "Aux Input" }, | ||
267 | |||
268 | /* Boost Mixer */ | ||
269 | {"Boost Mixer", "Mic PGA Switch", "Mic PGA"}, | ||
270 | {"Boost Mixer", "Mic Volume", "MICP"}, | ||
271 | {"Boost Mixer", "Aux Volume", "Aux Input"}, | ||
272 | |||
273 | {"ADC", NULL, "Boost Mixer"}, | ||
274 | }; | ||
275 | |||
276 | static int wm8510_add_widgets(struct snd_soc_codec *codec) | ||
277 | { | ||
278 | snd_soc_dapm_new_controls(codec, wm8510_dapm_widgets, | ||
279 | ARRAY_SIZE(wm8510_dapm_widgets)); | ||
280 | |||
281 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | ||
282 | |||
283 | snd_soc_dapm_new_widgets(codec); | ||
284 | return 0; | ||
285 | } | ||
286 | |||
287 | struct pll_ { | ||
288 | unsigned int pre_div:4; /* prescale - 1 */ | ||
289 | unsigned int n:4; | ||
290 | unsigned int k; | ||
291 | }; | ||
292 | |||
293 | static struct pll_ pll_div; | ||
294 | |||
295 | /* The size in bits of the pll divide multiplied by 10 | ||
296 | * to allow rounding later */ | ||
297 | #define FIXED_PLL_SIZE ((1 << 24) * 10) | ||
298 | |||
299 | static void pll_factors(unsigned int target, unsigned int source) | ||
300 | { | ||
301 | unsigned long long Kpart; | ||
302 | unsigned int K, Ndiv, Nmod; | ||
303 | |||
304 | Ndiv = target / source; | ||
305 | if (Ndiv < 6) { | ||
306 | source >>= 1; | ||
307 | pll_div.pre_div = 1; | ||
308 | Ndiv = target / source; | ||
309 | } else | ||
310 | pll_div.pre_div = 0; | ||
311 | |||
312 | if ((Ndiv < 6) || (Ndiv > 12)) | ||
313 | printk(KERN_WARNING | ||
314 | "WM8510 N value %d outwith recommended range!d\n", | ||
315 | Ndiv); | ||
316 | |||
317 | pll_div.n = Ndiv; | ||
318 | Nmod = target % source; | ||
319 | Kpart = FIXED_PLL_SIZE * (long long)Nmod; | ||
320 | |||
321 | do_div(Kpart, source); | ||
322 | |||
323 | K = Kpart & 0xFFFFFFFF; | ||
324 | |||
325 | /* Check if we need to round */ | ||
326 | if ((K % 10) >= 5) | ||
327 | K += 5; | ||
328 | |||
329 | /* Move down to proper range now rounding is done */ | ||
330 | K /= 10; | ||
331 | |||
332 | pll_div.k = K; | ||
333 | } | ||
334 | |||
335 | static int wm8510_set_dai_pll(struct snd_soc_dai *codec_dai, | ||
336 | int pll_id, unsigned int freq_in, unsigned int freq_out) | ||
337 | { | ||
338 | struct snd_soc_codec *codec = codec_dai->codec; | ||
339 | u16 reg; | ||
340 | |||
341 | if (freq_in == 0 || freq_out == 0) { | ||
342 | /* Clock CODEC directly from MCLK */ | ||
343 | reg = wm8510_read_reg_cache(codec, WM8510_CLOCK); | ||
344 | wm8510_write(codec, WM8510_CLOCK, reg & 0x0ff); | ||
345 | |||
346 | /* Turn off PLL */ | ||
347 | reg = wm8510_read_reg_cache(codec, WM8510_POWER1); | ||
348 | wm8510_write(codec, WM8510_POWER1, reg & 0x1df); | ||
349 | return 0; | ||
350 | } | ||
351 | |||
352 | pll_factors(freq_out*8, freq_in); | ||
353 | |||
354 | wm8510_write(codec, WM8510_PLLN, (pll_div.pre_div << 4) | pll_div.n); | ||
355 | wm8510_write(codec, WM8510_PLLK1, pll_div.k >> 18); | ||
356 | wm8510_write(codec, WM8510_PLLK2, (pll_div.k >> 9) & 0x1ff); | ||
357 | wm8510_write(codec, WM8510_PLLK3, pll_div.k & 0x1ff); | ||
358 | reg = wm8510_read_reg_cache(codec, WM8510_POWER1); | ||
359 | wm8510_write(codec, WM8510_POWER1, reg | 0x020); | ||
360 | |||
361 | /* Run CODEC from PLL instead of MCLK */ | ||
362 | reg = wm8510_read_reg_cache(codec, WM8510_CLOCK); | ||
363 | wm8510_write(codec, WM8510_CLOCK, reg | 0x100); | ||
364 | |||
365 | return 0; | ||
366 | } | ||
367 | |||
368 | /* | ||
369 | * Configure WM8510 clock dividers. | ||
370 | */ | ||
371 | static int wm8510_set_dai_clkdiv(struct snd_soc_dai *codec_dai, | ||
372 | int div_id, int div) | ||
373 | { | ||
374 | struct snd_soc_codec *codec = codec_dai->codec; | ||
375 | u16 reg; | ||
376 | |||
377 | switch (div_id) { | ||
378 | case WM8510_OPCLKDIV: | ||
379 | reg = wm8510_read_reg_cache(codec, WM8510_GPIO) & 0x1cf; | ||
380 | wm8510_write(codec, WM8510_GPIO, reg | div); | ||
381 | break; | ||
382 | case WM8510_MCLKDIV: | ||
383 | reg = wm8510_read_reg_cache(codec, WM8510_CLOCK) & 0x1f; | ||
384 | wm8510_write(codec, WM8510_CLOCK, reg | div); | ||
385 | break; | ||
386 | case WM8510_ADCCLK: | ||
387 | reg = wm8510_read_reg_cache(codec, WM8510_ADC) & 0x1f7; | ||
388 | wm8510_write(codec, WM8510_ADC, reg | div); | ||
389 | break; | ||
390 | case WM8510_DACCLK: | ||
391 | reg = wm8510_read_reg_cache(codec, WM8510_DAC) & 0x1f7; | ||
392 | wm8510_write(codec, WM8510_DAC, reg | div); | ||
393 | break; | ||
394 | case WM8510_BCLKDIV: | ||
395 | reg = wm8510_read_reg_cache(codec, WM8510_CLOCK) & 0x1e3; | ||
396 | wm8510_write(codec, WM8510_CLOCK, reg | div); | ||
397 | break; | ||
398 | default: | ||
399 | return -EINVAL; | ||
400 | } | ||
401 | |||
402 | return 0; | ||
403 | } | ||
404 | |||
405 | static int wm8510_set_dai_fmt(struct snd_soc_dai *codec_dai, | ||
406 | unsigned int fmt) | ||
407 | { | ||
408 | struct snd_soc_codec *codec = codec_dai->codec; | ||
409 | u16 iface = 0; | ||
410 | u16 clk = wm8510_read_reg_cache(codec, WM8510_CLOCK) & 0x1fe; | ||
411 | |||
412 | /* set master/slave audio interface */ | ||
413 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
414 | case SND_SOC_DAIFMT_CBM_CFM: | ||
415 | clk |= 0x0001; | ||
416 | break; | ||
417 | case SND_SOC_DAIFMT_CBS_CFS: | ||
418 | break; | ||
419 | default: | ||
420 | return -EINVAL; | ||
421 | } | ||
422 | |||
423 | /* interface format */ | ||
424 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
425 | case SND_SOC_DAIFMT_I2S: | ||
426 | iface |= 0x0010; | ||
427 | break; | ||
428 | case SND_SOC_DAIFMT_RIGHT_J: | ||
429 | break; | ||
430 | case SND_SOC_DAIFMT_LEFT_J: | ||
431 | iface |= 0x0008; | ||
432 | break; | ||
433 | case SND_SOC_DAIFMT_DSP_A: | ||
434 | iface |= 0x00018; | ||
435 | break; | ||
436 | default: | ||
437 | return -EINVAL; | ||
438 | } | ||
439 | |||
440 | /* clock inversion */ | ||
441 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
442 | case SND_SOC_DAIFMT_NB_NF: | ||
443 | break; | ||
444 | case SND_SOC_DAIFMT_IB_IF: | ||
445 | iface |= 0x0180; | ||
446 | break; | ||
447 | case SND_SOC_DAIFMT_IB_NF: | ||
448 | iface |= 0x0100; | ||
449 | break; | ||
450 | case SND_SOC_DAIFMT_NB_IF: | ||
451 | iface |= 0x0080; | ||
452 | break; | ||
453 | default: | ||
454 | return -EINVAL; | ||
455 | } | ||
456 | |||
457 | wm8510_write(codec, WM8510_IFACE, iface); | ||
458 | wm8510_write(codec, WM8510_CLOCK, clk); | ||
459 | return 0; | ||
460 | } | ||
461 | |||
462 | static int wm8510_pcm_hw_params(struct snd_pcm_substream *substream, | ||
463 | struct snd_pcm_hw_params *params) | ||
464 | { | ||
465 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
466 | struct snd_soc_device *socdev = rtd->socdev; | ||
467 | struct snd_soc_codec *codec = socdev->codec; | ||
468 | u16 iface = wm8510_read_reg_cache(codec, WM8510_IFACE) & 0x19f; | ||
469 | u16 adn = wm8510_read_reg_cache(codec, WM8510_ADD) & 0x1f1; | ||
470 | |||
471 | /* bit size */ | ||
472 | switch (params_format(params)) { | ||
473 | case SNDRV_PCM_FORMAT_S16_LE: | ||
474 | break; | ||
475 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
476 | iface |= 0x0020; | ||
477 | break; | ||
478 | case SNDRV_PCM_FORMAT_S24_LE: | ||
479 | iface |= 0x0040; | ||
480 | break; | ||
481 | case SNDRV_PCM_FORMAT_S32_LE: | ||
482 | iface |= 0x0060; | ||
483 | break; | ||
484 | } | ||
485 | |||
486 | /* filter coefficient */ | ||
487 | switch (params_rate(params)) { | ||
488 | case SNDRV_PCM_RATE_8000: | ||
489 | adn |= 0x5 << 1; | ||
490 | break; | ||
491 | case SNDRV_PCM_RATE_11025: | ||
492 | adn |= 0x4 << 1; | ||
493 | break; | ||
494 | case SNDRV_PCM_RATE_16000: | ||
495 | adn |= 0x3 << 1; | ||
496 | break; | ||
497 | case SNDRV_PCM_RATE_22050: | ||
498 | adn |= 0x2 << 1; | ||
499 | break; | ||
500 | case SNDRV_PCM_RATE_32000: | ||
501 | adn |= 0x1 << 1; | ||
502 | break; | ||
503 | case SNDRV_PCM_RATE_44100: | ||
504 | case SNDRV_PCM_RATE_48000: | ||
505 | break; | ||
506 | } | ||
507 | |||
508 | wm8510_write(codec, WM8510_IFACE, iface); | ||
509 | wm8510_write(codec, WM8510_ADD, adn); | ||
510 | return 0; | ||
511 | } | ||
512 | |||
513 | static int wm8510_mute(struct snd_soc_dai *dai, int mute) | ||
514 | { | ||
515 | struct snd_soc_codec *codec = dai->codec; | ||
516 | u16 mute_reg = wm8510_read_reg_cache(codec, WM8510_DAC) & 0xffbf; | ||
517 | |||
518 | if (mute) | ||
519 | wm8510_write(codec, WM8510_DAC, mute_reg | 0x40); | ||
520 | else | ||
521 | wm8510_write(codec, WM8510_DAC, mute_reg); | ||
522 | return 0; | ||
523 | } | ||
524 | |||
525 | /* liam need to make this lower power with dapm */ | ||
526 | static int wm8510_set_bias_level(struct snd_soc_codec *codec, | ||
527 | enum snd_soc_bias_level level) | ||
528 | { | ||
529 | |||
530 | switch (level) { | ||
531 | case SND_SOC_BIAS_ON: | ||
532 | wm8510_write(codec, WM8510_POWER1, 0x1ff); | ||
533 | wm8510_write(codec, WM8510_POWER2, 0x1ff); | ||
534 | wm8510_write(codec, WM8510_POWER3, 0x1ff); | ||
535 | break; | ||
536 | case SND_SOC_BIAS_PREPARE: | ||
537 | case SND_SOC_BIAS_STANDBY: | ||
538 | break; | ||
539 | case SND_SOC_BIAS_OFF: | ||
540 | /* everything off, dac mute, inactive */ | ||
541 | wm8510_write(codec, WM8510_POWER1, 0x0); | ||
542 | wm8510_write(codec, WM8510_POWER2, 0x0); | ||
543 | wm8510_write(codec, WM8510_POWER3, 0x0); | ||
544 | break; | ||
545 | } | ||
546 | codec->bias_level = level; | ||
547 | return 0; | ||
548 | } | ||
549 | |||
550 | #define WM8510_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | ||
551 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ | ||
552 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) | ||
553 | |||
554 | #define WM8510_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | ||
555 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) | ||
556 | |||
557 | struct snd_soc_dai wm8510_dai = { | ||
558 | .name = "WM8510 HiFi", | ||
559 | .playback = { | ||
560 | .stream_name = "Playback", | ||
561 | .channels_min = 2, | ||
562 | .channels_max = 2, | ||
563 | .rates = WM8510_RATES, | ||
564 | .formats = WM8510_FORMATS,}, | ||
565 | .capture = { | ||
566 | .stream_name = "Capture", | ||
567 | .channels_min = 2, | ||
568 | .channels_max = 2, | ||
569 | .rates = WM8510_RATES, | ||
570 | .formats = WM8510_FORMATS,}, | ||
571 | .ops = { | ||
572 | .hw_params = wm8510_pcm_hw_params, | ||
573 | }, | ||
574 | .dai_ops = { | ||
575 | .digital_mute = wm8510_mute, | ||
576 | .set_fmt = wm8510_set_dai_fmt, | ||
577 | .set_clkdiv = wm8510_set_dai_clkdiv, | ||
578 | .set_pll = wm8510_set_dai_pll, | ||
579 | }, | ||
580 | }; | ||
581 | EXPORT_SYMBOL_GPL(wm8510_dai); | ||
582 | |||
583 | static int wm8510_suspend(struct platform_device *pdev, pm_message_t state) | ||
584 | { | ||
585 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
586 | struct snd_soc_codec *codec = socdev->codec; | ||
587 | |||
588 | wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
589 | return 0; | ||
590 | } | ||
591 | |||
592 | static int wm8510_resume(struct platform_device *pdev) | ||
593 | { | ||
594 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
595 | struct snd_soc_codec *codec = socdev->codec; | ||
596 | int i; | ||
597 | u8 data[2]; | ||
598 | u16 *cache = codec->reg_cache; | ||
599 | |||
600 | /* Sync reg_cache with the hardware */ | ||
601 | for (i = 0; i < ARRAY_SIZE(wm8510_reg); i++) { | ||
602 | data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); | ||
603 | data[1] = cache[i] & 0x00ff; | ||
604 | codec->hw_write(codec->control_data, data, 2); | ||
605 | } | ||
606 | wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
607 | wm8510_set_bias_level(codec, codec->suspend_bias_level); | ||
608 | return 0; | ||
609 | } | ||
610 | |||
611 | /* | ||
612 | * initialise the WM8510 driver | ||
613 | * register the mixer and dsp interfaces with the kernel | ||
614 | */ | ||
615 | static int wm8510_init(struct snd_soc_device *socdev) | ||
616 | { | ||
617 | struct snd_soc_codec *codec = socdev->codec; | ||
618 | int ret = 0; | ||
619 | |||
620 | codec->name = "WM8510"; | ||
621 | codec->owner = THIS_MODULE; | ||
622 | codec->read = wm8510_read_reg_cache; | ||
623 | codec->write = wm8510_write; | ||
624 | codec->set_bias_level = wm8510_set_bias_level; | ||
625 | codec->dai = &wm8510_dai; | ||
626 | codec->num_dai = 1; | ||
627 | codec->reg_cache_size = ARRAY_SIZE(wm8510_reg); | ||
628 | codec->reg_cache = kmemdup(wm8510_reg, sizeof(wm8510_reg), GFP_KERNEL); | ||
629 | |||
630 | if (codec->reg_cache == NULL) | ||
631 | return -ENOMEM; | ||
632 | |||
633 | wm8510_reset(codec); | ||
634 | |||
635 | /* register pcms */ | ||
636 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
637 | if (ret < 0) { | ||
638 | printk(KERN_ERR "wm8510: failed to create pcms\n"); | ||
639 | goto pcm_err; | ||
640 | } | ||
641 | |||
642 | /* power on device */ | ||
643 | wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
644 | wm8510_add_controls(codec); | ||
645 | wm8510_add_widgets(codec); | ||
646 | ret = snd_soc_register_card(socdev); | ||
647 | if (ret < 0) { | ||
648 | printk(KERN_ERR "wm8510: failed to register card\n"); | ||
649 | goto card_err; | ||
650 | } | ||
651 | return ret; | ||
652 | |||
653 | card_err: | ||
654 | snd_soc_free_pcms(socdev); | ||
655 | snd_soc_dapm_free(socdev); | ||
656 | pcm_err: | ||
657 | kfree(codec->reg_cache); | ||
658 | return ret; | ||
659 | } | ||
660 | |||
661 | static struct snd_soc_device *wm8510_socdev; | ||
662 | |||
663 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
664 | |||
665 | /* | ||
666 | * WM8510 2 wire address is 0x1a | ||
667 | */ | ||
668 | #define I2C_DRIVERID_WM8510 0xfefe /* liam - need a proper id */ | ||
669 | |||
670 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | ||
671 | |||
672 | /* Magic definition of all other variables and things */ | ||
673 | I2C_CLIENT_INSMOD; | ||
674 | |||
675 | static struct i2c_driver wm8510_i2c_driver; | ||
676 | static struct i2c_client client_template; | ||
677 | |||
678 | /* If the i2c layer weren't so broken, we could pass this kind of data | ||
679 | around */ | ||
680 | |||
681 | static int wm8510_codec_probe(struct i2c_adapter *adap, int addr, int kind) | ||
682 | { | ||
683 | struct snd_soc_device *socdev = wm8510_socdev; | ||
684 | struct wm8510_setup_data *setup = socdev->codec_data; | ||
685 | struct snd_soc_codec *codec = socdev->codec; | ||
686 | struct i2c_client *i2c; | ||
687 | int ret; | ||
688 | |||
689 | if (addr != setup->i2c_address) | ||
690 | return -ENODEV; | ||
691 | |||
692 | client_template.adapter = adap; | ||
693 | client_template.addr = addr; | ||
694 | |||
695 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | ||
696 | if (i2c == NULL) { | ||
697 | kfree(codec); | ||
698 | return -ENOMEM; | ||
699 | } | ||
700 | i2c_set_clientdata(i2c, codec); | ||
701 | codec->control_data = i2c; | ||
702 | |||
703 | ret = i2c_attach_client(i2c); | ||
704 | if (ret < 0) { | ||
705 | pr_err("failed to attach codec at addr %x\n", addr); | ||
706 | goto err; | ||
707 | } | ||
708 | |||
709 | ret = wm8510_init(socdev); | ||
710 | if (ret < 0) { | ||
711 | pr_err("failed to initialise WM8510\n"); | ||
712 | goto err; | ||
713 | } | ||
714 | return ret; | ||
715 | |||
716 | err: | ||
717 | kfree(codec); | ||
718 | kfree(i2c); | ||
719 | return ret; | ||
720 | } | ||
721 | |||
722 | static int wm8510_i2c_detach(struct i2c_client *client) | ||
723 | { | ||
724 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | ||
725 | i2c_detach_client(client); | ||
726 | kfree(codec->reg_cache); | ||
727 | kfree(client); | ||
728 | return 0; | ||
729 | } | ||
730 | |||
731 | static int wm8510_i2c_attach(struct i2c_adapter *adap) | ||
732 | { | ||
733 | return i2c_probe(adap, &addr_data, wm8510_codec_probe); | ||
734 | } | ||
735 | |||
736 | /* corgi i2c codec control layer */ | ||
737 | static struct i2c_driver wm8510_i2c_driver = { | ||
738 | .driver = { | ||
739 | .name = "WM8510 I2C Codec", | ||
740 | .owner = THIS_MODULE, | ||
741 | }, | ||
742 | .id = I2C_DRIVERID_WM8510, | ||
743 | .attach_adapter = wm8510_i2c_attach, | ||
744 | .detach_client = wm8510_i2c_detach, | ||
745 | .command = NULL, | ||
746 | }; | ||
747 | |||
748 | static struct i2c_client client_template = { | ||
749 | .name = "WM8510", | ||
750 | .driver = &wm8510_i2c_driver, | ||
751 | }; | ||
752 | #endif | ||
753 | |||
754 | static int wm8510_probe(struct platform_device *pdev) | ||
755 | { | ||
756 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
757 | struct wm8510_setup_data *setup; | ||
758 | struct snd_soc_codec *codec; | ||
759 | int ret = 0; | ||
760 | |||
761 | pr_info("WM8510 Audio Codec %s", WM8510_VERSION); | ||
762 | |||
763 | setup = socdev->codec_data; | ||
764 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
765 | if (codec == NULL) | ||
766 | return -ENOMEM; | ||
767 | |||
768 | socdev->codec = codec; | ||
769 | mutex_init(&codec->mutex); | ||
770 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
771 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
772 | |||
773 | wm8510_socdev = socdev; | ||
774 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
775 | if (setup->i2c_address) { | ||
776 | normal_i2c[0] = setup->i2c_address; | ||
777 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
778 | ret = i2c_add_driver(&wm8510_i2c_driver); | ||
779 | if (ret != 0) | ||
780 | printk(KERN_ERR "can't add i2c driver"); | ||
781 | } | ||
782 | #else | ||
783 | /* Add other interfaces here */ | ||
784 | #endif | ||
785 | return ret; | ||
786 | } | ||
787 | |||
788 | /* power down chip */ | ||
789 | static int wm8510_remove(struct platform_device *pdev) | ||
790 | { | ||
791 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
792 | struct snd_soc_codec *codec = socdev->codec; | ||
793 | |||
794 | if (codec->control_data) | ||
795 | wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
796 | |||
797 | snd_soc_free_pcms(socdev); | ||
798 | snd_soc_dapm_free(socdev); | ||
799 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
800 | i2c_del_driver(&wm8510_i2c_driver); | ||
801 | #endif | ||
802 | kfree(codec); | ||
803 | |||
804 | return 0; | ||
805 | } | ||
806 | |||
807 | struct snd_soc_codec_device soc_codec_dev_wm8510 = { | ||
808 | .probe = wm8510_probe, | ||
809 | .remove = wm8510_remove, | ||
810 | .suspend = wm8510_suspend, | ||
811 | .resume = wm8510_resume, | ||
812 | }; | ||
813 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8510); | ||
814 | |||
815 | MODULE_DESCRIPTION("ASoC WM8510 driver"); | ||
816 | MODULE_AUTHOR("Liam Girdwood"); | ||
817 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/wm8510.h b/sound/soc/codecs/wm8510.h new file mode 100644 index 000000000000..f5d2e42eb3f4 --- /dev/null +++ b/sound/soc/codecs/wm8510.h | |||
@@ -0,0 +1,103 @@ | |||
1 | /* | ||
2 | * wm8510.h -- WM8510 Soc Audio driver | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #ifndef _WM8510_H | ||
10 | #define _WM8510_H | ||
11 | |||
12 | /* WM8510 register space */ | ||
13 | |||
14 | #define WM8510_RESET 0x0 | ||
15 | #define WM8510_POWER1 0x1 | ||
16 | #define WM8510_POWER2 0x2 | ||
17 | #define WM8510_POWER3 0x3 | ||
18 | #define WM8510_IFACE 0x4 | ||
19 | #define WM8510_COMP 0x5 | ||
20 | #define WM8510_CLOCK 0x6 | ||
21 | #define WM8510_ADD 0x7 | ||
22 | #define WM8510_GPIO 0x8 | ||
23 | #define WM8510_DAC 0xa | ||
24 | #define WM8510_DACVOL 0xb | ||
25 | #define WM8510_ADC 0xe | ||
26 | #define WM8510_ADCVOL 0xf | ||
27 | #define WM8510_EQ1 0x12 | ||
28 | #define WM8510_EQ2 0x13 | ||
29 | #define WM8510_EQ3 0x14 | ||
30 | #define WM8510_EQ4 0x15 | ||
31 | #define WM8510_EQ5 0x16 | ||
32 | #define WM8510_DACLIM1 0x18 | ||
33 | #define WM8510_DACLIM2 0x19 | ||
34 | #define WM8510_NOTCH1 0x1b | ||
35 | #define WM8510_NOTCH2 0x1c | ||
36 | #define WM8510_NOTCH3 0x1d | ||
37 | #define WM8510_NOTCH4 0x1e | ||
38 | #define WM8510_ALC1 0x20 | ||
39 | #define WM8510_ALC2 0x21 | ||
40 | #define WM8510_ALC3 0x22 | ||
41 | #define WM8510_NGATE 0x23 | ||
42 | #define WM8510_PLLN 0x24 | ||
43 | #define WM8510_PLLK1 0x25 | ||
44 | #define WM8510_PLLK2 0x26 | ||
45 | #define WM8510_PLLK3 0x27 | ||
46 | #define WM8510_ATTEN 0x28 | ||
47 | #define WM8510_INPUT 0x2c | ||
48 | #define WM8510_INPPGA 0x2d | ||
49 | #define WM8510_ADCBOOST 0x2f | ||
50 | #define WM8510_OUTPUT 0x31 | ||
51 | #define WM8510_SPKMIX 0x32 | ||
52 | #define WM8510_SPKVOL 0x36 | ||
53 | #define WM8510_MONOMIX 0x38 | ||
54 | |||
55 | #define WM8510_CACHEREGNUM 57 | ||
56 | |||
57 | /* Clock divider Id's */ | ||
58 | #define WM8510_OPCLKDIV 0 | ||
59 | #define WM8510_MCLKDIV 1 | ||
60 | #define WM8510_ADCCLK 2 | ||
61 | #define WM8510_DACCLK 3 | ||
62 | #define WM8510_BCLKDIV 4 | ||
63 | |||
64 | /* DAC clock dividers */ | ||
65 | #define WM8510_DACCLK_F2 (1 << 3) | ||
66 | #define WM8510_DACCLK_F4 (0 << 3) | ||
67 | |||
68 | /* ADC clock dividers */ | ||
69 | #define WM8510_ADCCLK_F2 (1 << 3) | ||
70 | #define WM8510_ADCCLK_F4 (0 << 3) | ||
71 | |||
72 | /* PLL Out dividers */ | ||
73 | #define WM8510_OPCLKDIV_1 (0 << 4) | ||
74 | #define WM8510_OPCLKDIV_2 (1 << 4) | ||
75 | #define WM8510_OPCLKDIV_3 (2 << 4) | ||
76 | #define WM8510_OPCLKDIV_4 (3 << 4) | ||
77 | |||
78 | /* BCLK clock dividers */ | ||
79 | #define WM8510_BCLKDIV_1 (0 << 2) | ||
80 | #define WM8510_BCLKDIV_2 (1 << 2) | ||
81 | #define WM8510_BCLKDIV_4 (2 << 2) | ||
82 | #define WM8510_BCLKDIV_8 (3 << 2) | ||
83 | #define WM8510_BCLKDIV_16 (4 << 2) | ||
84 | #define WM8510_BCLKDIV_32 (5 << 2) | ||
85 | |||
86 | /* MCLK clock dividers */ | ||
87 | #define WM8510_MCLKDIV_1 (0 << 5) | ||
88 | #define WM8510_MCLKDIV_1_5 (1 << 5) | ||
89 | #define WM8510_MCLKDIV_2 (2 << 5) | ||
90 | #define WM8510_MCLKDIV_3 (3 << 5) | ||
91 | #define WM8510_MCLKDIV_4 (4 << 5) | ||
92 | #define WM8510_MCLKDIV_6 (5 << 5) | ||
93 | #define WM8510_MCLKDIV_8 (6 << 5) | ||
94 | #define WM8510_MCLKDIV_12 (7 << 5) | ||
95 | |||
96 | struct wm8510_setup_data { | ||
97 | unsigned short i2c_address; | ||
98 | }; | ||
99 | |||
100 | extern struct snd_soc_dai wm8510_dai; | ||
101 | extern struct snd_soc_codec_device soc_codec_dev_wm8510; | ||
102 | |||
103 | #endif | ||
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 0cf9265fca8f..369d39c3f745 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c | |||
@@ -31,25 +31,6 @@ | |||
31 | #define AUDIO_NAME "wm8731" | 31 | #define AUDIO_NAME "wm8731" |
32 | #define WM8731_VERSION "0.13" | 32 | #define WM8731_VERSION "0.13" |
33 | 33 | ||
34 | /* | ||
35 | * Debug | ||
36 | */ | ||
37 | |||
38 | #define WM8731_DEBUG 0 | ||
39 | |||
40 | #ifdef WM8731_DEBUG | ||
41 | #define dbg(format, arg...) \ | ||
42 | printk(KERN_DEBUG AUDIO_NAME ": " format "\n" , ## arg) | ||
43 | #else | ||
44 | #define dbg(format, arg...) do {} while (0) | ||
45 | #endif | ||
46 | #define err(format, arg...) \ | ||
47 | printk(KERN_ERR AUDIO_NAME ": " format "\n" , ## arg) | ||
48 | #define info(format, arg...) \ | ||
49 | printk(KERN_INFO AUDIO_NAME ": " format "\n" , ## arg) | ||
50 | #define warn(format, arg...) \ | ||
51 | printk(KERN_WARNING AUDIO_NAME ": " format "\n" , ## arg) | ||
52 | |||
53 | struct snd_soc_codec_device soc_codec_dev_wm8731; | 34 | struct snd_soc_codec_device soc_codec_dev_wm8731; |
54 | 35 | ||
55 | /* codec private data */ | 36 | /* codec private data */ |
@@ -193,7 +174,7 @@ SND_SOC_DAPM_INPUT("RLINEIN"), | |||
193 | SND_SOC_DAPM_INPUT("LLINEIN"), | 174 | SND_SOC_DAPM_INPUT("LLINEIN"), |
194 | }; | 175 | }; |
195 | 176 | ||
196 | static const char *intercon[][3] = { | 177 | static const struct snd_soc_dapm_route intercon[] = { |
197 | /* output mixer */ | 178 | /* output mixer */ |
198 | {"Output Mixer", "Line Bypass Switch", "Line Input"}, | 179 | {"Output Mixer", "Line Bypass Switch", "Line Input"}, |
199 | {"Output Mixer", "HiFi Playback Switch", "DAC"}, | 180 | {"Output Mixer", "HiFi Playback Switch", "DAC"}, |
@@ -214,22 +195,14 @@ static const char *intercon[][3] = { | |||
214 | {"Line Input", NULL, "LLINEIN"}, | 195 | {"Line Input", NULL, "LLINEIN"}, |
215 | {"Line Input", NULL, "RLINEIN"}, | 196 | {"Line Input", NULL, "RLINEIN"}, |
216 | {"Mic Bias", NULL, "MICIN"}, | 197 | {"Mic Bias", NULL, "MICIN"}, |
217 | |||
218 | /* terminator */ | ||
219 | {NULL, NULL, NULL}, | ||
220 | }; | 198 | }; |
221 | 199 | ||
222 | static int wm8731_add_widgets(struct snd_soc_codec *codec) | 200 | static int wm8731_add_widgets(struct snd_soc_codec *codec) |
223 | { | 201 | { |
224 | int i; | 202 | snd_soc_dapm_new_controls(codec, wm8731_dapm_widgets, |
225 | 203 | ARRAY_SIZE(wm8731_dapm_widgets)); | |
226 | for (i = 0; i < ARRAY_SIZE(wm8731_dapm_widgets); i++) | ||
227 | snd_soc_dapm_new_control(codec, &wm8731_dapm_widgets[i]); | ||
228 | 204 | ||
229 | /* set up audio path interconnects */ | 205 | snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); |
230 | for (i = 0; intercon[i][0] != NULL; i++) | ||
231 | snd_soc_dapm_connect_input(codec, intercon[i][0], | ||
232 | intercon[i][1], intercon[i][2]); | ||
233 | 206 | ||
234 | snd_soc_dapm_new_widgets(codec); | 207 | snd_soc_dapm_new_widgets(codec); |
235 | return 0; | 208 | return 0; |
@@ -345,7 +318,7 @@ static void wm8731_shutdown(struct snd_pcm_substream *substream) | |||
345 | } | 318 | } |
346 | } | 319 | } |
347 | 320 | ||
348 | static int wm8731_mute(struct snd_soc_codec_dai *dai, int mute) | 321 | static int wm8731_mute(struct snd_soc_dai *dai, int mute) |
349 | { | 322 | { |
350 | struct snd_soc_codec *codec = dai->codec; | 323 | struct snd_soc_codec *codec = dai->codec; |
351 | u16 mute_reg = wm8731_read_reg_cache(codec, WM8731_APDIGI) & 0xfff7; | 324 | u16 mute_reg = wm8731_read_reg_cache(codec, WM8731_APDIGI) & 0xfff7; |
@@ -357,7 +330,7 @@ static int wm8731_mute(struct snd_soc_codec_dai *dai, int mute) | |||
357 | return 0; | 330 | return 0; |
358 | } | 331 | } |
359 | 332 | ||
360 | static int wm8731_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai, | 333 | static int wm8731_set_dai_sysclk(struct snd_soc_dai *codec_dai, |
361 | int clk_id, unsigned int freq, int dir) | 334 | int clk_id, unsigned int freq, int dir) |
362 | { | 335 | { |
363 | struct snd_soc_codec *codec = codec_dai->codec; | 336 | struct snd_soc_codec *codec = codec_dai->codec; |
@@ -376,7 +349,7 @@ static int wm8731_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai, | |||
376 | } | 349 | } |
377 | 350 | ||
378 | 351 | ||
379 | static int wm8731_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | 352 | static int wm8731_set_dai_fmt(struct snd_soc_dai *codec_dai, |
380 | unsigned int fmt) | 353 | unsigned int fmt) |
381 | { | 354 | { |
382 | struct snd_soc_codec *codec = codec_dai->codec; | 355 | struct snd_soc_codec *codec = codec_dai->codec; |
@@ -435,29 +408,29 @@ static int wm8731_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | |||
435 | return 0; | 408 | return 0; |
436 | } | 409 | } |
437 | 410 | ||
438 | static int wm8731_dapm_event(struct snd_soc_codec *codec, int event) | 411 | static int wm8731_set_bias_level(struct snd_soc_codec *codec, |
412 | enum snd_soc_bias_level level) | ||
439 | { | 413 | { |
440 | u16 reg = wm8731_read_reg_cache(codec, WM8731_PWR) & 0xff7f; | 414 | u16 reg = wm8731_read_reg_cache(codec, WM8731_PWR) & 0xff7f; |
441 | 415 | ||
442 | switch (event) { | 416 | switch (level) { |
443 | case SNDRV_CTL_POWER_D0: /* full On */ | 417 | case SND_SOC_BIAS_ON: |
444 | /* vref/mid, osc on, dac unmute */ | 418 | /* vref/mid, osc on, dac unmute */ |
445 | wm8731_write(codec, WM8731_PWR, reg); | 419 | wm8731_write(codec, WM8731_PWR, reg); |
446 | break; | 420 | break; |
447 | case SNDRV_CTL_POWER_D1: /* partial On */ | 421 | case SND_SOC_BIAS_PREPARE: |
448 | case SNDRV_CTL_POWER_D2: /* partial On */ | ||
449 | break; | 422 | break; |
450 | case SNDRV_CTL_POWER_D3hot: /* Off, with power */ | 423 | case SND_SOC_BIAS_STANDBY: |
451 | /* everything off except vref/vmid, */ | 424 | /* everything off except vref/vmid, */ |
452 | wm8731_write(codec, WM8731_PWR, reg | 0x0040); | 425 | wm8731_write(codec, WM8731_PWR, reg | 0x0040); |
453 | break; | 426 | break; |
454 | case SNDRV_CTL_POWER_D3cold: /* Off, without power */ | 427 | case SND_SOC_BIAS_OFF: |
455 | /* everything off, dac mute, inactive */ | 428 | /* everything off, dac mute, inactive */ |
456 | wm8731_write(codec, WM8731_ACTIVE, 0x0); | 429 | wm8731_write(codec, WM8731_ACTIVE, 0x0); |
457 | wm8731_write(codec, WM8731_PWR, 0xffff); | 430 | wm8731_write(codec, WM8731_PWR, 0xffff); |
458 | break; | 431 | break; |
459 | } | 432 | } |
460 | codec->dapm_state = event; | 433 | codec->bias_level = level; |
461 | return 0; | 434 | return 0; |
462 | } | 435 | } |
463 | 436 | ||
@@ -470,7 +443,7 @@ static int wm8731_dapm_event(struct snd_soc_codec *codec, int event) | |||
470 | #define WM8731_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | 443 | #define WM8731_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ |
471 | SNDRV_PCM_FMTBIT_S24_LE) | 444 | SNDRV_PCM_FMTBIT_S24_LE) |
472 | 445 | ||
473 | struct snd_soc_codec_dai wm8731_dai = { | 446 | struct snd_soc_dai wm8731_dai = { |
474 | .name = "WM8731", | 447 | .name = "WM8731", |
475 | .playback = { | 448 | .playback = { |
476 | .stream_name = "Playback", | 449 | .stream_name = "Playback", |
@@ -503,7 +476,7 @@ static int wm8731_suspend(struct platform_device *pdev, pm_message_t state) | |||
503 | struct snd_soc_codec *codec = socdev->codec; | 476 | struct snd_soc_codec *codec = socdev->codec; |
504 | 477 | ||
505 | wm8731_write(codec, WM8731_ACTIVE, 0x0); | 478 | wm8731_write(codec, WM8731_ACTIVE, 0x0); |
506 | wm8731_dapm_event(codec, SNDRV_CTL_POWER_D3cold); | 479 | wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF); |
507 | return 0; | 480 | return 0; |
508 | } | 481 | } |
509 | 482 | ||
@@ -521,8 +494,8 @@ static int wm8731_resume(struct platform_device *pdev) | |||
521 | data[1] = cache[i] & 0x00ff; | 494 | data[1] = cache[i] & 0x00ff; |
522 | codec->hw_write(codec->control_data, data, 2); | 495 | codec->hw_write(codec->control_data, data, 2); |
523 | } | 496 | } |
524 | wm8731_dapm_event(codec, SNDRV_CTL_POWER_D3hot); | 497 | wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
525 | wm8731_dapm_event(codec, codec->suspend_dapm_state); | 498 | wm8731_set_bias_level(codec, codec->suspend_bias_level); |
526 | return 0; | 499 | return 0; |
527 | } | 500 | } |
528 | 501 | ||
@@ -539,10 +512,10 @@ static int wm8731_init(struct snd_soc_device *socdev) | |||
539 | codec->owner = THIS_MODULE; | 512 | codec->owner = THIS_MODULE; |
540 | codec->read = wm8731_read_reg_cache; | 513 | codec->read = wm8731_read_reg_cache; |
541 | codec->write = wm8731_write; | 514 | codec->write = wm8731_write; |
542 | codec->dapm_event = wm8731_dapm_event; | 515 | codec->set_bias_level = wm8731_set_bias_level; |
543 | codec->dai = &wm8731_dai; | 516 | codec->dai = &wm8731_dai; |
544 | codec->num_dai = 1; | 517 | codec->num_dai = 1; |
545 | codec->reg_cache_size = sizeof(wm8731_reg); | 518 | codec->reg_cache_size = ARRAY_SIZE(wm8731_reg); |
546 | codec->reg_cache = kmemdup(wm8731_reg, sizeof(wm8731_reg), GFP_KERNEL); | 519 | codec->reg_cache = kmemdup(wm8731_reg, sizeof(wm8731_reg), GFP_KERNEL); |
547 | if (codec->reg_cache == NULL) | 520 | if (codec->reg_cache == NULL) |
548 | return -ENOMEM; | 521 | return -ENOMEM; |
@@ -557,7 +530,7 @@ static int wm8731_init(struct snd_soc_device *socdev) | |||
557 | } | 530 | } |
558 | 531 | ||
559 | /* power on device */ | 532 | /* power on device */ |
560 | wm8731_dapm_event(codec, SNDRV_CTL_POWER_D3hot); | 533 | wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
561 | 534 | ||
562 | /* set the update bits */ | 535 | /* set the update bits */ |
563 | reg = wm8731_read_reg_cache(codec, WM8731_LOUT1V); | 536 | reg = wm8731_read_reg_cache(codec, WM8731_LOUT1V); |
@@ -632,13 +605,13 @@ static int wm8731_codec_probe(struct i2c_adapter *adap, int addr, int kind) | |||
632 | 605 | ||
633 | ret = i2c_attach_client(i2c); | 606 | ret = i2c_attach_client(i2c); |
634 | if (ret < 0) { | 607 | if (ret < 0) { |
635 | err("failed to attach codec at addr %x\n", addr); | 608 | pr_err("failed to attach codec at addr %x\n", addr); |
636 | goto err; | 609 | goto err; |
637 | } | 610 | } |
638 | 611 | ||
639 | ret = wm8731_init(socdev); | 612 | ret = wm8731_init(socdev); |
640 | if (ret < 0) { | 613 | if (ret < 0) { |
641 | err("failed to initialise WM8731\n"); | 614 | pr_err("failed to initialise WM8731\n"); |
642 | goto err; | 615 | goto err; |
643 | } | 616 | } |
644 | return ret; | 617 | return ret; |
@@ -689,7 +662,7 @@ static int wm8731_probe(struct platform_device *pdev) | |||
689 | struct wm8731_priv *wm8731; | 662 | struct wm8731_priv *wm8731; |
690 | int ret = 0; | 663 | int ret = 0; |
691 | 664 | ||
692 | info("WM8731 Audio Codec %s", WM8731_VERSION); | 665 | pr_info("WM8731 Audio Codec %s", WM8731_VERSION); |
693 | 666 | ||
694 | setup = socdev->codec_data; | 667 | setup = socdev->codec_data; |
695 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | 668 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); |
@@ -730,7 +703,7 @@ static int wm8731_remove(struct platform_device *pdev) | |||
730 | struct snd_soc_codec *codec = socdev->codec; | 703 | struct snd_soc_codec *codec = socdev->codec; |
731 | 704 | ||
732 | if (codec->control_data) | 705 | if (codec->control_data) |
733 | wm8731_dapm_event(codec, SNDRV_CTL_POWER_D3cold); | 706 | wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF); |
734 | 707 | ||
735 | snd_soc_free_pcms(socdev); | 708 | snd_soc_free_pcms(socdev); |
736 | snd_soc_dapm_free(socdev); | 709 | snd_soc_dapm_free(socdev); |
diff --git a/sound/soc/codecs/wm8731.h b/sound/soc/codecs/wm8731.h index 5bcab6a7afb4..99f2e3c60e33 100644 --- a/sound/soc/codecs/wm8731.h +++ b/sound/soc/codecs/wm8731.h | |||
@@ -38,7 +38,7 @@ struct wm8731_setup_data { | |||
38 | unsigned short i2c_address; | 38 | unsigned short i2c_address; |
39 | }; | 39 | }; |
40 | 40 | ||
41 | extern struct snd_soc_codec_dai wm8731_dai; | 41 | extern struct snd_soc_dai wm8731_dai; |
42 | extern struct snd_soc_codec_device soc_codec_dev_wm8731; | 42 | extern struct snd_soc_codec_device soc_codec_dev_wm8731; |
43 | 43 | ||
44 | #endif | 44 | #endif |
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index 16cd5d4d5ad9..e23cb09f0d14 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c | |||
@@ -31,25 +31,6 @@ | |||
31 | #define AUDIO_NAME "WM8750" | 31 | #define AUDIO_NAME "WM8750" |
32 | #define WM8750_VERSION "0.12" | 32 | #define WM8750_VERSION "0.12" |
33 | 33 | ||
34 | /* | ||
35 | * Debug | ||
36 | */ | ||
37 | |||
38 | #define WM8750_DEBUG 0 | ||
39 | |||
40 | #ifdef WM8750_DEBUG | ||
41 | #define dbg(format, arg...) \ | ||
42 | printk(KERN_DEBUG AUDIO_NAME ": " format "\n" , ## arg) | ||
43 | #else | ||
44 | #define dbg(format, arg...) do {} while (0) | ||
45 | #endif | ||
46 | #define err(format, arg...) \ | ||
47 | printk(KERN_ERR AUDIO_NAME ": " format "\n" , ## arg) | ||
48 | #define info(format, arg...) \ | ||
49 | printk(KERN_INFO AUDIO_NAME ": " format "\n" , ## arg) | ||
50 | #define warn(format, arg...) \ | ||
51 | printk(KERN_WARNING AUDIO_NAME ": " format "\n" , ## arg) | ||
52 | |||
53 | /* codec private data */ | 34 | /* codec private data */ |
54 | struct wm8750_priv { | 35 | struct wm8750_priv { |
55 | unsigned int sysclk; | 36 | unsigned int sysclk; |
@@ -378,7 +359,7 @@ static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = { | |||
378 | SND_SOC_DAPM_INPUT("RINPUT3"), | 359 | SND_SOC_DAPM_INPUT("RINPUT3"), |
379 | }; | 360 | }; |
380 | 361 | ||
381 | static const char *audio_map[][3] = { | 362 | static const struct snd_soc_dapm_route audio_map[] = { |
382 | /* left mixer */ | 363 | /* left mixer */ |
383 | {"Left Mixer", "Playback Switch", "Left DAC"}, | 364 | {"Left Mixer", "Playback Switch", "Left DAC"}, |
384 | {"Left Mixer", "Left Bypass Switch", "Left Line Mux"}, | 365 | {"Left Mixer", "Left Bypass Switch", "Left Line Mux"}, |
@@ -470,22 +451,14 @@ static const char *audio_map[][3] = { | |||
470 | /* ADC */ | 451 | /* ADC */ |
471 | {"Left ADC", NULL, "Left ADC Mux"}, | 452 | {"Left ADC", NULL, "Left ADC Mux"}, |
472 | {"Right ADC", NULL, "Right ADC Mux"}, | 453 | {"Right ADC", NULL, "Right ADC Mux"}, |
473 | |||
474 | /* terminator */ | ||
475 | {NULL, NULL, NULL}, | ||
476 | }; | 454 | }; |
477 | 455 | ||
478 | static int wm8750_add_widgets(struct snd_soc_codec *codec) | 456 | static int wm8750_add_widgets(struct snd_soc_codec *codec) |
479 | { | 457 | { |
480 | int i; | 458 | snd_soc_dapm_new_controls(codec, wm8750_dapm_widgets, |
481 | 459 | ARRAY_SIZE(wm8750_dapm_widgets)); | |
482 | for (i = 0; i < ARRAY_SIZE(wm8750_dapm_widgets); i++) | ||
483 | snd_soc_dapm_new_control(codec, &wm8750_dapm_widgets[i]); | ||
484 | 460 | ||
485 | /* set up audio path audio_mapnects */ | 461 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); |
486 | for (i = 0; audio_map[i][0] != NULL; i++) | ||
487 | snd_soc_dapm_connect_input(codec, audio_map[i][0], | ||
488 | audio_map[i][1], audio_map[i][2]); | ||
489 | 462 | ||
490 | snd_soc_dapm_new_widgets(codec); | 463 | snd_soc_dapm_new_widgets(codec); |
491 | return 0; | 464 | return 0; |
@@ -563,7 +536,7 @@ static inline int get_coeff(int mclk, int rate) | |||
563 | return -EINVAL; | 536 | return -EINVAL; |
564 | } | 537 | } |
565 | 538 | ||
566 | static int wm8750_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai, | 539 | static int wm8750_set_dai_sysclk(struct snd_soc_dai *codec_dai, |
567 | int clk_id, unsigned int freq, int dir) | 540 | int clk_id, unsigned int freq, int dir) |
568 | { | 541 | { |
569 | struct snd_soc_codec *codec = codec_dai->codec; | 542 | struct snd_soc_codec *codec = codec_dai->codec; |
@@ -581,7 +554,7 @@ static int wm8750_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai, | |||
581 | return -EINVAL; | 554 | return -EINVAL; |
582 | } | 555 | } |
583 | 556 | ||
584 | static int wm8750_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | 557 | static int wm8750_set_dai_fmt(struct snd_soc_dai *codec_dai, |
585 | unsigned int fmt) | 558 | unsigned int fmt) |
586 | { | 559 | { |
587 | struct snd_soc_codec *codec = codec_dai->codec; | 560 | struct snd_soc_codec *codec = codec_dai->codec; |
@@ -674,7 +647,7 @@ static int wm8750_pcm_hw_params(struct snd_pcm_substream *substream, | |||
674 | return 0; | 647 | return 0; |
675 | } | 648 | } |
676 | 649 | ||
677 | static int wm8750_mute(struct snd_soc_codec_dai *dai, int mute) | 650 | static int wm8750_mute(struct snd_soc_dai *dai, int mute) |
678 | { | 651 | { |
679 | struct snd_soc_codec *codec = dai->codec; | 652 | struct snd_soc_codec *codec = dai->codec; |
680 | u16 mute_reg = wm8750_read_reg_cache(codec, WM8750_ADCDAC) & 0xfff7; | 653 | u16 mute_reg = wm8750_read_reg_cache(codec, WM8750_ADCDAC) & 0xfff7; |
@@ -686,29 +659,29 @@ static int wm8750_mute(struct snd_soc_codec_dai *dai, int mute) | |||
686 | return 0; | 659 | return 0; |
687 | } | 660 | } |
688 | 661 | ||
689 | static int wm8750_dapm_event(struct snd_soc_codec *codec, int event) | 662 | static int wm8750_set_bias_level(struct snd_soc_codec *codec, |
663 | enum snd_soc_bias_level level) | ||
690 | { | 664 | { |
691 | u16 pwr_reg = wm8750_read_reg_cache(codec, WM8750_PWR1) & 0xfe3e; | 665 | u16 pwr_reg = wm8750_read_reg_cache(codec, WM8750_PWR1) & 0xfe3e; |
692 | 666 | ||
693 | switch (event) { | 667 | switch (level) { |
694 | case SNDRV_CTL_POWER_D0: /* full On */ | 668 | case SND_SOC_BIAS_ON: |
695 | /* set vmid to 50k and unmute dac */ | 669 | /* set vmid to 50k and unmute dac */ |
696 | wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x00c0); | 670 | wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x00c0); |
697 | break; | 671 | break; |
698 | case SNDRV_CTL_POWER_D1: /* partial On */ | 672 | case SND_SOC_BIAS_PREPARE: |
699 | case SNDRV_CTL_POWER_D2: /* partial On */ | ||
700 | /* set vmid to 5k for quick power up */ | 673 | /* set vmid to 5k for quick power up */ |
701 | wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x01c1); | 674 | wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x01c1); |
702 | break; | 675 | break; |
703 | case SNDRV_CTL_POWER_D3hot: /* Off, with power */ | 676 | case SND_SOC_BIAS_STANDBY: |
704 | /* mute dac and set vmid to 500k, enable VREF */ | 677 | /* mute dac and set vmid to 500k, enable VREF */ |
705 | wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x0141); | 678 | wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x0141); |
706 | break; | 679 | break; |
707 | case SNDRV_CTL_POWER_D3cold: /* Off, without power */ | 680 | case SND_SOC_BIAS_OFF: |
708 | wm8750_write(codec, WM8750_PWR1, 0x0001); | 681 | wm8750_write(codec, WM8750_PWR1, 0x0001); |
709 | break; | 682 | break; |
710 | } | 683 | } |
711 | codec->dapm_state = event; | 684 | codec->bias_level = level; |
712 | return 0; | 685 | return 0; |
713 | } | 686 | } |
714 | 687 | ||
@@ -719,7 +692,7 @@ static int wm8750_dapm_event(struct snd_soc_codec *codec, int event) | |||
719 | #define WM8750_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | 692 | #define WM8750_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ |
720 | SNDRV_PCM_FMTBIT_S24_LE) | 693 | SNDRV_PCM_FMTBIT_S24_LE) |
721 | 694 | ||
722 | struct snd_soc_codec_dai wm8750_dai = { | 695 | struct snd_soc_dai wm8750_dai = { |
723 | .name = "WM8750", | 696 | .name = "WM8750", |
724 | .playback = { | 697 | .playback = { |
725 | .stream_name = "Playback", | 698 | .stream_name = "Playback", |
@@ -748,7 +721,7 @@ static void wm8750_work(struct work_struct *work) | |||
748 | { | 721 | { |
749 | struct snd_soc_codec *codec = | 722 | struct snd_soc_codec *codec = |
750 | container_of(work, struct snd_soc_codec, delayed_work.work); | 723 | container_of(work, struct snd_soc_codec, delayed_work.work); |
751 | wm8750_dapm_event(codec, codec->dapm_state); | 724 | wm8750_set_bias_level(codec, codec->bias_level); |
752 | } | 725 | } |
753 | 726 | ||
754 | static int wm8750_suspend(struct platform_device *pdev, pm_message_t state) | 727 | static int wm8750_suspend(struct platform_device *pdev, pm_message_t state) |
@@ -756,7 +729,7 @@ static int wm8750_suspend(struct platform_device *pdev, pm_message_t state) | |||
756 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 729 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
757 | struct snd_soc_codec *codec = socdev->codec; | 730 | struct snd_soc_codec *codec = socdev->codec; |
758 | 731 | ||
759 | wm8750_dapm_event(codec, SNDRV_CTL_POWER_D3cold); | 732 | wm8750_set_bias_level(codec, SND_SOC_BIAS_OFF); |
760 | return 0; | 733 | return 0; |
761 | } | 734 | } |
762 | 735 | ||
@@ -777,12 +750,12 @@ static int wm8750_resume(struct platform_device *pdev) | |||
777 | codec->hw_write(codec->control_data, data, 2); | 750 | codec->hw_write(codec->control_data, data, 2); |
778 | } | 751 | } |
779 | 752 | ||
780 | wm8750_dapm_event(codec, SNDRV_CTL_POWER_D3hot); | 753 | wm8750_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
781 | 754 | ||
782 | /* charge wm8750 caps */ | 755 | /* charge wm8750 caps */ |
783 | if (codec->suspend_dapm_state == SNDRV_CTL_POWER_D0) { | 756 | if (codec->suspend_bias_level == SND_SOC_BIAS_ON) { |
784 | wm8750_dapm_event(codec, SNDRV_CTL_POWER_D2); | 757 | wm8750_set_bias_level(codec, SND_SOC_BIAS_PREPARE); |
785 | codec->dapm_state = SNDRV_CTL_POWER_D0; | 758 | codec->bias_level = SND_SOC_BIAS_ON; |
786 | schedule_delayed_work(&codec->delayed_work, | 759 | schedule_delayed_work(&codec->delayed_work, |
787 | msecs_to_jiffies(1000)); | 760 | msecs_to_jiffies(1000)); |
788 | } | 761 | } |
@@ -803,10 +776,10 @@ static int wm8750_init(struct snd_soc_device *socdev) | |||
803 | codec->owner = THIS_MODULE; | 776 | codec->owner = THIS_MODULE; |
804 | codec->read = wm8750_read_reg_cache; | 777 | codec->read = wm8750_read_reg_cache; |
805 | codec->write = wm8750_write; | 778 | codec->write = wm8750_write; |
806 | codec->dapm_event = wm8750_dapm_event; | 779 | codec->set_bias_level = wm8750_set_bias_level; |
807 | codec->dai = &wm8750_dai; | 780 | codec->dai = &wm8750_dai; |
808 | codec->num_dai = 1; | 781 | codec->num_dai = 1; |
809 | codec->reg_cache_size = sizeof(wm8750_reg); | 782 | codec->reg_cache_size = ARRAY_SIZE(wm8750_reg); |
810 | codec->reg_cache = kmemdup(wm8750_reg, sizeof(wm8750_reg), GFP_KERNEL); | 783 | codec->reg_cache = kmemdup(wm8750_reg, sizeof(wm8750_reg), GFP_KERNEL); |
811 | if (codec->reg_cache == NULL) | 784 | if (codec->reg_cache == NULL) |
812 | return -ENOMEM; | 785 | return -ENOMEM; |
@@ -821,8 +794,8 @@ static int wm8750_init(struct snd_soc_device *socdev) | |||
821 | } | 794 | } |
822 | 795 | ||
823 | /* charge output caps */ | 796 | /* charge output caps */ |
824 | wm8750_dapm_event(codec, SNDRV_CTL_POWER_D2); | 797 | wm8750_set_bias_level(codec, SND_SOC_BIAS_PREPARE); |
825 | codec->dapm_state = SNDRV_CTL_POWER_D3hot; | 798 | codec->bias_level = SND_SOC_BIAS_STANDBY; |
826 | schedule_delayed_work(&codec->delayed_work, msecs_to_jiffies(1000)); | 799 | schedule_delayed_work(&codec->delayed_work, msecs_to_jiffies(1000)); |
827 | 800 | ||
828 | /* set the update bits */ | 801 | /* set the update bits */ |
@@ -904,13 +877,13 @@ static int wm8750_codec_probe(struct i2c_adapter *adap, int addr, int kind) | |||
904 | 877 | ||
905 | ret = i2c_attach_client(i2c); | 878 | ret = i2c_attach_client(i2c); |
906 | if (ret < 0) { | 879 | if (ret < 0) { |
907 | err("failed to attach codec at addr %x\n", addr); | 880 | pr_err("failed to attach codec at addr %x\n", addr); |
908 | goto err; | 881 | goto err; |
909 | } | 882 | } |
910 | 883 | ||
911 | ret = wm8750_init(socdev); | 884 | ret = wm8750_init(socdev); |
912 | if (ret < 0) { | 885 | if (ret < 0) { |
913 | err("failed to initialise WM8750\n"); | 886 | pr_err("failed to initialise WM8750\n"); |
914 | goto err; | 887 | goto err; |
915 | } | 888 | } |
916 | return ret; | 889 | return ret; |
@@ -961,7 +934,7 @@ static int wm8750_probe(struct platform_device *pdev) | |||
961 | struct wm8750_priv *wm8750; | 934 | struct wm8750_priv *wm8750; |
962 | int ret = 0; | 935 | int ret = 0; |
963 | 936 | ||
964 | info("WM8750 Audio Codec %s", WM8750_VERSION); | 937 | pr_info("WM8750 Audio Codec %s", WM8750_VERSION); |
965 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | 938 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); |
966 | if (codec == NULL) | 939 | if (codec == NULL) |
967 | return -ENOMEM; | 940 | return -ENOMEM; |
@@ -1021,7 +994,7 @@ static int wm8750_remove(struct platform_device *pdev) | |||
1021 | struct snd_soc_codec *codec = socdev->codec; | 994 | struct snd_soc_codec *codec = socdev->codec; |
1022 | 995 | ||
1023 | if (codec->control_data) | 996 | if (codec->control_data) |
1024 | wm8750_dapm_event(codec, SNDRV_CTL_POWER_D3cold); | 997 | wm8750_set_bias_level(codec, SND_SOC_BIAS_OFF); |
1025 | run_delayed_work(&codec->delayed_work); | 998 | run_delayed_work(&codec->delayed_work); |
1026 | snd_soc_free_pcms(socdev); | 999 | snd_soc_free_pcms(socdev); |
1027 | snd_soc_dapm_free(socdev); | 1000 | snd_soc_dapm_free(socdev); |
diff --git a/sound/soc/codecs/wm8750.h b/sound/soc/codecs/wm8750.h index a97a54a6348e..8ef30e628b21 100644 --- a/sound/soc/codecs/wm8750.h +++ b/sound/soc/codecs/wm8750.h | |||
@@ -61,7 +61,7 @@ struct wm8750_setup_data { | |||
61 | unsigned short i2c_address; | 61 | unsigned short i2c_address; |
62 | }; | 62 | }; |
63 | 63 | ||
64 | extern struct snd_soc_codec_dai wm8750_dai; | 64 | extern struct snd_soc_dai wm8750_dai; |
65 | extern struct snd_soc_codec_device soc_codec_dev_wm8750; | 65 | extern struct snd_soc_codec_device soc_codec_dev_wm8750; |
66 | 66 | ||
67 | #endif | 67 | #endif |
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index fb41826c4c4c..8604809f0c36 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c | |||
@@ -55,25 +55,6 @@ | |||
55 | #define AUDIO_NAME "wm8753" | 55 | #define AUDIO_NAME "wm8753" |
56 | #define WM8753_VERSION "0.16" | 56 | #define WM8753_VERSION "0.16" |
57 | 57 | ||
58 | /* | ||
59 | * Debug | ||
60 | */ | ||
61 | |||
62 | #define WM8753_DEBUG 0 | ||
63 | |||
64 | #ifdef WM8753_DEBUG | ||
65 | #define dbg(format, arg...) \ | ||
66 | printk(KERN_DEBUG AUDIO_NAME ": " format "\n" , ## arg) | ||
67 | #else | ||
68 | #define dbg(format, arg...) do {} while (0) | ||
69 | #endif | ||
70 | #define err(format, arg...) \ | ||
71 | printk(KERN_ERR AUDIO_NAME ": " format "\n" , ## arg) | ||
72 | #define info(format, arg...) \ | ||
73 | printk(KERN_INFO AUDIO_NAME ": " format "\n" , ## arg) | ||
74 | #define warn(format, arg...) \ | ||
75 | printk(KERN_WARNING AUDIO_NAME ": " format "\n" , ## arg) | ||
76 | |||
77 | static int caps_charge = 2000; | 58 | static int caps_charge = 2000; |
78 | module_param(caps_charge, int, 0); | 59 | module_param(caps_charge, int, 0); |
79 | MODULE_PARM_DESC(caps_charge, "WM8753 cap charge time (msecs)"); | 60 | MODULE_PARM_DESC(caps_charge, "WM8753 cap charge time (msecs)"); |
@@ -260,28 +241,50 @@ static int wm8753_set_dai(struct snd_kcontrol *kcontrol, | |||
260 | return 1; | 241 | return 1; |
261 | } | 242 | } |
262 | 243 | ||
263 | static const DECLARE_TLV_DB_LINEAR(rec_mix_tlv, -1500, 600); | 244 | static const DECLARE_TLV_DB_SCALE(rec_mix_tlv, -1500, 300, 0); |
245 | static const DECLARE_TLV_DB_SCALE(mic_preamp_tlv, 1200, 600, 0); | ||
246 | static const DECLARE_TLV_DB_SCALE(adc_tlv, -9750, 50, 1); | ||
247 | static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1); | ||
248 | static const unsigned int out_tlv[] = { | ||
249 | TLV_DB_RANGE_HEAD(2), | ||
250 | /* 0000000 - 0101111 = "Analogue mute" */ | ||
251 | 0, 48, TLV_DB_SCALE_ITEM(-25500, 0, 0), | ||
252 | 48, 127, TLV_DB_SCALE_ITEM(-7300, 100, 0), | ||
253 | }; | ||
254 | static const DECLARE_TLV_DB_SCALE(mix_tlv, -1500, 300, 0); | ||
255 | static const DECLARE_TLV_DB_SCALE(voice_mix_tlv, -1200, 300, 0); | ||
256 | static const DECLARE_TLV_DB_SCALE(pga_tlv, -1725, 75, 0); | ||
264 | 257 | ||
265 | static const struct snd_kcontrol_new wm8753_snd_controls[] = { | 258 | static const struct snd_kcontrol_new wm8753_snd_controls[] = { |
266 | SOC_DOUBLE_R("PCM Volume", WM8753_LDAC, WM8753_RDAC, 0, 255, 0), | 259 | SOC_DOUBLE_R_TLV("PCM Volume", WM8753_LDAC, WM8753_RDAC, 0, 255, 0, dac_tlv), |
267 | 260 | ||
268 | SOC_DOUBLE_R("ADC Capture Volume", WM8753_LADC, WM8753_RADC, 0, 255, 0), | 261 | SOC_DOUBLE_R_TLV("ADC Capture Volume", WM8753_LADC, WM8753_RADC, 0, 255, 0, |
269 | 262 | adc_tlv), | |
270 | SOC_DOUBLE_R("Headphone Playback Volume", WM8753_LOUT1V, WM8753_ROUT1V, 0, 127, 0), | 263 | |
271 | SOC_DOUBLE_R("Speaker Playback Volume", WM8753_LOUT2V, WM8753_ROUT2V, 0, 127, 0), | 264 | SOC_DOUBLE_R_TLV("Headphone Playback Volume", WM8753_LOUT1V, WM8753_ROUT1V, |
272 | 265 | 0, 127, 0, out_tlv), | |
273 | SOC_SINGLE("Mono Playback Volume", WM8753_MOUTV, 0, 127, 0), | 266 | SOC_DOUBLE_R_TLV("Speaker Playback Volume", WM8753_LOUT2V, WM8753_ROUT2V, 0, |
274 | 267 | 127, 0, out_tlv), | |
275 | SOC_DOUBLE_R("Bypass Playback Volume", WM8753_LOUTM1, WM8753_ROUTM1, 4, 7, 1), | 268 | |
276 | SOC_DOUBLE_R("Sidetone Playback Volume", WM8753_LOUTM2, WM8753_ROUTM2, 4, 7, 1), | 269 | SOC_SINGLE_TLV("Mono Playback Volume", WM8753_MOUTV, 0, 127, 0, out_tlv), |
277 | SOC_DOUBLE_R("Voice Playback Volume", WM8753_LOUTM2, WM8753_ROUTM2, 0, 7, 1), | 270 | |
278 | 271 | SOC_DOUBLE_R_TLV("Bypass Playback Volume", WM8753_LOUTM1, WM8753_ROUTM1, 4, 7, | |
279 | SOC_DOUBLE_R("Headphone Playback ZC Switch", WM8753_LOUT1V, WM8753_ROUT1V, 7, 1, 0), | 272 | 1, mix_tlv), |
280 | SOC_DOUBLE_R("Speaker Playback ZC Switch", WM8753_LOUT2V, WM8753_ROUT2V, 7, 1, 0), | 273 | SOC_DOUBLE_R_TLV("Sidetone Playback Volume", WM8753_LOUTM2, WM8753_ROUTM2, 4, |
281 | 274 | 7, 1, mix_tlv), | |
282 | SOC_SINGLE("Mono Bypass Playback Volume", WM8753_MOUTM1, 4, 7, 1), | 275 | SOC_DOUBLE_R_TLV("Voice Playback Volume", WM8753_LOUTM2, WM8753_ROUTM2, 0, 7, |
283 | SOC_SINGLE("Mono Sidetone Playback Volume", WM8753_MOUTM2, 4, 7, 1), | 276 | 1, voice_mix_tlv), |
284 | SOC_SINGLE("Mono Voice Playback Volume", WM8753_MOUTM2, 0, 7, 1), | 277 | |
278 | SOC_DOUBLE_R("Headphone Playback ZC Switch", WM8753_LOUT1V, WM8753_ROUT1V, 7, | ||
279 | 1, 0), | ||
280 | SOC_DOUBLE_R("Speaker Playback ZC Switch", WM8753_LOUT2V, WM8753_ROUT2V, 7, | ||
281 | 1, 0), | ||
282 | |||
283 | SOC_SINGLE_TLV("Mono Bypass Playback Volume", WM8753_MOUTM1, 4, 7, 1, mix_tlv), | ||
284 | SOC_SINGLE_TLV("Mono Sidetone Playback Volume", WM8753_MOUTM2, 4, 7, 1, | ||
285 | mix_tlv), | ||
286 | SOC_SINGLE_TLV("Mono Voice Playback Volume", WM8753_MOUTM2, 0, 7, 1, | ||
287 | voice_mix_tlv), | ||
285 | SOC_SINGLE("Mono Playback ZC Switch", WM8753_MOUTV, 7, 1, 0), | 288 | SOC_SINGLE("Mono Playback ZC Switch", WM8753_MOUTV, 7, 1, 0), |
286 | 289 | ||
287 | SOC_ENUM("Bass Boost", wm8753_enum[0]), | 290 | SOC_ENUM("Bass Boost", wm8753_enum[0]), |
@@ -291,10 +294,13 @@ SOC_SINGLE("Bass Volume", WM8753_BASS, 0, 15, 1), | |||
291 | SOC_SINGLE("Treble Volume", WM8753_TREBLE, 0, 15, 1), | 294 | SOC_SINGLE("Treble Volume", WM8753_TREBLE, 0, 15, 1), |
292 | SOC_ENUM("Treble Cut-off", wm8753_enum[2]), | 295 | SOC_ENUM("Treble Cut-off", wm8753_enum[2]), |
293 | 296 | ||
294 | SOC_DOUBLE_TLV("Sidetone Capture Volume", WM8753_RECMIX1, 0, 4, 7, 1, rec_mix_tlv), | 297 | SOC_DOUBLE_TLV("Sidetone Capture Volume", WM8753_RECMIX1, 0, 4, 7, 1, |
295 | SOC_SINGLE_TLV("Voice Sidetone Capture Volume", WM8753_RECMIX2, 0, 7, 1, rec_mix_tlv), | 298 | rec_mix_tlv), |
299 | SOC_SINGLE_TLV("Voice Sidetone Capture Volume", WM8753_RECMIX2, 0, 7, 1, | ||
300 | rec_mix_tlv), | ||
296 | 301 | ||
297 | SOC_DOUBLE_R("Capture Volume", WM8753_LINVOL, WM8753_RINVOL, 0, 63, 0), | 302 | SOC_DOUBLE_R_TLV("Capture Volume", WM8753_LINVOL, WM8753_RINVOL, 0, 63, 0, |
303 | pga_tlv), | ||
298 | SOC_DOUBLE_R("Capture ZC Switch", WM8753_LINVOL, WM8753_RINVOL, 6, 1, 0), | 304 | SOC_DOUBLE_R("Capture ZC Switch", WM8753_LINVOL, WM8753_RINVOL, 6, 1, 0), |
299 | SOC_DOUBLE_R("Capture Switch", WM8753_LINVOL, WM8753_RINVOL, 7, 1, 1), | 305 | SOC_DOUBLE_R("Capture Switch", WM8753_LINVOL, WM8753_RINVOL, 7, 1, 1), |
300 | 306 | ||
@@ -326,8 +332,8 @@ SOC_ENUM("De-emphasis", wm8753_enum[8]), | |||
326 | SOC_ENUM("Playback Mono Mix", wm8753_enum[9]), | 332 | SOC_ENUM("Playback Mono Mix", wm8753_enum[9]), |
327 | SOC_ENUM("Playback Phase", wm8753_enum[10]), | 333 | SOC_ENUM("Playback Phase", wm8753_enum[10]), |
328 | 334 | ||
329 | SOC_SINGLE("Mic2 Capture Volume", WM8753_INCTL1, 7, 3, 0), | 335 | SOC_SINGLE_TLV("Mic2 Capture Volume", WM8753_INCTL1, 7, 3, 0, mic_preamp_tlv), |
330 | SOC_SINGLE("Mic1 Capture Volume", WM8753_INCTL1, 5, 3, 0), | 336 | SOC_SINGLE_TLV("Mic1 Capture Volume", WM8753_INCTL1, 5, 3, 0, mic_preamp_tlv), |
331 | 337 | ||
332 | SOC_ENUM_EXT("DAI Mode", wm8753_enum[26], wm8753_get_dai, wm8753_set_dai), | 338 | SOC_ENUM_EXT("DAI Mode", wm8753_enum[26], wm8753_get_dai, wm8753_set_dai), |
333 | 339 | ||
@@ -523,7 +529,7 @@ SND_SOC_DAPM_INPUT("MIC2"), | |||
523 | SND_SOC_DAPM_VMID("VREF"), | 529 | SND_SOC_DAPM_VMID("VREF"), |
524 | }; | 530 | }; |
525 | 531 | ||
526 | static const char *audio_map[][3] = { | 532 | static const struct snd_soc_dapm_route audio_map[] = { |
527 | /* left mixer */ | 533 | /* left mixer */ |
528 | {"Left Mixer", "Left Playback Switch", "Left DAC"}, | 534 | {"Left Mixer", "Left Playback Switch", "Left DAC"}, |
529 | {"Left Mixer", "Voice Playback Switch", "Voice DAC"}, | 535 | {"Left Mixer", "Voice Playback Switch", "Voice DAC"}, |
@@ -674,23 +680,14 @@ static const char *audio_map[][3] = { | |||
674 | 680 | ||
675 | /* ACOP */ | 681 | /* ACOP */ |
676 | {"ACOP", NULL, "ALC Mixer"}, | 682 | {"ACOP", NULL, "ALC Mixer"}, |
677 | |||
678 | /* terminator */ | ||
679 | {NULL, NULL, NULL}, | ||
680 | }; | 683 | }; |
681 | 684 | ||
682 | static int wm8753_add_widgets(struct snd_soc_codec *codec) | 685 | static int wm8753_add_widgets(struct snd_soc_codec *codec) |
683 | { | 686 | { |
684 | int i; | 687 | snd_soc_dapm_new_controls(codec, wm8753_dapm_widgets, |
688 | ARRAY_SIZE(wm8753_dapm_widgets)); | ||
685 | 689 | ||
686 | for (i = 0; i < ARRAY_SIZE(wm8753_dapm_widgets); i++) | 690 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); |
687 | snd_soc_dapm_new_control(codec, &wm8753_dapm_widgets[i]); | ||
688 | |||
689 | /* set up the WM8753 audio map */ | ||
690 | for (i = 0; audio_map[i][0] != NULL; i++) { | ||
691 | snd_soc_dapm_connect_input(codec, audio_map[i][0], | ||
692 | audio_map[i][1], audio_map[i][2]); | ||
693 | } | ||
694 | 691 | ||
695 | snd_soc_dapm_new_widgets(codec); | 692 | snd_soc_dapm_new_widgets(codec); |
696 | return 0; | 693 | return 0; |
@@ -743,7 +740,7 @@ static void pll_factors(struct _pll_div *pll_div, unsigned int target, | |||
743 | pll_div->k = K; | 740 | pll_div->k = K; |
744 | } | 741 | } |
745 | 742 | ||
746 | static int wm8753_set_dai_pll(struct snd_soc_codec_dai *codec_dai, | 743 | static int wm8753_set_dai_pll(struct snd_soc_dai *codec_dai, |
747 | int pll_id, unsigned int freq_in, unsigned int freq_out) | 744 | int pll_id, unsigned int freq_in, unsigned int freq_out) |
748 | { | 745 | { |
749 | u16 reg, enable; | 746 | u16 reg, enable; |
@@ -866,7 +863,7 @@ static int get_coeff(int mclk, int rate) | |||
866 | /* | 863 | /* |
867 | * Clock after PLL and dividers | 864 | * Clock after PLL and dividers |
868 | */ | 865 | */ |
869 | static int wm8753_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai, | 866 | static int wm8753_set_dai_sysclk(struct snd_soc_dai *codec_dai, |
870 | int clk_id, unsigned int freq, int dir) | 867 | int clk_id, unsigned int freq, int dir) |
871 | { | 868 | { |
872 | struct snd_soc_codec *codec = codec_dai->codec; | 869 | struct snd_soc_codec *codec = codec_dai->codec; |
@@ -893,7 +890,7 @@ static int wm8753_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai, | |||
893 | /* | 890 | /* |
894 | * Set's ADC and Voice DAC format. | 891 | * Set's ADC and Voice DAC format. |
895 | */ | 892 | */ |
896 | static int wm8753_vdac_adc_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | 893 | static int wm8753_vdac_adc_set_dai_fmt(struct snd_soc_dai *codec_dai, |
897 | unsigned int fmt) | 894 | unsigned int fmt) |
898 | { | 895 | { |
899 | struct snd_soc_codec *codec = codec_dai->codec; | 896 | struct snd_soc_codec *codec = codec_dai->codec; |
@@ -963,7 +960,7 @@ static int wm8753_pcm_hw_params(struct snd_pcm_substream *substream, | |||
963 | /* | 960 | /* |
964 | * Set's PCM dai fmt and BCLK. | 961 | * Set's PCM dai fmt and BCLK. |
965 | */ | 962 | */ |
966 | static int wm8753_pcm_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | 963 | static int wm8753_pcm_set_dai_fmt(struct snd_soc_dai *codec_dai, |
967 | unsigned int fmt) | 964 | unsigned int fmt) |
968 | { | 965 | { |
969 | struct snd_soc_codec *codec = codec_dai->codec; | 966 | struct snd_soc_codec *codec = codec_dai->codec; |
@@ -1029,7 +1026,7 @@ static int wm8753_pcm_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | |||
1029 | return 0; | 1026 | return 0; |
1030 | } | 1027 | } |
1031 | 1028 | ||
1032 | static int wm8753_set_dai_clkdiv(struct snd_soc_codec_dai *codec_dai, | 1029 | static int wm8753_set_dai_clkdiv(struct snd_soc_dai *codec_dai, |
1033 | int div_id, int div) | 1030 | int div_id, int div) |
1034 | { | 1031 | { |
1035 | struct snd_soc_codec *codec = codec_dai->codec; | 1032 | struct snd_soc_codec *codec = codec_dai->codec; |
@@ -1057,7 +1054,7 @@ static int wm8753_set_dai_clkdiv(struct snd_soc_codec_dai *codec_dai, | |||
1057 | /* | 1054 | /* |
1058 | * Set's HiFi DAC format. | 1055 | * Set's HiFi DAC format. |
1059 | */ | 1056 | */ |
1060 | static int wm8753_hdac_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | 1057 | static int wm8753_hdac_set_dai_fmt(struct snd_soc_dai *codec_dai, |
1061 | unsigned int fmt) | 1058 | unsigned int fmt) |
1062 | { | 1059 | { |
1063 | struct snd_soc_codec *codec = codec_dai->codec; | 1060 | struct snd_soc_codec *codec = codec_dai->codec; |
@@ -1090,7 +1087,7 @@ static int wm8753_hdac_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | |||
1090 | /* | 1087 | /* |
1091 | * Set's I2S DAI format. | 1088 | * Set's I2S DAI format. |
1092 | */ | 1089 | */ |
1093 | static int wm8753_i2s_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | 1090 | static int wm8753_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai, |
1094 | unsigned int fmt) | 1091 | unsigned int fmt) |
1095 | { | 1092 | { |
1096 | struct snd_soc_codec *codec = codec_dai->codec; | 1093 | struct snd_soc_codec *codec = codec_dai->codec; |
@@ -1198,7 +1195,7 @@ static int wm8753_i2s_hw_params(struct snd_pcm_substream *substream, | |||
1198 | return 0; | 1195 | return 0; |
1199 | } | 1196 | } |
1200 | 1197 | ||
1201 | static int wm8753_mode1v_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | 1198 | static int wm8753_mode1v_set_dai_fmt(struct snd_soc_dai *codec_dai, |
1202 | unsigned int fmt) | 1199 | unsigned int fmt) |
1203 | { | 1200 | { |
1204 | struct snd_soc_codec *codec = codec_dai->codec; | 1201 | struct snd_soc_codec *codec = codec_dai->codec; |
@@ -1213,7 +1210,7 @@ static int wm8753_mode1v_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | |||
1213 | return wm8753_pcm_set_dai_fmt(codec_dai, fmt); | 1210 | return wm8753_pcm_set_dai_fmt(codec_dai, fmt); |
1214 | } | 1211 | } |
1215 | 1212 | ||
1216 | static int wm8753_mode1h_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | 1213 | static int wm8753_mode1h_set_dai_fmt(struct snd_soc_dai *codec_dai, |
1217 | unsigned int fmt) | 1214 | unsigned int fmt) |
1218 | { | 1215 | { |
1219 | if (wm8753_hdac_set_dai_fmt(codec_dai, fmt) < 0) | 1216 | if (wm8753_hdac_set_dai_fmt(codec_dai, fmt) < 0) |
@@ -1221,7 +1218,7 @@ static int wm8753_mode1h_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | |||
1221 | return wm8753_i2s_set_dai_fmt(codec_dai, fmt); | 1218 | return wm8753_i2s_set_dai_fmt(codec_dai, fmt); |
1222 | } | 1219 | } |
1223 | 1220 | ||
1224 | static int wm8753_mode2_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | 1221 | static int wm8753_mode2_set_dai_fmt(struct snd_soc_dai *codec_dai, |
1225 | unsigned int fmt) | 1222 | unsigned int fmt) |
1226 | { | 1223 | { |
1227 | struct snd_soc_codec *codec = codec_dai->codec; | 1224 | struct snd_soc_codec *codec = codec_dai->codec; |
@@ -1236,7 +1233,7 @@ static int wm8753_mode2_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | |||
1236 | return wm8753_i2s_set_dai_fmt(codec_dai, fmt); | 1233 | return wm8753_i2s_set_dai_fmt(codec_dai, fmt); |
1237 | } | 1234 | } |
1238 | 1235 | ||
1239 | static int wm8753_mode3_4_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | 1236 | static int wm8753_mode3_4_set_dai_fmt(struct snd_soc_dai *codec_dai, |
1240 | unsigned int fmt) | 1237 | unsigned int fmt) |
1241 | { | 1238 | { |
1242 | struct snd_soc_codec *codec = codec_dai->codec; | 1239 | struct snd_soc_codec *codec = codec_dai->codec; |
@@ -1253,7 +1250,7 @@ static int wm8753_mode3_4_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | |||
1253 | return wm8753_i2s_set_dai_fmt(codec_dai, fmt); | 1250 | return wm8753_i2s_set_dai_fmt(codec_dai, fmt); |
1254 | } | 1251 | } |
1255 | 1252 | ||
1256 | static int wm8753_mute(struct snd_soc_codec_dai *dai, int mute) | 1253 | static int wm8753_mute(struct snd_soc_dai *dai, int mute) |
1257 | { | 1254 | { |
1258 | struct snd_soc_codec *codec = dai->codec; | 1255 | struct snd_soc_codec *codec = dai->codec; |
1259 | u16 mute_reg = wm8753_read_reg_cache(codec, WM8753_DAC) & 0xfff7; | 1256 | u16 mute_reg = wm8753_read_reg_cache(codec, WM8753_DAC) & 0xfff7; |
@@ -1274,29 +1271,29 @@ static int wm8753_mute(struct snd_soc_codec_dai *dai, int mute) | |||
1274 | return 0; | 1271 | return 0; |
1275 | } | 1272 | } |
1276 | 1273 | ||
1277 | static int wm8753_dapm_event(struct snd_soc_codec *codec, int event) | 1274 | static int wm8753_set_bias_level(struct snd_soc_codec *codec, |
1275 | enum snd_soc_bias_level level) | ||
1278 | { | 1276 | { |
1279 | u16 pwr_reg = wm8753_read_reg_cache(codec, WM8753_PWR1) & 0xfe3e; | 1277 | u16 pwr_reg = wm8753_read_reg_cache(codec, WM8753_PWR1) & 0xfe3e; |
1280 | 1278 | ||
1281 | switch (event) { | 1279 | switch (level) { |
1282 | case SNDRV_CTL_POWER_D0: /* full On */ | 1280 | case SND_SOC_BIAS_ON: |
1283 | /* set vmid to 50k and unmute dac */ | 1281 | /* set vmid to 50k and unmute dac */ |
1284 | wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x00c0); | 1282 | wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x00c0); |
1285 | break; | 1283 | break; |
1286 | case SNDRV_CTL_POWER_D1: /* partial On */ | 1284 | case SND_SOC_BIAS_PREPARE: |
1287 | case SNDRV_CTL_POWER_D2: /* partial On */ | ||
1288 | /* set vmid to 5k for quick power up */ | 1285 | /* set vmid to 5k for quick power up */ |
1289 | wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x01c1); | 1286 | wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x01c1); |
1290 | break; | 1287 | break; |
1291 | case SNDRV_CTL_POWER_D3hot: /* Off, with power */ | 1288 | case SND_SOC_BIAS_STANDBY: |
1292 | /* mute dac and set vmid to 500k, enable VREF */ | 1289 | /* mute dac and set vmid to 500k, enable VREF */ |
1293 | wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x0141); | 1290 | wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x0141); |
1294 | break; | 1291 | break; |
1295 | case SNDRV_CTL_POWER_D3cold: /* Off, without power */ | 1292 | case SND_SOC_BIAS_OFF: |
1296 | wm8753_write(codec, WM8753_PWR1, 0x0001); | 1293 | wm8753_write(codec, WM8753_PWR1, 0x0001); |
1297 | break; | 1294 | break; |
1298 | } | 1295 | } |
1299 | codec->dapm_state = event; | 1296 | codec->bias_level = level; |
1300 | return 0; | 1297 | return 0; |
1301 | } | 1298 | } |
1302 | 1299 | ||
@@ -1319,7 +1316,7 @@ static int wm8753_dapm_event(struct snd_soc_codec *codec, int event) | |||
1319 | * 3. Voice disabled - HIFI over HIFI | 1316 | * 3. Voice disabled - HIFI over HIFI |
1320 | * 4. Voice disabled - HIFI over HIFI, uses voice DAI LRC for capture | 1317 | * 4. Voice disabled - HIFI over HIFI, uses voice DAI LRC for capture |
1321 | */ | 1318 | */ |
1322 | static const struct snd_soc_codec_dai wm8753_all_dai[] = { | 1319 | static const struct snd_soc_dai wm8753_all_dai[] = { |
1323 | /* DAI HiFi mode 1 */ | 1320 | /* DAI HiFi mode 1 */ |
1324 | { .name = "WM8753 HiFi", | 1321 | { .name = "WM8753 HiFi", |
1325 | .id = 1, | 1322 | .id = 1, |
@@ -1459,7 +1456,7 @@ static const struct snd_soc_codec_dai wm8753_all_dai[] = { | |||
1459 | }, | 1456 | }, |
1460 | }; | 1457 | }; |
1461 | 1458 | ||
1462 | struct snd_soc_codec_dai wm8753_dai[2]; | 1459 | struct snd_soc_dai wm8753_dai[2]; |
1463 | EXPORT_SYMBOL_GPL(wm8753_dai); | 1460 | EXPORT_SYMBOL_GPL(wm8753_dai); |
1464 | 1461 | ||
1465 | static void wm8753_set_dai_mode(struct snd_soc_codec *codec, unsigned int mode) | 1462 | static void wm8753_set_dai_mode(struct snd_soc_codec *codec, unsigned int mode) |
@@ -1500,7 +1497,7 @@ static void wm8753_work(struct work_struct *work) | |||
1500 | { | 1497 | { |
1501 | struct snd_soc_codec *codec = | 1498 | struct snd_soc_codec *codec = |
1502 | container_of(work, struct snd_soc_codec, delayed_work.work); | 1499 | container_of(work, struct snd_soc_codec, delayed_work.work); |
1503 | wm8753_dapm_event(codec, codec->dapm_state); | 1500 | wm8753_set_bias_level(codec, codec->bias_level); |
1504 | } | 1501 | } |
1505 | 1502 | ||
1506 | static int wm8753_suspend(struct platform_device *pdev, pm_message_t state) | 1503 | static int wm8753_suspend(struct platform_device *pdev, pm_message_t state) |
@@ -1512,7 +1509,7 @@ static int wm8753_suspend(struct platform_device *pdev, pm_message_t state) | |||
1512 | if (!codec->card) | 1509 | if (!codec->card) |
1513 | return 0; | 1510 | return 0; |
1514 | 1511 | ||
1515 | wm8753_dapm_event(codec, SNDRV_CTL_POWER_D3cold); | 1512 | wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF); |
1516 | return 0; | 1513 | return 0; |
1517 | } | 1514 | } |
1518 | 1515 | ||
@@ -1537,12 +1534,12 @@ static int wm8753_resume(struct platform_device *pdev) | |||
1537 | codec->hw_write(codec->control_data, data, 2); | 1534 | codec->hw_write(codec->control_data, data, 2); |
1538 | } | 1535 | } |
1539 | 1536 | ||
1540 | wm8753_dapm_event(codec, SNDRV_CTL_POWER_D3hot); | 1537 | wm8753_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
1541 | 1538 | ||
1542 | /* charge wm8753 caps */ | 1539 | /* charge wm8753 caps */ |
1543 | if (codec->suspend_dapm_state == SNDRV_CTL_POWER_D0) { | 1540 | if (codec->suspend_bias_level == SND_SOC_BIAS_ON) { |
1544 | wm8753_dapm_event(codec, SNDRV_CTL_POWER_D2); | 1541 | wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE); |
1545 | codec->dapm_state = SNDRV_CTL_POWER_D0; | 1542 | codec->bias_level = SND_SOC_BIAS_ON; |
1546 | schedule_delayed_work(&codec->delayed_work, | 1543 | schedule_delayed_work(&codec->delayed_work, |
1547 | msecs_to_jiffies(caps_charge)); | 1544 | msecs_to_jiffies(caps_charge)); |
1548 | } | 1545 | } |
@@ -1563,10 +1560,10 @@ static int wm8753_init(struct snd_soc_device *socdev) | |||
1563 | codec->owner = THIS_MODULE; | 1560 | codec->owner = THIS_MODULE; |
1564 | codec->read = wm8753_read_reg_cache; | 1561 | codec->read = wm8753_read_reg_cache; |
1565 | codec->write = wm8753_write; | 1562 | codec->write = wm8753_write; |
1566 | codec->dapm_event = wm8753_dapm_event; | 1563 | codec->set_bias_level = wm8753_set_bias_level; |
1567 | codec->dai = wm8753_dai; | 1564 | codec->dai = wm8753_dai; |
1568 | codec->num_dai = 2; | 1565 | codec->num_dai = 2; |
1569 | codec->reg_cache_size = sizeof(wm8753_reg); | 1566 | codec->reg_cache_size = ARRAY_SIZE(wm8753_reg); |
1570 | codec->reg_cache = kmemdup(wm8753_reg, sizeof(wm8753_reg), GFP_KERNEL); | 1567 | codec->reg_cache = kmemdup(wm8753_reg, sizeof(wm8753_reg), GFP_KERNEL); |
1571 | 1568 | ||
1572 | if (codec->reg_cache == NULL) | 1569 | if (codec->reg_cache == NULL) |
@@ -1584,8 +1581,8 @@ static int wm8753_init(struct snd_soc_device *socdev) | |||
1584 | } | 1581 | } |
1585 | 1582 | ||
1586 | /* charge output caps */ | 1583 | /* charge output caps */ |
1587 | wm8753_dapm_event(codec, SNDRV_CTL_POWER_D2); | 1584 | wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE); |
1588 | codec->dapm_state = SNDRV_CTL_POWER_D3hot; | 1585 | codec->bias_level = SND_SOC_BIAS_STANDBY; |
1589 | schedule_delayed_work(&codec->delayed_work, | 1586 | schedule_delayed_work(&codec->delayed_work, |
1590 | msecs_to_jiffies(caps_charge)); | 1587 | msecs_to_jiffies(caps_charge)); |
1591 | 1588 | ||
@@ -1673,13 +1670,13 @@ static int wm8753_codec_probe(struct i2c_adapter *adap, int addr, int kind) | |||
1673 | 1670 | ||
1674 | ret = i2c_attach_client(i2c); | 1671 | ret = i2c_attach_client(i2c); |
1675 | if (ret < 0) { | 1672 | if (ret < 0) { |
1676 | err("failed to attach codec at addr %x\n", addr); | 1673 | pr_err("failed to attach codec at addr %x\n", addr); |
1677 | goto err; | 1674 | goto err; |
1678 | } | 1675 | } |
1679 | 1676 | ||
1680 | ret = wm8753_init(socdev); | 1677 | ret = wm8753_init(socdev); |
1681 | if (ret < 0) { | 1678 | if (ret < 0) { |
1682 | err("failed to initialise WM8753\n"); | 1679 | pr_err("failed to initialise WM8753\n"); |
1683 | goto err; | 1680 | goto err; |
1684 | } | 1681 | } |
1685 | 1682 | ||
@@ -1731,7 +1728,7 @@ static int wm8753_probe(struct platform_device *pdev) | |||
1731 | struct wm8753_priv *wm8753; | 1728 | struct wm8753_priv *wm8753; |
1732 | int ret = 0; | 1729 | int ret = 0; |
1733 | 1730 | ||
1734 | info("WM8753 Audio Codec %s", WM8753_VERSION); | 1731 | pr_info("WM8753 Audio Codec %s", WM8753_VERSION); |
1735 | 1732 | ||
1736 | setup = socdev->codec_data; | 1733 | setup = socdev->codec_data; |
1737 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | 1734 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); |
@@ -1792,7 +1789,7 @@ static int wm8753_remove(struct platform_device *pdev) | |||
1792 | struct snd_soc_codec *codec = socdev->codec; | 1789 | struct snd_soc_codec *codec = socdev->codec; |
1793 | 1790 | ||
1794 | if (codec->control_data) | 1791 | if (codec->control_data) |
1795 | wm8753_dapm_event(codec, SNDRV_CTL_POWER_D3cold); | 1792 | wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF); |
1796 | run_delayed_work(&codec->delayed_work); | 1793 | run_delayed_work(&codec->delayed_work); |
1797 | snd_soc_free_pcms(socdev); | 1794 | snd_soc_free_pcms(socdev); |
1798 | snd_soc_dapm_free(socdev); | 1795 | snd_soc_dapm_free(socdev); |
diff --git a/sound/soc/codecs/wm8753.h b/sound/soc/codecs/wm8753.h index 95e2a1f53169..44f5f1ff0cc7 100644 --- a/sound/soc/codecs/wm8753.h +++ b/sound/soc/codecs/wm8753.h | |||
@@ -120,7 +120,7 @@ struct wm8753_setup_data { | |||
120 | #define WM8753_DAI_HIFI 0 | 120 | #define WM8753_DAI_HIFI 0 |
121 | #define WM8753_DAI_VOICE 1 | 121 | #define WM8753_DAI_VOICE 1 |
122 | 122 | ||
123 | extern struct snd_soc_codec_dai wm8753_dai[2]; | 123 | extern struct snd_soc_dai wm8753_dai[2]; |
124 | extern struct snd_soc_codec_device soc_codec_dev_wm8753; | 124 | extern struct snd_soc_codec_device soc_codec_dev_wm8753; |
125 | 125 | ||
126 | #endif | 126 | #endif |
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c new file mode 100644 index 000000000000..3ecce5168e94 --- /dev/null +++ b/sound/soc/codecs/wm8990.c | |||
@@ -0,0 +1,1626 @@ | |||
1 | /* | ||
2 | * wm8990.c -- WM8990 ALSA Soc Audio driver | ||
3 | * | ||
4 | * Copyright 2008 Wolfson Microelectronics PLC. | ||
5 | * Author: Liam Girdwood | ||
6 | * lg@opensource.wolfsonmicro.com or linux@wolfsonmicro.com | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/moduleparam.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/delay.h> | ||
19 | #include <linux/pm.h> | ||
20 | #include <linux/i2c.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | #include <sound/core.h> | ||
23 | #include <sound/pcm.h> | ||
24 | #include <sound/pcm_params.h> | ||
25 | #include <sound/soc.h> | ||
26 | #include <sound/soc-dapm.h> | ||
27 | #include <sound/initval.h> | ||
28 | #include <sound/tlv.h> | ||
29 | #include <asm/div64.h> | ||
30 | |||
31 | #include "wm8990.h" | ||
32 | |||
33 | #define AUDIO_NAME "wm8990" | ||
34 | #define WM8990_VERSION "0.2" | ||
35 | |||
36 | /* codec private data */ | ||
37 | struct wm8990_priv { | ||
38 | unsigned int sysclk; | ||
39 | unsigned int pcmclk; | ||
40 | }; | ||
41 | |||
42 | /* | ||
43 | * wm8990 register cache. Note that register 0 is not included in the | ||
44 | * cache. | ||
45 | */ | ||
46 | static const u16 wm8990_reg[] = { | ||
47 | 0x8990, /* R0 - Reset */ | ||
48 | 0x0000, /* R1 - Power Management (1) */ | ||
49 | 0x6000, /* R2 - Power Management (2) */ | ||
50 | 0x0000, /* R3 - Power Management (3) */ | ||
51 | 0x4050, /* R4 - Audio Interface (1) */ | ||
52 | 0x4000, /* R5 - Audio Interface (2) */ | ||
53 | 0x01C8, /* R6 - Clocking (1) */ | ||
54 | 0x0000, /* R7 - Clocking (2) */ | ||
55 | 0x0040, /* R8 - Audio Interface (3) */ | ||
56 | 0x0040, /* R9 - Audio Interface (4) */ | ||
57 | 0x0004, /* R10 - DAC CTRL */ | ||
58 | 0x00C0, /* R11 - Left DAC Digital Volume */ | ||
59 | 0x00C0, /* R12 - Right DAC Digital Volume */ | ||
60 | 0x0000, /* R13 - Digital Side Tone */ | ||
61 | 0x0100, /* R14 - ADC CTRL */ | ||
62 | 0x00C0, /* R15 - Left ADC Digital Volume */ | ||
63 | 0x00C0, /* R16 - Right ADC Digital Volume */ | ||
64 | 0x0000, /* R17 */ | ||
65 | 0x0000, /* R18 - GPIO CTRL 1 */ | ||
66 | 0x1000, /* R19 - GPIO1 & GPIO2 */ | ||
67 | 0x1010, /* R20 - GPIO3 & GPIO4 */ | ||
68 | 0x1010, /* R21 - GPIO5 & GPIO6 */ | ||
69 | 0x8000, /* R22 - GPIOCTRL 2 */ | ||
70 | 0x0800, /* R23 - GPIO_POL */ | ||
71 | 0x008B, /* R24 - Left Line Input 1&2 Volume */ | ||
72 | 0x008B, /* R25 - Left Line Input 3&4 Volume */ | ||
73 | 0x008B, /* R26 - Right Line Input 1&2 Volume */ | ||
74 | 0x008B, /* R27 - Right Line Input 3&4 Volume */ | ||
75 | 0x0000, /* R28 - Left Output Volume */ | ||
76 | 0x0000, /* R29 - Right Output Volume */ | ||
77 | 0x0066, /* R30 - Line Outputs Volume */ | ||
78 | 0x0022, /* R31 - Out3/4 Volume */ | ||
79 | 0x0079, /* R32 - Left OPGA Volume */ | ||
80 | 0x0079, /* R33 - Right OPGA Volume */ | ||
81 | 0x0003, /* R34 - Speaker Volume */ | ||
82 | 0x0003, /* R35 - ClassD1 */ | ||
83 | 0x0000, /* R36 */ | ||
84 | 0x0100, /* R37 - ClassD3 */ | ||
85 | 0x0000, /* R38 */ | ||
86 | 0x0000, /* R39 - Input Mixer1 */ | ||
87 | 0x0000, /* R40 - Input Mixer2 */ | ||
88 | 0x0000, /* R41 - Input Mixer3 */ | ||
89 | 0x0000, /* R42 - Input Mixer4 */ | ||
90 | 0x0000, /* R43 - Input Mixer5 */ | ||
91 | 0x0000, /* R44 - Input Mixer6 */ | ||
92 | 0x0000, /* R45 - Output Mixer1 */ | ||
93 | 0x0000, /* R46 - Output Mixer2 */ | ||
94 | 0x0000, /* R47 - Output Mixer3 */ | ||
95 | 0x0000, /* R48 - Output Mixer4 */ | ||
96 | 0x0000, /* R49 - Output Mixer5 */ | ||
97 | 0x0000, /* R50 - Output Mixer6 */ | ||
98 | 0x0180, /* R51 - Out3/4 Mixer */ | ||
99 | 0x0000, /* R52 - Line Mixer1 */ | ||
100 | 0x0000, /* R53 - Line Mixer2 */ | ||
101 | 0x0000, /* R54 - Speaker Mixer */ | ||
102 | 0x0000, /* R55 - Additional Control */ | ||
103 | 0x0000, /* R56 - AntiPOP1 */ | ||
104 | 0x0000, /* R57 - AntiPOP2 */ | ||
105 | 0x0000, /* R58 - MICBIAS */ | ||
106 | 0x0000, /* R59 */ | ||
107 | 0x0008, /* R60 - PLL1 */ | ||
108 | 0x0031, /* R61 - PLL2 */ | ||
109 | 0x0026, /* R62 - PLL3 */ | ||
110 | }; | ||
111 | |||
112 | /* | ||
113 | * read wm8990 register cache | ||
114 | */ | ||
115 | static inline unsigned int wm8990_read_reg_cache(struct snd_soc_codec *codec, | ||
116 | unsigned int reg) | ||
117 | { | ||
118 | u16 *cache = codec->reg_cache; | ||
119 | BUG_ON(reg > (ARRAY_SIZE(wm8990_reg)) - 1); | ||
120 | return cache[reg]; | ||
121 | } | ||
122 | |||
123 | /* | ||
124 | * write wm8990 register cache | ||
125 | */ | ||
126 | static inline void wm8990_write_reg_cache(struct snd_soc_codec *codec, | ||
127 | unsigned int reg, unsigned int value) | ||
128 | { | ||
129 | u16 *cache = codec->reg_cache; | ||
130 | BUG_ON(reg > (ARRAY_SIZE(wm8990_reg)) - 1); | ||
131 | |||
132 | /* Reset register is uncached */ | ||
133 | if (reg == 0) | ||
134 | return; | ||
135 | |||
136 | cache[reg] = value; | ||
137 | } | ||
138 | |||
139 | /* | ||
140 | * write to the wm8990 register space | ||
141 | */ | ||
142 | static int wm8990_write(struct snd_soc_codec *codec, unsigned int reg, | ||
143 | unsigned int value) | ||
144 | { | ||
145 | u8 data[3]; | ||
146 | |||
147 | data[0] = reg & 0xFF; | ||
148 | data[1] = (value >> 8) & 0xFF; | ||
149 | data[2] = value & 0xFF; | ||
150 | |||
151 | wm8990_write_reg_cache(codec, reg, value); | ||
152 | |||
153 | if (codec->hw_write(codec->control_data, data, 3) == 2) | ||
154 | return 0; | ||
155 | else | ||
156 | return -EIO; | ||
157 | } | ||
158 | |||
159 | #define wm8990_reset(c) wm8990_write(c, WM8990_RESET, 0) | ||
160 | |||
161 | static const DECLARE_TLV_DB_LINEAR(rec_mix_tlv, -1500, 600); | ||
162 | |||
163 | static const DECLARE_TLV_DB_LINEAR(in_pga_tlv, -1650, 3000); | ||
164 | |||
165 | static const DECLARE_TLV_DB_LINEAR(out_mix_tlv, 0, -2100); | ||
166 | |||
167 | static const DECLARE_TLV_DB_LINEAR(out_pga_tlv, -7300, 600); | ||
168 | |||
169 | static const DECLARE_TLV_DB_LINEAR(out_omix_tlv, -600, 0); | ||
170 | |||
171 | static const DECLARE_TLV_DB_LINEAR(out_dac_tlv, -7163, 0); | ||
172 | |||
173 | static const DECLARE_TLV_DB_LINEAR(in_adc_tlv, -7163, 1763); | ||
174 | |||
175 | static const DECLARE_TLV_DB_LINEAR(out_sidetone_tlv, -3600, 0); | ||
176 | |||
177 | static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol, | ||
178 | struct snd_ctl_elem_value *ucontrol) | ||
179 | { | ||
180 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
181 | int reg = kcontrol->private_value & 0xff; | ||
182 | int ret; | ||
183 | u16 val; | ||
184 | |||
185 | ret = snd_soc_put_volsw(kcontrol, ucontrol); | ||
186 | if (ret < 0) | ||
187 | return ret; | ||
188 | |||
189 | /* now hit the volume update bits (always bit 8) */ | ||
190 | val = wm8990_read_reg_cache(codec, reg); | ||
191 | return wm8990_write(codec, reg, val | 0x0100); | ||
192 | } | ||
193 | |||
194 | #define SOC_WM899X_OUTPGA_SINGLE_R_TLV(xname, reg, shift, max, invert,\ | ||
195 | tlv_array) {\ | ||
196 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ | ||
197 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ | ||
198 | SNDRV_CTL_ELEM_ACCESS_READWRITE,\ | ||
199 | .tlv.p = (tlv_array), \ | ||
200 | .info = snd_soc_info_volsw, \ | ||
201 | .get = snd_soc_get_volsw, .put = wm899x_outpga_put_volsw_vu, \ | ||
202 | .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) } | ||
203 | |||
204 | |||
205 | static const char *wm8990_digital_sidetone[] = | ||
206 | {"None", "Left ADC", "Right ADC", "Reserved"}; | ||
207 | |||
208 | static const struct soc_enum wm8990_left_digital_sidetone_enum = | ||
209 | SOC_ENUM_SINGLE(WM8990_DIGITAL_SIDE_TONE, | ||
210 | WM8990_ADC_TO_DACL_SHIFT, | ||
211 | WM8990_ADC_TO_DACL_MASK, | ||
212 | wm8990_digital_sidetone); | ||
213 | |||
214 | static const struct soc_enum wm8990_right_digital_sidetone_enum = | ||
215 | SOC_ENUM_SINGLE(WM8990_DIGITAL_SIDE_TONE, | ||
216 | WM8990_ADC_TO_DACR_SHIFT, | ||
217 | WM8990_ADC_TO_DACR_MASK, | ||
218 | wm8990_digital_sidetone); | ||
219 | |||
220 | static const char *wm8990_adcmode[] = | ||
221 | {"Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3"}; | ||
222 | |||
223 | static const struct soc_enum wm8990_right_adcmode_enum = | ||
224 | SOC_ENUM_SINGLE(WM8990_ADC_CTRL, | ||
225 | WM8990_ADC_HPF_CUT_SHIFT, | ||
226 | WM8990_ADC_HPF_CUT_MASK, | ||
227 | wm8990_adcmode); | ||
228 | |||
229 | static const struct snd_kcontrol_new wm8990_snd_controls[] = { | ||
230 | /* INMIXL */ | ||
231 | SOC_SINGLE("LIN12 PGA Boost", WM8990_INPUT_MIXER3, WM8990_L12MNBST_BIT, 1, 0), | ||
232 | SOC_SINGLE("LIN34 PGA Boost", WM8990_INPUT_MIXER3, WM8990_L34MNBST_BIT, 1, 0), | ||
233 | /* INMIXR */ | ||
234 | SOC_SINGLE("RIN12 PGA Boost", WM8990_INPUT_MIXER3, WM8990_R12MNBST_BIT, 1, 0), | ||
235 | SOC_SINGLE("RIN34 PGA Boost", WM8990_INPUT_MIXER3, WM8990_R34MNBST_BIT, 1, 0), | ||
236 | |||
237 | /* LOMIX */ | ||
238 | SOC_SINGLE_TLV("LOMIX LIN3 Bypass Volume", WM8990_OUTPUT_MIXER3, | ||
239 | WM8990_LLI3LOVOL_SHIFT, WM8990_LLI3LOVOL_MASK, 1, out_mix_tlv), | ||
240 | SOC_SINGLE_TLV("LOMIX RIN12 PGA Bypass Volume", WM8990_OUTPUT_MIXER3, | ||
241 | WM8990_LR12LOVOL_SHIFT, WM8990_LR12LOVOL_MASK, 1, out_mix_tlv), | ||
242 | SOC_SINGLE_TLV("LOMIX LIN12 PGA Bypass Volume", WM8990_OUTPUT_MIXER3, | ||
243 | WM8990_LL12LOVOL_SHIFT, WM8990_LL12LOVOL_MASK, 1, out_mix_tlv), | ||
244 | SOC_SINGLE_TLV("LOMIX RIN3 Bypass Volume", WM8990_OUTPUT_MIXER5, | ||
245 | WM8990_LRI3LOVOL_SHIFT, WM8990_LRI3LOVOL_MASK, 1, out_mix_tlv), | ||
246 | SOC_SINGLE_TLV("LOMIX AINRMUX Bypass Volume", WM8990_OUTPUT_MIXER5, | ||
247 | WM8990_LRBLOVOL_SHIFT, WM8990_LRBLOVOL_MASK, 1, out_mix_tlv), | ||
248 | SOC_SINGLE_TLV("LOMIX AINLMUX Bypass Volume", WM8990_OUTPUT_MIXER5, | ||
249 | WM8990_LRBLOVOL_SHIFT, WM8990_LRBLOVOL_MASK, 1, out_mix_tlv), | ||
250 | |||
251 | /* ROMIX */ | ||
252 | SOC_SINGLE_TLV("ROMIX RIN3 Bypass Volume", WM8990_OUTPUT_MIXER4, | ||
253 | WM8990_RRI3ROVOL_SHIFT, WM8990_RRI3ROVOL_MASK, 1, out_mix_tlv), | ||
254 | SOC_SINGLE_TLV("ROMIX LIN12 PGA Bypass Volume", WM8990_OUTPUT_MIXER4, | ||
255 | WM8990_RL12ROVOL_SHIFT, WM8990_RL12ROVOL_MASK, 1, out_mix_tlv), | ||
256 | SOC_SINGLE_TLV("ROMIX RIN12 PGA Bypass Volume", WM8990_OUTPUT_MIXER4, | ||
257 | WM8990_RR12ROVOL_SHIFT, WM8990_RR12ROVOL_MASK, 1, out_mix_tlv), | ||
258 | SOC_SINGLE_TLV("ROMIX LIN3 Bypass Volume", WM8990_OUTPUT_MIXER6, | ||
259 | WM8990_RLI3ROVOL_SHIFT, WM8990_RLI3ROVOL_MASK, 1, out_mix_tlv), | ||
260 | SOC_SINGLE_TLV("ROMIX AINLMUX Bypass Volume", WM8990_OUTPUT_MIXER6, | ||
261 | WM8990_RLBROVOL_SHIFT, WM8990_RLBROVOL_MASK, 1, out_mix_tlv), | ||
262 | SOC_SINGLE_TLV("ROMIX AINRMUX Bypass Volume", WM8990_OUTPUT_MIXER6, | ||
263 | WM8990_RRBROVOL_SHIFT, WM8990_RRBROVOL_MASK, 1, out_mix_tlv), | ||
264 | |||
265 | /* LOUT */ | ||
266 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("LOUT Volume", WM8990_LEFT_OUTPUT_VOLUME, | ||
267 | WM8990_LOUTVOL_SHIFT, WM8990_LOUTVOL_MASK, 0, out_pga_tlv), | ||
268 | SOC_SINGLE("LOUT ZC", WM8990_LEFT_OUTPUT_VOLUME, WM8990_LOZC_BIT, 1, 0), | ||
269 | |||
270 | /* ROUT */ | ||
271 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("ROUT Volume", WM8990_RIGHT_OUTPUT_VOLUME, | ||
272 | WM8990_ROUTVOL_SHIFT, WM8990_ROUTVOL_MASK, 0, out_pga_tlv), | ||
273 | SOC_SINGLE("ROUT ZC", WM8990_RIGHT_OUTPUT_VOLUME, WM8990_ROZC_BIT, 1, 0), | ||
274 | |||
275 | /* LOPGA */ | ||
276 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("LOPGA Volume", WM8990_LEFT_OPGA_VOLUME, | ||
277 | WM8990_LOPGAVOL_SHIFT, WM8990_LOPGAVOL_MASK, 0, out_pga_tlv), | ||
278 | SOC_SINGLE("LOPGA ZC Switch", WM8990_LEFT_OPGA_VOLUME, | ||
279 | WM8990_LOPGAZC_BIT, 1, 0), | ||
280 | |||
281 | /* ROPGA */ | ||
282 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("ROPGA Volume", WM8990_RIGHT_OPGA_VOLUME, | ||
283 | WM8990_ROPGAVOL_SHIFT, WM8990_ROPGAVOL_MASK, 0, out_pga_tlv), | ||
284 | SOC_SINGLE("ROPGA ZC Switch", WM8990_RIGHT_OPGA_VOLUME, | ||
285 | WM8990_ROPGAZC_BIT, 1, 0), | ||
286 | |||
287 | SOC_SINGLE("LON Mute Switch", WM8990_LINE_OUTPUTS_VOLUME, | ||
288 | WM8990_LONMUTE_BIT, 1, 0), | ||
289 | SOC_SINGLE("LOP Mute Switch", WM8990_LINE_OUTPUTS_VOLUME, | ||
290 | WM8990_LOPMUTE_BIT, 1, 0), | ||
291 | SOC_SINGLE("LOP Attenuation Switch", WM8990_LINE_OUTPUTS_VOLUME, | ||
292 | WM8990_LOATTN_BIT, 1, 0), | ||
293 | SOC_SINGLE("RON Mute Switch", WM8990_LINE_OUTPUTS_VOLUME, | ||
294 | WM8990_RONMUTE_BIT, 1, 0), | ||
295 | SOC_SINGLE("ROP Mute Switch", WM8990_LINE_OUTPUTS_VOLUME, | ||
296 | WM8990_ROPMUTE_BIT, 1, 0), | ||
297 | SOC_SINGLE("ROP Attenuation Switch", WM8990_LINE_OUTPUTS_VOLUME, | ||
298 | WM8990_ROATTN_BIT, 1, 0), | ||
299 | |||
300 | SOC_SINGLE("OUT3 Mute Switch", WM8990_OUT3_4_VOLUME, | ||
301 | WM8990_OUT3MUTE_BIT, 1, 0), | ||
302 | SOC_SINGLE("OUT3 Attenuation Switch", WM8990_OUT3_4_VOLUME, | ||
303 | WM8990_OUT3ATTN_BIT, 1, 0), | ||
304 | |||
305 | SOC_SINGLE("OUT4 Mute Switch", WM8990_OUT3_4_VOLUME, | ||
306 | WM8990_OUT4MUTE_BIT, 1, 0), | ||
307 | SOC_SINGLE("OUT4 Attenuation Switch", WM8990_OUT3_4_VOLUME, | ||
308 | WM8990_OUT4ATTN_BIT, 1, 0), | ||
309 | |||
310 | SOC_SINGLE("Speaker Mode Switch", WM8990_CLASSD1, | ||
311 | WM8990_CDMODE_BIT, 1, 0), | ||
312 | |||
313 | SOC_SINGLE("Speaker Output Attenuation Volume", WM8990_SPEAKER_VOLUME, | ||
314 | WM8990_SPKVOL_SHIFT, WM8990_SPKVOL_MASK, 0), | ||
315 | SOC_SINGLE("Speaker DC Boost Volume", WM8990_CLASSD3, | ||
316 | WM8990_DCGAIN_SHIFT, WM8990_DCGAIN_MASK, 0), | ||
317 | SOC_SINGLE("Speaker AC Boost Volume", WM8990_CLASSD3, | ||
318 | WM8990_ACGAIN_SHIFT, WM8990_ACGAIN_MASK, 0), | ||
319 | |||
320 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("Left DAC Digital Volume", | ||
321 | WM8990_LEFT_DAC_DIGITAL_VOLUME, | ||
322 | WM8990_DACL_VOL_SHIFT, | ||
323 | WM8990_DACL_VOL_MASK, | ||
324 | 0, | ||
325 | out_dac_tlv), | ||
326 | |||
327 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("Right DAC Digital Volume", | ||
328 | WM8990_RIGHT_DAC_DIGITAL_VOLUME, | ||
329 | WM8990_DACR_VOL_SHIFT, | ||
330 | WM8990_DACR_VOL_MASK, | ||
331 | 0, | ||
332 | out_dac_tlv), | ||
333 | |||
334 | SOC_ENUM("Left Digital Sidetone", wm8990_left_digital_sidetone_enum), | ||
335 | SOC_ENUM("Right Digital Sidetone", wm8990_right_digital_sidetone_enum), | ||
336 | |||
337 | SOC_SINGLE_TLV("Left Digital Sidetone Volume", WM8990_DIGITAL_SIDE_TONE, | ||
338 | WM8990_ADCL_DAC_SVOL_SHIFT, WM8990_ADCL_DAC_SVOL_MASK, 0, | ||
339 | out_sidetone_tlv), | ||
340 | SOC_SINGLE_TLV("Right Digital Sidetone Volume", WM8990_DIGITAL_SIDE_TONE, | ||
341 | WM8990_ADCR_DAC_SVOL_SHIFT, WM8990_ADCR_DAC_SVOL_MASK, 0, | ||
342 | out_sidetone_tlv), | ||
343 | |||
344 | SOC_SINGLE("ADC Digital High Pass Filter Switch", WM8990_ADC_CTRL, | ||
345 | WM8990_ADC_HPF_ENA_BIT, 1, 0), | ||
346 | |||
347 | SOC_ENUM("ADC HPF Mode", wm8990_right_adcmode_enum), | ||
348 | |||
349 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("Left ADC Digital Volume", | ||
350 | WM8990_LEFT_ADC_DIGITAL_VOLUME, | ||
351 | WM8990_ADCL_VOL_SHIFT, | ||
352 | WM8990_ADCL_VOL_MASK, | ||
353 | 0, | ||
354 | in_adc_tlv), | ||
355 | |||
356 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("Right ADC Digital Volume", | ||
357 | WM8990_RIGHT_ADC_DIGITAL_VOLUME, | ||
358 | WM8990_ADCR_VOL_SHIFT, | ||
359 | WM8990_ADCR_VOL_MASK, | ||
360 | 0, | ||
361 | in_adc_tlv), | ||
362 | |||
363 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("LIN12 Volume", | ||
364 | WM8990_LEFT_LINE_INPUT_1_2_VOLUME, | ||
365 | WM8990_LIN12VOL_SHIFT, | ||
366 | WM8990_LIN12VOL_MASK, | ||
367 | 0, | ||
368 | in_pga_tlv), | ||
369 | |||
370 | SOC_SINGLE("LIN12 ZC Switch", WM8990_LEFT_LINE_INPUT_1_2_VOLUME, | ||
371 | WM8990_LI12ZC_BIT, 1, 0), | ||
372 | |||
373 | SOC_SINGLE("LIN12 Mute Switch", WM8990_LEFT_LINE_INPUT_1_2_VOLUME, | ||
374 | WM8990_LI12MUTE_BIT, 1, 0), | ||
375 | |||
376 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("LIN34 Volume", | ||
377 | WM8990_LEFT_LINE_INPUT_3_4_VOLUME, | ||
378 | WM8990_LIN34VOL_SHIFT, | ||
379 | WM8990_LIN34VOL_MASK, | ||
380 | 0, | ||
381 | in_pga_tlv), | ||
382 | |||
383 | SOC_SINGLE("LIN34 ZC Switch", WM8990_LEFT_LINE_INPUT_3_4_VOLUME, | ||
384 | WM8990_LI34ZC_BIT, 1, 0), | ||
385 | |||
386 | SOC_SINGLE("LIN34 Mute Switch", WM8990_LEFT_LINE_INPUT_3_4_VOLUME, | ||
387 | WM8990_LI34MUTE_BIT, 1, 0), | ||
388 | |||
389 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("RIN12 Volume", | ||
390 | WM8990_RIGHT_LINE_INPUT_1_2_VOLUME, | ||
391 | WM8990_RIN12VOL_SHIFT, | ||
392 | WM8990_RIN12VOL_MASK, | ||
393 | 0, | ||
394 | in_pga_tlv), | ||
395 | |||
396 | SOC_SINGLE("RIN12 ZC Switch", WM8990_RIGHT_LINE_INPUT_1_2_VOLUME, | ||
397 | WM8990_RI12ZC_BIT, 1, 0), | ||
398 | |||
399 | SOC_SINGLE("RIN12 Mute Switch", WM8990_RIGHT_LINE_INPUT_1_2_VOLUME, | ||
400 | WM8990_RI12MUTE_BIT, 1, 0), | ||
401 | |||
402 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("RIN34 Volume", | ||
403 | WM8990_RIGHT_LINE_INPUT_3_4_VOLUME, | ||
404 | WM8990_RIN34VOL_SHIFT, | ||
405 | WM8990_RIN34VOL_MASK, | ||
406 | 0, | ||
407 | in_pga_tlv), | ||
408 | |||
409 | SOC_SINGLE("RIN34 ZC Switch", WM8990_RIGHT_LINE_INPUT_3_4_VOLUME, | ||
410 | WM8990_RI34ZC_BIT, 1, 0), | ||
411 | |||
412 | SOC_SINGLE("RIN34 Mute Switch", WM8990_RIGHT_LINE_INPUT_3_4_VOLUME, | ||
413 | WM8990_RI34MUTE_BIT, 1, 0), | ||
414 | |||
415 | }; | ||
416 | |||
417 | /* add non dapm controls */ | ||
418 | static int wm8990_add_controls(struct snd_soc_codec *codec) | ||
419 | { | ||
420 | int err, i; | ||
421 | |||
422 | for (i = 0; i < ARRAY_SIZE(wm8990_snd_controls); i++) { | ||
423 | err = snd_ctl_add(codec->card, | ||
424 | snd_soc_cnew(&wm8990_snd_controls[i], codec, | ||
425 | NULL)); | ||
426 | if (err < 0) | ||
427 | return err; | ||
428 | } | ||
429 | return 0; | ||
430 | } | ||
431 | |||
432 | /* | ||
433 | * _DAPM_ Controls | ||
434 | */ | ||
435 | |||
436 | static int inmixer_event(struct snd_soc_dapm_widget *w, | ||
437 | struct snd_kcontrol *kcontrol, int event) | ||
438 | { | ||
439 | u16 reg, fakepower; | ||
440 | |||
441 | reg = wm8990_read_reg_cache(w->codec, WM8990_POWER_MANAGEMENT_2); | ||
442 | fakepower = wm8990_read_reg_cache(w->codec, WM8990_INTDRIVBITS); | ||
443 | |||
444 | if (fakepower & ((1 << WM8990_INMIXL_PWR_BIT) | | ||
445 | (1 << WM8990_AINLMUX_PWR_BIT))) { | ||
446 | reg |= WM8990_AINL_ENA; | ||
447 | } else { | ||
448 | reg &= ~WM8990_AINL_ENA; | ||
449 | } | ||
450 | |||
451 | if (fakepower & ((1 << WM8990_INMIXR_PWR_BIT) | | ||
452 | (1 << WM8990_AINRMUX_PWR_BIT))) { | ||
453 | reg |= WM8990_AINR_ENA; | ||
454 | } else { | ||
455 | reg &= ~WM8990_AINL_ENA; | ||
456 | } | ||
457 | wm8990_write(w->codec, WM8990_POWER_MANAGEMENT_2, reg); | ||
458 | |||
459 | return 0; | ||
460 | } | ||
461 | |||
462 | static int outmixer_event(struct snd_soc_dapm_widget *w, | ||
463 | struct snd_kcontrol *kcontrol, int event) | ||
464 | { | ||
465 | u32 reg_shift = kcontrol->private_value & 0xfff; | ||
466 | int ret = 0; | ||
467 | u16 reg; | ||
468 | |||
469 | switch (reg_shift) { | ||
470 | case WM8990_SPEAKER_MIXER | (WM8990_LDSPK_BIT << 8) : | ||
471 | reg = wm8990_read_reg_cache(w->codec, WM8990_OUTPUT_MIXER1); | ||
472 | if (reg & WM8990_LDLO) { | ||
473 | printk(KERN_WARNING | ||
474 | "Cannot set as Output Mixer 1 LDLO Set\n"); | ||
475 | ret = -1; | ||
476 | } | ||
477 | break; | ||
478 | case WM8990_SPEAKER_MIXER | (WM8990_RDSPK_BIT << 8): | ||
479 | reg = wm8990_read_reg_cache(w->codec, WM8990_OUTPUT_MIXER2); | ||
480 | if (reg & WM8990_RDRO) { | ||
481 | printk(KERN_WARNING | ||
482 | "Cannot set as Output Mixer 2 RDRO Set\n"); | ||
483 | ret = -1; | ||
484 | } | ||
485 | break; | ||
486 | case WM8990_OUTPUT_MIXER1 | (WM8990_LDLO_BIT << 8): | ||
487 | reg = wm8990_read_reg_cache(w->codec, WM8990_SPEAKER_MIXER); | ||
488 | if (reg & WM8990_LDSPK) { | ||
489 | printk(KERN_WARNING | ||
490 | "Cannot set as Speaker Mixer LDSPK Set\n"); | ||
491 | ret = -1; | ||
492 | } | ||
493 | break; | ||
494 | case WM8990_OUTPUT_MIXER2 | (WM8990_RDRO_BIT << 8): | ||
495 | reg = wm8990_read_reg_cache(w->codec, WM8990_SPEAKER_MIXER); | ||
496 | if (reg & WM8990_RDSPK) { | ||
497 | printk(KERN_WARNING | ||
498 | "Cannot set as Speaker Mixer RDSPK Set\n"); | ||
499 | ret = -1; | ||
500 | } | ||
501 | break; | ||
502 | } | ||
503 | |||
504 | return ret; | ||
505 | } | ||
506 | |||
507 | /* INMIX dB values */ | ||
508 | static const unsigned int in_mix_tlv[] = { | ||
509 | TLV_DB_RANGE_HEAD(1), | ||
510 | 0, 7, TLV_DB_LINEAR_ITEM(-1200, 600), | ||
511 | }; | ||
512 | |||
513 | /* Left In PGA Connections */ | ||
514 | static const struct snd_kcontrol_new wm8990_dapm_lin12_pga_controls[] = { | ||
515 | SOC_DAPM_SINGLE("LIN1 Switch", WM8990_INPUT_MIXER2, WM8990_LMN1_BIT, 1, 0), | ||
516 | SOC_DAPM_SINGLE("LIN2 Switch", WM8990_INPUT_MIXER2, WM8990_LMP2_BIT, 1, 0), | ||
517 | }; | ||
518 | |||
519 | static const struct snd_kcontrol_new wm8990_dapm_lin34_pga_controls[] = { | ||
520 | SOC_DAPM_SINGLE("LIN3 Switch", WM8990_INPUT_MIXER2, WM8990_LMN3_BIT, 1, 0), | ||
521 | SOC_DAPM_SINGLE("LIN4 Switch", WM8990_INPUT_MIXER2, WM8990_LMP4_BIT, 1, 0), | ||
522 | }; | ||
523 | |||
524 | /* Right In PGA Connections */ | ||
525 | static const struct snd_kcontrol_new wm8990_dapm_rin12_pga_controls[] = { | ||
526 | SOC_DAPM_SINGLE("RIN1 Switch", WM8990_INPUT_MIXER2, WM8990_RMN1_BIT, 1, 0), | ||
527 | SOC_DAPM_SINGLE("RIN2 Switch", WM8990_INPUT_MIXER2, WM8990_RMP2_BIT, 1, 0), | ||
528 | }; | ||
529 | |||
530 | static const struct snd_kcontrol_new wm8990_dapm_rin34_pga_controls[] = { | ||
531 | SOC_DAPM_SINGLE("RIN3 Switch", WM8990_INPUT_MIXER2, WM8990_RMN3_BIT, 1, 0), | ||
532 | SOC_DAPM_SINGLE("RIN4 Switch", WM8990_INPUT_MIXER2, WM8990_RMP4_BIT, 1, 0), | ||
533 | }; | ||
534 | |||
535 | /* INMIXL */ | ||
536 | static const struct snd_kcontrol_new wm8990_dapm_inmixl_controls[] = { | ||
537 | SOC_DAPM_SINGLE_TLV("Record Left Volume", WM8990_INPUT_MIXER3, | ||
538 | WM8990_LDBVOL_SHIFT, WM8990_LDBVOL_MASK, 0, in_mix_tlv), | ||
539 | SOC_DAPM_SINGLE_TLV("LIN2 Volume", WM8990_INPUT_MIXER5, WM8990_LI2BVOL_SHIFT, | ||
540 | 7, 0, in_mix_tlv), | ||
541 | SOC_DAPM_SINGLE("LINPGA12 Switch", WM8990_INPUT_MIXER3, WM8990_L12MNB_BIT, | ||
542 | 1, 0), | ||
543 | SOC_DAPM_SINGLE("LINPGA34 Switch", WM8990_INPUT_MIXER3, WM8990_L34MNB_BIT, | ||
544 | 1, 0), | ||
545 | }; | ||
546 | |||
547 | /* INMIXR */ | ||
548 | static const struct snd_kcontrol_new wm8990_dapm_inmixr_controls[] = { | ||
549 | SOC_DAPM_SINGLE_TLV("Record Right Volume", WM8990_INPUT_MIXER4, | ||
550 | WM8990_RDBVOL_SHIFT, WM8990_RDBVOL_MASK, 0, in_mix_tlv), | ||
551 | SOC_DAPM_SINGLE_TLV("RIN2 Volume", WM8990_INPUT_MIXER6, WM8990_RI2BVOL_SHIFT, | ||
552 | 7, 0, in_mix_tlv), | ||
553 | SOC_DAPM_SINGLE("RINPGA12 Switch", WM8990_INPUT_MIXER3, WM8990_L12MNB_BIT, | ||
554 | 1, 0), | ||
555 | SOC_DAPM_SINGLE("RINPGA34 Switch", WM8990_INPUT_MIXER3, WM8990_L34MNB_BIT, | ||
556 | 1, 0), | ||
557 | }; | ||
558 | |||
559 | /* AINLMUX */ | ||
560 | static const char *wm8990_ainlmux[] = | ||
561 | {"INMIXL Mix", "RXVOICE Mix", "DIFFINL Mix"}; | ||
562 | |||
563 | static const struct soc_enum wm8990_ainlmux_enum = | ||
564 | SOC_ENUM_SINGLE(WM8990_INPUT_MIXER1, WM8990_AINLMODE_SHIFT, | ||
565 | ARRAY_SIZE(wm8990_ainlmux), wm8990_ainlmux); | ||
566 | |||
567 | static const struct snd_kcontrol_new wm8990_dapm_ainlmux_controls = | ||
568 | SOC_DAPM_ENUM("Route", wm8990_ainlmux_enum); | ||
569 | |||
570 | /* DIFFINL */ | ||
571 | |||
572 | /* AINRMUX */ | ||
573 | static const char *wm8990_ainrmux[] = | ||
574 | {"INMIXR Mix", "RXVOICE Mix", "DIFFINR Mix"}; | ||
575 | |||
576 | static const struct soc_enum wm8990_ainrmux_enum = | ||
577 | SOC_ENUM_SINGLE(WM8990_INPUT_MIXER1, WM8990_AINRMODE_SHIFT, | ||
578 | ARRAY_SIZE(wm8990_ainrmux), wm8990_ainrmux); | ||
579 | |||
580 | static const struct snd_kcontrol_new wm8990_dapm_ainrmux_controls = | ||
581 | SOC_DAPM_ENUM("Route", wm8990_ainrmux_enum); | ||
582 | |||
583 | /* RXVOICE */ | ||
584 | static const struct snd_kcontrol_new wm8990_dapm_rxvoice_controls[] = { | ||
585 | SOC_DAPM_SINGLE_TLV("LIN4/RXN", WM8990_INPUT_MIXER5, WM8990_LR4BVOL_SHIFT, | ||
586 | WM8990_LR4BVOL_MASK, 0, in_mix_tlv), | ||
587 | SOC_DAPM_SINGLE_TLV("RIN4/RXP", WM8990_INPUT_MIXER6, WM8990_RL4BVOL_SHIFT, | ||
588 | WM8990_RL4BVOL_MASK, 0, in_mix_tlv), | ||
589 | }; | ||
590 | |||
591 | /* LOMIX */ | ||
592 | static const struct snd_kcontrol_new wm8990_dapm_lomix_controls[] = { | ||
593 | SOC_DAPM_SINGLE("LOMIX Right ADC Bypass Switch", WM8990_OUTPUT_MIXER1, | ||
594 | WM8990_LRBLO_BIT, 1, 0), | ||
595 | SOC_DAPM_SINGLE("LOMIX Left ADC Bypass Switch", WM8990_OUTPUT_MIXER1, | ||
596 | WM8990_LLBLO_BIT, 1, 0), | ||
597 | SOC_DAPM_SINGLE("LOMIX RIN3 Bypass Switch", WM8990_OUTPUT_MIXER1, | ||
598 | WM8990_LRI3LO_BIT, 1, 0), | ||
599 | SOC_DAPM_SINGLE("LOMIX LIN3 Bypass Switch", WM8990_OUTPUT_MIXER1, | ||
600 | WM8990_LLI3LO_BIT, 1, 0), | ||
601 | SOC_DAPM_SINGLE("LOMIX RIN12 PGA Bypass Switch", WM8990_OUTPUT_MIXER1, | ||
602 | WM8990_LR12LO_BIT, 1, 0), | ||
603 | SOC_DAPM_SINGLE("LOMIX LIN12 PGA Bypass Switch", WM8990_OUTPUT_MIXER1, | ||
604 | WM8990_LL12LO_BIT, 1, 0), | ||
605 | SOC_DAPM_SINGLE("LOMIX Left DAC Switch", WM8990_OUTPUT_MIXER1, | ||
606 | WM8990_LDLO_BIT, 1, 0), | ||
607 | }; | ||
608 | |||
609 | /* ROMIX */ | ||
610 | static const struct snd_kcontrol_new wm8990_dapm_romix_controls[] = { | ||
611 | SOC_DAPM_SINGLE("ROMIX Left ADC Bypass Switch", WM8990_OUTPUT_MIXER2, | ||
612 | WM8990_RLBRO_BIT, 1, 0), | ||
613 | SOC_DAPM_SINGLE("ROMIX Right ADC Bypass Switch", WM8990_OUTPUT_MIXER2, | ||
614 | WM8990_RRBRO_BIT, 1, 0), | ||
615 | SOC_DAPM_SINGLE("ROMIX LIN3 Bypass Switch", WM8990_OUTPUT_MIXER2, | ||
616 | WM8990_RLI3RO_BIT, 1, 0), | ||
617 | SOC_DAPM_SINGLE("ROMIX RIN3 Bypass Switch", WM8990_OUTPUT_MIXER2, | ||
618 | WM8990_RRI3RO_BIT, 1, 0), | ||
619 | SOC_DAPM_SINGLE("ROMIX LIN12 PGA Bypass Switch", WM8990_OUTPUT_MIXER2, | ||
620 | WM8990_RL12RO_BIT, 1, 0), | ||
621 | SOC_DAPM_SINGLE("ROMIX RIN12 PGA Bypass Switch", WM8990_OUTPUT_MIXER2, | ||
622 | WM8990_RR12RO_BIT, 1, 0), | ||
623 | SOC_DAPM_SINGLE("ROMIX Right DAC Switch", WM8990_OUTPUT_MIXER2, | ||
624 | WM8990_RDRO_BIT, 1, 0), | ||
625 | }; | ||
626 | |||
627 | /* LONMIX */ | ||
628 | static const struct snd_kcontrol_new wm8990_dapm_lonmix_controls[] = { | ||
629 | SOC_DAPM_SINGLE("LONMIX Left Mixer PGA Switch", WM8990_LINE_MIXER1, | ||
630 | WM8990_LLOPGALON_BIT, 1, 0), | ||
631 | SOC_DAPM_SINGLE("LONMIX Right Mixer PGA Switch", WM8990_LINE_MIXER1, | ||
632 | WM8990_LROPGALON_BIT, 1, 0), | ||
633 | SOC_DAPM_SINGLE("LONMIX Inverted LOP Switch", WM8990_LINE_MIXER1, | ||
634 | WM8990_LOPLON_BIT, 1, 0), | ||
635 | }; | ||
636 | |||
637 | /* LOPMIX */ | ||
638 | static const struct snd_kcontrol_new wm8990_dapm_lopmix_controls[] = { | ||
639 | SOC_DAPM_SINGLE("LOPMIX Right Mic Bypass Switch", WM8990_LINE_MIXER1, | ||
640 | WM8990_LR12LOP_BIT, 1, 0), | ||
641 | SOC_DAPM_SINGLE("LOPMIX Left Mic Bypass Switch", WM8990_LINE_MIXER1, | ||
642 | WM8990_LL12LOP_BIT, 1, 0), | ||
643 | SOC_DAPM_SINGLE("LOPMIX Left Mixer PGA Switch", WM8990_LINE_MIXER1, | ||
644 | WM8990_LLOPGALOP_BIT, 1, 0), | ||
645 | }; | ||
646 | |||
647 | /* RONMIX */ | ||
648 | static const struct snd_kcontrol_new wm8990_dapm_ronmix_controls[] = { | ||
649 | SOC_DAPM_SINGLE("RONMIX Right Mixer PGA Switch", WM8990_LINE_MIXER2, | ||
650 | WM8990_RROPGARON_BIT, 1, 0), | ||
651 | SOC_DAPM_SINGLE("RONMIX Left Mixer PGA Switch", WM8990_LINE_MIXER2, | ||
652 | WM8990_RLOPGARON_BIT, 1, 0), | ||
653 | SOC_DAPM_SINGLE("RONMIX Inverted ROP Switch", WM8990_LINE_MIXER2, | ||
654 | WM8990_ROPRON_BIT, 1, 0), | ||
655 | }; | ||
656 | |||
657 | /* ROPMIX */ | ||
658 | static const struct snd_kcontrol_new wm8990_dapm_ropmix_controls[] = { | ||
659 | SOC_DAPM_SINGLE("ROPMIX Left Mic Bypass Switch", WM8990_LINE_MIXER2, | ||
660 | WM8990_RL12ROP_BIT, 1, 0), | ||
661 | SOC_DAPM_SINGLE("ROPMIX Right Mic Bypass Switch", WM8990_LINE_MIXER2, | ||
662 | WM8990_RR12ROP_BIT, 1, 0), | ||
663 | SOC_DAPM_SINGLE("ROPMIX Right Mixer PGA Switch", WM8990_LINE_MIXER2, | ||
664 | WM8990_RROPGAROP_BIT, 1, 0), | ||
665 | }; | ||
666 | |||
667 | /* OUT3MIX */ | ||
668 | static const struct snd_kcontrol_new wm8990_dapm_out3mix_controls[] = { | ||
669 | SOC_DAPM_SINGLE("OUT3MIX LIN4/RXP Bypass Switch", WM8990_OUT3_4_MIXER, | ||
670 | WM8990_LI4O3_BIT, 1, 0), | ||
671 | SOC_DAPM_SINGLE("OUT3MIX Left Out PGA Switch", WM8990_OUT3_4_MIXER, | ||
672 | WM8990_LPGAO3_BIT, 1, 0), | ||
673 | }; | ||
674 | |||
675 | /* OUT4MIX */ | ||
676 | static const struct snd_kcontrol_new wm8990_dapm_out4mix_controls[] = { | ||
677 | SOC_DAPM_SINGLE("OUT4MIX Right Out PGA Switch", WM8990_OUT3_4_MIXER, | ||
678 | WM8990_RPGAO4_BIT, 1, 0), | ||
679 | SOC_DAPM_SINGLE("OUT4MIX RIN4/RXP Bypass Switch", WM8990_OUT3_4_MIXER, | ||
680 | WM8990_RI4O4_BIT, 1, 0), | ||
681 | }; | ||
682 | |||
683 | /* SPKMIX */ | ||
684 | static const struct snd_kcontrol_new wm8990_dapm_spkmix_controls[] = { | ||
685 | SOC_DAPM_SINGLE("SPKMIX LIN2 Bypass Switch", WM8990_SPEAKER_MIXER, | ||
686 | WM8990_LI2SPK_BIT, 1, 0), | ||
687 | SOC_DAPM_SINGLE("SPKMIX LADC Bypass Switch", WM8990_SPEAKER_MIXER, | ||
688 | WM8990_LB2SPK_BIT, 1, 0), | ||
689 | SOC_DAPM_SINGLE("SPKMIX Left Mixer PGA Switch", WM8990_SPEAKER_MIXER, | ||
690 | WM8990_LOPGASPK_BIT, 1, 0), | ||
691 | SOC_DAPM_SINGLE("SPKMIX Left DAC Switch", WM8990_SPEAKER_MIXER, | ||
692 | WM8990_LDSPK_BIT, 1, 0), | ||
693 | SOC_DAPM_SINGLE("SPKMIX Right DAC Switch", WM8990_SPEAKER_MIXER, | ||
694 | WM8990_RDSPK_BIT, 1, 0), | ||
695 | SOC_DAPM_SINGLE("SPKMIX Right Mixer PGA Switch", WM8990_SPEAKER_MIXER, | ||
696 | WM8990_ROPGASPK_BIT, 1, 0), | ||
697 | SOC_DAPM_SINGLE("SPKMIX RADC Bypass Switch", WM8990_SPEAKER_MIXER, | ||
698 | WM8990_RL12ROP_BIT, 1, 0), | ||
699 | SOC_DAPM_SINGLE("SPKMIX RIN2 Bypass Switch", WM8990_SPEAKER_MIXER, | ||
700 | WM8990_RI2SPK_BIT, 1, 0), | ||
701 | }; | ||
702 | |||
703 | static const struct snd_soc_dapm_widget wm8990_dapm_widgets[] = { | ||
704 | /* Input Side */ | ||
705 | /* Input Lines */ | ||
706 | SND_SOC_DAPM_INPUT("LIN1"), | ||
707 | SND_SOC_DAPM_INPUT("LIN2"), | ||
708 | SND_SOC_DAPM_INPUT("LIN3"), | ||
709 | SND_SOC_DAPM_INPUT("LIN4/RXN"), | ||
710 | SND_SOC_DAPM_INPUT("RIN3"), | ||
711 | SND_SOC_DAPM_INPUT("RIN4/RXP"), | ||
712 | SND_SOC_DAPM_INPUT("RIN1"), | ||
713 | SND_SOC_DAPM_INPUT("RIN2"), | ||
714 | SND_SOC_DAPM_INPUT("Internal ADC Source"), | ||
715 | |||
716 | /* DACs */ | ||
717 | SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8990_POWER_MANAGEMENT_2, | ||
718 | WM8990_ADCL_ENA_BIT, 0), | ||
719 | SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8990_POWER_MANAGEMENT_2, | ||
720 | WM8990_ADCR_ENA_BIT, 0), | ||
721 | |||
722 | /* Input PGAs */ | ||
723 | SND_SOC_DAPM_MIXER("LIN12 PGA", WM8990_POWER_MANAGEMENT_2, WM8990_LIN12_ENA_BIT, | ||
724 | 0, &wm8990_dapm_lin12_pga_controls[0], | ||
725 | ARRAY_SIZE(wm8990_dapm_lin12_pga_controls)), | ||
726 | SND_SOC_DAPM_MIXER("LIN34 PGA", WM8990_POWER_MANAGEMENT_2, WM8990_LIN34_ENA_BIT, | ||
727 | 0, &wm8990_dapm_lin34_pga_controls[0], | ||
728 | ARRAY_SIZE(wm8990_dapm_lin34_pga_controls)), | ||
729 | SND_SOC_DAPM_MIXER("RIN12 PGA", WM8990_POWER_MANAGEMENT_2, WM8990_RIN12_ENA_BIT, | ||
730 | 0, &wm8990_dapm_rin12_pga_controls[0], | ||
731 | ARRAY_SIZE(wm8990_dapm_rin12_pga_controls)), | ||
732 | SND_SOC_DAPM_MIXER("RIN34 PGA", WM8990_POWER_MANAGEMENT_2, WM8990_RIN34_ENA_BIT, | ||
733 | 0, &wm8990_dapm_rin34_pga_controls[0], | ||
734 | ARRAY_SIZE(wm8990_dapm_rin34_pga_controls)), | ||
735 | |||
736 | /* INMIXL */ | ||
737 | SND_SOC_DAPM_MIXER_E("INMIXL", WM8990_INTDRIVBITS, WM8990_INMIXL_PWR_BIT, 0, | ||
738 | &wm8990_dapm_inmixl_controls[0], | ||
739 | ARRAY_SIZE(wm8990_dapm_inmixl_controls), | ||
740 | inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), | ||
741 | |||
742 | /* AINLMUX */ | ||
743 | SND_SOC_DAPM_MUX_E("AILNMUX", WM8990_INTDRIVBITS, WM8990_AINLMUX_PWR_BIT, 0, | ||
744 | &wm8990_dapm_ainlmux_controls, inmixer_event, | ||
745 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), | ||
746 | |||
747 | /* INMIXR */ | ||
748 | SND_SOC_DAPM_MIXER_E("INMIXR", WM8990_INTDRIVBITS, WM8990_INMIXR_PWR_BIT, 0, | ||
749 | &wm8990_dapm_inmixr_controls[0], | ||
750 | ARRAY_SIZE(wm8990_dapm_inmixr_controls), | ||
751 | inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), | ||
752 | |||
753 | /* AINRMUX */ | ||
754 | SND_SOC_DAPM_MUX_E("AIRNMUX", WM8990_INTDRIVBITS, WM8990_AINRMUX_PWR_BIT, 0, | ||
755 | &wm8990_dapm_ainrmux_controls, inmixer_event, | ||
756 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), | ||
757 | |||
758 | /* Output Side */ | ||
759 | /* DACs */ | ||
760 | SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8990_POWER_MANAGEMENT_3, | ||
761 | WM8990_DACL_ENA_BIT, 0), | ||
762 | SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8990_POWER_MANAGEMENT_3, | ||
763 | WM8990_DACR_ENA_BIT, 0), | ||
764 | |||
765 | /* LOMIX */ | ||
766 | SND_SOC_DAPM_MIXER_E("LOMIX", WM8990_POWER_MANAGEMENT_3, WM8990_LOMIX_ENA_BIT, | ||
767 | 0, &wm8990_dapm_lomix_controls[0], | ||
768 | ARRAY_SIZE(wm8990_dapm_lomix_controls), | ||
769 | outmixer_event, SND_SOC_DAPM_PRE_REG), | ||
770 | |||
771 | /* LONMIX */ | ||
772 | SND_SOC_DAPM_MIXER("LONMIX", WM8990_POWER_MANAGEMENT_3, WM8990_LON_ENA_BIT, 0, | ||
773 | &wm8990_dapm_lonmix_controls[0], | ||
774 | ARRAY_SIZE(wm8990_dapm_lonmix_controls)), | ||
775 | |||
776 | /* LOPMIX */ | ||
777 | SND_SOC_DAPM_MIXER("LOPMIX", WM8990_POWER_MANAGEMENT_3, WM8990_LOP_ENA_BIT, 0, | ||
778 | &wm8990_dapm_lopmix_controls[0], | ||
779 | ARRAY_SIZE(wm8990_dapm_lopmix_controls)), | ||
780 | |||
781 | /* OUT3MIX */ | ||
782 | SND_SOC_DAPM_MIXER("OUT3MIX", WM8990_POWER_MANAGEMENT_1, WM8990_OUT3_ENA_BIT, 0, | ||
783 | &wm8990_dapm_out3mix_controls[0], | ||
784 | ARRAY_SIZE(wm8990_dapm_out3mix_controls)), | ||
785 | |||
786 | /* SPKMIX */ | ||
787 | SND_SOC_DAPM_MIXER_E("SPKMIX", WM8990_POWER_MANAGEMENT_1, WM8990_SPK_ENA_BIT, 0, | ||
788 | &wm8990_dapm_spkmix_controls[0], | ||
789 | ARRAY_SIZE(wm8990_dapm_spkmix_controls), outmixer_event, | ||
790 | SND_SOC_DAPM_PRE_REG), | ||
791 | |||
792 | /* OUT4MIX */ | ||
793 | SND_SOC_DAPM_MIXER("OUT4MIX", WM8990_POWER_MANAGEMENT_1, WM8990_OUT4_ENA_BIT, 0, | ||
794 | &wm8990_dapm_out4mix_controls[0], | ||
795 | ARRAY_SIZE(wm8990_dapm_out4mix_controls)), | ||
796 | |||
797 | /* ROPMIX */ | ||
798 | SND_SOC_DAPM_MIXER("ROPMIX", WM8990_POWER_MANAGEMENT_3, WM8990_ROP_ENA_BIT, 0, | ||
799 | &wm8990_dapm_ropmix_controls[0], | ||
800 | ARRAY_SIZE(wm8990_dapm_ropmix_controls)), | ||
801 | |||
802 | /* RONMIX */ | ||
803 | SND_SOC_DAPM_MIXER("RONMIX", WM8990_POWER_MANAGEMENT_3, WM8990_RON_ENA_BIT, 0, | ||
804 | &wm8990_dapm_ronmix_controls[0], | ||
805 | ARRAY_SIZE(wm8990_dapm_ronmix_controls)), | ||
806 | |||
807 | /* ROMIX */ | ||
808 | SND_SOC_DAPM_MIXER_E("ROMIX", WM8990_POWER_MANAGEMENT_3, WM8990_ROMIX_ENA_BIT, | ||
809 | 0, &wm8990_dapm_romix_controls[0], | ||
810 | ARRAY_SIZE(wm8990_dapm_romix_controls), | ||
811 | outmixer_event, SND_SOC_DAPM_PRE_REG), | ||
812 | |||
813 | /* LOUT PGA */ | ||
814 | SND_SOC_DAPM_PGA("LOUT PGA", WM8990_POWER_MANAGEMENT_1, WM8990_LOUT_ENA_BIT, 0, | ||
815 | NULL, 0), | ||
816 | |||
817 | /* ROUT PGA */ | ||
818 | SND_SOC_DAPM_PGA("ROUT PGA", WM8990_POWER_MANAGEMENT_1, WM8990_ROUT_ENA_BIT, 0, | ||
819 | NULL, 0), | ||
820 | |||
821 | /* LOPGA */ | ||
822 | SND_SOC_DAPM_PGA("LOPGA", WM8990_POWER_MANAGEMENT_3, WM8990_LOPGA_ENA_BIT, 0, | ||
823 | NULL, 0), | ||
824 | |||
825 | /* ROPGA */ | ||
826 | SND_SOC_DAPM_PGA("ROPGA", WM8990_POWER_MANAGEMENT_3, WM8990_ROPGA_ENA_BIT, 0, | ||
827 | NULL, 0), | ||
828 | |||
829 | /* MICBIAS */ | ||
830 | SND_SOC_DAPM_MICBIAS("MICBIAS", WM8990_POWER_MANAGEMENT_1, | ||
831 | WM8990_MICBIAS_ENA_BIT, 0), | ||
832 | |||
833 | SND_SOC_DAPM_OUTPUT("LON"), | ||
834 | SND_SOC_DAPM_OUTPUT("LOP"), | ||
835 | SND_SOC_DAPM_OUTPUT("OUT3"), | ||
836 | SND_SOC_DAPM_OUTPUT("LOUT"), | ||
837 | SND_SOC_DAPM_OUTPUT("SPKN"), | ||
838 | SND_SOC_DAPM_OUTPUT("SPKP"), | ||
839 | SND_SOC_DAPM_OUTPUT("ROUT"), | ||
840 | SND_SOC_DAPM_OUTPUT("OUT4"), | ||
841 | SND_SOC_DAPM_OUTPUT("ROP"), | ||
842 | SND_SOC_DAPM_OUTPUT("RON"), | ||
843 | |||
844 | SND_SOC_DAPM_OUTPUT("Internal DAC Sink"), | ||
845 | }; | ||
846 | |||
847 | static const struct snd_soc_dapm_route audio_map[] = { | ||
848 | /* Make DACs turn on when playing even if not mixed into any outputs */ | ||
849 | {"Internal DAC Sink", NULL, "Left DAC"}, | ||
850 | {"Internal DAC Sink", NULL, "Right DAC"}, | ||
851 | |||
852 | /* Make ADCs turn on when recording even if not mixed from any inputs */ | ||
853 | {"Left ADC", NULL, "Internal ADC Source"}, | ||
854 | {"Right ADC", NULL, "Internal ADC Source"}, | ||
855 | |||
856 | /* Input Side */ | ||
857 | /* LIN12 PGA */ | ||
858 | {"LIN12 PGA", "LIN1 Switch", "LIN1"}, | ||
859 | {"LIN12 PGA", "LIN2 Switch", "LIN2"}, | ||
860 | /* LIN34 PGA */ | ||
861 | {"LIN34 PGA", "LIN3 Switch", "LIN3"}, | ||
862 | {"LIN34 PGA", "LIN4 Switch", "LIN4"}, | ||
863 | /* INMIXL */ | ||
864 | {"INMIXL", "Record Left Volume", "LOMIX"}, | ||
865 | {"INMIXL", "LIN2 Volume", "LIN2"}, | ||
866 | {"INMIXL", "LINPGA12 Switch", "LIN12 PGA"}, | ||
867 | {"INMIXL", "LINPGA34 Switch", "LIN34 PGA"}, | ||
868 | /* AILNMUX */ | ||
869 | {"AILNMUX", "INMIXL Mix", "INMIXL"}, | ||
870 | {"AILNMUX", "DIFFINL Mix", "LIN12PGA"}, | ||
871 | {"AILNMUX", "DIFFINL Mix", "LIN34PGA"}, | ||
872 | {"AILNMUX", "RXVOICE Mix", "LIN4/RXN"}, | ||
873 | {"AILNMUX", "RXVOICE Mix", "RIN4/RXP"}, | ||
874 | /* ADC */ | ||
875 | {"Left ADC", NULL, "AILNMUX"}, | ||
876 | |||
877 | /* RIN12 PGA */ | ||
878 | {"RIN12 PGA", "RIN1 Switch", "RIN1"}, | ||
879 | {"RIN12 PGA", "RIN2 Switch", "RIN2"}, | ||
880 | /* RIN34 PGA */ | ||
881 | {"RIN34 PGA", "RIN3 Switch", "RIN3"}, | ||
882 | {"RIN34 PGA", "RIN4 Switch", "RIN4"}, | ||
883 | /* INMIXL */ | ||
884 | {"INMIXR", "Record Right Volume", "ROMIX"}, | ||
885 | {"INMIXR", "RIN2 Volume", "RIN2"}, | ||
886 | {"INMIXR", "RINPGA12 Switch", "RIN12 PGA"}, | ||
887 | {"INMIXR", "RINPGA34 Switch", "RIN34 PGA"}, | ||
888 | /* AIRNMUX */ | ||
889 | {"AIRNMUX", "INMIXR Mix", "INMIXR"}, | ||
890 | {"AIRNMUX", "DIFFINR Mix", "RIN12PGA"}, | ||
891 | {"AIRNMUX", "DIFFINR Mix", "RIN34PGA"}, | ||
892 | {"AIRNMUX", "RXVOICE Mix", "RIN4/RXN"}, | ||
893 | {"AIRNMUX", "RXVOICE Mix", "RIN4/RXP"}, | ||
894 | /* ADC */ | ||
895 | {"Right ADC", NULL, "AIRNMUX"}, | ||
896 | |||
897 | /* LOMIX */ | ||
898 | {"LOMIX", "LOMIX RIN3 Bypass Switch", "RIN3"}, | ||
899 | {"LOMIX", "LOMIX LIN3 Bypass Switch", "LIN3"}, | ||
900 | {"LOMIX", "LOMIX LIN12 PGA Bypass Switch", "LIN12 PGA"}, | ||
901 | {"LOMIX", "LOMIX RIN12 PGA Bypass Switch", "RIN12 PGA"}, | ||
902 | {"LOMIX", "LOMIX Right ADC Bypass Switch", "AINRMUX"}, | ||
903 | {"LOMIX", "LOMIX Left ADC Bypass Switch", "AINLMUX"}, | ||
904 | {"LOMIX", "LOMIX Left DAC Switch", "Left DAC"}, | ||
905 | |||
906 | /* ROMIX */ | ||
907 | {"ROMIX", "ROMIX RIN3 Bypass Switch", "RIN3"}, | ||
908 | {"ROMIX", "ROMIX LIN3 Bypass Switch", "LIN3"}, | ||
909 | {"ROMIX", "ROMIX LIN12 PGA Bypass Switch", "LIN12 PGA"}, | ||
910 | {"ROMIX", "ROMIX RIN12 PGA Bypass Switch", "RIN12 PGA"}, | ||
911 | {"ROMIX", "ROMIX Right ADC Bypass Switch", "AINRMUX"}, | ||
912 | {"ROMIX", "ROMIX Left ADC Bypass Switch", "AINLMUX"}, | ||
913 | {"ROMIX", "ROMIX Right DAC Switch", "Right DAC"}, | ||
914 | |||
915 | /* SPKMIX */ | ||
916 | {"SPKMIX", "SPKMIX LIN2 Bypass Switch", "LIN2"}, | ||
917 | {"SPKMIX", "SPKMIX RIN2 Bypass Switch", "RIN2"}, | ||
918 | {"SPKMIX", "SPKMIX LADC Bypass Switch", "AINLMUX"}, | ||
919 | {"SPKMIX", "SPKMIX RADC Bypass Switch", "AINRMUX"}, | ||
920 | {"SPKMIX", "SPKMIX Left Mixer PGA Switch", "LOPGA"}, | ||
921 | {"SPKMIX", "SPKMIX Right Mixer PGA Switch", "ROPGA"}, | ||
922 | {"SPKMIX", "SPKMIX Right DAC Switch", "Right DAC"}, | ||
923 | {"SPKMIX", "SPKMIX Left DAC Switch", "Right DAC"}, | ||
924 | |||
925 | /* LONMIX */ | ||
926 | {"LONMIX", "LONMIX Left Mixer PGA Switch", "LOPGA"}, | ||
927 | {"LONMIX", "LONMIX Right Mixer PGA Switch", "ROPGA"}, | ||
928 | {"LONMIX", "LONMIX Inverted LOP Switch", "LOPMIX"}, | ||
929 | |||
930 | /* LOPMIX */ | ||
931 | {"LOPMIX", "LOPMIX Right Mic Bypass Switch", "RIN12 PGA"}, | ||
932 | {"LOPMIX", "LOPMIX Left Mic Bypass Switch", "LIN12 PGA"}, | ||
933 | {"LOPMIX", "LOPMIX Left Mixer PGA Switch", "LOPGA"}, | ||
934 | |||
935 | /* OUT3MIX */ | ||
936 | {"OUT3MIX", "OUT3MIX LIN4/RXP Bypass Switch", "LIN4/RXP"}, | ||
937 | {"OUT3MIX", "OUT3MIX Left Out PGA Switch", "LOPGA"}, | ||
938 | |||
939 | /* OUT4MIX */ | ||
940 | {"OUT4MIX", "OUT4MIX Right Out PGA Switch", "ROPGA"}, | ||
941 | {"OUT4MIX", "OUT4MIX RIN4/RXP Bypass Switch", "RIN4/RXP"}, | ||
942 | |||
943 | /* RONMIX */ | ||
944 | {"RONMIX", "RONMIX Right Mixer PGA Switch", "ROPGA"}, | ||
945 | {"RONMIX", "RONMIX Left Mixer PGA Switch", "LOPGA"}, | ||
946 | {"RONMIX", "RONMIX Inverted ROP Switch", "ROPMIX"}, | ||
947 | |||
948 | /* ROPMIX */ | ||
949 | {"ROPMIX", "ROPMIX Left Mic Bypass Switch", "LIN12 PGA"}, | ||
950 | {"ROPMIX", "ROPMIX Right Mic Bypass Switch", "RIN12 PGA"}, | ||
951 | {"ROPMIX", "ROPMIX Right Mixer PGA Switch", "ROPGA"}, | ||
952 | |||
953 | /* Out Mixer PGAs */ | ||
954 | {"LOPGA", NULL, "LOMIX"}, | ||
955 | {"ROPGA", NULL, "ROMIX"}, | ||
956 | |||
957 | {"LOUT PGA", NULL, "LOMIX"}, | ||
958 | {"ROUT PGA", NULL, "ROMIX"}, | ||
959 | |||
960 | /* Output Pins */ | ||
961 | {"LON", NULL, "LONMIX"}, | ||
962 | {"LOP", NULL, "LOPMIX"}, | ||
963 | {"OUT", NULL, "OUT3MIX"}, | ||
964 | {"LOUT", NULL, "LOUT PGA"}, | ||
965 | {"SPKN", NULL, "SPKMIX"}, | ||
966 | {"ROUT", NULL, "ROUT PGA"}, | ||
967 | {"OUT4", NULL, "OUT4MIX"}, | ||
968 | {"ROP", NULL, "ROPMIX"}, | ||
969 | {"RON", NULL, "RONMIX"}, | ||
970 | }; | ||
971 | |||
972 | static int wm8990_add_widgets(struct snd_soc_codec *codec) | ||
973 | { | ||
974 | snd_soc_dapm_new_controls(codec, wm8990_dapm_widgets, | ||
975 | ARRAY_SIZE(wm8990_dapm_widgets)); | ||
976 | |||
977 | /* set up the WM8990 audio map */ | ||
978 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | ||
979 | |||
980 | snd_soc_dapm_new_widgets(codec); | ||
981 | return 0; | ||
982 | } | ||
983 | |||
984 | /* PLL divisors */ | ||
985 | struct _pll_div { | ||
986 | u32 div2; | ||
987 | u32 n; | ||
988 | u32 k; | ||
989 | }; | ||
990 | |||
991 | /* The size in bits of the pll divide multiplied by 10 | ||
992 | * to allow rounding later */ | ||
993 | #define FIXED_PLL_SIZE ((1 << 16) * 10) | ||
994 | |||
995 | static void pll_factors(struct _pll_div *pll_div, unsigned int target, | ||
996 | unsigned int source) | ||
997 | { | ||
998 | u64 Kpart; | ||
999 | unsigned int K, Ndiv, Nmod; | ||
1000 | |||
1001 | |||
1002 | Ndiv = target / source; | ||
1003 | if (Ndiv < 6) { | ||
1004 | source >>= 1; | ||
1005 | pll_div->div2 = 1; | ||
1006 | Ndiv = target / source; | ||
1007 | } else | ||
1008 | pll_div->div2 = 0; | ||
1009 | |||
1010 | if ((Ndiv < 6) || (Ndiv > 12)) | ||
1011 | printk(KERN_WARNING | ||
1012 | "WM8990 N value outwith recommended range! N = %d\n", Ndiv); | ||
1013 | |||
1014 | pll_div->n = Ndiv; | ||
1015 | Nmod = target % source; | ||
1016 | Kpart = FIXED_PLL_SIZE * (long long)Nmod; | ||
1017 | |||
1018 | do_div(Kpart, source); | ||
1019 | |||
1020 | K = Kpart & 0xFFFFFFFF; | ||
1021 | |||
1022 | /* Check if we need to round */ | ||
1023 | if ((K % 10) >= 5) | ||
1024 | K += 5; | ||
1025 | |||
1026 | /* Move down to proper range now rounding is done */ | ||
1027 | K /= 10; | ||
1028 | |||
1029 | pll_div->k = K; | ||
1030 | } | ||
1031 | |||
1032 | static int wm8990_set_dai_pll(struct snd_soc_dai *codec_dai, | ||
1033 | int pll_id, unsigned int freq_in, unsigned int freq_out) | ||
1034 | { | ||
1035 | u16 reg; | ||
1036 | struct snd_soc_codec *codec = codec_dai->codec; | ||
1037 | struct _pll_div pll_div; | ||
1038 | |||
1039 | if (freq_in && freq_out) { | ||
1040 | pll_factors(&pll_div, freq_out * 4, freq_in); | ||
1041 | |||
1042 | /* Turn on PLL */ | ||
1043 | reg = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_2); | ||
1044 | reg |= WM8990_PLL_ENA; | ||
1045 | wm8990_write(codec, WM8990_POWER_MANAGEMENT_2, reg); | ||
1046 | |||
1047 | /* sysclk comes from PLL */ | ||
1048 | reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_2); | ||
1049 | wm8990_write(codec, WM8990_CLOCKING_2, reg | WM8990_SYSCLK_SRC); | ||
1050 | |||
1051 | /* set up N , fractional mode and pre-divisor if neccessary */ | ||
1052 | wm8990_write(codec, WM8990_PLL1, pll_div.n | WM8990_SDM | | ||
1053 | (pll_div.div2?WM8990_PRESCALE:0)); | ||
1054 | wm8990_write(codec, WM8990_PLL2, (u8)(pll_div.k>>8)); | ||
1055 | wm8990_write(codec, WM8990_PLL3, (u8)(pll_div.k & 0xFF)); | ||
1056 | } else { | ||
1057 | /* Turn on PLL */ | ||
1058 | reg = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_2); | ||
1059 | reg &= ~WM8990_PLL_ENA; | ||
1060 | wm8990_write(codec, WM8990_POWER_MANAGEMENT_2, reg); | ||
1061 | } | ||
1062 | return 0; | ||
1063 | } | ||
1064 | |||
1065 | /* | ||
1066 | * Clock after PLL and dividers | ||
1067 | */ | ||
1068 | static int wm8990_set_dai_sysclk(struct snd_soc_dai *codec_dai, | ||
1069 | int clk_id, unsigned int freq, int dir) | ||
1070 | { | ||
1071 | struct snd_soc_codec *codec = codec_dai->codec; | ||
1072 | struct wm8990_priv *wm8990 = codec->private_data; | ||
1073 | |||
1074 | wm8990->sysclk = freq; | ||
1075 | return 0; | ||
1076 | } | ||
1077 | |||
1078 | /* | ||
1079 | * Set's ADC and Voice DAC format. | ||
1080 | */ | ||
1081 | static int wm8990_set_dai_fmt(struct snd_soc_dai *codec_dai, | ||
1082 | unsigned int fmt) | ||
1083 | { | ||
1084 | struct snd_soc_codec *codec = codec_dai->codec; | ||
1085 | u16 audio1, audio3; | ||
1086 | |||
1087 | audio1 = wm8990_read_reg_cache(codec, WM8990_AUDIO_INTERFACE_1); | ||
1088 | audio3 = wm8990_read_reg_cache(codec, WM8990_AUDIO_INTERFACE_3); | ||
1089 | |||
1090 | /* set master/slave audio interface */ | ||
1091 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
1092 | case SND_SOC_DAIFMT_CBS_CFS: | ||
1093 | audio3 &= ~WM8990_AIF_MSTR1; | ||
1094 | break; | ||
1095 | case SND_SOC_DAIFMT_CBM_CFM: | ||
1096 | audio3 |= WM8990_AIF_MSTR1; | ||
1097 | break; | ||
1098 | default: | ||
1099 | return -EINVAL; | ||
1100 | } | ||
1101 | |||
1102 | audio1 &= ~WM8990_AIF_FMT_MASK; | ||
1103 | |||
1104 | /* interface format */ | ||
1105 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
1106 | case SND_SOC_DAIFMT_I2S: | ||
1107 | audio1 |= WM8990_AIF_TMF_I2S; | ||
1108 | audio1 &= ~WM8990_AIF_LRCLK_INV; | ||
1109 | break; | ||
1110 | case SND_SOC_DAIFMT_RIGHT_J: | ||
1111 | audio1 |= WM8990_AIF_TMF_RIGHTJ; | ||
1112 | audio1 &= ~WM8990_AIF_LRCLK_INV; | ||
1113 | break; | ||
1114 | case SND_SOC_DAIFMT_LEFT_J: | ||
1115 | audio1 |= WM8990_AIF_TMF_LEFTJ; | ||
1116 | audio1 &= ~WM8990_AIF_LRCLK_INV; | ||
1117 | break; | ||
1118 | case SND_SOC_DAIFMT_DSP_A: | ||
1119 | audio1 |= WM8990_AIF_TMF_DSP; | ||
1120 | audio1 &= ~WM8990_AIF_LRCLK_INV; | ||
1121 | break; | ||
1122 | case SND_SOC_DAIFMT_DSP_B: | ||
1123 | audio1 |= WM8990_AIF_TMF_DSP | WM8990_AIF_LRCLK_INV; | ||
1124 | break; | ||
1125 | default: | ||
1126 | return -EINVAL; | ||
1127 | } | ||
1128 | |||
1129 | wm8990_write(codec, WM8990_AUDIO_INTERFACE_1, audio1); | ||
1130 | wm8990_write(codec, WM8990_AUDIO_INTERFACE_3, audio3); | ||
1131 | return 0; | ||
1132 | } | ||
1133 | |||
1134 | static int wm8990_set_dai_clkdiv(struct snd_soc_dai *codec_dai, | ||
1135 | int div_id, int div) | ||
1136 | { | ||
1137 | struct snd_soc_codec *codec = codec_dai->codec; | ||
1138 | u16 reg; | ||
1139 | |||
1140 | switch (div_id) { | ||
1141 | case WM8990_MCLK_DIV: | ||
1142 | reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_2) & | ||
1143 | ~WM8990_MCLK_DIV_MASK; | ||
1144 | wm8990_write(codec, WM8990_CLOCKING_2, reg | div); | ||
1145 | break; | ||
1146 | case WM8990_DACCLK_DIV: | ||
1147 | reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_2) & | ||
1148 | ~WM8990_DAC_CLKDIV_MASK; | ||
1149 | wm8990_write(codec, WM8990_CLOCKING_2, reg | div); | ||
1150 | break; | ||
1151 | case WM8990_ADCCLK_DIV: | ||
1152 | reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_2) & | ||
1153 | ~WM8990_ADC_CLKDIV_MASK; | ||
1154 | wm8990_write(codec, WM8990_CLOCKING_2, reg | div); | ||
1155 | break; | ||
1156 | case WM8990_BCLK_DIV: | ||
1157 | reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_1) & | ||
1158 | ~WM8990_BCLK_DIV_MASK; | ||
1159 | wm8990_write(codec, WM8990_CLOCKING_1, reg | div); | ||
1160 | break; | ||
1161 | default: | ||
1162 | return -EINVAL; | ||
1163 | } | ||
1164 | |||
1165 | return 0; | ||
1166 | } | ||
1167 | |||
1168 | /* | ||
1169 | * Set PCM DAI bit size and sample rate. | ||
1170 | */ | ||
1171 | static int wm8990_hw_params(struct snd_pcm_substream *substream, | ||
1172 | struct snd_pcm_hw_params *params) | ||
1173 | { | ||
1174 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
1175 | struct snd_soc_device *socdev = rtd->socdev; | ||
1176 | struct snd_soc_codec *codec = socdev->codec; | ||
1177 | u16 audio1 = wm8990_read_reg_cache(codec, WM8990_AUDIO_INTERFACE_1); | ||
1178 | |||
1179 | audio1 &= ~WM8990_AIF_WL_MASK; | ||
1180 | /* bit size */ | ||
1181 | switch (params_format(params)) { | ||
1182 | case SNDRV_PCM_FORMAT_S16_LE: | ||
1183 | break; | ||
1184 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
1185 | audio1 |= WM8990_AIF_WL_20BITS; | ||
1186 | break; | ||
1187 | case SNDRV_PCM_FORMAT_S24_LE: | ||
1188 | audio1 |= WM8990_AIF_WL_24BITS; | ||
1189 | break; | ||
1190 | case SNDRV_PCM_FORMAT_S32_LE: | ||
1191 | audio1 |= WM8990_AIF_WL_32BITS; | ||
1192 | break; | ||
1193 | } | ||
1194 | |||
1195 | wm8990_write(codec, WM8990_AUDIO_INTERFACE_1, audio1); | ||
1196 | return 0; | ||
1197 | } | ||
1198 | |||
1199 | static int wm8990_mute(struct snd_soc_dai *dai, int mute) | ||
1200 | { | ||
1201 | struct snd_soc_codec *codec = dai->codec; | ||
1202 | u16 val; | ||
1203 | |||
1204 | val = wm8990_read_reg_cache(codec, WM8990_DAC_CTRL) & ~WM8990_DAC_MUTE; | ||
1205 | |||
1206 | if (mute) | ||
1207 | wm8990_write(codec, WM8990_DAC_CTRL, val | WM8990_DAC_MUTE); | ||
1208 | else | ||
1209 | wm8990_write(codec, WM8990_DAC_CTRL, val); | ||
1210 | |||
1211 | return 0; | ||
1212 | } | ||
1213 | |||
1214 | static int wm8990_set_bias_level(struct snd_soc_codec *codec, | ||
1215 | enum snd_soc_bias_level level) | ||
1216 | { | ||
1217 | u16 val; | ||
1218 | |||
1219 | switch (level) { | ||
1220 | case SND_SOC_BIAS_ON: | ||
1221 | break; | ||
1222 | case SND_SOC_BIAS_PREPARE: | ||
1223 | break; | ||
1224 | case SND_SOC_BIAS_STANDBY: | ||
1225 | if (codec->bias_level == SND_SOC_BIAS_OFF) { | ||
1226 | /* Enable all output discharge bits */ | ||
1227 | wm8990_write(codec, WM8990_ANTIPOP1, WM8990_DIS_LLINE | | ||
1228 | WM8990_DIS_RLINE | WM8990_DIS_OUT3 | | ||
1229 | WM8990_DIS_OUT4 | WM8990_DIS_LOUT | | ||
1230 | WM8990_DIS_ROUT); | ||
1231 | |||
1232 | /* Enable POBCTRL, SOFT_ST, VMIDTOG and BUFDCOPEN */ | ||
1233 | wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | | ||
1234 | WM8990_BUFDCOPEN | WM8990_POBCTRL | | ||
1235 | WM8990_VMIDTOG); | ||
1236 | |||
1237 | /* Delay to allow output caps to discharge */ | ||
1238 | msleep(msecs_to_jiffies(300)); | ||
1239 | |||
1240 | /* Disable VMIDTOG */ | ||
1241 | wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | | ||
1242 | WM8990_BUFDCOPEN | WM8990_POBCTRL); | ||
1243 | |||
1244 | /* disable all output discharge bits */ | ||
1245 | wm8990_write(codec, WM8990_ANTIPOP1, 0); | ||
1246 | |||
1247 | /* Enable outputs */ | ||
1248 | wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1b00); | ||
1249 | |||
1250 | msleep(msecs_to_jiffies(50)); | ||
1251 | |||
1252 | /* Enable VMID at 2x50k */ | ||
1253 | wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f02); | ||
1254 | |||
1255 | msleep(msecs_to_jiffies(100)); | ||
1256 | |||
1257 | /* Enable VREF */ | ||
1258 | wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f03); | ||
1259 | |||
1260 | msleep(msecs_to_jiffies(600)); | ||
1261 | |||
1262 | /* Enable BUFIOEN */ | ||
1263 | wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | | ||
1264 | WM8990_BUFDCOPEN | WM8990_POBCTRL | | ||
1265 | WM8990_BUFIOEN); | ||
1266 | |||
1267 | /* Disable outputs */ | ||
1268 | wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x3); | ||
1269 | |||
1270 | /* disable POBCTRL, SOFT_ST and BUFDCOPEN */ | ||
1271 | wm8990_write(codec, WM8990_ANTIPOP2, WM8990_BUFIOEN); | ||
1272 | } else { | ||
1273 | /* ON -> standby */ | ||
1274 | |||
1275 | } | ||
1276 | break; | ||
1277 | |||
1278 | case SND_SOC_BIAS_OFF: | ||
1279 | /* Enable POBCTRL and SOFT_ST */ | ||
1280 | wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | | ||
1281 | WM8990_POBCTRL | WM8990_BUFIOEN); | ||
1282 | |||
1283 | /* Enable POBCTRL, SOFT_ST and BUFDCOPEN */ | ||
1284 | wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | | ||
1285 | WM8990_BUFDCOPEN | WM8990_POBCTRL | | ||
1286 | WM8990_BUFIOEN); | ||
1287 | |||
1288 | /* mute DAC */ | ||
1289 | val = wm8990_read_reg_cache(codec, WM8990_DAC_CTRL); | ||
1290 | wm8990_write(codec, WM8990_DAC_CTRL, val | WM8990_DAC_MUTE); | ||
1291 | |||
1292 | /* Enable any disabled outputs */ | ||
1293 | wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f03); | ||
1294 | |||
1295 | /* Disable VMID */ | ||
1296 | wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f01); | ||
1297 | |||
1298 | msleep(msecs_to_jiffies(300)); | ||
1299 | |||
1300 | /* Enable all output discharge bits */ | ||
1301 | wm8990_write(codec, WM8990_ANTIPOP1, WM8990_DIS_LLINE | | ||
1302 | WM8990_DIS_RLINE | WM8990_DIS_OUT3 | | ||
1303 | WM8990_DIS_OUT4 | WM8990_DIS_LOUT | | ||
1304 | WM8990_DIS_ROUT); | ||
1305 | |||
1306 | /* Disable VREF */ | ||
1307 | wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x0); | ||
1308 | |||
1309 | /* disable POBCTRL, SOFT_ST and BUFDCOPEN */ | ||
1310 | wm8990_write(codec, WM8990_ANTIPOP2, 0x0); | ||
1311 | break; | ||
1312 | } | ||
1313 | |||
1314 | codec->bias_level = level; | ||
1315 | return 0; | ||
1316 | } | ||
1317 | |||
1318 | #define WM8990_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | ||
1319 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \ | ||
1320 | SNDRV_PCM_RATE_48000) | ||
1321 | |||
1322 | #define WM8990_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | ||
1323 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) | ||
1324 | |||
1325 | /* | ||
1326 | * The WM8990 supports 2 different and mutually exclusive DAI | ||
1327 | * configurations. | ||
1328 | * | ||
1329 | * 1. ADC/DAC on Primary Interface | ||
1330 | * 2. ADC on Primary Interface/DAC on secondary | ||
1331 | */ | ||
1332 | struct snd_soc_dai wm8990_dai = { | ||
1333 | /* ADC/DAC on primary */ | ||
1334 | .name = "WM8990 ADC/DAC Primary", | ||
1335 | .id = 1, | ||
1336 | .playback = { | ||
1337 | .stream_name = "Playback", | ||
1338 | .channels_min = 1, | ||
1339 | .channels_max = 2, | ||
1340 | .rates = WM8990_RATES, | ||
1341 | .formats = WM8990_FORMATS,}, | ||
1342 | .capture = { | ||
1343 | .stream_name = "Capture", | ||
1344 | .channels_min = 1, | ||
1345 | .channels_max = 2, | ||
1346 | .rates = WM8990_RATES, | ||
1347 | .formats = WM8990_FORMATS,}, | ||
1348 | .ops = { | ||
1349 | .hw_params = wm8990_hw_params,}, | ||
1350 | .dai_ops = { | ||
1351 | .digital_mute = wm8990_mute, | ||
1352 | .set_fmt = wm8990_set_dai_fmt, | ||
1353 | .set_clkdiv = wm8990_set_dai_clkdiv, | ||
1354 | .set_pll = wm8990_set_dai_pll, | ||
1355 | .set_sysclk = wm8990_set_dai_sysclk, | ||
1356 | }, | ||
1357 | }; | ||
1358 | EXPORT_SYMBOL_GPL(wm8990_dai); | ||
1359 | |||
1360 | static int wm8990_suspend(struct platform_device *pdev, pm_message_t state) | ||
1361 | { | ||
1362 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1363 | struct snd_soc_codec *codec = socdev->codec; | ||
1364 | |||
1365 | /* we only need to suspend if we are a valid card */ | ||
1366 | if (!codec->card) | ||
1367 | return 0; | ||
1368 | |||
1369 | wm8990_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1370 | return 0; | ||
1371 | } | ||
1372 | |||
1373 | static int wm8990_resume(struct platform_device *pdev) | ||
1374 | { | ||
1375 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1376 | struct snd_soc_codec *codec = socdev->codec; | ||
1377 | int i; | ||
1378 | u8 data[2]; | ||
1379 | u16 *cache = codec->reg_cache; | ||
1380 | |||
1381 | /* we only need to resume if we are a valid card */ | ||
1382 | if (!codec->card) | ||
1383 | return 0; | ||
1384 | |||
1385 | /* Sync reg_cache with the hardware */ | ||
1386 | for (i = 0; i < ARRAY_SIZE(wm8990_reg); i++) { | ||
1387 | if (i + 1 == WM8990_RESET) | ||
1388 | continue; | ||
1389 | data[0] = ((i + 1) << 1) | ((cache[i] >> 8) & 0x0001); | ||
1390 | data[1] = cache[i] & 0x00ff; | ||
1391 | codec->hw_write(codec->control_data, data, 2); | ||
1392 | } | ||
1393 | |||
1394 | wm8990_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1395 | return 0; | ||
1396 | } | ||
1397 | |||
1398 | /* | ||
1399 | * initialise the WM8990 driver | ||
1400 | * register the mixer and dsp interfaces with the kernel | ||
1401 | */ | ||
1402 | static int wm8990_init(struct snd_soc_device *socdev) | ||
1403 | { | ||
1404 | struct snd_soc_codec *codec = socdev->codec; | ||
1405 | u16 reg; | ||
1406 | int ret = 0; | ||
1407 | |||
1408 | codec->name = "WM8990"; | ||
1409 | codec->owner = THIS_MODULE; | ||
1410 | codec->read = wm8990_read_reg_cache; | ||
1411 | codec->write = wm8990_write; | ||
1412 | codec->set_bias_level = wm8990_set_bias_level; | ||
1413 | codec->dai = &wm8990_dai; | ||
1414 | codec->num_dai = 2; | ||
1415 | codec->reg_cache_size = ARRAY_SIZE(wm8990_reg); | ||
1416 | codec->reg_cache = kmemdup(wm8990_reg, sizeof(wm8990_reg), GFP_KERNEL); | ||
1417 | |||
1418 | if (codec->reg_cache == NULL) | ||
1419 | return -ENOMEM; | ||
1420 | |||
1421 | wm8990_reset(codec); | ||
1422 | |||
1423 | /* register pcms */ | ||
1424 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
1425 | if (ret < 0) { | ||
1426 | printk(KERN_ERR "wm8990: failed to create pcms\n"); | ||
1427 | goto pcm_err; | ||
1428 | } | ||
1429 | |||
1430 | /* charge output caps */ | ||
1431 | codec->bias_level = SND_SOC_BIAS_OFF; | ||
1432 | wm8990_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1433 | |||
1434 | reg = wm8990_read_reg_cache(codec, WM8990_AUDIO_INTERFACE_4); | ||
1435 | wm8990_write(codec, WM8990_AUDIO_INTERFACE_4, reg | WM8990_ALRCGPIO1); | ||
1436 | |||
1437 | reg = wm8990_read_reg_cache(codec, WM8990_GPIO1_GPIO2) & | ||
1438 | ~WM8990_GPIO1_SEL_MASK; | ||
1439 | wm8990_write(codec, WM8990_GPIO1_GPIO2, reg | 1); | ||
1440 | |||
1441 | reg = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_2); | ||
1442 | wm8990_write(codec, WM8990_POWER_MANAGEMENT_2, reg | WM8990_OPCLK_ENA); | ||
1443 | |||
1444 | wm8990_write(codec, WM8990_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8)); | ||
1445 | wm8990_write(codec, WM8990_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8)); | ||
1446 | |||
1447 | wm8990_add_controls(codec); | ||
1448 | wm8990_add_widgets(codec); | ||
1449 | ret = snd_soc_register_card(socdev); | ||
1450 | if (ret < 0) { | ||
1451 | printk(KERN_ERR "wm8990: failed to register card\n"); | ||
1452 | goto card_err; | ||
1453 | } | ||
1454 | return ret; | ||
1455 | |||
1456 | card_err: | ||
1457 | snd_soc_free_pcms(socdev); | ||
1458 | snd_soc_dapm_free(socdev); | ||
1459 | pcm_err: | ||
1460 | kfree(codec->reg_cache); | ||
1461 | return ret; | ||
1462 | } | ||
1463 | |||
1464 | /* If the i2c layer weren't so broken, we could pass this kind of data | ||
1465 | around */ | ||
1466 | static struct snd_soc_device *wm8990_socdev; | ||
1467 | |||
1468 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
1469 | |||
1470 | /* | ||
1471 | * WM891 2 wire address is determined by GPIO5 | ||
1472 | * state during powerup. | ||
1473 | * low = 0x34 | ||
1474 | * high = 0x36 | ||
1475 | */ | ||
1476 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | ||
1477 | |||
1478 | /* Magic definition of all other variables and things */ | ||
1479 | I2C_CLIENT_INSMOD; | ||
1480 | |||
1481 | static struct i2c_driver wm8990_i2c_driver; | ||
1482 | static struct i2c_client client_template; | ||
1483 | |||
1484 | static int wm8990_codec_probe(struct i2c_adapter *adap, int addr, int kind) | ||
1485 | { | ||
1486 | struct snd_soc_device *socdev = wm8990_socdev; | ||
1487 | struct wm8990_setup_data *setup = socdev->codec_data; | ||
1488 | struct snd_soc_codec *codec = socdev->codec; | ||
1489 | struct i2c_client *i2c; | ||
1490 | int ret; | ||
1491 | |||
1492 | if (addr != setup->i2c_address) | ||
1493 | return -ENODEV; | ||
1494 | |||
1495 | client_template.adapter = adap; | ||
1496 | client_template.addr = addr; | ||
1497 | |||
1498 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | ||
1499 | if (i2c == NULL) { | ||
1500 | kfree(codec); | ||
1501 | return -ENOMEM; | ||
1502 | } | ||
1503 | i2c_set_clientdata(i2c, codec); | ||
1504 | codec->control_data = i2c; | ||
1505 | |||
1506 | ret = i2c_attach_client(i2c); | ||
1507 | if (ret < 0) { | ||
1508 | pr_err("failed to attach codec at addr %x\n", addr); | ||
1509 | goto err; | ||
1510 | } | ||
1511 | |||
1512 | ret = wm8990_init(socdev); | ||
1513 | if (ret < 0) { | ||
1514 | pr_err("failed to initialise WM8990\n"); | ||
1515 | goto err; | ||
1516 | } | ||
1517 | return ret; | ||
1518 | |||
1519 | err: | ||
1520 | kfree(codec); | ||
1521 | kfree(i2c); | ||
1522 | return ret; | ||
1523 | } | ||
1524 | |||
1525 | static int wm8990_i2c_detach(struct i2c_client *client) | ||
1526 | { | ||
1527 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | ||
1528 | i2c_detach_client(client); | ||
1529 | kfree(codec->reg_cache); | ||
1530 | kfree(client); | ||
1531 | return 0; | ||
1532 | } | ||
1533 | |||
1534 | static int wm8990_i2c_attach(struct i2c_adapter *adap) | ||
1535 | { | ||
1536 | return i2c_probe(adap, &addr_data, wm8990_codec_probe); | ||
1537 | } | ||
1538 | |||
1539 | static struct i2c_driver wm8990_i2c_driver = { | ||
1540 | .driver = { | ||
1541 | .name = "WM8990 I2C Codec", | ||
1542 | .owner = THIS_MODULE, | ||
1543 | }, | ||
1544 | .attach_adapter = wm8990_i2c_attach, | ||
1545 | .detach_client = wm8990_i2c_detach, | ||
1546 | .command = NULL, | ||
1547 | }; | ||
1548 | |||
1549 | static struct i2c_client client_template = { | ||
1550 | .name = "WM8990", | ||
1551 | .driver = &wm8990_i2c_driver, | ||
1552 | }; | ||
1553 | #endif | ||
1554 | |||
1555 | static int wm8990_probe(struct platform_device *pdev) | ||
1556 | { | ||
1557 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1558 | struct wm8990_setup_data *setup; | ||
1559 | struct snd_soc_codec *codec; | ||
1560 | struct wm8990_priv *wm8990; | ||
1561 | int ret = 0; | ||
1562 | |||
1563 | pr_info("WM8990 Audio Codec %s\n", WM8990_VERSION); | ||
1564 | |||
1565 | setup = socdev->codec_data; | ||
1566 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
1567 | if (codec == NULL) | ||
1568 | return -ENOMEM; | ||
1569 | |||
1570 | wm8990 = kzalloc(sizeof(struct wm8990_priv), GFP_KERNEL); | ||
1571 | if (wm8990 == NULL) { | ||
1572 | kfree(codec); | ||
1573 | return -ENOMEM; | ||
1574 | } | ||
1575 | |||
1576 | codec->private_data = wm8990; | ||
1577 | socdev->codec = codec; | ||
1578 | mutex_init(&codec->mutex); | ||
1579 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
1580 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
1581 | wm8990_socdev = socdev; | ||
1582 | |||
1583 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
1584 | if (setup->i2c_address) { | ||
1585 | normal_i2c[0] = setup->i2c_address; | ||
1586 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
1587 | ret = i2c_add_driver(&wm8990_i2c_driver); | ||
1588 | if (ret != 0) | ||
1589 | printk(KERN_ERR "can't add i2c driver"); | ||
1590 | } | ||
1591 | #else | ||
1592 | /* Add other interfaces here */ | ||
1593 | #endif | ||
1594 | return ret; | ||
1595 | } | ||
1596 | |||
1597 | /* power down chip */ | ||
1598 | static int wm8990_remove(struct platform_device *pdev) | ||
1599 | { | ||
1600 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1601 | struct snd_soc_codec *codec = socdev->codec; | ||
1602 | |||
1603 | if (codec->control_data) | ||
1604 | wm8990_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1605 | snd_soc_free_pcms(socdev); | ||
1606 | snd_soc_dapm_free(socdev); | ||
1607 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
1608 | i2c_del_driver(&wm8990_i2c_driver); | ||
1609 | #endif | ||
1610 | kfree(codec->private_data); | ||
1611 | kfree(codec); | ||
1612 | |||
1613 | return 0; | ||
1614 | } | ||
1615 | |||
1616 | struct snd_soc_codec_device soc_codec_dev_wm8990 = { | ||
1617 | .probe = wm8990_probe, | ||
1618 | .remove = wm8990_remove, | ||
1619 | .suspend = wm8990_suspend, | ||
1620 | .resume = wm8990_resume, | ||
1621 | }; | ||
1622 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8990); | ||
1623 | |||
1624 | MODULE_DESCRIPTION("ASoC WM8990 driver"); | ||
1625 | MODULE_AUTHOR("Liam Girdwood"); | ||
1626 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/wm8990.h b/sound/soc/codecs/wm8990.h new file mode 100644 index 000000000000..6bea57485283 --- /dev/null +++ b/sound/soc/codecs/wm8990.h | |||
@@ -0,0 +1,832 @@ | |||
1 | /* | ||
2 | * wm8990.h -- audio driver for WM8990 | ||
3 | * | ||
4 | * Copyright 2007 Wolfson Microelectronics PLC. | ||
5 | * Author: Graeme Gregory | ||
6 | * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #ifndef __WM8990REGISTERDEFS_H__ | ||
16 | #define __WM8990REGISTERDEFS_H__ | ||
17 | |||
18 | /* | ||
19 | * Register values. | ||
20 | */ | ||
21 | #define WM8990_RESET 0x00 | ||
22 | #define WM8990_POWER_MANAGEMENT_1 0x01 | ||
23 | #define WM8990_POWER_MANAGEMENT_2 0x02 | ||
24 | #define WM8990_POWER_MANAGEMENT_3 0x03 | ||
25 | #define WM8990_AUDIO_INTERFACE_1 0x04 | ||
26 | #define WM8990_AUDIO_INTERFACE_2 0x05 | ||
27 | #define WM8990_CLOCKING_1 0x06 | ||
28 | #define WM8990_CLOCKING_2 0x07 | ||
29 | #define WM8990_AUDIO_INTERFACE_3 0x08 | ||
30 | #define WM8990_AUDIO_INTERFACE_4 0x09 | ||
31 | #define WM8990_DAC_CTRL 0x0A | ||
32 | #define WM8990_LEFT_DAC_DIGITAL_VOLUME 0x0B | ||
33 | #define WM8990_RIGHT_DAC_DIGITAL_VOLUME 0x0C | ||
34 | #define WM8990_DIGITAL_SIDE_TONE 0x0D | ||
35 | #define WM8990_ADC_CTRL 0x0E | ||
36 | #define WM8990_LEFT_ADC_DIGITAL_VOLUME 0x0F | ||
37 | #define WM8990_RIGHT_ADC_DIGITAL_VOLUME 0x10 | ||
38 | #define WM8990_GPIO_CTRL_1 0x12 | ||
39 | #define WM8990_GPIO1_GPIO2 0x13 | ||
40 | #define WM8990_GPIO3_GPIO4 0x14 | ||
41 | #define WM8990_GPIO5_GPIO6 0x15 | ||
42 | #define WM8990_GPIOCTRL_2 0x16 | ||
43 | #define WM8990_GPIO_POL 0x17 | ||
44 | #define WM8990_LEFT_LINE_INPUT_1_2_VOLUME 0x18 | ||
45 | #define WM8990_LEFT_LINE_INPUT_3_4_VOLUME 0x19 | ||
46 | #define WM8990_RIGHT_LINE_INPUT_1_2_VOLUME 0x1A | ||
47 | #define WM8990_RIGHT_LINE_INPUT_3_4_VOLUME 0x1B | ||
48 | #define WM8990_LEFT_OUTPUT_VOLUME 0x1C | ||
49 | #define WM8990_RIGHT_OUTPUT_VOLUME 0x1D | ||
50 | #define WM8990_LINE_OUTPUTS_VOLUME 0x1E | ||
51 | #define WM8990_OUT3_4_VOLUME 0x1F | ||
52 | #define WM8990_LEFT_OPGA_VOLUME 0x20 | ||
53 | #define WM8990_RIGHT_OPGA_VOLUME 0x21 | ||
54 | #define WM8990_SPEAKER_VOLUME 0x22 | ||
55 | #define WM8990_CLASSD1 0x23 | ||
56 | #define WM8990_CLASSD3 0x25 | ||
57 | #define WM8990_INPUT_MIXER1 0x27 | ||
58 | #define WM8990_INPUT_MIXER2 0x28 | ||
59 | #define WM8990_INPUT_MIXER3 0x29 | ||
60 | #define WM8990_INPUT_MIXER4 0x2A | ||
61 | #define WM8990_INPUT_MIXER5 0x2B | ||
62 | #define WM8990_INPUT_MIXER6 0x2C | ||
63 | #define WM8990_OUTPUT_MIXER1 0x2D | ||
64 | #define WM8990_OUTPUT_MIXER2 0x2E | ||
65 | #define WM8990_OUTPUT_MIXER3 0x2F | ||
66 | #define WM8990_OUTPUT_MIXER4 0x30 | ||
67 | #define WM8990_OUTPUT_MIXER5 0x31 | ||
68 | #define WM8990_OUTPUT_MIXER6 0x32 | ||
69 | #define WM8990_OUT3_4_MIXER 0x33 | ||
70 | #define WM8990_LINE_MIXER1 0x34 | ||
71 | #define WM8990_LINE_MIXER2 0x35 | ||
72 | #define WM8990_SPEAKER_MIXER 0x36 | ||
73 | #define WM8990_ADDITIONAL_CONTROL 0x37 | ||
74 | #define WM8990_ANTIPOP1 0x38 | ||
75 | #define WM8990_ANTIPOP2 0x39 | ||
76 | #define WM8990_MICBIAS 0x3A | ||
77 | #define WM8990_PLL1 0x3C | ||
78 | #define WM8990_PLL2 0x3D | ||
79 | #define WM8990_PLL3 0x3E | ||
80 | #define WM8990_INTDRIVBITS 0x3F | ||
81 | |||
82 | #define WM8990_REGISTER_COUNT 60 | ||
83 | #define WM8990_MAX_REGISTER 0x3F | ||
84 | |||
85 | /* | ||
86 | * Field Definitions. | ||
87 | */ | ||
88 | |||
89 | /* | ||
90 | * R0 (0x00) - Reset | ||
91 | */ | ||
92 | #define WM8990_SW_RESET_CHIP_ID_MASK 0xFFFF /* SW_RESET_CHIP_ID */ | ||
93 | |||
94 | /* | ||
95 | * R1 (0x01) - Power Management (1) | ||
96 | */ | ||
97 | #define WM8990_SPK_ENA 0x1000 /* SPK_ENA */ | ||
98 | #define WM8990_SPK_ENA_BIT 12 | ||
99 | #define WM8990_OUT3_ENA 0x0800 /* OUT3_ENA */ | ||
100 | #define WM8990_OUT3_ENA_BIT 11 | ||
101 | #define WM8990_OUT4_ENA 0x0400 /* OUT4_ENA */ | ||
102 | #define WM8990_OUT4_ENA_BIT 10 | ||
103 | #define WM8990_LOUT_ENA 0x0200 /* LOUT_ENA */ | ||
104 | #define WM8990_LOUT_ENA_BIT 9 | ||
105 | #define WM8990_ROUT_ENA 0x0100 /* ROUT_ENA */ | ||
106 | #define WM8990_ROUT_ENA_BIT 8 | ||
107 | #define WM8990_MICBIAS_ENA 0x0010 /* MICBIAS_ENA */ | ||
108 | #define WM8990_MICBIAS_ENA_BIT 4 | ||
109 | #define WM8990_VMID_MODE_MASK 0x0006 /* VMID_MODE - [2:1] */ | ||
110 | #define WM8990_VREF_ENA 0x0001 /* VREF_ENA */ | ||
111 | #define WM8990_VREF_ENA_BIT 0 | ||
112 | |||
113 | /* | ||
114 | * R2 (0x02) - Power Management (2) | ||
115 | */ | ||
116 | #define WM8990_PLL_ENA 0x8000 /* PLL_ENA */ | ||
117 | #define WM8990_PLL_ENA_BIT 15 | ||
118 | #define WM8990_TSHUT_ENA 0x4000 /* TSHUT_ENA */ | ||
119 | #define WM8990_TSHUT_ENA_BIT 14 | ||
120 | #define WM8990_TSHUT_OPDIS 0x2000 /* TSHUT_OPDIS */ | ||
121 | #define WM8990_TSHUT_OPDIS_BIT 13 | ||
122 | #define WM8990_OPCLK_ENA 0x0800 /* OPCLK_ENA */ | ||
123 | #define WM8990_OPCLK_ENA_BIT 11 | ||
124 | #define WM8990_AINL_ENA 0x0200 /* AINL_ENA */ | ||
125 | #define WM8990_AINL_ENA_BIT 9 | ||
126 | #define WM8990_AINR_ENA 0x0100 /* AINR_ENA */ | ||
127 | #define WM8990_AINR_ENA_BIT 8 | ||
128 | #define WM8990_LIN34_ENA 0x0080 /* LIN34_ENA */ | ||
129 | #define WM8990_LIN34_ENA_BIT 7 | ||
130 | #define WM8990_LIN12_ENA 0x0040 /* LIN12_ENA */ | ||
131 | #define WM8990_LIN12_ENA_BIT 6 | ||
132 | #define WM8990_RIN34_ENA 0x0020 /* RIN34_ENA */ | ||
133 | #define WM8990_RIN34_ENA_BIT 5 | ||
134 | #define WM8990_RIN12_ENA 0x0010 /* RIN12_ENA */ | ||
135 | #define WM8990_RIN12_ENA_BIT 4 | ||
136 | #define WM8990_ADCL_ENA 0x0002 /* ADCL_ENA */ | ||
137 | #define WM8990_ADCL_ENA_BIT 1 | ||
138 | #define WM8990_ADCR_ENA 0x0001 /* ADCR_ENA */ | ||
139 | #define WM8990_ADCR_ENA_BIT 0 | ||
140 | |||
141 | /* | ||
142 | * R3 (0x03) - Power Management (3) | ||
143 | */ | ||
144 | #define WM8990_LON_ENA 0x2000 /* LON_ENA */ | ||
145 | #define WM8990_LON_ENA_BIT 13 | ||
146 | #define WM8990_LOP_ENA 0x1000 /* LOP_ENA */ | ||
147 | #define WM8990_LOP_ENA_BIT 12 | ||
148 | #define WM8990_RON_ENA 0x0800 /* RON_ENA */ | ||
149 | #define WM8990_RON_ENA_BIT 11 | ||
150 | #define WM8990_ROP_ENA 0x0400 /* ROP_ENA */ | ||
151 | #define WM8990_ROP_ENA_BIT 10 | ||
152 | #define WM8990_LOPGA_ENA 0x0080 /* LOPGA_ENA */ | ||
153 | #define WM8990_LOPGA_ENA_BIT 7 | ||
154 | #define WM8990_ROPGA_ENA 0x0040 /* ROPGA_ENA */ | ||
155 | #define WM8990_ROPGA_ENA_BIT 6 | ||
156 | #define WM8990_LOMIX_ENA 0x0020 /* LOMIX_ENA */ | ||
157 | #define WM8990_LOMIX_ENA_BIT 5 | ||
158 | #define WM8990_ROMIX_ENA 0x0010 /* ROMIX_ENA */ | ||
159 | #define WM8990_ROMIX_ENA_BIT 4 | ||
160 | #define WM8990_DACL_ENA 0x0002 /* DACL_ENA */ | ||
161 | #define WM8990_DACL_ENA_BIT 1 | ||
162 | #define WM8990_DACR_ENA 0x0001 /* DACR_ENA */ | ||
163 | #define WM8990_DACR_ENA_BIT 0 | ||
164 | |||
165 | /* | ||
166 | * R4 (0x04) - Audio Interface (1) | ||
167 | */ | ||
168 | #define WM8990_AIFADCL_SRC 0x8000 /* AIFADCL_SRC */ | ||
169 | #define WM8990_AIFADCR_SRC 0x4000 /* AIFADCR_SRC */ | ||
170 | #define WM8990_AIFADC_TDM 0x2000 /* AIFADC_TDM */ | ||
171 | #define WM8990_AIFADC_TDM_CHAN 0x1000 /* AIFADC_TDM_CHAN */ | ||
172 | #define WM8990_AIF_BCLK_INV 0x0100 /* AIF_BCLK_INV */ | ||
173 | #define WM8990_AIF_LRCLK_INV 0x0080 /* AIF_LRCLK_INV */ | ||
174 | #define WM8990_AIF_WL_MASK 0x0060 /* AIF_WL - [6:5] */ | ||
175 | #define WM8990_AIF_WL_16BITS (0 << 5) | ||
176 | #define WM8990_AIF_WL_20BITS (1 << 5) | ||
177 | #define WM8990_AIF_WL_24BITS (2 << 5) | ||
178 | #define WM8990_AIF_WL_32BITS (3 << 5) | ||
179 | #define WM8990_AIF_FMT_MASK 0x0018 /* AIF_FMT - [4:3] */ | ||
180 | #define WM8990_AIF_TMF_RIGHTJ (0 << 3) | ||
181 | #define WM8990_AIF_TMF_LEFTJ (1 << 3) | ||
182 | #define WM8990_AIF_TMF_I2S (2 << 3) | ||
183 | #define WM8990_AIF_TMF_DSP (3 << 3) | ||
184 | |||
185 | /* | ||
186 | * R5 (0x05) - Audio Interface (2) | ||
187 | */ | ||
188 | #define WM8990_DACL_SRC 0x8000 /* DACL_SRC */ | ||
189 | #define WM8990_DACR_SRC 0x4000 /* DACR_SRC */ | ||
190 | #define WM8990_AIFDAC_TDM 0x2000 /* AIFDAC_TDM */ | ||
191 | #define WM8990_AIFDAC_TDM_CHAN 0x1000 /* AIFDAC_TDM_CHAN */ | ||
192 | #define WM8990_DAC_BOOST_MASK 0x0C00 /* DAC_BOOST */ | ||
193 | #define WM8990_DAC_COMP 0x0010 /* DAC_COMP */ | ||
194 | #define WM8990_DAC_COMPMODE 0x0008 /* DAC_COMPMODE */ | ||
195 | #define WM8990_ADC_COMP 0x0004 /* ADC_COMP */ | ||
196 | #define WM8990_ADC_COMPMODE 0x0002 /* ADC_COMPMODE */ | ||
197 | #define WM8990_LOOPBACK 0x0001 /* LOOPBACK */ | ||
198 | |||
199 | /* | ||
200 | * R6 (0x06) - Clocking (1) | ||
201 | */ | ||
202 | #define WM8990_TOCLK_RATE 0x8000 /* TOCLK_RATE */ | ||
203 | #define WM8990_TOCLK_ENA 0x4000 /* TOCLK_ENA */ | ||
204 | #define WM8990_OPCLKDIV_MASK 0x1E00 /* OPCLKDIV - [12:9] */ | ||
205 | #define WM8990_DCLKDIV_MASK 0x01C0 /* DCLKDIV - [8:6] */ | ||
206 | #define WM8990_BCLK_DIV_MASK 0x001E /* BCLK_DIV - [4:1] */ | ||
207 | #define WM8990_BCLK_DIV_1 (0x0 << 1) | ||
208 | #define WM8990_BCLK_DIV_1_5 (0x1 << 1) | ||
209 | #define WM8990_BCLK_DIV_2 (0x2 << 1) | ||
210 | #define WM8990_BCLK_DIV_3 (0x3 << 1) | ||
211 | #define WM8990_BCLK_DIV_4 (0x4 << 1) | ||
212 | #define WM8990_BCLK_DIV_5_5 (0x5 << 1) | ||
213 | #define WM8990_BCLK_DIV_6 (0x6 << 1) | ||
214 | #define WM8990_BCLK_DIV_8 (0x7 << 1) | ||
215 | #define WM8990_BCLK_DIV_11 (0x8 << 1) | ||
216 | #define WM8990_BCLK_DIV_12 (0x9 << 1) | ||
217 | #define WM8990_BCLK_DIV_16 (0xA << 1) | ||
218 | #define WM8990_BCLK_DIV_22 (0xB << 1) | ||
219 | #define WM8990_BCLK_DIV_24 (0xC << 1) | ||
220 | #define WM8990_BCLK_DIV_32 (0xD << 1) | ||
221 | #define WM8990_BCLK_DIV_44 (0xE << 1) | ||
222 | #define WM8990_BCLK_DIV_48 (0xF << 1) | ||
223 | |||
224 | /* | ||
225 | * R7 (0x07) - Clocking (2) | ||
226 | */ | ||
227 | #define WM8990_MCLK_SRC 0x8000 /* MCLK_SRC */ | ||
228 | #define WM8990_SYSCLK_SRC 0x4000 /* SYSCLK_SRC */ | ||
229 | #define WM8990_CLK_FORCE 0x2000 /* CLK_FORCE */ | ||
230 | #define WM8990_MCLK_DIV_MASK 0x1800 /* MCLK_DIV - [12:11] */ | ||
231 | #define WM8990_MCLK_DIV_1 (0 << 11) | ||
232 | #define WM8990_MCLK_DIV_2 (2 << 11) | ||
233 | #define WM8990_MCLK_INV 0x0400 /* MCLK_INV */ | ||
234 | #define WM8990_ADC_CLKDIV_MASK 0x00E0 /* ADC_CLKDIV */ | ||
235 | #define WM8990_ADC_CLKDIV_1 (0 << 5) | ||
236 | #define WM8990_ADC_CLKDIV_1_5 (1 << 5) | ||
237 | #define WM8990_ADC_CLKDIV_2 (2 << 5) | ||
238 | #define WM8990_ADC_CLKDIV_3 (3 << 5) | ||
239 | #define WM8990_ADC_CLKDIV_4 (4 << 5) | ||
240 | #define WM8990_ADC_CLKDIV_5_5 (5 << 5) | ||
241 | #define WM8990_ADC_CLKDIV_6 (6 << 5) | ||
242 | #define WM8990_DAC_CLKDIV_MASK 0x001C /* DAC_CLKDIV - [4:2] */ | ||
243 | #define WM8990_DAC_CLKDIV_1 (0 << 2) | ||
244 | #define WM8990_DAC_CLKDIV_1_5 (1 << 2) | ||
245 | #define WM8990_DAC_CLKDIV_2 (2 << 2) | ||
246 | #define WM8990_DAC_CLKDIV_3 (3 << 2) | ||
247 | #define WM8990_DAC_CLKDIV_4 (4 << 2) | ||
248 | #define WM8990_DAC_CLKDIV_5_5 (5 << 2) | ||
249 | #define WM8990_DAC_CLKDIV_6 (6 << 2) | ||
250 | |||
251 | /* | ||
252 | * R8 (0x08) - Audio Interface (3) | ||
253 | */ | ||
254 | #define WM8990_AIF_MSTR1 0x8000 /* AIF_MSTR1 */ | ||
255 | #define WM8990_AIF_MSTR2 0x4000 /* AIF_MSTR2 */ | ||
256 | #define WM8990_AIF_SEL 0x2000 /* AIF_SEL */ | ||
257 | #define WM8990_ADCLRC_DIR 0x0800 /* ADCLRC_DIR */ | ||
258 | #define WM8990_ADCLRC_RATE_MASK 0x07FF /* ADCLRC_RATE */ | ||
259 | |||
260 | /* | ||
261 | * R9 (0x09) - Audio Interface (4) | ||
262 | */ | ||
263 | #define WM8990_ALRCGPIO1 0x8000 /* ALRCGPIO1 */ | ||
264 | #define WM8990_ALRCBGPIO6 0x4000 /* ALRCBGPIO6 */ | ||
265 | #define WM8990_AIF_TRIS 0x2000 /* AIF_TRIS */ | ||
266 | #define WM8990_DACLRC_DIR 0x0800 /* DACLRC_DIR */ | ||
267 | #define WM8990_DACLRC_RATE_MASK 0x07FF /* DACLRC_RATE */ | ||
268 | |||
269 | /* | ||
270 | * R10 (0x0A) - DAC CTRL | ||
271 | */ | ||
272 | #define WM8990_AIF_LRCLKRATE 0x0400 /* AIF_LRCLKRATE */ | ||
273 | #define WM8990_DAC_MONO 0x0200 /* DAC_MONO */ | ||
274 | #define WM8990_DAC_SB_FILT 0x0100 /* DAC_SB_FILT */ | ||
275 | #define WM8990_DAC_MUTERATE 0x0080 /* DAC_MUTERATE */ | ||
276 | #define WM8990_DAC_MUTEMODE 0x0040 /* DAC_MUTEMODE */ | ||
277 | #define WM8990_DEEMP_MASK 0x0030 /* DEEMP - [5:4] */ | ||
278 | #define WM8990_DAC_MUTE 0x0004 /* DAC_MUTE */ | ||
279 | #define WM8990_DACL_DATINV 0x0002 /* DACL_DATINV */ | ||
280 | #define WM8990_DACR_DATINV 0x0001 /* DACR_DATINV */ | ||
281 | |||
282 | /* | ||
283 | * R11 (0x0B) - Left DAC Digital Volume | ||
284 | */ | ||
285 | #define WM8990_DAC_VU 0x0100 /* DAC_VU */ | ||
286 | #define WM8990_DACL_VOL_MASK 0x00FF /* DACL_VOL - [7:0] */ | ||
287 | #define WM8990_DACL_VOL_SHIFT 0 | ||
288 | /* | ||
289 | * R12 (0x0C) - Right DAC Digital Volume | ||
290 | */ | ||
291 | #define WM8990_DAC_VU 0x0100 /* DAC_VU */ | ||
292 | #define WM8990_DACR_VOL_MASK 0x00FF /* DACR_VOL - [7:0] */ | ||
293 | #define WM8990_DACR_VOL_SHIFT 0 | ||
294 | /* | ||
295 | * R13 (0x0D) - Digital Side Tone | ||
296 | */ | ||
297 | #define WM8990_ADCL_DAC_SVOL_MASK 0x0F /* ADCL_DAC_SVOL */ | ||
298 | #define WM8990_ADCL_DAC_SVOL_SHIFT 9 | ||
299 | #define WM8990_ADCR_DAC_SVOL_MASK 0x0F /* ADCR_DAC_SVOL */ | ||
300 | #define WM8990_ADCR_DAC_SVOL_SHIFT 5 | ||
301 | #define WM8990_ADC_TO_DACL_MASK 0x03 /* ADC_TO_DACL - [3:2] */ | ||
302 | #define WM8990_ADC_TO_DACL_SHIFT 2 | ||
303 | #define WM8990_ADC_TO_DACR_MASK 0x03 /* ADC_TO_DACR - [1:0] */ | ||
304 | #define WM8990_ADC_TO_DACR_SHIFT 0 | ||
305 | |||
306 | /* | ||
307 | * R14 (0x0E) - ADC CTRL | ||
308 | */ | ||
309 | #define WM8990_ADC_HPF_ENA 0x0100 /* ADC_HPF_ENA */ | ||
310 | #define WM8990_ADC_HPF_ENA_BIT 8 | ||
311 | #define WM8990_ADC_HPF_CUT_MASK 0x03 /* ADC_HPF_CUT - [6:5] */ | ||
312 | #define WM8990_ADC_HPF_CUT_SHIFT 5 | ||
313 | #define WM8990_ADCL_DATINV 0x0002 /* ADCL_DATINV */ | ||
314 | #define WM8990_ADCL_DATINV_BIT 1 | ||
315 | #define WM8990_ADCR_DATINV 0x0001 /* ADCR_DATINV */ | ||
316 | #define WM8990_ADCR_DATINV_BIT 0 | ||
317 | |||
318 | /* | ||
319 | * R15 (0x0F) - Left ADC Digital Volume | ||
320 | */ | ||
321 | #define WM8990_ADC_VU 0x0100 /* ADC_VU */ | ||
322 | #define WM8990_ADCL_VOL_MASK 0x00FF /* ADCL_VOL - [7:0] */ | ||
323 | #define WM8990_ADCL_VOL_SHIFT 0 | ||
324 | |||
325 | /* | ||
326 | * R16 (0x10) - Right ADC Digital Volume | ||
327 | */ | ||
328 | #define WM8990_ADC_VU 0x0100 /* ADC_VU */ | ||
329 | #define WM8990_ADCR_VOL_MASK 0x00FF /* ADCR_VOL - [7:0] */ | ||
330 | #define WM8990_ADCR_VOL_SHIFT 0 | ||
331 | |||
332 | /* | ||
333 | * R18 (0x12) - GPIO CTRL 1 | ||
334 | */ | ||
335 | #define WM8990_IRQ 0x1000 /* IRQ */ | ||
336 | #define WM8990_TEMPOK 0x0800 /* TEMPOK */ | ||
337 | #define WM8990_MICSHRT 0x0400 /* MICSHRT */ | ||
338 | #define WM8990_MICDET 0x0200 /* MICDET */ | ||
339 | #define WM8990_PLL_LCK 0x0100 /* PLL_LCK */ | ||
340 | #define WM8990_GPI8_STATUS 0x0080 /* GPI8_STATUS */ | ||
341 | #define WM8990_GPI7_STATUS 0x0040 /* GPI7_STATUS */ | ||
342 | #define WM8990_GPIO6_STATUS 0x0020 /* GPIO6_STATUS */ | ||
343 | #define WM8990_GPIO5_STATUS 0x0010 /* GPIO5_STATUS */ | ||
344 | #define WM8990_GPIO4_STATUS 0x0008 /* GPIO4_STATUS */ | ||
345 | #define WM8990_GPIO3_STATUS 0x0004 /* GPIO3_STATUS */ | ||
346 | #define WM8990_GPIO2_STATUS 0x0002 /* GPIO2_STATUS */ | ||
347 | #define WM8990_GPIO1_STATUS 0x0001 /* GPIO1_STATUS */ | ||
348 | |||
349 | /* | ||
350 | * R19 (0x13) - GPIO1 & GPIO2 | ||
351 | */ | ||
352 | #define WM8990_GPIO2_DEB_ENA 0x8000 /* GPIO2_DEB_ENA */ | ||
353 | #define WM8990_GPIO2_IRQ_ENA 0x4000 /* GPIO2_IRQ_ENA */ | ||
354 | #define WM8990_GPIO2_PU 0x2000 /* GPIO2_PU */ | ||
355 | #define WM8990_GPIO2_PD 0x1000 /* GPIO2_PD */ | ||
356 | #define WM8990_GPIO2_SEL_MASK 0x0F00 /* GPIO2_SEL - [11:8] */ | ||
357 | #define WM8990_GPIO1_DEB_ENA 0x0080 /* GPIO1_DEB_ENA */ | ||
358 | #define WM8990_GPIO1_IRQ_ENA 0x0040 /* GPIO1_IRQ_ENA */ | ||
359 | #define WM8990_GPIO1_PU 0x0020 /* GPIO1_PU */ | ||
360 | #define WM8990_GPIO1_PD 0x0010 /* GPIO1_PD */ | ||
361 | #define WM8990_GPIO1_SEL_MASK 0x000F /* GPIO1_SEL - [3:0] */ | ||
362 | |||
363 | /* | ||
364 | * R20 (0x14) - GPIO3 & GPIO4 | ||
365 | */ | ||
366 | #define WM8990_GPIO4_DEB_ENA 0x8000 /* GPIO4_DEB_ENA */ | ||
367 | #define WM8990_GPIO4_IRQ_ENA 0x4000 /* GPIO4_IRQ_ENA */ | ||
368 | #define WM8990_GPIO4_PU 0x2000 /* GPIO4_PU */ | ||
369 | #define WM8990_GPIO4_PD 0x1000 /* GPIO4_PD */ | ||
370 | #define WM8990_GPIO4_SEL_MASK 0x0F00 /* GPIO4_SEL - [11:8] */ | ||
371 | #define WM8990_GPIO3_DEB_ENA 0x0080 /* GPIO3_DEB_ENA */ | ||
372 | #define WM8990_GPIO3_IRQ_ENA 0x0040 /* GPIO3_IRQ_ENA */ | ||
373 | #define WM8990_GPIO3_PU 0x0020 /* GPIO3_PU */ | ||
374 | #define WM8990_GPIO3_PD 0x0010 /* GPIO3_PD */ | ||
375 | #define WM8990_GPIO3_SEL_MASK 0x000F /* GPIO3_SEL - [3:0] */ | ||
376 | |||
377 | /* | ||
378 | * R21 (0x15) - GPIO5 & GPIO6 | ||
379 | */ | ||
380 | #define WM8990_GPIO6_DEB_ENA 0x8000 /* GPIO6_DEB_ENA */ | ||
381 | #define WM8990_GPIO6_IRQ_ENA 0x4000 /* GPIO6_IRQ_ENA */ | ||
382 | #define WM8990_GPIO6_PU 0x2000 /* GPIO6_PU */ | ||
383 | #define WM8990_GPIO6_PD 0x1000 /* GPIO6_PD */ | ||
384 | #define WM8990_GPIO6_SEL_MASK 0x0F00 /* GPIO6_SEL - [11:8] */ | ||
385 | #define WM8990_GPIO5_DEB_ENA 0x0080 /* GPIO5_DEB_ENA */ | ||
386 | #define WM8990_GPIO5_IRQ_ENA 0x0040 /* GPIO5_IRQ_ENA */ | ||
387 | #define WM8990_GPIO5_PU 0x0020 /* GPIO5_PU */ | ||
388 | #define WM8990_GPIO5_PD 0x0010 /* GPIO5_PD */ | ||
389 | #define WM8990_GPIO5_SEL_MASK 0x000F /* GPIO5_SEL - [3:0] */ | ||
390 | |||
391 | /* | ||
392 | * R22 (0x16) - GPIOCTRL 2 | ||
393 | */ | ||
394 | #define WM8990_RD_3W_ENA 0x8000 /* RD_3W_ENA */ | ||
395 | #define WM8990_MODE_3W4W 0x4000 /* MODE_3W4W */ | ||
396 | #define WM8990_TEMPOK_IRQ_ENA 0x0800 /* TEMPOK_IRQ_ENA */ | ||
397 | #define WM8990_MICSHRT_IRQ_ENA 0x0400 /* MICSHRT_IRQ_ENA */ | ||
398 | #define WM8990_MICDET_IRQ_ENA 0x0200 /* MICDET_IRQ_ENA */ | ||
399 | #define WM8990_PLL_LCK_IRQ_ENA 0x0100 /* PLL_LCK_IRQ_ENA */ | ||
400 | #define WM8990_GPI8_DEB_ENA 0x0080 /* GPI8_DEB_ENA */ | ||
401 | #define WM8990_GPI8_IRQ_ENA 0x0040 /* GPI8_IRQ_ENA */ | ||
402 | #define WM8990_GPI8_ENA 0x0010 /* GPI8_ENA */ | ||
403 | #define WM8990_GPI7_DEB_ENA 0x0008 /* GPI7_DEB_ENA */ | ||
404 | #define WM8990_GPI7_IRQ_ENA 0x0004 /* GPI7_IRQ_ENA */ | ||
405 | #define WM8990_GPI7_ENA 0x0001 /* GPI7_ENA */ | ||
406 | |||
407 | /* | ||
408 | * R23 (0x17) - GPIO_POL | ||
409 | */ | ||
410 | #define WM8990_IRQ_INV 0x1000 /* IRQ_INV */ | ||
411 | #define WM8990_TEMPOK_POL 0x0800 /* TEMPOK_POL */ | ||
412 | #define WM8990_MICSHRT_POL 0x0400 /* MICSHRT_POL */ | ||
413 | #define WM8990_MICDET_POL 0x0200 /* MICDET_POL */ | ||
414 | #define WM8990_PLL_LCK_POL 0x0100 /* PLL_LCK_POL */ | ||
415 | #define WM8990_GPI8_POL 0x0080 /* GPI8_POL */ | ||
416 | #define WM8990_GPI7_POL 0x0040 /* GPI7_POL */ | ||
417 | #define WM8990_GPIO6_POL 0x0020 /* GPIO6_POL */ | ||
418 | #define WM8990_GPIO5_POL 0x0010 /* GPIO5_POL */ | ||
419 | #define WM8990_GPIO4_POL 0x0008 /* GPIO4_POL */ | ||
420 | #define WM8990_GPIO3_POL 0x0004 /* GPIO3_POL */ | ||
421 | #define WM8990_GPIO2_POL 0x0002 /* GPIO2_POL */ | ||
422 | #define WM8990_GPIO1_POL 0x0001 /* GPIO1_POL */ | ||
423 | |||
424 | /* | ||
425 | * R24 (0x18) - Left Line Input 1&2 Volume | ||
426 | */ | ||
427 | #define WM8990_IPVU 0x0100 /* IPVU */ | ||
428 | #define WM8990_LI12MUTE 0x0080 /* LI12MUTE */ | ||
429 | #define WM8990_LI12MUTE_BIT 7 | ||
430 | #define WM8990_LI12ZC 0x0040 /* LI12ZC */ | ||
431 | #define WM8990_LI12ZC_BIT 6 | ||
432 | #define WM8990_LIN12VOL_MASK 0x001F /* LIN12VOL - [4:0] */ | ||
433 | #define WM8990_LIN12VOL_SHIFT 0 | ||
434 | /* | ||
435 | * R25 (0x19) - Left Line Input 3&4 Volume | ||
436 | */ | ||
437 | #define WM8990_IPVU 0x0100 /* IPVU */ | ||
438 | #define WM8990_LI34MUTE 0x0080 /* LI34MUTE */ | ||
439 | #define WM8990_LI34MUTE_BIT 7 | ||
440 | #define WM8990_LI34ZC 0x0040 /* LI34ZC */ | ||
441 | #define WM8990_LI34ZC_BIT 6 | ||
442 | #define WM8990_LIN34VOL_MASK 0x001F /* LIN34VOL - [4:0] */ | ||
443 | #define WM8990_LIN34VOL_SHIFT 0 | ||
444 | |||
445 | /* | ||
446 | * R26 (0x1A) - Right Line Input 1&2 Volume | ||
447 | */ | ||
448 | #define WM8990_IPVU 0x0100 /* IPVU */ | ||
449 | #define WM8990_RI12MUTE 0x0080 /* RI12MUTE */ | ||
450 | #define WM8990_RI12MUTE_BIT 7 | ||
451 | #define WM8990_RI12ZC 0x0040 /* RI12ZC */ | ||
452 | #define WM8990_RI12ZC_BIT 6 | ||
453 | #define WM8990_RIN12VOL_MASK 0x001F /* RIN12VOL - [4:0] */ | ||
454 | #define WM8990_RIN12VOL_SHIFT 0 | ||
455 | |||
456 | /* | ||
457 | * R27 (0x1B) - Right Line Input 3&4 Volume | ||
458 | */ | ||
459 | #define WM8990_IPVU 0x0100 /* IPVU */ | ||
460 | #define WM8990_RI34MUTE 0x0080 /* RI34MUTE */ | ||
461 | #define WM8990_RI34MUTE_BIT 7 | ||
462 | #define WM8990_RI34ZC 0x0040 /* RI34ZC */ | ||
463 | #define WM8990_RI34ZC_BIT 6 | ||
464 | #define WM8990_RIN34VOL_MASK 0x001F /* RIN34VOL - [4:0] */ | ||
465 | #define WM8990_RIN34VOL_SHIFT 0 | ||
466 | |||
467 | /* | ||
468 | * R28 (0x1C) - Left Output Volume | ||
469 | */ | ||
470 | #define WM8990_OPVU 0x0100 /* OPVU */ | ||
471 | #define WM8990_LOZC 0x0080 /* LOZC */ | ||
472 | #define WM8990_LOZC_BIT 7 | ||
473 | #define WM8990_LOUTVOL_MASK 0x007F /* LOUTVOL - [6:0] */ | ||
474 | #define WM8990_LOUTVOL_SHIFT 0 | ||
475 | /* | ||
476 | * R29 (0x1D) - Right Output Volume | ||
477 | */ | ||
478 | #define WM8990_OPVU 0x0100 /* OPVU */ | ||
479 | #define WM8990_ROZC 0x0080 /* ROZC */ | ||
480 | #define WM8990_ROZC_BIT 7 | ||
481 | #define WM8990_ROUTVOL_MASK 0x007F /* ROUTVOL - [6:0] */ | ||
482 | #define WM8990_ROUTVOL_SHIFT 0 | ||
483 | /* | ||
484 | * R30 (0x1E) - Line Outputs Volume | ||
485 | */ | ||
486 | #define WM8990_LONMUTE 0x0040 /* LONMUTE */ | ||
487 | #define WM8990_LONMUTE_BIT 6 | ||
488 | #define WM8990_LOPMUTE 0x0020 /* LOPMUTE */ | ||
489 | #define WM8990_LOPMUTE_BIT 5 | ||
490 | #define WM8990_LOATTN 0x0010 /* LOATTN */ | ||
491 | #define WM8990_LOATTN_BIT 4 | ||
492 | #define WM8990_RONMUTE 0x0004 /* RONMUTE */ | ||
493 | #define WM8990_RONMUTE_BIT 2 | ||
494 | #define WM8990_ROPMUTE 0x0002 /* ROPMUTE */ | ||
495 | #define WM8990_ROPMUTE_BIT 1 | ||
496 | #define WM8990_ROATTN 0x0001 /* ROATTN */ | ||
497 | #define WM8990_ROATTN_BIT 0 | ||
498 | |||
499 | /* | ||
500 | * R31 (0x1F) - Out3/4 Volume | ||
501 | */ | ||
502 | #define WM8990_OUT3MUTE 0x0020 /* OUT3MUTE */ | ||
503 | #define WM8990_OUT3MUTE_BIT 5 | ||
504 | #define WM8990_OUT3ATTN 0x0010 /* OUT3ATTN */ | ||
505 | #define WM8990_OUT3ATTN_BIT 4 | ||
506 | #define WM8990_OUT4MUTE 0x0002 /* OUT4MUTE */ | ||
507 | #define WM8990_OUT4MUTE_BIT 1 | ||
508 | #define WM8990_OUT4ATTN 0x0001 /* OUT4ATTN */ | ||
509 | #define WM8990_OUT4ATTN_BIT 0 | ||
510 | |||
511 | /* | ||
512 | * R32 (0x20) - Left OPGA Volume | ||
513 | */ | ||
514 | #define WM8990_OPVU 0x0100 /* OPVU */ | ||
515 | #define WM8990_LOPGAZC 0x0080 /* LOPGAZC */ | ||
516 | #define WM8990_LOPGAZC_BIT 7 | ||
517 | #define WM8990_LOPGAVOL_MASK 0x007F /* LOPGAVOL - [6:0] */ | ||
518 | #define WM8990_LOPGAVOL_SHIFT 0 | ||
519 | |||
520 | /* | ||
521 | * R33 (0x21) - Right OPGA Volume | ||
522 | */ | ||
523 | #define WM8990_OPVU 0x0100 /* OPVU */ | ||
524 | #define WM8990_ROPGAZC 0x0080 /* ROPGAZC */ | ||
525 | #define WM8990_ROPGAZC_BIT 7 | ||
526 | #define WM8990_ROPGAVOL_MASK 0x007F /* ROPGAVOL - [6:0] */ | ||
527 | #define WM8990_ROPGAVOL_SHIFT 0 | ||
528 | /* | ||
529 | * R34 (0x22) - Speaker Volume | ||
530 | */ | ||
531 | #define WM8990_SPKVOL_MASK 0x0003 /* SPKVOL - [1:0] */ | ||
532 | #define WM8990_SPKVOL_SHIFT 0 | ||
533 | |||
534 | /* | ||
535 | * R35 (0x23) - ClassD1 | ||
536 | */ | ||
537 | #define WM8990_CDMODE 0x0100 /* CDMODE */ | ||
538 | #define WM8990_CDMODE_BIT 8 | ||
539 | |||
540 | /* | ||
541 | * R37 (0x25) - ClassD3 | ||
542 | */ | ||
543 | #define WM8990_DCGAIN_MASK 0x0007 /* DCGAIN - [5:3] */ | ||
544 | #define WM8990_DCGAIN_SHIFT 3 | ||
545 | #define WM8990_ACGAIN_MASK 0x0007 /* ACGAIN - [2:0] */ | ||
546 | #define WM8990_ACGAIN_SHIFT 0 | ||
547 | /* | ||
548 | * R39 (0x27) - Input Mixer1 | ||
549 | */ | ||
550 | #define WM8990_AINLMODE_MASK 0x000C /* AINLMODE - [3:2] */ | ||
551 | #define WM8990_AINLMODE_SHIFT 2 | ||
552 | #define WM8990_AINRMODE_MASK 0x0003 /* AINRMODE - [1:0] */ | ||
553 | #define WM8990_AINRMODE_SHIFT 0 | ||
554 | |||
555 | /* | ||
556 | * R40 (0x28) - Input Mixer2 | ||
557 | */ | ||
558 | #define WM8990_LMP4 0x0080 /* LMP4 */ | ||
559 | #define WM8990_LMP4_BIT 7 /* LMP4 */ | ||
560 | #define WM8990_LMN3 0x0040 /* LMN3 */ | ||
561 | #define WM8990_LMN3_BIT 6 /* LMN3 */ | ||
562 | #define WM8990_LMP2 0x0020 /* LMP2 */ | ||
563 | #define WM8990_LMP2_BIT 5 /* LMP2 */ | ||
564 | #define WM8990_LMN1 0x0010 /* LMN1 */ | ||
565 | #define WM8990_LMN1_BIT 4 /* LMN1 */ | ||
566 | #define WM8990_RMP4 0x0008 /* RMP4 */ | ||
567 | #define WM8990_RMP4_BIT 3 /* RMP4 */ | ||
568 | #define WM8990_RMN3 0x0004 /* RMN3 */ | ||
569 | #define WM8990_RMN3_BIT 2 /* RMN3 */ | ||
570 | #define WM8990_RMP2 0x0002 /* RMP2 */ | ||
571 | #define WM8990_RMP2_BIT 1 /* RMP2 */ | ||
572 | #define WM8990_RMN1 0x0001 /* RMN1 */ | ||
573 | #define WM8990_RMN1_BIT 0 /* RMN1 */ | ||
574 | |||
575 | /* | ||
576 | * R41 (0x29) - Input Mixer3 | ||
577 | */ | ||
578 | #define WM8990_L34MNB 0x0100 /* L34MNB */ | ||
579 | #define WM8990_L34MNB_BIT 8 | ||
580 | #define WM8990_L34MNBST 0x0080 /* L34MNBST */ | ||
581 | #define WM8990_L34MNBST_BIT 7 | ||
582 | #define WM8990_L12MNB 0x0020 /* L12MNB */ | ||
583 | #define WM8990_L12MNB_BIT 5 | ||
584 | #define WM8990_L12MNBST 0x0010 /* L12MNBST */ | ||
585 | #define WM8990_L12MNBST_BIT 4 | ||
586 | #define WM8990_LDBVOL_MASK 0x0007 /* LDBVOL - [2:0] */ | ||
587 | #define WM8990_LDBVOL_SHIFT 0 | ||
588 | |||
589 | /* | ||
590 | * R42 (0x2A) - Input Mixer4 | ||
591 | */ | ||
592 | #define WM8990_R34MNB 0x0100 /* R34MNB */ | ||
593 | #define WM8990_R34MNB_BIT 8 | ||
594 | #define WM8990_R34MNBST 0x0080 /* R34MNBST */ | ||
595 | #define WM8990_R34MNBST_BIT 7 | ||
596 | #define WM8990_R12MNB 0x0020 /* R12MNB */ | ||
597 | #define WM8990_R12MNB_BIT 5 | ||
598 | #define WM8990_R12MNBST 0x0010 /* R12MNBST */ | ||
599 | #define WM8990_R12MNBST_BIT 4 | ||
600 | #define WM8990_RDBVOL_MASK 0x0007 /* RDBVOL - [2:0] */ | ||
601 | #define WM8990_RDBVOL_SHIFT 0 | ||
602 | |||
603 | /* | ||
604 | * R43 (0x2B) - Input Mixer5 | ||
605 | */ | ||
606 | #define WM8990_LI2BVOL_MASK 0x07 /* LI2BVOL - [8:6] */ | ||
607 | #define WM8990_LI2BVOL_SHIFT 6 | ||
608 | #define WM8990_LR4BVOL_MASK 0x07 /* LR4BVOL - [5:3] */ | ||
609 | #define WM8990_LR4BVOL_SHIFT 3 | ||
610 | #define WM8990_LL4BVOL_MASK 0x07 /* LL4BVOL - [2:0] */ | ||
611 | #define WM8990_LL4BVOL_SHIFT 0 | ||
612 | |||
613 | /* | ||
614 | * R44 (0x2C) - Input Mixer6 | ||
615 | */ | ||
616 | #define WM8990_RI2BVOL_MASK 0x07 /* RI2BVOL - [8:6] */ | ||
617 | #define WM8990_RI2BVOL_SHIFT 6 | ||
618 | #define WM8990_RL4BVOL_MASK 0x07 /* RL4BVOL - [5:3] */ | ||
619 | #define WM8990_RL4BVOL_SHIFT 3 | ||
620 | #define WM8990_RR4BVOL_MASK 0x07 /* RR4BVOL - [2:0] */ | ||
621 | #define WM8990_RR4BVOL_SHIFT 0 | ||
622 | |||
623 | /* | ||
624 | * R45 (0x2D) - Output Mixer1 | ||
625 | */ | ||
626 | #define WM8990_LRBLO 0x0080 /* LRBLO */ | ||
627 | #define WM8990_LRBLO_BIT 7 | ||
628 | #define WM8990_LLBLO 0x0040 /* LLBLO */ | ||
629 | #define WM8990_LLBLO_BIT 6 | ||
630 | #define WM8990_LRI3LO 0x0020 /* LRI3LO */ | ||
631 | #define WM8990_LRI3LO_BIT 5 | ||
632 | #define WM8990_LLI3LO 0x0010 /* LLI3LO */ | ||
633 | #define WM8990_LLI3LO_BIT 4 | ||
634 | #define WM8990_LR12LO 0x0008 /* LR12LO */ | ||
635 | #define WM8990_LR12LO_BIT 3 | ||
636 | #define WM8990_LL12LO 0x0004 /* LL12LO */ | ||
637 | #define WM8990_LL12LO_BIT 2 | ||
638 | #define WM8990_LDLO 0x0001 /* LDLO */ | ||
639 | #define WM8990_LDLO_BIT 0 | ||
640 | |||
641 | /* | ||
642 | * R46 (0x2E) - Output Mixer2 | ||
643 | */ | ||
644 | #define WM8990_RLBRO 0x0080 /* RLBRO */ | ||
645 | #define WM8990_RLBRO_BIT 7 | ||
646 | #define WM8990_RRBRO 0x0040 /* RRBRO */ | ||
647 | #define WM8990_RRBRO_BIT 6 | ||
648 | #define WM8990_RLI3RO 0x0020 /* RLI3RO */ | ||
649 | #define WM8990_RLI3RO_BIT 5 | ||
650 | #define WM8990_RRI3RO 0x0010 /* RRI3RO */ | ||
651 | #define WM8990_RRI3RO_BIT 4 | ||
652 | #define WM8990_RL12RO 0x0008 /* RL12RO */ | ||
653 | #define WM8990_RL12RO_BIT 3 | ||
654 | #define WM8990_RR12RO 0x0004 /* RR12RO */ | ||
655 | #define WM8990_RR12RO_BIT 2 | ||
656 | #define WM8990_RDRO 0x0001 /* RDRO */ | ||
657 | #define WM8990_RDRO_BIT 0 | ||
658 | |||
659 | /* | ||
660 | * R47 (0x2F) - Output Mixer3 | ||
661 | */ | ||
662 | #define WM8990_LLI3LOVOL_MASK 0x07 /* LLI3LOVOL - [8:6] */ | ||
663 | #define WM8990_LLI3LOVOL_SHIFT 6 | ||
664 | #define WM8990_LR12LOVOL_MASK 0x07 /* LR12LOVOL - [5:3] */ | ||
665 | #define WM8990_LR12LOVOL_SHIFT 3 | ||
666 | #define WM8990_LL12LOVOL_MASK 0x07 /* LL12LOVOL - [2:0] */ | ||
667 | #define WM8990_LL12LOVOL_SHIFT 0 | ||
668 | |||
669 | /* | ||
670 | * R48 (0x30) - Output Mixer4 | ||
671 | */ | ||
672 | #define WM8990_RRI3ROVOL_MASK 0x07 /* RRI3ROVOL - [8:6] */ | ||
673 | #define WM8990_RRI3ROVOL_SHIFT 6 | ||
674 | #define WM8990_RL12ROVOL_MASK 0x07 /* RL12ROVOL - [5:3] */ | ||
675 | #define WM8990_RL12ROVOL_SHIFT 3 | ||
676 | #define WM8990_RR12ROVOL_MASK 0x07 /* RR12ROVOL - [2:0] */ | ||
677 | #define WM8990_RR12ROVOL_SHIFT 0 | ||
678 | |||
679 | /* | ||
680 | * R49 (0x31) - Output Mixer5 | ||
681 | */ | ||
682 | #define WM8990_LRI3LOVOL_MASK 0x07 /* LRI3LOVOL - [8:6] */ | ||
683 | #define WM8990_LRI3LOVOL_SHIFT 6 | ||
684 | #define WM8990_LRBLOVOL_MASK 0x07 /* LRBLOVOL - [5:3] */ | ||
685 | #define WM8990_LRBLOVOL_SHIFT 3 | ||
686 | #define WM8990_LLBLOVOL_MASK 0x07 /* LLBLOVOL - [2:0] */ | ||
687 | #define WM8990_LLBLOVOL_SHIFT 0 | ||
688 | |||
689 | /* | ||
690 | * R50 (0x32) - Output Mixer6 | ||
691 | */ | ||
692 | #define WM8990_RLI3ROVOL_MASK 0x07 /* RLI3ROVOL - [8:6] */ | ||
693 | #define WM8990_RLI3ROVOL_SHIFT 6 | ||
694 | #define WM8990_RLBROVOL_MASK 0x07 /* RLBROVOL - [5:3] */ | ||
695 | #define WM8990_RLBROVOL_SHIFT 3 | ||
696 | #define WM8990_RRBROVOL_MASK 0x07 /* RRBROVOL - [2:0] */ | ||
697 | #define WM8990_RRBROVOL_SHIFT 0 | ||
698 | |||
699 | /* | ||
700 | * R51 (0x33) - Out3/4 Mixer | ||
701 | */ | ||
702 | #define WM8990_VSEL_MASK 0x0180 /* VSEL - [8:7] */ | ||
703 | #define WM8990_LI4O3 0x0020 /* LI4O3 */ | ||
704 | #define WM8990_LI4O3_BIT 5 | ||
705 | #define WM8990_LPGAO3 0x0010 /* LPGAO3 */ | ||
706 | #define WM8990_LPGAO3_BIT 4 | ||
707 | #define WM8990_RI4O4 0x0002 /* RI4O4 */ | ||
708 | #define WM8990_RI4O4_BIT 1 | ||
709 | #define WM8990_RPGAO4 0x0001 /* RPGAO4 */ | ||
710 | #define WM8990_RPGAO4_BIT 0 | ||
711 | /* | ||
712 | * R52 (0x34) - Line Mixer1 | ||
713 | */ | ||
714 | #define WM8990_LLOPGALON 0x0040 /* LLOPGALON */ | ||
715 | #define WM8990_LLOPGALON_BIT 6 | ||
716 | #define WM8990_LROPGALON 0x0020 /* LROPGALON */ | ||
717 | #define WM8990_LROPGALON_BIT 5 | ||
718 | #define WM8990_LOPLON 0x0010 /* LOPLON */ | ||
719 | #define WM8990_LOPLON_BIT 4 | ||
720 | #define WM8990_LR12LOP 0x0004 /* LR12LOP */ | ||
721 | #define WM8990_LR12LOP_BIT 2 | ||
722 | #define WM8990_LL12LOP 0x0002 /* LL12LOP */ | ||
723 | #define WM8990_LL12LOP_BIT 1 | ||
724 | #define WM8990_LLOPGALOP 0x0001 /* LLOPGALOP */ | ||
725 | #define WM8990_LLOPGALOP_BIT 0 | ||
726 | /* | ||
727 | * R53 (0x35) - Line Mixer2 | ||
728 | */ | ||
729 | #define WM8990_RROPGARON 0x0040 /* RROPGARON */ | ||
730 | #define WM8990_RROPGARON_BIT 6 | ||
731 | #define WM8990_RLOPGARON 0x0020 /* RLOPGARON */ | ||
732 | #define WM8990_RLOPGARON_BIT 5 | ||
733 | #define WM8990_ROPRON 0x0010 /* ROPRON */ | ||
734 | #define WM8990_ROPRON_BIT 4 | ||
735 | #define WM8990_RL12ROP 0x0004 /* RL12ROP */ | ||
736 | #define WM8990_RL12ROP_BIT 2 | ||
737 | #define WM8990_RR12ROP 0x0002 /* RR12ROP */ | ||
738 | #define WM8990_RR12ROP_BIT 1 | ||
739 | #define WM8990_RROPGAROP 0x0001 /* RROPGAROP */ | ||
740 | #define WM8990_RROPGAROP_BIT 0 | ||
741 | |||
742 | /* | ||
743 | * R54 (0x36) - Speaker Mixer | ||
744 | */ | ||
745 | #define WM8990_LB2SPK 0x0080 /* LB2SPK */ | ||
746 | #define WM8990_LB2SPK_BIT 7 | ||
747 | #define WM8990_RB2SPK 0x0040 /* RB2SPK */ | ||
748 | #define WM8990_RB2SPK_BIT 6 | ||
749 | #define WM8990_LI2SPK 0x0020 /* LI2SPK */ | ||
750 | #define WM8990_LI2SPK_BIT 5 | ||
751 | #define WM8990_RI2SPK 0x0010 /* RI2SPK */ | ||
752 | #define WM8990_RI2SPK_BIT 4 | ||
753 | #define WM8990_LOPGASPK 0x0008 /* LOPGASPK */ | ||
754 | #define WM8990_LOPGASPK_BIT 3 | ||
755 | #define WM8990_ROPGASPK 0x0004 /* ROPGASPK */ | ||
756 | #define WM8990_ROPGASPK_BIT 2 | ||
757 | #define WM8990_LDSPK 0x0002 /* LDSPK */ | ||
758 | #define WM8990_LDSPK_BIT 1 | ||
759 | #define WM8990_RDSPK 0x0001 /* RDSPK */ | ||
760 | #define WM8990_RDSPK_BIT 0 | ||
761 | |||
762 | /* | ||
763 | * R55 (0x37) - Additional Control | ||
764 | */ | ||
765 | #define WM8990_VROI 0x0001 /* VROI */ | ||
766 | |||
767 | /* | ||
768 | * R56 (0x38) - AntiPOP1 | ||
769 | */ | ||
770 | #define WM8990_DIS_LLINE 0x0020 /* DIS_LLINE */ | ||
771 | #define WM8990_DIS_RLINE 0x0010 /* DIS_RLINE */ | ||
772 | #define WM8990_DIS_OUT3 0x0008 /* DIS_OUT3 */ | ||
773 | #define WM8990_DIS_OUT4 0x0004 /* DIS_OUT4 */ | ||
774 | #define WM8990_DIS_LOUT 0x0002 /* DIS_LOUT */ | ||
775 | #define WM8990_DIS_ROUT 0x0001 /* DIS_ROUT */ | ||
776 | |||
777 | /* | ||
778 | * R57 (0x39) - AntiPOP2 | ||
779 | */ | ||
780 | #define WM8990_SOFTST 0x0040 /* SOFTST */ | ||
781 | #define WM8990_BUFIOEN 0x0008 /* BUFIOEN */ | ||
782 | #define WM8990_BUFDCOPEN 0x0004 /* BUFDCOPEN */ | ||
783 | #define WM8990_POBCTRL 0x0002 /* POBCTRL */ | ||
784 | #define WM8990_VMIDTOG 0x0001 /* VMIDTOG */ | ||
785 | |||
786 | /* | ||
787 | * R58 (0x3A) - MICBIAS | ||
788 | */ | ||
789 | #define WM8990_MCDSCTH_MASK 0x00C0 /* MCDSCTH - [7:6] */ | ||
790 | #define WM8990_MCDTHR_MASK 0x0038 /* MCDTHR - [5:3] */ | ||
791 | #define WM8990_MCD 0x0004 /* MCD */ | ||
792 | #define WM8990_MBSEL 0x0001 /* MBSEL */ | ||
793 | |||
794 | /* | ||
795 | * R60 (0x3C) - PLL1 | ||
796 | */ | ||
797 | #define WM8990_SDM 0x0080 /* SDM */ | ||
798 | #define WM8990_PRESCALE 0x0040 /* PRESCALE */ | ||
799 | #define WM8990_PLLN_MASK 0x000F /* PLLN - [3:0] */ | ||
800 | |||
801 | /* | ||
802 | * R61 (0x3D) - PLL2 | ||
803 | */ | ||
804 | #define WM8990_PLLK1_MASK 0x00FF /* PLLK1 - [7:0] */ | ||
805 | |||
806 | /* | ||
807 | * R62 (0x3E) - PLL3 | ||
808 | */ | ||
809 | #define WM8990_PLLK2_MASK 0x00FF /* PLLK2 - [7:0] */ | ||
810 | |||
811 | /* | ||
812 | * R63 (0x3F) - Internal Driver Bits | ||
813 | */ | ||
814 | #define WM8990_INMIXL_PWR_BIT 0 | ||
815 | #define WM8990_AINLMUX_PWR_BIT 1 | ||
816 | #define WM8990_INMIXR_PWR_BIT 2 | ||
817 | #define WM8990_AINRMUX_PWR_BIT 3 | ||
818 | |||
819 | struct wm8990_setup_data { | ||
820 | unsigned short i2c_address; | ||
821 | }; | ||
822 | |||
823 | #define WM8990_MCLK_DIV 0 | ||
824 | #define WM8990_DACCLK_DIV 1 | ||
825 | #define WM8990_ADCCLK_DIV 2 | ||
826 | #define WM8990_BCLK_DIV 3 | ||
827 | |||
828 | extern struct snd_soc_dai wm8990_dai; | ||
829 | extern struct snd_soc_codec_device soc_codec_dev_wm8990; | ||
830 | |||
831 | #endif /* __WM8990REGISTERDEFS_H__ */ | ||
832 | /*------------------------------ END OF FILE ---------------------------------*/ | ||
diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index 76c1e2d33e7d..9fc8edd82225 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c | |||
@@ -9,9 +9,6 @@ | |||
9 | * under the terms of the GNU General Public License as published by the | 9 | * under the terms of the GNU General Public License as published by the |
10 | * Free Software Foundation; either version 2 of the License, or (at your | 10 | * Free Software Foundation; either version 2 of the License, or (at your |
11 | * option) any later version. | 11 | * option) any later version. |
12 | * | ||
13 | * Revision history | ||
14 | * 4th Feb 2006 Initial version. | ||
15 | */ | 12 | */ |
16 | 13 | ||
17 | #include <linux/init.h> | 14 | #include <linux/init.h> |
@@ -25,6 +22,7 @@ | |||
25 | #include <sound/initval.h> | 22 | #include <sound/initval.h> |
26 | #include <sound/soc.h> | 23 | #include <sound/soc.h> |
27 | #include <sound/soc-dapm.h> | 24 | #include <sound/soc-dapm.h> |
25 | #include "wm9712.h" | ||
28 | 26 | ||
29 | #define WM9712_VERSION "0.4" | 27 | #define WM9712_VERSION "0.4" |
30 | 28 | ||
@@ -351,7 +349,7 @@ SND_SOC_DAPM_INPUT("MIC1"), | |||
351 | SND_SOC_DAPM_INPUT("MIC2"), | 349 | SND_SOC_DAPM_INPUT("MIC2"), |
352 | }; | 350 | }; |
353 | 351 | ||
354 | static const char *audio_map[][3] = { | 352 | static const struct snd_soc_dapm_route audio_map[] = { |
355 | /* virtual mixer - mixes left & right channels for spk and mono */ | 353 | /* virtual mixer - mixes left & right channels for spk and mono */ |
356 | {"AC97 Mixer", NULL, "Left DAC"}, | 354 | {"AC97 Mixer", NULL, "Left DAC"}, |
357 | {"AC97 Mixer", NULL, "Right DAC"}, | 355 | {"AC97 Mixer", NULL, "Right DAC"}, |
@@ -446,21 +444,14 @@ static const char *audio_map[][3] = { | |||
446 | {"Speaker PGA", NULL, "Speaker Mux"}, | 444 | {"Speaker PGA", NULL, "Speaker Mux"}, |
447 | {"LOUT2", NULL, "Speaker PGA"}, | 445 | {"LOUT2", NULL, "Speaker PGA"}, |
448 | {"ROUT2", NULL, "Speaker PGA"}, | 446 | {"ROUT2", NULL, "Speaker PGA"}, |
449 | |||
450 | {NULL, NULL, NULL}, | ||
451 | }; | 447 | }; |
452 | 448 | ||
453 | static int wm9712_add_widgets(struct snd_soc_codec *codec) | 449 | static int wm9712_add_widgets(struct snd_soc_codec *codec) |
454 | { | 450 | { |
455 | int i; | 451 | snd_soc_dapm_new_controls(codec, wm9712_dapm_widgets, |
456 | 452 | ARRAY_SIZE(wm9712_dapm_widgets)); | |
457 | for (i = 0; i < ARRAY_SIZE(wm9712_dapm_widgets); i++) | ||
458 | snd_soc_dapm_new_control(codec, &wm9712_dapm_widgets[i]); | ||
459 | 453 | ||
460 | /* set up audio path connects */ | 454 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); |
461 | for (i = 0; audio_map[i][0] != NULL; i++) | ||
462 | snd_soc_dapm_connect_input(codec, audio_map[i][0], | ||
463 | audio_map[i][1], audio_map[i][2]); | ||
464 | 455 | ||
465 | snd_soc_dapm_new_widgets(codec); | 456 | snd_soc_dapm_new_widgets(codec); |
466 | return 0; | 457 | return 0; |
@@ -541,7 +532,7 @@ static int ac97_aux_prepare(struct snd_pcm_substream *substream) | |||
541 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 |\ | 532 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 |\ |
542 | SNDRV_PCM_RATE_48000) | 533 | SNDRV_PCM_RATE_48000) |
543 | 534 | ||
544 | struct snd_soc_codec_dai wm9712_dai[] = { | 535 | struct snd_soc_dai wm9712_dai[] = { |
545 | { | 536 | { |
546 | .name = "AC97 HiFi", | 537 | .name = "AC97 HiFi", |
547 | .type = SND_SOC_DAI_AC97_BUS, | 538 | .type = SND_SOC_DAI_AC97_BUS, |
@@ -574,23 +565,23 @@ struct snd_soc_codec_dai wm9712_dai[] = { | |||
574 | }; | 565 | }; |
575 | EXPORT_SYMBOL_GPL(wm9712_dai); | 566 | EXPORT_SYMBOL_GPL(wm9712_dai); |
576 | 567 | ||
577 | static int wm9712_dapm_event(struct snd_soc_codec *codec, int event) | 568 | static int wm9712_set_bias_level(struct snd_soc_codec *codec, |
569 | enum snd_soc_bias_level level) | ||
578 | { | 570 | { |
579 | switch (event) { | 571 | switch (level) { |
580 | case SNDRV_CTL_POWER_D0: /* full On */ | 572 | case SND_SOC_BIAS_ON: |
581 | case SNDRV_CTL_POWER_D1: /* partial On */ | 573 | case SND_SOC_BIAS_PREPARE: |
582 | case SNDRV_CTL_POWER_D2: /* partial On */ | ||
583 | break; | 574 | break; |
584 | case SNDRV_CTL_POWER_D3hot: /* Off, with power */ | 575 | case SND_SOC_BIAS_STANDBY: |
585 | ac97_write(codec, AC97_POWERDOWN, 0x0000); | 576 | ac97_write(codec, AC97_POWERDOWN, 0x0000); |
586 | break; | 577 | break; |
587 | case SNDRV_CTL_POWER_D3cold: /* Off, without power */ | 578 | case SND_SOC_BIAS_OFF: |
588 | /* disable everything including AC link */ | 579 | /* disable everything including AC link */ |
589 | ac97_write(codec, AC97_EXTENDED_MSTATUS, 0xffff); | 580 | ac97_write(codec, AC97_EXTENDED_MSTATUS, 0xffff); |
590 | ac97_write(codec, AC97_POWERDOWN, 0xffff); | 581 | ac97_write(codec, AC97_POWERDOWN, 0xffff); |
591 | break; | 582 | break; |
592 | } | 583 | } |
593 | codec->dapm_state = event; | 584 | codec->bias_level = level; |
594 | return 0; | 585 | return 0; |
595 | } | 586 | } |
596 | 587 | ||
@@ -598,12 +589,12 @@ static int wm9712_reset(struct snd_soc_codec *codec, int try_warm) | |||
598 | { | 589 | { |
599 | if (try_warm && soc_ac97_ops.warm_reset) { | 590 | if (try_warm && soc_ac97_ops.warm_reset) { |
600 | soc_ac97_ops.warm_reset(codec->ac97); | 591 | soc_ac97_ops.warm_reset(codec->ac97); |
601 | if (!(ac97_read(codec, 0) & 0x8000)) | 592 | if (ac97_read(codec, 0) == wm9712_reg[0]) |
602 | return 1; | 593 | return 1; |
603 | } | 594 | } |
604 | 595 | ||
605 | soc_ac97_ops.reset(codec->ac97); | 596 | soc_ac97_ops.reset(codec->ac97); |
606 | if (ac97_read(codec, 0) & 0x8000) | 597 | if (ac97_read(codec, 0) != wm9712_reg[0]) |
607 | goto err; | 598 | goto err; |
608 | return 0; | 599 | return 0; |
609 | 600 | ||
@@ -618,7 +609,7 @@ static int wm9712_soc_suspend(struct platform_device *pdev, | |||
618 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 609 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
619 | struct snd_soc_codec *codec = socdev->codec; | 610 | struct snd_soc_codec *codec = socdev->codec; |
620 | 611 | ||
621 | wm9712_dapm_event(codec, SNDRV_CTL_POWER_D3cold); | 612 | wm9712_set_bias_level(codec, SND_SOC_BIAS_OFF); |
622 | return 0; | 613 | return 0; |
623 | } | 614 | } |
624 | 615 | ||
@@ -635,7 +626,7 @@ static int wm9712_soc_resume(struct platform_device *pdev) | |||
635 | return ret; | 626 | return ret; |
636 | } | 627 | } |
637 | 628 | ||
638 | wm9712_dapm_event(codec, SNDRV_CTL_POWER_D3hot); | 629 | wm9712_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
639 | 630 | ||
640 | if (ret == 0) { | 631 | if (ret == 0) { |
641 | /* Sync reg_cache with the hardware after cold reset */ | 632 | /* Sync reg_cache with the hardware after cold reset */ |
@@ -647,8 +638,8 @@ static int wm9712_soc_resume(struct platform_device *pdev) | |||
647 | } | 638 | } |
648 | } | 639 | } |
649 | 640 | ||
650 | if (codec->suspend_dapm_state == SNDRV_CTL_POWER_D0) | 641 | if (codec->suspend_bias_level == SND_SOC_BIAS_ON) |
651 | wm9712_dapm_event(codec, SNDRV_CTL_POWER_D0); | 642 | wm9712_set_bias_level(codec, SND_SOC_BIAS_ON); |
652 | 643 | ||
653 | return ret; | 644 | return ret; |
654 | } | 645 | } |
@@ -682,7 +673,7 @@ static int wm9712_soc_probe(struct platform_device *pdev) | |||
682 | codec->num_dai = ARRAY_SIZE(wm9712_dai); | 673 | codec->num_dai = ARRAY_SIZE(wm9712_dai); |
683 | codec->write = ac97_write; | 674 | codec->write = ac97_write; |
684 | codec->read = ac97_read; | 675 | codec->read = ac97_read; |
685 | codec->dapm_event = wm9712_dapm_event; | 676 | codec->set_bias_level = wm9712_set_bias_level; |
686 | INIT_LIST_HEAD(&codec->dapm_widgets); | 677 | INIT_LIST_HEAD(&codec->dapm_widgets); |
687 | INIT_LIST_HEAD(&codec->dapm_paths); | 678 | INIT_LIST_HEAD(&codec->dapm_paths); |
688 | 679 | ||
@@ -706,7 +697,7 @@ static int wm9712_soc_probe(struct platform_device *pdev) | |||
706 | /* set alc mux to none */ | 697 | /* set alc mux to none */ |
707 | ac97_write(codec, AC97_VIDEO, ac97_read(codec, AC97_VIDEO) | 0x3000); | 698 | ac97_write(codec, AC97_VIDEO, ac97_read(codec, AC97_VIDEO) | 0x3000); |
708 | 699 | ||
709 | wm9712_dapm_event(codec, SNDRV_CTL_POWER_D3hot); | 700 | wm9712_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
710 | wm9712_add_controls(codec); | 701 | wm9712_add_controls(codec); |
711 | wm9712_add_widgets(codec); | 702 | wm9712_add_widgets(codec); |
712 | ret = snd_soc_register_card(socdev); | 703 | ret = snd_soc_register_card(socdev); |
diff --git a/sound/soc/codecs/wm9712.h b/sound/soc/codecs/wm9712.h index 719105d61e65..d29e8a18ca6d 100644 --- a/sound/soc/codecs/wm9712.h +++ b/sound/soc/codecs/wm9712.h | |||
@@ -8,7 +8,7 @@ | |||
8 | #define WM9712_DAI_AC97_HIFI 0 | 8 | #define WM9712_DAI_AC97_HIFI 0 |
9 | #define WM9712_DAI_AC97_AUX 1 | 9 | #define WM9712_DAI_AC97_AUX 1 |
10 | 10 | ||
11 | extern struct snd_soc_codec_dai wm9712_dai[2]; | 11 | extern struct snd_soc_dai wm9712_dai[2]; |
12 | extern struct snd_soc_codec_device soc_codec_dev_wm9712; | 12 | extern struct snd_soc_codec_device soc_codec_dev_wm9712; |
13 | 13 | ||
14 | #endif | 14 | #endif |
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index 1f241161445c..38d1fe0971fc 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c | |||
@@ -10,9 +10,6 @@ | |||
10 | * Free Software Foundation; either version 2 of the License, or (at your | 10 | * Free Software Foundation; either version 2 of the License, or (at your |
11 | * option) any later version. | 11 | * option) any later version. |
12 | * | 12 | * |
13 | * Revision history | ||
14 | * 4th Feb 2006 Initial version. | ||
15 | * | ||
16 | * Features:- | 13 | * Features:- |
17 | * | 14 | * |
18 | * o Support for AC97 Codec, Voice DAC and Aux DAC | 15 | * o Support for AC97 Codec, Voice DAC and Aux DAC |
@@ -456,7 +453,7 @@ SND_SOC_DAPM_INPUT("MIC2B"), | |||
456 | SND_SOC_DAPM_VMID("VMID"), | 453 | SND_SOC_DAPM_VMID("VMID"), |
457 | }; | 454 | }; |
458 | 455 | ||
459 | static const char *audio_map[][3] = { | 456 | static const struct snd_soc_dapm_route audio_map[] = { |
460 | /* left HP mixer */ | 457 | /* left HP mixer */ |
461 | {"Left HP Mixer", "PC Beep Playback Switch", "PCBEEP"}, | 458 | {"Left HP Mixer", "PC Beep Playback Switch", "PCBEEP"}, |
462 | {"Left HP Mixer", "Voice Playback Switch", "Voice DAC"}, | 459 | {"Left HP Mixer", "Voice Playback Switch", "Voice DAC"}, |
@@ -607,21 +604,14 @@ static const char *audio_map[][3] = { | |||
607 | {"Capture Mono Mux", "Stereo", "Capture Mixer"}, | 604 | {"Capture Mono Mux", "Stereo", "Capture Mixer"}, |
608 | {"Capture Mono Mux", "Left", "Left Capture Source"}, | 605 | {"Capture Mono Mux", "Left", "Left Capture Source"}, |
609 | {"Capture Mono Mux", "Right", "Right Capture Source"}, | 606 | {"Capture Mono Mux", "Right", "Right Capture Source"}, |
610 | |||
611 | {NULL, NULL, NULL}, | ||
612 | }; | 607 | }; |
613 | 608 | ||
614 | static int wm9713_add_widgets(struct snd_soc_codec *codec) | 609 | static int wm9713_add_widgets(struct snd_soc_codec *codec) |
615 | { | 610 | { |
616 | int i; | 611 | snd_soc_dapm_new_controls(codec, wm9713_dapm_widgets, |
617 | 612 | ARRAY_SIZE(wm9713_dapm_widgets)); | |
618 | for (i = 0; i < ARRAY_SIZE(wm9713_dapm_widgets); i++) | ||
619 | snd_soc_dapm_new_control(codec, &wm9713_dapm_widgets[i]); | ||
620 | 613 | ||
621 | /* set up audio path audio_mapnects */ | 614 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); |
622 | for (i = 0; audio_map[i][0] != NULL; i++) | ||
623 | snd_soc_dapm_connect_input(codec, audio_map[i][0], | ||
624 | audio_map[i][1], audio_map[i][2]); | ||
625 | 615 | ||
626 | snd_soc_dapm_new_widgets(codec); | 616 | snd_soc_dapm_new_widgets(codec); |
627 | return 0; | 617 | return 0; |
@@ -799,7 +789,7 @@ static int wm9713_set_pll(struct snd_soc_codec *codec, | |||
799 | return 0; | 789 | return 0; |
800 | } | 790 | } |
801 | 791 | ||
802 | static int wm9713_set_dai_pll(struct snd_soc_codec_dai *codec_dai, | 792 | static int wm9713_set_dai_pll(struct snd_soc_dai *codec_dai, |
803 | int pll_id, unsigned int freq_in, unsigned int freq_out) | 793 | int pll_id, unsigned int freq_in, unsigned int freq_out) |
804 | { | 794 | { |
805 | struct snd_soc_codec *codec = codec_dai->codec; | 795 | struct snd_soc_codec *codec = codec_dai->codec; |
@@ -810,7 +800,7 @@ static int wm9713_set_dai_pll(struct snd_soc_codec_dai *codec_dai, | |||
810 | * Tristate the PCM DAI lines, tristate can be disabled by calling | 800 | * Tristate the PCM DAI lines, tristate can be disabled by calling |
811 | * wm9713_set_dai_fmt() | 801 | * wm9713_set_dai_fmt() |
812 | */ | 802 | */ |
813 | static int wm9713_set_dai_tristate(struct snd_soc_codec_dai *codec_dai, | 803 | static int wm9713_set_dai_tristate(struct snd_soc_dai *codec_dai, |
814 | int tristate) | 804 | int tristate) |
815 | { | 805 | { |
816 | struct snd_soc_codec *codec = codec_dai->codec; | 806 | struct snd_soc_codec *codec = codec_dai->codec; |
@@ -826,7 +816,7 @@ static int wm9713_set_dai_tristate(struct snd_soc_codec_dai *codec_dai, | |||
826 | * Configure WM9713 clock dividers. | 816 | * Configure WM9713 clock dividers. |
827 | * Voice DAC needs 256 FS | 817 | * Voice DAC needs 256 FS |
828 | */ | 818 | */ |
829 | static int wm9713_set_dai_clkdiv(struct snd_soc_codec_dai *codec_dai, | 819 | static int wm9713_set_dai_clkdiv(struct snd_soc_dai *codec_dai, |
830 | int div_id, int div) | 820 | int div_id, int div) |
831 | { | 821 | { |
832 | struct snd_soc_codec *codec = codec_dai->codec; | 822 | struct snd_soc_codec *codec = codec_dai->codec; |
@@ -868,7 +858,7 @@ static int wm9713_set_dai_clkdiv(struct snd_soc_codec_dai *codec_dai, | |||
868 | return 0; | 858 | return 0; |
869 | } | 859 | } |
870 | 860 | ||
871 | static int wm9713_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | 861 | static int wm9713_set_dai_fmt(struct snd_soc_dai *codec_dai, |
872 | unsigned int fmt) | 862 | unsigned int fmt) |
873 | { | 863 | { |
874 | struct snd_soc_codec *codec = codec_dai->codec; | 864 | struct snd_soc_codec *codec = codec_dai->codec; |
@@ -886,7 +876,7 @@ static int wm9713_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | |||
886 | gpio |= 0x0018; | 876 | gpio |= 0x0018; |
887 | break; | 877 | break; |
888 | case SND_SOC_DAIFMT_CBS_CFS: | 878 | case SND_SOC_DAIFMT_CBS_CFS: |
889 | reg |= 0x0200; | 879 | reg |= 0x2000; |
890 | gpio |= 0x001a; | 880 | gpio |= 0x001a; |
891 | break; | 881 | break; |
892 | case SND_SOC_DAIFMT_CBS_CFM: | 882 | case SND_SOC_DAIFMT_CBS_CFM: |
@@ -1011,15 +1001,24 @@ static int ac97_aux_prepare(struct snd_pcm_substream *substream) | |||
1011 | return ac97_write(codec, AC97_PCM_SURR_DAC_RATE, runtime->rate); | 1001 | return ac97_write(codec, AC97_PCM_SURR_DAC_RATE, runtime->rate); |
1012 | } | 1002 | } |
1013 | 1003 | ||
1014 | #define WM9713_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | 1004 | #define WM9713_RATES (SNDRV_PCM_RATE_8000 | \ |
1015 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 |\ | 1005 | SNDRV_PCM_RATE_11025 | \ |
1016 | SNDRV_PCM_RATE_48000) | 1006 | SNDRV_PCM_RATE_22050 | \ |
1007 | SNDRV_PCM_RATE_44100 | \ | ||
1008 | SNDRV_PCM_RATE_48000) | ||
1009 | |||
1010 | #define WM9713_PCM_RATES (SNDRV_PCM_RATE_8000 | \ | ||
1011 | SNDRV_PCM_RATE_11025 | \ | ||
1012 | SNDRV_PCM_RATE_16000 | \ | ||
1013 | SNDRV_PCM_RATE_22050 | \ | ||
1014 | SNDRV_PCM_RATE_44100 | \ | ||
1015 | SNDRV_PCM_RATE_48000) | ||
1017 | 1016 | ||
1018 | #define WM9713_PCM_FORMATS \ | 1017 | #define WM9713_PCM_FORMATS \ |
1019 | (SNDRV_PCM_FORMAT_S16_LE | SNDRV_PCM_FORMAT_S20_3LE | \ | 1018 | (SNDRV_PCM_FORMAT_S16_LE | SNDRV_PCM_FORMAT_S20_3LE | \ |
1020 | SNDRV_PCM_FORMAT_S24_LE) | 1019 | SNDRV_PCM_FORMAT_S24_LE) |
1021 | 1020 | ||
1022 | struct snd_soc_codec_dai wm9713_dai[] = { | 1021 | struct snd_soc_dai wm9713_dai[] = { |
1023 | { | 1022 | { |
1024 | .name = "AC97 HiFi", | 1023 | .name = "AC97 HiFi", |
1025 | .type = SND_SOC_DAI_AC97_BUS, | 1024 | .type = SND_SOC_DAI_AC97_BUS, |
@@ -1061,13 +1060,13 @@ struct snd_soc_codec_dai wm9713_dai[] = { | |||
1061 | .stream_name = "Voice Playback", | 1060 | .stream_name = "Voice Playback", |
1062 | .channels_min = 1, | 1061 | .channels_min = 1, |
1063 | .channels_max = 1, | 1062 | .channels_max = 1, |
1064 | .rates = WM9713_RATES, | 1063 | .rates = WM9713_PCM_RATES, |
1065 | .formats = WM9713_PCM_FORMATS,}, | 1064 | .formats = WM9713_PCM_FORMATS,}, |
1066 | .capture = { | 1065 | .capture = { |
1067 | .stream_name = "Voice Capture", | 1066 | .stream_name = "Voice Capture", |
1068 | .channels_min = 1, | 1067 | .channels_min = 1, |
1069 | .channels_max = 2, | 1068 | .channels_max = 2, |
1070 | .rates = WM9713_RATES, | 1069 | .rates = WM9713_PCM_RATES, |
1071 | .formats = WM9713_PCM_FORMATS,}, | 1070 | .formats = WM9713_PCM_FORMATS,}, |
1072 | .ops = { | 1071 | .ops = { |
1073 | .hw_params = wm9713_pcm_hw_params, | 1072 | .hw_params = wm9713_pcm_hw_params, |
@@ -1086,44 +1085,44 @@ int wm9713_reset(struct snd_soc_codec *codec, int try_warm) | |||
1086 | { | 1085 | { |
1087 | if (try_warm && soc_ac97_ops.warm_reset) { | 1086 | if (try_warm && soc_ac97_ops.warm_reset) { |
1088 | soc_ac97_ops.warm_reset(codec->ac97); | 1087 | soc_ac97_ops.warm_reset(codec->ac97); |
1089 | if (!(ac97_read(codec, 0) & 0x8000)) | 1088 | if (ac97_read(codec, 0) == wm9713_reg[0]) |
1090 | return 1; | 1089 | return 1; |
1091 | } | 1090 | } |
1092 | 1091 | ||
1093 | soc_ac97_ops.reset(codec->ac97); | 1092 | soc_ac97_ops.reset(codec->ac97); |
1094 | if (ac97_read(codec, 0) & 0x8000) | 1093 | if (ac97_read(codec, 0) != wm9713_reg[0]) |
1095 | return -EIO; | 1094 | return -EIO; |
1096 | return 0; | 1095 | return 0; |
1097 | } | 1096 | } |
1098 | EXPORT_SYMBOL_GPL(wm9713_reset); | 1097 | EXPORT_SYMBOL_GPL(wm9713_reset); |
1099 | 1098 | ||
1100 | static int wm9713_dapm_event(struct snd_soc_codec *codec, int event) | 1099 | static int wm9713_set_bias_level(struct snd_soc_codec *codec, |
1100 | enum snd_soc_bias_level level) | ||
1101 | { | 1101 | { |
1102 | u16 reg; | 1102 | u16 reg; |
1103 | 1103 | ||
1104 | switch (event) { | 1104 | switch (level) { |
1105 | case SNDRV_CTL_POWER_D0: /* full On */ | 1105 | case SND_SOC_BIAS_ON: |
1106 | /* enable thermal shutdown */ | 1106 | /* enable thermal shutdown */ |
1107 | reg = ac97_read(codec, AC97_EXTENDED_MID) & 0x1bff; | 1107 | reg = ac97_read(codec, AC97_EXTENDED_MID) & 0x1bff; |
1108 | ac97_write(codec, AC97_EXTENDED_MID, reg); | 1108 | ac97_write(codec, AC97_EXTENDED_MID, reg); |
1109 | break; | 1109 | break; |
1110 | case SNDRV_CTL_POWER_D1: /* partial On */ | 1110 | case SND_SOC_BIAS_PREPARE: |
1111 | case SNDRV_CTL_POWER_D2: /* partial On */ | ||
1112 | break; | 1111 | break; |
1113 | case SNDRV_CTL_POWER_D3hot: /* Off, with power */ | 1112 | case SND_SOC_BIAS_STANDBY: |
1114 | /* enable master bias and vmid */ | 1113 | /* enable master bias and vmid */ |
1115 | reg = ac97_read(codec, AC97_EXTENDED_MID) & 0x3bff; | 1114 | reg = ac97_read(codec, AC97_EXTENDED_MID) & 0x3bff; |
1116 | ac97_write(codec, AC97_EXTENDED_MID, reg); | 1115 | ac97_write(codec, AC97_EXTENDED_MID, reg); |
1117 | ac97_write(codec, AC97_POWERDOWN, 0x0000); | 1116 | ac97_write(codec, AC97_POWERDOWN, 0x0000); |
1118 | break; | 1117 | break; |
1119 | case SNDRV_CTL_POWER_D3cold: /* Off, without power */ | 1118 | case SND_SOC_BIAS_OFF: |
1120 | /* disable everything including AC link */ | 1119 | /* disable everything including AC link */ |
1121 | ac97_write(codec, AC97_EXTENDED_MID, 0xffff); | 1120 | ac97_write(codec, AC97_EXTENDED_MID, 0xffff); |
1122 | ac97_write(codec, AC97_EXTENDED_MSTATUS, 0xffff); | 1121 | ac97_write(codec, AC97_EXTENDED_MSTATUS, 0xffff); |
1123 | ac97_write(codec, AC97_POWERDOWN, 0xffff); | 1122 | ac97_write(codec, AC97_POWERDOWN, 0xffff); |
1124 | break; | 1123 | break; |
1125 | } | 1124 | } |
1126 | codec->dapm_state = event; | 1125 | codec->bias_level = level; |
1127 | return 0; | 1126 | return 0; |
1128 | } | 1127 | } |
1129 | 1128 | ||
@@ -1160,7 +1159,7 @@ static int wm9713_soc_resume(struct platform_device *pdev) | |||
1160 | return ret; | 1159 | return ret; |
1161 | } | 1160 | } |
1162 | 1161 | ||
1163 | wm9713_dapm_event(codec, SNDRV_CTL_POWER_D3hot); | 1162 | wm9713_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
1164 | 1163 | ||
1165 | /* do we need to re-start the PLL ? */ | 1164 | /* do we need to re-start the PLL ? */ |
1166 | if (wm9713->pll_out) | 1165 | if (wm9713->pll_out) |
@@ -1176,8 +1175,8 @@ static int wm9713_soc_resume(struct platform_device *pdev) | |||
1176 | } | 1175 | } |
1177 | } | 1176 | } |
1178 | 1177 | ||
1179 | if (codec->suspend_dapm_state == SNDRV_CTL_POWER_D0) | 1178 | if (codec->suspend_bias_level == SND_SOC_BIAS_ON) |
1180 | wm9713_dapm_event(codec, SNDRV_CTL_POWER_D0); | 1179 | wm9713_set_bias_level(codec, SND_SOC_BIAS_ON); |
1181 | 1180 | ||
1182 | return ret; | 1181 | return ret; |
1183 | } | 1182 | } |
@@ -1216,7 +1215,7 @@ static int wm9713_soc_probe(struct platform_device *pdev) | |||
1216 | codec->num_dai = ARRAY_SIZE(wm9713_dai); | 1215 | codec->num_dai = ARRAY_SIZE(wm9713_dai); |
1217 | codec->write = ac97_write; | 1216 | codec->write = ac97_write; |
1218 | codec->read = ac97_read; | 1217 | codec->read = ac97_read; |
1219 | codec->dapm_event = wm9713_dapm_event; | 1218 | codec->set_bias_level = wm9713_set_bias_level; |
1220 | INIT_LIST_HEAD(&codec->dapm_widgets); | 1219 | INIT_LIST_HEAD(&codec->dapm_widgets); |
1221 | INIT_LIST_HEAD(&codec->dapm_paths); | 1220 | INIT_LIST_HEAD(&codec->dapm_paths); |
1222 | 1221 | ||
@@ -1238,7 +1237,7 @@ static int wm9713_soc_probe(struct platform_device *pdev) | |||
1238 | goto reset_err; | 1237 | goto reset_err; |
1239 | } | 1238 | } |
1240 | 1239 | ||
1241 | wm9713_dapm_event(codec, SNDRV_CTL_POWER_D3hot); | 1240 | wm9713_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
1242 | 1241 | ||
1243 | /* unmute the adc - move to kcontrol */ | 1242 | /* unmute the adc - move to kcontrol */ |
1244 | reg = ac97_read(codec, AC97_CD) & 0x7fff; | 1243 | reg = ac97_read(codec, AC97_CD) & 0x7fff; |
diff --git a/sound/soc/codecs/wm9713.h b/sound/soc/codecs/wm9713.h index d357b6c8134b..63b8d81756e3 100644 --- a/sound/soc/codecs/wm9713.h +++ b/sound/soc/codecs/wm9713.h | |||
@@ -46,7 +46,7 @@ | |||
46 | #define WM9713_DAI_PCM_VOICE 2 | 46 | #define WM9713_DAI_PCM_VOICE 2 |
47 | 47 | ||
48 | extern struct snd_soc_codec_device soc_codec_dev_wm9713; | 48 | extern struct snd_soc_codec_device soc_codec_dev_wm9713; |
49 | extern struct snd_soc_codec_dai wm9713_dai[3]; | 49 | extern struct snd_soc_dai wm9713_dai[3]; |
50 | 50 | ||
51 | int wm9713_reset(struct snd_soc_codec *codec, int try_warm); | 51 | int wm9713_reset(struct snd_soc_codec *codec, int try_warm); |
52 | 52 | ||