diff options
Diffstat (limited to 'sound')
48 files changed, 2432 insertions, 176 deletions
diff --git a/sound/soc/atmel/playpaq_wm8510.c b/sound/soc/atmel/playpaq_wm8510.c index 9eb610c2ba91..9df4c68ef000 100644 --- a/sound/soc/atmel/playpaq_wm8510.c +++ b/sound/soc/atmel/playpaq_wm8510.c | |||
@@ -268,7 +268,7 @@ static int playpaq_wm8510_hw_params(struct snd_pcm_substream *substream, | |||
268 | #endif /* CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE */ | 268 | #endif /* CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE */ |
269 | 269 | ||
270 | 270 | ||
271 | ret = snd_soc_dai_set_pll(codec_dai, 0, | 271 | ret = snd_soc_dai_set_pll(codec_dai, 0, 0, |
272 | clk_get_rate(CODEC_CLK), pll_out); | 272 | clk_get_rate(CODEC_CLK), pll_out); |
273 | if (ret < 0) { | 273 | if (ret < 0) { |
274 | pr_warning("playpaq_wm8510: Failed to set CODEC DAI PLL (%d)\n", | 274 | pr_warning("playpaq_wm8510: Failed to set CODEC DAI PLL (%d)\n", |
diff --git a/sound/soc/blackfin/bf5xx-ad1836.c b/sound/soc/blackfin/bf5xx-ad1836.c index cd361e304b0f..0f45a3f56be8 100644 --- a/sound/soc/blackfin/bf5xx-ad1836.c +++ b/sound/soc/blackfin/bf5xx-ad1836.c | |||
@@ -52,6 +52,7 @@ static int bf5xx_ad1836_hw_params(struct snd_pcm_substream *substream, | |||
52 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 52 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
53 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | 53 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
54 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; | 54 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; |
55 | unsigned int channel_map[] = {0, 4, 1, 5, 2, 6, 3, 7}; | ||
55 | int ret = 0; | 56 | int ret = 0; |
56 | /* set cpu DAI configuration */ | 57 | /* set cpu DAI configuration */ |
57 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A | | 58 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A | |
@@ -65,6 +66,12 @@ static int bf5xx_ad1836_hw_params(struct snd_pcm_substream *substream, | |||
65 | if (ret < 0) | 66 | if (ret < 0) |
66 | return ret; | 67 | return ret; |
67 | 68 | ||
69 | /* set cpu DAI channel mapping */ | ||
70 | ret = snd_soc_dai_set_channel_map(cpu_dai, ARRAY_SIZE(channel_map), | ||
71 | channel_map, ARRAY_SIZE(channel_map), channel_map); | ||
72 | if (ret < 0) | ||
73 | return ret; | ||
74 | |||
68 | return 0; | 75 | return 0; |
69 | } | 76 | } |
70 | 77 | ||
diff --git a/sound/soc/blackfin/bf5xx-ad1938.c b/sound/soc/blackfin/bf5xx-ad1938.c index 08269e91810c..2ef1e5013b8c 100644 --- a/sound/soc/blackfin/bf5xx-ad1938.c +++ b/sound/soc/blackfin/bf5xx-ad1938.c | |||
@@ -61,6 +61,7 @@ static int bf5xx_ad1938_hw_params(struct snd_pcm_substream *substream, | |||
61 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 61 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
62 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | 62 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
63 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; | 63 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; |
64 | unsigned int channel_map[] = {0, 1, 2, 3, 4, 5, 6, 7}; | ||
64 | int ret = 0; | 65 | int ret = 0; |
65 | /* set cpu DAI configuration */ | 66 | /* set cpu DAI configuration */ |
66 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A | | 67 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A | |
@@ -75,7 +76,13 @@ static int bf5xx_ad1938_hw_params(struct snd_pcm_substream *substream, | |||
75 | return ret; | 76 | return ret; |
76 | 77 | ||
77 | /* set codec DAI slots, 8 channels, all channels are enabled */ | 78 | /* set codec DAI slots, 8 channels, all channels are enabled */ |
78 | ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xFF, 8); | 79 | ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xFF, 0xFF, 8, 32); |
80 | if (ret < 0) | ||
81 | return ret; | ||
82 | |||
83 | /* set cpu DAI channel mapping */ | ||
84 | ret = snd_soc_dai_set_channel_map(cpu_dai, ARRAY_SIZE(channel_map), | ||
85 | channel_map, ARRAY_SIZE(channel_map), channel_map); | ||
79 | if (ret < 0) | 86 | if (ret < 0) |
80 | return ret; | 87 | return ret; |
81 | 88 | ||
diff --git a/sound/soc/blackfin/bf5xx-i2s.c b/sound/soc/blackfin/bf5xx-i2s.c index 084b68884ada..3e6ada0dd1c4 100644 --- a/sound/soc/blackfin/bf5xx-i2s.c +++ b/sound/soc/blackfin/bf5xx-i2s.c | |||
@@ -49,7 +49,6 @@ struct bf5xx_i2s_port { | |||
49 | u16 rcr1; | 49 | u16 rcr1; |
50 | u16 tcr2; | 50 | u16 tcr2; |
51 | u16 rcr2; | 51 | u16 rcr2; |
52 | int counter; | ||
53 | int configured; | 52 | int configured; |
54 | }; | 53 | }; |
55 | 54 | ||
@@ -133,16 +132,6 @@ static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, | |||
133 | return ret; | 132 | return ret; |
134 | } | 133 | } |
135 | 134 | ||
136 | static int bf5xx_i2s_startup(struct snd_pcm_substream *substream, | ||
137 | struct snd_soc_dai *dai) | ||
138 | { | ||
139 | pr_debug("%s enter\n", __func__); | ||
140 | |||
141 | /*this counter is used for counting how many pcm streams are opened*/ | ||
142 | bf5xx_i2s.counter++; | ||
143 | return 0; | ||
144 | } | ||
145 | |||
146 | static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream, | 135 | static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream, |
147 | struct snd_pcm_hw_params *params, | 136 | struct snd_pcm_hw_params *params, |
148 | struct snd_soc_dai *dai) | 137 | struct snd_soc_dai *dai) |
@@ -201,9 +190,8 @@ static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream, | |||
201 | struct snd_soc_dai *dai) | 190 | struct snd_soc_dai *dai) |
202 | { | 191 | { |
203 | pr_debug("%s enter\n", __func__); | 192 | pr_debug("%s enter\n", __func__); |
204 | bf5xx_i2s.counter--; | ||
205 | /* No active stream, SPORT is allowed to be configured again. */ | 193 | /* No active stream, SPORT is allowed to be configured again. */ |
206 | if (!bf5xx_i2s.counter) | 194 | if (!dai->active) |
207 | bf5xx_i2s.configured = 0; | 195 | bf5xx_i2s.configured = 0; |
208 | } | 196 | } |
209 | 197 | ||
@@ -284,7 +272,6 @@ static int bf5xx_i2s_resume(struct snd_soc_dai *dai) | |||
284 | SNDRV_PCM_FMTBIT_S32_LE) | 272 | SNDRV_PCM_FMTBIT_S32_LE) |
285 | 273 | ||
286 | static struct snd_soc_dai_ops bf5xx_i2s_dai_ops = { | 274 | static struct snd_soc_dai_ops bf5xx_i2s_dai_ops = { |
287 | .startup = bf5xx_i2s_startup, | ||
288 | .shutdown = bf5xx_i2s_shutdown, | 275 | .shutdown = bf5xx_i2s_shutdown, |
289 | .hw_params = bf5xx_i2s_hw_params, | 276 | .hw_params = bf5xx_i2s_hw_params, |
290 | .set_fmt = bf5xx_i2s_set_dai_fmt, | 277 | .set_fmt = bf5xx_i2s_set_dai_fmt, |
diff --git a/sound/soc/blackfin/bf5xx-tdm-pcm.c b/sound/soc/blackfin/bf5xx-tdm-pcm.c index ccb5e823bd18..a8c73cbbd685 100644 --- a/sound/soc/blackfin/bf5xx-tdm-pcm.c +++ b/sound/soc/blackfin/bf5xx-tdm-pcm.c | |||
@@ -43,7 +43,7 @@ | |||
43 | #include "bf5xx-tdm.h" | 43 | #include "bf5xx-tdm.h" |
44 | #include "bf5xx-sport.h" | 44 | #include "bf5xx-sport.h" |
45 | 45 | ||
46 | #define PCM_BUFFER_MAX 0x10000 | 46 | #define PCM_BUFFER_MAX 0x8000 |
47 | #define FRAGMENT_SIZE_MIN (4*1024) | 47 | #define FRAGMENT_SIZE_MIN (4*1024) |
48 | #define FRAGMENTS_MIN 2 | 48 | #define FRAGMENTS_MIN 2 |
49 | #define FRAGMENTS_MAX 32 | 49 | #define FRAGMENTS_MAX 32 |
@@ -177,6 +177,9 @@ out: | |||
177 | static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel, | 177 | static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel, |
178 | snd_pcm_uframes_t pos, void *buf, snd_pcm_uframes_t count) | 178 | snd_pcm_uframes_t pos, void *buf, snd_pcm_uframes_t count) |
179 | { | 179 | { |
180 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
181 | struct sport_device *sport = runtime->private_data; | ||
182 | struct bf5xx_tdm_port *tdm_port = sport->private_data; | ||
180 | unsigned int *src; | 183 | unsigned int *src; |
181 | unsigned int *dst; | 184 | unsigned int *dst; |
182 | int i; | 185 | int i; |
@@ -188,7 +191,7 @@ static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel, | |||
188 | dst += pos * 8; | 191 | dst += pos * 8; |
189 | while (count--) { | 192 | while (count--) { |
190 | for (i = 0; i < substream->runtime->channels; i++) | 193 | for (i = 0; i < substream->runtime->channels; i++) |
191 | *(dst + i) = *src++; | 194 | *(dst + tdm_port->tx_map[i]) = *src++; |
192 | dst += 8; | 195 | dst += 8; |
193 | } | 196 | } |
194 | } else { | 197 | } else { |
@@ -198,7 +201,7 @@ static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel, | |||
198 | src += pos * 8; | 201 | src += pos * 8; |
199 | while (count--) { | 202 | while (count--) { |
200 | for (i = 0; i < substream->runtime->channels; i++) | 203 | for (i = 0; i < substream->runtime->channels; i++) |
201 | *dst++ = *(src+i); | 204 | *dst++ = *(src + tdm_port->rx_map[i]); |
202 | src += 8; | 205 | src += 8; |
203 | } | 206 | } |
204 | } | 207 | } |
diff --git a/sound/soc/blackfin/bf5xx-tdm.c b/sound/soc/blackfin/bf5xx-tdm.c index ff546e91a22e..4b360124083e 100644 --- a/sound/soc/blackfin/bf5xx-tdm.c +++ b/sound/soc/blackfin/bf5xx-tdm.c | |||
@@ -46,14 +46,6 @@ | |||
46 | #include "bf5xx-sport.h" | 46 | #include "bf5xx-sport.h" |
47 | #include "bf5xx-tdm.h" | 47 | #include "bf5xx-tdm.h" |
48 | 48 | ||
49 | struct bf5xx_tdm_port { | ||
50 | u16 tcr1; | ||
51 | u16 rcr1; | ||
52 | u16 tcr2; | ||
53 | u16 rcr2; | ||
54 | int configured; | ||
55 | }; | ||
56 | |||
57 | static struct bf5xx_tdm_port bf5xx_tdm; | 49 | static struct bf5xx_tdm_port bf5xx_tdm; |
58 | static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM; | 50 | static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM; |
59 | 51 | ||
@@ -181,6 +173,40 @@ static void bf5xx_tdm_shutdown(struct snd_pcm_substream *substream, | |||
181 | bf5xx_tdm.configured = 0; | 173 | bf5xx_tdm.configured = 0; |
182 | } | 174 | } |
183 | 175 | ||
176 | static int bf5xx_tdm_set_channel_map(struct snd_soc_dai *dai, | ||
177 | unsigned int tx_num, unsigned int *tx_slot, | ||
178 | unsigned int rx_num, unsigned int *rx_slot) | ||
179 | { | ||
180 | int i; | ||
181 | unsigned int slot; | ||
182 | unsigned int tx_mapped = 0, rx_mapped = 0; | ||
183 | |||
184 | if ((tx_num > BFIN_TDM_DAI_MAX_SLOTS) || | ||
185 | (rx_num > BFIN_TDM_DAI_MAX_SLOTS)) | ||
186 | return -EINVAL; | ||
187 | |||
188 | for (i = 0; i < tx_num; i++) { | ||
189 | slot = tx_slot[i]; | ||
190 | if ((slot < BFIN_TDM_DAI_MAX_SLOTS) && | ||
191 | (!(tx_mapped & (1 << slot)))) { | ||
192 | bf5xx_tdm.tx_map[i] = slot; | ||
193 | tx_mapped |= 1 << slot; | ||
194 | } else | ||
195 | return -EINVAL; | ||
196 | } | ||
197 | for (i = 0; i < rx_num; i++) { | ||
198 | slot = rx_slot[i]; | ||
199 | if ((slot < BFIN_TDM_DAI_MAX_SLOTS) && | ||
200 | (!(rx_mapped & (1 << slot)))) { | ||
201 | bf5xx_tdm.rx_map[i] = slot; | ||
202 | rx_mapped |= 1 << slot; | ||
203 | } else | ||
204 | return -EINVAL; | ||
205 | } | ||
206 | |||
207 | return 0; | ||
208 | } | ||
209 | |||
184 | #ifdef CONFIG_PM | 210 | #ifdef CONFIG_PM |
185 | static int bf5xx_tdm_suspend(struct snd_soc_dai *dai) | 211 | static int bf5xx_tdm_suspend(struct snd_soc_dai *dai) |
186 | { | 212 | { |
@@ -235,6 +261,7 @@ static struct snd_soc_dai_ops bf5xx_tdm_dai_ops = { | |||
235 | .hw_params = bf5xx_tdm_hw_params, | 261 | .hw_params = bf5xx_tdm_hw_params, |
236 | .set_fmt = bf5xx_tdm_set_dai_fmt, | 262 | .set_fmt = bf5xx_tdm_set_dai_fmt, |
237 | .shutdown = bf5xx_tdm_shutdown, | 263 | .shutdown = bf5xx_tdm_shutdown, |
264 | .set_channel_map = bf5xx_tdm_set_channel_map, | ||
238 | }; | 265 | }; |
239 | 266 | ||
240 | struct snd_soc_dai bf5xx_tdm_dai = { | 267 | struct snd_soc_dai bf5xx_tdm_dai = { |
@@ -300,6 +327,8 @@ static int __devinit bfin_tdm_probe(struct platform_device *pdev) | |||
300 | pr_err("Failed to register DAI: %d\n", ret); | 327 | pr_err("Failed to register DAI: %d\n", ret); |
301 | goto sport_config_err; | 328 | goto sport_config_err; |
302 | } | 329 | } |
330 | |||
331 | sport_handle->private_data = &bf5xx_tdm; | ||
303 | return 0; | 332 | return 0; |
304 | 333 | ||
305 | sport_config_err: | 334 | sport_config_err: |
diff --git a/sound/soc/blackfin/bf5xx-tdm.h b/sound/soc/blackfin/bf5xx-tdm.h index 618ec3d90cd4..04189a18c1ba 100644 --- a/sound/soc/blackfin/bf5xx-tdm.h +++ b/sound/soc/blackfin/bf5xx-tdm.h | |||
@@ -9,6 +9,17 @@ | |||
9 | #ifndef _BF5XX_TDM_H | 9 | #ifndef _BF5XX_TDM_H |
10 | #define _BF5XX_TDM_H | 10 | #define _BF5XX_TDM_H |
11 | 11 | ||
12 | #define BFIN_TDM_DAI_MAX_SLOTS 8 | ||
13 | struct bf5xx_tdm_port { | ||
14 | u16 tcr1; | ||
15 | u16 rcr1; | ||
16 | u16 tcr2; | ||
17 | u16 rcr2; | ||
18 | unsigned int tx_map[BFIN_TDM_DAI_MAX_SLOTS]; | ||
19 | unsigned int rx_map[BFIN_TDM_DAI_MAX_SLOTS]; | ||
20 | int configured; | ||
21 | }; | ||
22 | |||
12 | extern struct snd_soc_dai bf5xx_tdm_dai; | 23 | extern struct snd_soc_dai bf5xx_tdm_dai; |
13 | 24 | ||
14 | #endif | 25 | #endif |
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 0edca93af3b0..3c46f34928ec 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig | |||
@@ -19,6 +19,7 @@ config SND_SOC_ALL_CODECS | |||
19 | select SND_SOC_AK4104 if SPI_MASTER | 19 | select SND_SOC_AK4104 if SPI_MASTER |
20 | select SND_SOC_AK4535 if I2C | 20 | select SND_SOC_AK4535 if I2C |
21 | select SND_SOC_AK4642 if I2C | 21 | select SND_SOC_AK4642 if I2C |
22 | select SND_SOC_AK4671 if I2C | ||
22 | select SND_SOC_CS4270 if I2C | 23 | select SND_SOC_CS4270 if I2C |
23 | select SND_SOC_MAX9877 if I2C | 24 | select SND_SOC_MAX9877 if I2C |
24 | select SND_SOC_PCM3008 | 25 | select SND_SOC_PCM3008 |
@@ -36,6 +37,7 @@ config SND_SOC_ALL_CODECS | |||
36 | select SND_SOC_WM8510 if SND_SOC_I2C_AND_SPI | 37 | select SND_SOC_WM8510 if SND_SOC_I2C_AND_SPI |
37 | select SND_SOC_WM8523 if I2C | 38 | select SND_SOC_WM8523 if I2C |
38 | select SND_SOC_WM8580 if I2C | 39 | select SND_SOC_WM8580 if I2C |
40 | select SND_SOC_WM8711 if SND_SOC_I2C_AND_SPI | ||
39 | select SND_SOC_WM8728 if SND_SOC_I2C_AND_SPI | 41 | select SND_SOC_WM8728 if SND_SOC_I2C_AND_SPI |
40 | select SND_SOC_WM8731 if SND_SOC_I2C_AND_SPI | 42 | select SND_SOC_WM8731 if SND_SOC_I2C_AND_SPI |
41 | select SND_SOC_WM8750 if SND_SOC_I2C_AND_SPI | 43 | select SND_SOC_WM8750 if SND_SOC_I2C_AND_SPI |
@@ -96,6 +98,9 @@ config SND_SOC_AK4535 | |||
96 | config SND_SOC_AK4642 | 98 | config SND_SOC_AK4642 |
97 | tristate | 99 | tristate |
98 | 100 | ||
101 | config SND_SOC_AK4671 | ||
102 | tristate | ||
103 | |||
99 | # Cirrus Logic CS4270 Codec | 104 | # Cirrus Logic CS4270 Codec |
100 | config SND_SOC_CS4270 | 105 | config SND_SOC_CS4270 |
101 | tristate | 106 | tristate |
@@ -160,6 +165,9 @@ config SND_SOC_WM8523 | |||
160 | config SND_SOC_WM8580 | 165 | config SND_SOC_WM8580 |
161 | tristate | 166 | tristate |
162 | 167 | ||
168 | config SND_SOC_WM8711 | ||
169 | tristate | ||
170 | |||
163 | config SND_SOC_WM8728 | 171 | config SND_SOC_WM8728 |
164 | tristate | 172 | tristate |
165 | 173 | ||
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index fb4af28486ba..fc1c458cbe2f 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile | |||
@@ -6,6 +6,7 @@ snd-soc-ad73311-objs := ad73311.o | |||
6 | snd-soc-ak4104-objs := ak4104.o | 6 | snd-soc-ak4104-objs := ak4104.o |
7 | snd-soc-ak4535-objs := ak4535.o | 7 | snd-soc-ak4535-objs := ak4535.o |
8 | snd-soc-ak4642-objs := ak4642.o | 8 | snd-soc-ak4642-objs := ak4642.o |
9 | snd-soc-ak4671-objs := ak4671.o | ||
9 | snd-soc-cs4270-objs := cs4270.o | 10 | snd-soc-cs4270-objs := cs4270.o |
10 | snd-soc-cx20442-objs := cx20442.o | 11 | snd-soc-cx20442-objs := cx20442.o |
11 | snd-soc-l3-objs := l3.o | 12 | snd-soc-l3-objs := l3.o |
@@ -24,6 +25,7 @@ snd-soc-wm8400-objs := wm8400.o | |||
24 | snd-soc-wm8510-objs := wm8510.o | 25 | snd-soc-wm8510-objs := wm8510.o |
25 | snd-soc-wm8523-objs := wm8523.o | 26 | snd-soc-wm8523-objs := wm8523.o |
26 | snd-soc-wm8580-objs := wm8580.o | 27 | snd-soc-wm8580-objs := wm8580.o |
28 | snd-soc-wm8711-objs := wm8711.o | ||
27 | snd-soc-wm8728-objs := wm8728.o | 29 | snd-soc-wm8728-objs := wm8728.o |
28 | snd-soc-wm8731-objs := wm8731.o | 30 | snd-soc-wm8731-objs := wm8731.o |
29 | snd-soc-wm8750-objs := wm8750.o | 31 | snd-soc-wm8750-objs := wm8750.o |
@@ -56,6 +58,7 @@ obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o | |||
56 | obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o | 58 | obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o |
57 | obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o | 59 | obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o |
58 | obj-$(CONFIG_SND_SOC_AK4642) += snd-soc-ak4642.o | 60 | obj-$(CONFIG_SND_SOC_AK4642) += snd-soc-ak4642.o |
61 | obj-$(CONFIG_SND_SOC_AK4671) += snd-soc-ak4671.o | ||
59 | obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o | 62 | obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o |
60 | obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o | 63 | obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o |
61 | obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o | 64 | obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o |
@@ -74,6 +77,7 @@ obj-$(CONFIG_SND_SOC_WM8400) += snd-soc-wm8400.o | |||
74 | obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o | 77 | obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o |
75 | obj-$(CONFIG_SND_SOC_WM8523) += snd-soc-wm8523.o | 78 | obj-$(CONFIG_SND_SOC_WM8523) += snd-soc-wm8523.o |
76 | obj-$(CONFIG_SND_SOC_WM8580) += snd-soc-wm8580.o | 79 | obj-$(CONFIG_SND_SOC_WM8580) += snd-soc-wm8580.o |
80 | obj-$(CONFIG_SND_SOC_WM8711) += snd-soc-wm8711.o | ||
77 | obj-$(CONFIG_SND_SOC_WM8728) += snd-soc-wm8728.o | 81 | obj-$(CONFIG_SND_SOC_WM8728) += snd-soc-wm8728.o |
78 | obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o | 82 | obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o |
79 | obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o | 83 | obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o |
diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c new file mode 100644 index 000000000000..b61214d1c5de --- /dev/null +++ b/sound/soc/codecs/ak4671.c | |||
@@ -0,0 +1,825 @@ | |||
1 | /* | ||
2 | * ak4671.c -- audio driver for AK4671 | ||
3 | * | ||
4 | * Copyright (C) 2009 Samsung Electronics Co.Ltd | ||
5 | * Author: Joonyoung Shim <jy0922.shim@samsung.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/i2c.h> | ||
17 | #include <linux/delay.h> | ||
18 | #include <sound/soc.h> | ||
19 | #include <sound/soc-dapm.h> | ||
20 | #include <sound/initval.h> | ||
21 | #include <sound/tlv.h> | ||
22 | |||
23 | #include "ak4671.h" | ||
24 | |||
25 | static struct snd_soc_codec *ak4671_codec; | ||
26 | |||
27 | /* codec private data */ | ||
28 | struct ak4671_priv { | ||
29 | struct snd_soc_codec codec; | ||
30 | u8 reg_cache[AK4671_CACHEREGNUM]; | ||
31 | }; | ||
32 | |||
33 | /* ak4671 register cache & default register settings */ | ||
34 | static const u8 ak4671_reg[AK4671_CACHEREGNUM] = { | ||
35 | 0x00, /* AK4671_AD_DA_POWER_MANAGEMENT (0x00) */ | ||
36 | 0xf6, /* AK4671_PLL_MODE_SELECT0 (0x01) */ | ||
37 | 0x00, /* AK4671_PLL_MODE_SELECT1 (0x02) */ | ||
38 | 0x02, /* AK4671_FORMAT_SELECT (0x03) */ | ||
39 | 0x00, /* AK4671_MIC_SIGNAL_SELECT (0x04) */ | ||
40 | 0x55, /* AK4671_MIC_AMP_GAIN (0x05) */ | ||
41 | 0x00, /* AK4671_MIXING_POWER_MANAGEMENT0 (0x06) */ | ||
42 | 0x00, /* AK4671_MIXING_POWER_MANAGEMENT1 (0x07) */ | ||
43 | 0xb5, /* AK4671_OUTPUT_VOLUME_CONTROL (0x08) */ | ||
44 | 0x00, /* AK4671_LOUT1_SIGNAL_SELECT (0x09) */ | ||
45 | 0x00, /* AK4671_ROUT1_SIGNAL_SELECT (0x0a) */ | ||
46 | 0x00, /* AK4671_LOUT2_SIGNAL_SELECT (0x0b) */ | ||
47 | 0x00, /* AK4671_ROUT2_SIGNAL_SELECT (0x0c) */ | ||
48 | 0x00, /* AK4671_LOUT3_SIGNAL_SELECT (0x0d) */ | ||
49 | 0x00, /* AK4671_ROUT3_SIGNAL_SELECT (0x0e) */ | ||
50 | 0x00, /* AK4671_LOUT1_POWER_MANAGERMENT (0x0f) */ | ||
51 | 0x00, /* AK4671_LOUT2_POWER_MANAGERMENT (0x10) */ | ||
52 | 0x80, /* AK4671_LOUT3_POWER_MANAGERMENT (0x11) */ | ||
53 | 0x91, /* AK4671_LCH_INPUT_VOLUME_CONTROL (0x12) */ | ||
54 | 0x91, /* AK4671_RCH_INPUT_VOLUME_CONTROL (0x13) */ | ||
55 | 0xe1, /* AK4671_ALC_REFERENCE_SELECT (0x14) */ | ||
56 | 0x00, /* AK4671_DIGITAL_MIXING_CONTROL (0x15) */ | ||
57 | 0x00, /* AK4671_ALC_TIMER_SELECT (0x16) */ | ||
58 | 0x00, /* AK4671_ALC_MODE_CONTROL (0x17) */ | ||
59 | 0x02, /* AK4671_MODE_CONTROL1 (0x18) */ | ||
60 | 0x01, /* AK4671_MODE_CONTROL2 (0x19) */ | ||
61 | 0x18, /* AK4671_LCH_OUTPUT_VOLUME_CONTROL (0x1a) */ | ||
62 | 0x18, /* AK4671_RCH_OUTPUT_VOLUME_CONTROL (0x1b) */ | ||
63 | 0x00, /* AK4671_SIDETONE_A_CONTROL (0x1c) */ | ||
64 | 0x02, /* AK4671_DIGITAL_FILTER_SELECT (0x1d) */ | ||
65 | 0x00, /* AK4671_FIL3_COEFFICIENT0 (0x1e) */ | ||
66 | 0x00, /* AK4671_FIL3_COEFFICIENT1 (0x1f) */ | ||
67 | 0x00, /* AK4671_FIL3_COEFFICIENT2 (0x20) */ | ||
68 | 0x00, /* AK4671_FIL3_COEFFICIENT3 (0x21) */ | ||
69 | 0x00, /* AK4671_EQ_COEFFICIENT0 (0x22) */ | ||
70 | 0x00, /* AK4671_EQ_COEFFICIENT1 (0x23) */ | ||
71 | 0x00, /* AK4671_EQ_COEFFICIENT2 (0x24) */ | ||
72 | 0x00, /* AK4671_EQ_COEFFICIENT3 (0x25) */ | ||
73 | 0x00, /* AK4671_EQ_COEFFICIENT4 (0x26) */ | ||
74 | 0x00, /* AK4671_EQ_COEFFICIENT5 (0x27) */ | ||
75 | 0xa9, /* AK4671_FIL1_COEFFICIENT0 (0x28) */ | ||
76 | 0x1f, /* AK4671_FIL1_COEFFICIENT1 (0x29) */ | ||
77 | 0xad, /* AK4671_FIL1_COEFFICIENT2 (0x2a) */ | ||
78 | 0x20, /* AK4671_FIL1_COEFFICIENT3 (0x2b) */ | ||
79 | 0x00, /* AK4671_FIL2_COEFFICIENT0 (0x2c) */ | ||
80 | 0x00, /* AK4671_FIL2_COEFFICIENT1 (0x2d) */ | ||
81 | 0x00, /* AK4671_FIL2_COEFFICIENT2 (0x2e) */ | ||
82 | 0x00, /* AK4671_FIL2_COEFFICIENT3 (0x2f) */ | ||
83 | 0x00, /* AK4671_DIGITAL_FILTER_SELECT2 (0x30) */ | ||
84 | 0x00, /* this register not used */ | ||
85 | 0x00, /* AK4671_E1_COEFFICIENT0 (0x32) */ | ||
86 | 0x00, /* AK4671_E1_COEFFICIENT1 (0x33) */ | ||
87 | 0x00, /* AK4671_E1_COEFFICIENT2 (0x34) */ | ||
88 | 0x00, /* AK4671_E1_COEFFICIENT3 (0x35) */ | ||
89 | 0x00, /* AK4671_E1_COEFFICIENT4 (0x36) */ | ||
90 | 0x00, /* AK4671_E1_COEFFICIENT5 (0x37) */ | ||
91 | 0x00, /* AK4671_E2_COEFFICIENT0 (0x38) */ | ||
92 | 0x00, /* AK4671_E2_COEFFICIENT1 (0x39) */ | ||
93 | 0x00, /* AK4671_E2_COEFFICIENT2 (0x3a) */ | ||
94 | 0x00, /* AK4671_E2_COEFFICIENT3 (0x3b) */ | ||
95 | 0x00, /* AK4671_E2_COEFFICIENT4 (0x3c) */ | ||
96 | 0x00, /* AK4671_E2_COEFFICIENT5 (0x3d) */ | ||
97 | 0x00, /* AK4671_E3_COEFFICIENT0 (0x3e) */ | ||
98 | 0x00, /* AK4671_E3_COEFFICIENT1 (0x3f) */ | ||
99 | 0x00, /* AK4671_E3_COEFFICIENT2 (0x40) */ | ||
100 | 0x00, /* AK4671_E3_COEFFICIENT3 (0x41) */ | ||
101 | 0x00, /* AK4671_E3_COEFFICIENT4 (0x42) */ | ||
102 | 0x00, /* AK4671_E3_COEFFICIENT5 (0x43) */ | ||
103 | 0x00, /* AK4671_E4_COEFFICIENT0 (0x44) */ | ||
104 | 0x00, /* AK4671_E4_COEFFICIENT1 (0x45) */ | ||
105 | 0x00, /* AK4671_E4_COEFFICIENT2 (0x46) */ | ||
106 | 0x00, /* AK4671_E4_COEFFICIENT3 (0x47) */ | ||
107 | 0x00, /* AK4671_E4_COEFFICIENT4 (0x48) */ | ||
108 | 0x00, /* AK4671_E4_COEFFICIENT5 (0x49) */ | ||
109 | 0x00, /* AK4671_E5_COEFFICIENT0 (0x4a) */ | ||
110 | 0x00, /* AK4671_E5_COEFFICIENT1 (0x4b) */ | ||
111 | 0x00, /* AK4671_E5_COEFFICIENT2 (0x4c) */ | ||
112 | 0x00, /* AK4671_E5_COEFFICIENT3 (0x4d) */ | ||
113 | 0x00, /* AK4671_E5_COEFFICIENT4 (0x4e) */ | ||
114 | 0x00, /* AK4671_E5_COEFFICIENT5 (0x4f) */ | ||
115 | 0x88, /* AK4671_EQ_CONTROL_250HZ_100HZ (0x50) */ | ||
116 | 0x88, /* AK4671_EQ_CONTROL_3500HZ_1KHZ (0x51) */ | ||
117 | 0x08, /* AK4671_EQ_CONTRO_10KHZ (0x52) */ | ||
118 | 0x00, /* AK4671_PCM_IF_CONTROL0 (0x53) */ | ||
119 | 0x00, /* AK4671_PCM_IF_CONTROL1 (0x54) */ | ||
120 | 0x00, /* AK4671_PCM_IF_CONTROL2 (0x55) */ | ||
121 | 0x18, /* AK4671_DIGITAL_VOLUME_B_CONTROL (0x56) */ | ||
122 | 0x18, /* AK4671_DIGITAL_VOLUME_C_CONTROL (0x57) */ | ||
123 | 0x00, /* AK4671_SIDETONE_VOLUME_CONTROL (0x58) */ | ||
124 | 0x00, /* AK4671_DIGITAL_MIXING_CONTROL2 (0x59) */ | ||
125 | 0x00, /* AK4671_SAR_ADC_CONTROL (0x5a) */ | ||
126 | }; | ||
127 | |||
128 | /* | ||
129 | * LOUT1/ROUT1 output volume control: | ||
130 | * from -24 to 6 dB in 6 dB steps (mute instead of -30 dB) | ||
131 | */ | ||
132 | static DECLARE_TLV_DB_SCALE(out1_tlv, -3000, 600, 1); | ||
133 | |||
134 | /* | ||
135 | * LOUT2/ROUT2 output volume control: | ||
136 | * from -33 to 6 dB in 3 dB steps (mute instead of -33 dB) | ||
137 | */ | ||
138 | static DECLARE_TLV_DB_SCALE(out2_tlv, -3300, 300, 1); | ||
139 | |||
140 | /* | ||
141 | * LOUT3/ROUT3 output volume control: | ||
142 | * from -6 to 3 dB in 3 dB steps | ||
143 | */ | ||
144 | static DECLARE_TLV_DB_SCALE(out3_tlv, -600, 300, 0); | ||
145 | |||
146 | /* | ||
147 | * Mic amp gain control: | ||
148 | * from -15 to 30 dB in 3 dB steps | ||
149 | * REVISIT: The actual min value(0x01) is -12 dB and the reg value 0x00 is not | ||
150 | * available | ||
151 | */ | ||
152 | static DECLARE_TLV_DB_SCALE(mic_amp_tlv, -1500, 300, 0); | ||
153 | |||
154 | static const struct snd_kcontrol_new ak4671_snd_controls[] = { | ||
155 | /* Common playback gain controls */ | ||
156 | SOC_SINGLE_TLV("Line Output1 Playback Volume", | ||
157 | AK4671_OUTPUT_VOLUME_CONTROL, 0, 0x6, 0, out1_tlv), | ||
158 | SOC_SINGLE_TLV("Headphone Output2 Playback Volume", | ||
159 | AK4671_OUTPUT_VOLUME_CONTROL, 4, 0xd, 0, out2_tlv), | ||
160 | SOC_SINGLE_TLV("Line Output3 Playback Volume", | ||
161 | AK4671_LOUT3_POWER_MANAGERMENT, 6, 0x3, 0, out3_tlv), | ||
162 | |||
163 | /* Common capture gain controls */ | ||
164 | SOC_DOUBLE_TLV("Mic Amp Capture Volume", | ||
165 | AK4671_MIC_AMP_GAIN, 0, 4, 0xf, 0, mic_amp_tlv), | ||
166 | }; | ||
167 | |||
168 | /* event handlers */ | ||
169 | static int ak4671_out2_event(struct snd_soc_dapm_widget *w, | ||
170 | struct snd_kcontrol *kcontrol, int event) | ||
171 | { | ||
172 | struct snd_soc_codec *codec = w->codec; | ||
173 | u8 reg; | ||
174 | |||
175 | switch (event) { | ||
176 | case SND_SOC_DAPM_POST_PMU: | ||
177 | reg = snd_soc_read(codec, AK4671_LOUT2_POWER_MANAGERMENT); | ||
178 | reg |= AK4671_MUTEN; | ||
179 | snd_soc_write(codec, AK4671_LOUT2_POWER_MANAGERMENT, reg); | ||
180 | break; | ||
181 | case SND_SOC_DAPM_PRE_PMD: | ||
182 | reg = snd_soc_read(codec, AK4671_LOUT2_POWER_MANAGERMENT); | ||
183 | reg &= ~AK4671_MUTEN; | ||
184 | snd_soc_write(codec, AK4671_LOUT2_POWER_MANAGERMENT, reg); | ||
185 | break; | ||
186 | } | ||
187 | |||
188 | return 0; | ||
189 | } | ||
190 | |||
191 | /* Output Mixers */ | ||
192 | static const struct snd_kcontrol_new ak4671_lout1_mixer_controls[] = { | ||
193 | SOC_DAPM_SINGLE("DACL", AK4671_LOUT1_SIGNAL_SELECT, 0, 1, 0), | ||
194 | SOC_DAPM_SINGLE("LINL1", AK4671_LOUT1_SIGNAL_SELECT, 1, 1, 0), | ||
195 | SOC_DAPM_SINGLE("LINL2", AK4671_LOUT1_SIGNAL_SELECT, 2, 1, 0), | ||
196 | SOC_DAPM_SINGLE("LINL3", AK4671_LOUT1_SIGNAL_SELECT, 3, 1, 0), | ||
197 | SOC_DAPM_SINGLE("LINL4", AK4671_LOUT1_SIGNAL_SELECT, 4, 1, 0), | ||
198 | SOC_DAPM_SINGLE("LOOPL", AK4671_LOUT1_SIGNAL_SELECT, 5, 1, 0), | ||
199 | }; | ||
200 | |||
201 | static const struct snd_kcontrol_new ak4671_rout1_mixer_controls[] = { | ||
202 | SOC_DAPM_SINGLE("DACR", AK4671_ROUT1_SIGNAL_SELECT, 0, 1, 0), | ||
203 | SOC_DAPM_SINGLE("RINR1", AK4671_ROUT1_SIGNAL_SELECT, 1, 1, 0), | ||
204 | SOC_DAPM_SINGLE("RINR2", AK4671_ROUT1_SIGNAL_SELECT, 2, 1, 0), | ||
205 | SOC_DAPM_SINGLE("RINR3", AK4671_ROUT1_SIGNAL_SELECT, 3, 1, 0), | ||
206 | SOC_DAPM_SINGLE("RINR4", AK4671_ROUT1_SIGNAL_SELECT, 4, 1, 0), | ||
207 | SOC_DAPM_SINGLE("LOOPR", AK4671_ROUT1_SIGNAL_SELECT, 5, 1, 0), | ||
208 | }; | ||
209 | |||
210 | static const struct snd_kcontrol_new ak4671_lout2_mixer_controls[] = { | ||
211 | SOC_DAPM_SINGLE("DACHL", AK4671_LOUT2_SIGNAL_SELECT, 0, 1, 0), | ||
212 | SOC_DAPM_SINGLE("LINH1", AK4671_LOUT2_SIGNAL_SELECT, 1, 1, 0), | ||
213 | SOC_DAPM_SINGLE("LINH2", AK4671_LOUT2_SIGNAL_SELECT, 2, 1, 0), | ||
214 | SOC_DAPM_SINGLE("LINH3", AK4671_LOUT2_SIGNAL_SELECT, 3, 1, 0), | ||
215 | SOC_DAPM_SINGLE("LINH4", AK4671_LOUT2_SIGNAL_SELECT, 4, 1, 0), | ||
216 | SOC_DAPM_SINGLE("LOOPHL", AK4671_LOUT2_SIGNAL_SELECT, 5, 1, 0), | ||
217 | }; | ||
218 | |||
219 | static const struct snd_kcontrol_new ak4671_rout2_mixer_controls[] = { | ||
220 | SOC_DAPM_SINGLE("DACHR", AK4671_ROUT2_SIGNAL_SELECT, 0, 1, 0), | ||
221 | SOC_DAPM_SINGLE("RINH1", AK4671_ROUT2_SIGNAL_SELECT, 1, 1, 0), | ||
222 | SOC_DAPM_SINGLE("RINH2", AK4671_ROUT2_SIGNAL_SELECT, 2, 1, 0), | ||
223 | SOC_DAPM_SINGLE("RINH3", AK4671_ROUT2_SIGNAL_SELECT, 3, 1, 0), | ||
224 | SOC_DAPM_SINGLE("RINH4", AK4671_ROUT2_SIGNAL_SELECT, 4, 1, 0), | ||
225 | SOC_DAPM_SINGLE("LOOPHR", AK4671_ROUT2_SIGNAL_SELECT, 5, 1, 0), | ||
226 | }; | ||
227 | |||
228 | static const struct snd_kcontrol_new ak4671_lout3_mixer_controls[] = { | ||
229 | SOC_DAPM_SINGLE("DACSL", AK4671_LOUT3_SIGNAL_SELECT, 0, 1, 0), | ||
230 | SOC_DAPM_SINGLE("LINS1", AK4671_LOUT3_SIGNAL_SELECT, 1, 1, 0), | ||
231 | SOC_DAPM_SINGLE("LINS2", AK4671_LOUT3_SIGNAL_SELECT, 2, 1, 0), | ||
232 | SOC_DAPM_SINGLE("LINS3", AK4671_LOUT3_SIGNAL_SELECT, 3, 1, 0), | ||
233 | SOC_DAPM_SINGLE("LINS4", AK4671_LOUT3_SIGNAL_SELECT, 4, 1, 0), | ||
234 | SOC_DAPM_SINGLE("LOOPSL", AK4671_LOUT3_SIGNAL_SELECT, 5, 1, 0), | ||
235 | }; | ||
236 | |||
237 | static const struct snd_kcontrol_new ak4671_rout3_mixer_controls[] = { | ||
238 | SOC_DAPM_SINGLE("DACSR", AK4671_ROUT3_SIGNAL_SELECT, 0, 1, 0), | ||
239 | SOC_DAPM_SINGLE("RINS1", AK4671_ROUT3_SIGNAL_SELECT, 1, 1, 0), | ||
240 | SOC_DAPM_SINGLE("RINS2", AK4671_ROUT3_SIGNAL_SELECT, 2, 1, 0), | ||
241 | SOC_DAPM_SINGLE("RINS3", AK4671_ROUT3_SIGNAL_SELECT, 3, 1, 0), | ||
242 | SOC_DAPM_SINGLE("RINS4", AK4671_ROUT3_SIGNAL_SELECT, 4, 1, 0), | ||
243 | SOC_DAPM_SINGLE("LOOPSR", AK4671_ROUT3_SIGNAL_SELECT, 5, 1, 0), | ||
244 | }; | ||
245 | |||
246 | /* Input MUXs */ | ||
247 | static const char *ak4671_lin_mux_texts[] = | ||
248 | {"LIN1", "LIN2", "LIN3", "LIN4"}; | ||
249 | static const struct soc_enum ak4671_lin_mux_enum = | ||
250 | SOC_ENUM_SINGLE(AK4671_MIC_SIGNAL_SELECT, 0, | ||
251 | ARRAY_SIZE(ak4671_lin_mux_texts), | ||
252 | ak4671_lin_mux_texts); | ||
253 | static const struct snd_kcontrol_new ak4671_lin_mux_control = | ||
254 | SOC_DAPM_ENUM("Route", ak4671_lin_mux_enum); | ||
255 | |||
256 | static const char *ak4671_rin_mux_texts[] = | ||
257 | {"RIN1", "RIN2", "RIN3", "RIN4"}; | ||
258 | static const struct soc_enum ak4671_rin_mux_enum = | ||
259 | SOC_ENUM_SINGLE(AK4671_MIC_SIGNAL_SELECT, 2, | ||
260 | ARRAY_SIZE(ak4671_rin_mux_texts), | ||
261 | ak4671_rin_mux_texts); | ||
262 | static const struct snd_kcontrol_new ak4671_rin_mux_control = | ||
263 | SOC_DAPM_ENUM("Route", ak4671_rin_mux_enum); | ||
264 | |||
265 | static const struct snd_soc_dapm_widget ak4671_dapm_widgets[] = { | ||
266 | /* Inputs */ | ||
267 | SND_SOC_DAPM_INPUT("LIN1"), | ||
268 | SND_SOC_DAPM_INPUT("RIN1"), | ||
269 | SND_SOC_DAPM_INPUT("LIN2"), | ||
270 | SND_SOC_DAPM_INPUT("RIN2"), | ||
271 | SND_SOC_DAPM_INPUT("LIN3"), | ||
272 | SND_SOC_DAPM_INPUT("RIN3"), | ||
273 | SND_SOC_DAPM_INPUT("LIN4"), | ||
274 | SND_SOC_DAPM_INPUT("RIN4"), | ||
275 | |||
276 | /* Outputs */ | ||
277 | SND_SOC_DAPM_OUTPUT("LOUT1"), | ||
278 | SND_SOC_DAPM_OUTPUT("ROUT1"), | ||
279 | SND_SOC_DAPM_OUTPUT("LOUT2"), | ||
280 | SND_SOC_DAPM_OUTPUT("ROUT2"), | ||
281 | SND_SOC_DAPM_OUTPUT("LOUT3"), | ||
282 | SND_SOC_DAPM_OUTPUT("ROUT3"), | ||
283 | |||
284 | /* DAC */ | ||
285 | SND_SOC_DAPM_DAC("DAC Left", "Left HiFi Playback", | ||
286 | AK4671_AD_DA_POWER_MANAGEMENT, 6, 0), | ||
287 | SND_SOC_DAPM_DAC("DAC Right", "Right HiFi Playback", | ||
288 | AK4671_AD_DA_POWER_MANAGEMENT, 7, 0), | ||
289 | |||
290 | /* ADC */ | ||
291 | SND_SOC_DAPM_ADC("ADC Left", "Left HiFi Capture", | ||
292 | AK4671_AD_DA_POWER_MANAGEMENT, 4, 0), | ||
293 | SND_SOC_DAPM_ADC("ADC Right", "Right HiFi Capture", | ||
294 | AK4671_AD_DA_POWER_MANAGEMENT, 5, 0), | ||
295 | |||
296 | /* PGA */ | ||
297 | SND_SOC_DAPM_PGA("LOUT2 Mix Amp", | ||
298 | AK4671_LOUT2_POWER_MANAGERMENT, 5, 0, NULL, 0), | ||
299 | SND_SOC_DAPM_PGA("ROUT2 Mix Amp", | ||
300 | AK4671_LOUT2_POWER_MANAGERMENT, 6, 0, NULL, 0), | ||
301 | |||
302 | SND_SOC_DAPM_PGA("LIN1 Mixing Circuit", | ||
303 | AK4671_MIXING_POWER_MANAGEMENT1, 0, 0, NULL, 0), | ||
304 | SND_SOC_DAPM_PGA("RIN1 Mixing Circuit", | ||
305 | AK4671_MIXING_POWER_MANAGEMENT1, 1, 0, NULL, 0), | ||
306 | SND_SOC_DAPM_PGA("LIN2 Mixing Circuit", | ||
307 | AK4671_MIXING_POWER_MANAGEMENT1, 2, 0, NULL, 0), | ||
308 | SND_SOC_DAPM_PGA("RIN2 Mixing Circuit", | ||
309 | AK4671_MIXING_POWER_MANAGEMENT1, 3, 0, NULL, 0), | ||
310 | SND_SOC_DAPM_PGA("LIN3 Mixing Circuit", | ||
311 | AK4671_MIXING_POWER_MANAGEMENT1, 4, 0, NULL, 0), | ||
312 | SND_SOC_DAPM_PGA("RIN3 Mixing Circuit", | ||
313 | AK4671_MIXING_POWER_MANAGEMENT1, 5, 0, NULL, 0), | ||
314 | SND_SOC_DAPM_PGA("LIN4 Mixing Circuit", | ||
315 | AK4671_MIXING_POWER_MANAGEMENT1, 6, 0, NULL, 0), | ||
316 | SND_SOC_DAPM_PGA("RIN4 Mixing Circuit", | ||
317 | AK4671_MIXING_POWER_MANAGEMENT1, 7, 0, NULL, 0), | ||
318 | |||
319 | /* Output Mixers */ | ||
320 | SND_SOC_DAPM_MIXER("LOUT1 Mixer", AK4671_LOUT1_POWER_MANAGERMENT, 0, 0, | ||
321 | &ak4671_lout1_mixer_controls[0], | ||
322 | ARRAY_SIZE(ak4671_lout1_mixer_controls)), | ||
323 | SND_SOC_DAPM_MIXER("ROUT1 Mixer", AK4671_LOUT1_POWER_MANAGERMENT, 1, 0, | ||
324 | &ak4671_rout1_mixer_controls[0], | ||
325 | ARRAY_SIZE(ak4671_rout1_mixer_controls)), | ||
326 | SND_SOC_DAPM_MIXER_E("LOUT2 Mixer", AK4671_LOUT2_POWER_MANAGERMENT, | ||
327 | 0, 0, &ak4671_lout2_mixer_controls[0], | ||
328 | ARRAY_SIZE(ak4671_lout2_mixer_controls), | ||
329 | ak4671_out2_event, | ||
330 | SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_PRE_PMD), | ||
331 | SND_SOC_DAPM_MIXER_E("ROUT2 Mixer", AK4671_LOUT2_POWER_MANAGERMENT, | ||
332 | 1, 0, &ak4671_rout2_mixer_controls[0], | ||
333 | ARRAY_SIZE(ak4671_rout2_mixer_controls), | ||
334 | ak4671_out2_event, | ||
335 | SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_PRE_PMD), | ||
336 | SND_SOC_DAPM_MIXER("LOUT3 Mixer", AK4671_LOUT3_POWER_MANAGERMENT, 0, 0, | ||
337 | &ak4671_lout3_mixer_controls[0], | ||
338 | ARRAY_SIZE(ak4671_lout3_mixer_controls)), | ||
339 | SND_SOC_DAPM_MIXER("ROUT3 Mixer", AK4671_LOUT3_POWER_MANAGERMENT, 1, 0, | ||
340 | &ak4671_rout3_mixer_controls[0], | ||
341 | ARRAY_SIZE(ak4671_rout3_mixer_controls)), | ||
342 | |||
343 | /* Input MUXs */ | ||
344 | SND_SOC_DAPM_MUX("LIN MUX", AK4671_AD_DA_POWER_MANAGEMENT, 2, 0, | ||
345 | &ak4671_lin_mux_control), | ||
346 | SND_SOC_DAPM_MUX("RIN MUX", AK4671_AD_DA_POWER_MANAGEMENT, 3, 0, | ||
347 | &ak4671_rin_mux_control), | ||
348 | |||
349 | /* Mic Power */ | ||
350 | SND_SOC_DAPM_MICBIAS("Mic Bias", AK4671_AD_DA_POWER_MANAGEMENT, 1, 0), | ||
351 | |||
352 | /* Supply */ | ||
353 | SND_SOC_DAPM_SUPPLY("PMPLL", AK4671_PLL_MODE_SELECT1, 0, 0, NULL, 0), | ||
354 | }; | ||
355 | |||
356 | static const struct snd_soc_dapm_route intercon[] = { | ||
357 | {"DAC Left", "NULL", "PMPLL"}, | ||
358 | {"DAC Right", "NULL", "PMPLL"}, | ||
359 | {"ADC Left", "NULL", "PMPLL"}, | ||
360 | {"ADC Right", "NULL", "PMPLL"}, | ||
361 | |||
362 | /* Outputs */ | ||
363 | {"LOUT1", "NULL", "LOUT1 Mixer"}, | ||
364 | {"ROUT1", "NULL", "ROUT1 Mixer"}, | ||
365 | {"LOUT2", "NULL", "LOUT2 Mix Amp"}, | ||
366 | {"ROUT2", "NULL", "ROUT2 Mix Amp"}, | ||
367 | {"LOUT3", "NULL", "LOUT3 Mixer"}, | ||
368 | {"ROUT3", "NULL", "ROUT3 Mixer"}, | ||
369 | |||
370 | {"LOUT1 Mixer", "DACL", "DAC Left"}, | ||
371 | {"ROUT1 Mixer", "DACR", "DAC Right"}, | ||
372 | {"LOUT2 Mixer", "DACHL", "DAC Left"}, | ||
373 | {"ROUT2 Mixer", "DACHR", "DAC Right"}, | ||
374 | {"LOUT2 Mix Amp", "NULL", "LOUT2 Mixer"}, | ||
375 | {"ROUT2 Mix Amp", "NULL", "ROUT2 Mixer"}, | ||
376 | {"LOUT3 Mixer", "DACSL", "DAC Left"}, | ||
377 | {"ROUT3 Mixer", "DACSR", "DAC Right"}, | ||
378 | |||
379 | /* Inputs */ | ||
380 | {"LIN MUX", "LIN1", "LIN1"}, | ||
381 | {"LIN MUX", "LIN2", "LIN2"}, | ||
382 | {"LIN MUX", "LIN3", "LIN3"}, | ||
383 | {"LIN MUX", "LIN4", "LIN4"}, | ||
384 | |||
385 | {"RIN MUX", "RIN1", "RIN1"}, | ||
386 | {"RIN MUX", "RIN2", "RIN2"}, | ||
387 | {"RIN MUX", "RIN3", "RIN3"}, | ||
388 | {"RIN MUX", "RIN4", "RIN4"}, | ||
389 | |||
390 | {"LIN1", NULL, "Mic Bias"}, | ||
391 | {"RIN1", NULL, "Mic Bias"}, | ||
392 | {"LIN2", NULL, "Mic Bias"}, | ||
393 | {"RIN2", NULL, "Mic Bias"}, | ||
394 | |||
395 | {"ADC Left", "NULL", "LIN MUX"}, | ||
396 | {"ADC Right", "NULL", "RIN MUX"}, | ||
397 | |||
398 | /* Analog Loops */ | ||
399 | {"LIN1 Mixing Circuit", "NULL", "LIN1"}, | ||
400 | {"RIN1 Mixing Circuit", "NULL", "RIN1"}, | ||
401 | {"LIN2 Mixing Circuit", "NULL", "LIN2"}, | ||
402 | {"RIN2 Mixing Circuit", "NULL", "RIN2"}, | ||
403 | {"LIN3 Mixing Circuit", "NULL", "LIN3"}, | ||
404 | {"RIN3 Mixing Circuit", "NULL", "RIN3"}, | ||
405 | {"LIN4 Mixing Circuit", "NULL", "LIN4"}, | ||
406 | {"RIN4 Mixing Circuit", "NULL", "RIN4"}, | ||
407 | |||
408 | {"LOUT1 Mixer", "LINL1", "LIN1 Mixing Circuit"}, | ||
409 | {"ROUT1 Mixer", "RINR1", "RIN1 Mixing Circuit"}, | ||
410 | {"LOUT2 Mixer", "LINH1", "LIN1 Mixing Circuit"}, | ||
411 | {"ROUT2 Mixer", "RINH1", "RIN1 Mixing Circuit"}, | ||
412 | {"LOUT3 Mixer", "LINS1", "LIN1 Mixing Circuit"}, | ||
413 | {"ROUT3 Mixer", "RINS1", "RIN1 Mixing Circuit"}, | ||
414 | |||
415 | {"LOUT1 Mixer", "LINL2", "LIN2 Mixing Circuit"}, | ||
416 | {"ROUT1 Mixer", "RINR2", "RIN2 Mixing Circuit"}, | ||
417 | {"LOUT2 Mixer", "LINH2", "LIN2 Mixing Circuit"}, | ||
418 | {"ROUT2 Mixer", "RINH2", "RIN2 Mixing Circuit"}, | ||
419 | {"LOUT3 Mixer", "LINS2", "LIN2 Mixing Circuit"}, | ||
420 | {"ROUT3 Mixer", "RINS2", "RIN2 Mixing Circuit"}, | ||
421 | |||
422 | {"LOUT1 Mixer", "LINL3", "LIN3 Mixing Circuit"}, | ||
423 | {"ROUT1 Mixer", "RINR3", "RIN3 Mixing Circuit"}, | ||
424 | {"LOUT2 Mixer", "LINH3", "LIN3 Mixing Circuit"}, | ||
425 | {"ROUT2 Mixer", "RINH3", "RIN3 Mixing Circuit"}, | ||
426 | {"LOUT3 Mixer", "LINS3", "LIN3 Mixing Circuit"}, | ||
427 | {"ROUT3 Mixer", "RINS3", "RIN3 Mixing Circuit"}, | ||
428 | |||
429 | {"LOUT1 Mixer", "LINL4", "LIN4 Mixing Circuit"}, | ||
430 | {"ROUT1 Mixer", "RINR4", "RIN4 Mixing Circuit"}, | ||
431 | {"LOUT2 Mixer", "LINH4", "LIN4 Mixing Circuit"}, | ||
432 | {"ROUT2 Mixer", "RINH4", "RIN4 Mixing Circuit"}, | ||
433 | {"LOUT3 Mixer", "LINS4", "LIN4 Mixing Circuit"}, | ||
434 | {"ROUT3 Mixer", "RINS4", "RIN4 Mixing Circuit"}, | ||
435 | }; | ||
436 | |||
437 | static int ak4671_add_widgets(struct snd_soc_codec *codec) | ||
438 | { | ||
439 | snd_soc_dapm_new_controls(codec, ak4671_dapm_widgets, | ||
440 | ARRAY_SIZE(ak4671_dapm_widgets)); | ||
441 | |||
442 | snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); | ||
443 | |||
444 | snd_soc_dapm_new_widgets(codec); | ||
445 | return 0; | ||
446 | } | ||
447 | |||
448 | static int ak4671_hw_params(struct snd_pcm_substream *substream, | ||
449 | struct snd_pcm_hw_params *params, | ||
450 | struct snd_soc_dai *dai) | ||
451 | { | ||
452 | struct snd_soc_codec *codec = dai->codec; | ||
453 | u8 fs; | ||
454 | |||
455 | fs = snd_soc_read(codec, AK4671_PLL_MODE_SELECT0); | ||
456 | fs &= ~AK4671_FS; | ||
457 | |||
458 | switch (params_rate(params)) { | ||
459 | case 8000: | ||
460 | fs |= AK4671_FS_8KHZ; | ||
461 | break; | ||
462 | case 12000: | ||
463 | fs |= AK4671_FS_12KHZ; | ||
464 | break; | ||
465 | case 16000: | ||
466 | fs |= AK4671_FS_16KHZ; | ||
467 | break; | ||
468 | case 24000: | ||
469 | fs |= AK4671_FS_24KHZ; | ||
470 | break; | ||
471 | case 11025: | ||
472 | fs |= AK4671_FS_11_025KHZ; | ||
473 | break; | ||
474 | case 22050: | ||
475 | fs |= AK4671_FS_22_05KHZ; | ||
476 | break; | ||
477 | case 32000: | ||
478 | fs |= AK4671_FS_32KHZ; | ||
479 | break; | ||
480 | case 44100: | ||
481 | fs |= AK4671_FS_44_1KHZ; | ||
482 | break; | ||
483 | case 48000: | ||
484 | fs |= AK4671_FS_48KHZ; | ||
485 | break; | ||
486 | default: | ||
487 | return -EINVAL; | ||
488 | } | ||
489 | |||
490 | snd_soc_write(codec, AK4671_PLL_MODE_SELECT0, fs); | ||
491 | |||
492 | return 0; | ||
493 | } | ||
494 | |||
495 | static int ak4671_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, | ||
496 | unsigned int freq, int dir) | ||
497 | { | ||
498 | struct snd_soc_codec *codec = dai->codec; | ||
499 | u8 pll; | ||
500 | |||
501 | pll = snd_soc_read(codec, AK4671_PLL_MODE_SELECT0); | ||
502 | pll &= ~AK4671_PLL; | ||
503 | |||
504 | switch (freq) { | ||
505 | case 11289600: | ||
506 | pll |= AK4671_PLL_11_2896MHZ; | ||
507 | break; | ||
508 | case 12000000: | ||
509 | pll |= AK4671_PLL_12MHZ; | ||
510 | break; | ||
511 | case 12288000: | ||
512 | pll |= AK4671_PLL_12_288MHZ; | ||
513 | break; | ||
514 | case 13000000: | ||
515 | pll |= AK4671_PLL_13MHZ; | ||
516 | break; | ||
517 | case 13500000: | ||
518 | pll |= AK4671_PLL_13_5MHZ; | ||
519 | break; | ||
520 | case 19200000: | ||
521 | pll |= AK4671_PLL_19_2MHZ; | ||
522 | break; | ||
523 | case 24000000: | ||
524 | pll |= AK4671_PLL_24MHZ; | ||
525 | break; | ||
526 | case 26000000: | ||
527 | pll |= AK4671_PLL_26MHZ; | ||
528 | break; | ||
529 | case 27000000: | ||
530 | pll |= AK4671_PLL_27MHZ; | ||
531 | break; | ||
532 | default: | ||
533 | return -EINVAL; | ||
534 | } | ||
535 | |||
536 | snd_soc_write(codec, AK4671_PLL_MODE_SELECT0, pll); | ||
537 | |||
538 | return 0; | ||
539 | } | ||
540 | |||
541 | static int ak4671_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) | ||
542 | { | ||
543 | struct snd_soc_codec *codec = dai->codec; | ||
544 | u8 mode; | ||
545 | u8 format; | ||
546 | |||
547 | /* set master/slave audio interface */ | ||
548 | mode = snd_soc_read(codec, AK4671_PLL_MODE_SELECT1); | ||
549 | |||
550 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
551 | case SND_SOC_DAIFMT_CBM_CFM: | ||
552 | mode |= AK4671_M_S; | ||
553 | break; | ||
554 | case SND_SOC_DAIFMT_CBM_CFS: | ||
555 | mode &= ~(AK4671_M_S); | ||
556 | break; | ||
557 | default: | ||
558 | return -EINVAL; | ||
559 | } | ||
560 | |||
561 | /* interface format */ | ||
562 | format = snd_soc_read(codec, AK4671_FORMAT_SELECT); | ||
563 | format &= ~AK4671_DIF; | ||
564 | |||
565 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
566 | case SND_SOC_DAIFMT_I2S: | ||
567 | format |= AK4671_DIF_I2S_MODE; | ||
568 | break; | ||
569 | case SND_SOC_DAIFMT_LEFT_J: | ||
570 | format |= AK4671_DIF_MSB_MODE; | ||
571 | break; | ||
572 | case SND_SOC_DAIFMT_DSP_A: | ||
573 | format |= AK4671_DIF_DSP_MODE; | ||
574 | format |= AK4671_BCKP; | ||
575 | format |= AK4671_MSBS; | ||
576 | break; | ||
577 | default: | ||
578 | return -EINVAL; | ||
579 | } | ||
580 | |||
581 | /* set mode and format */ | ||
582 | snd_soc_write(codec, AK4671_PLL_MODE_SELECT1, mode); | ||
583 | snd_soc_write(codec, AK4671_FORMAT_SELECT, format); | ||
584 | |||
585 | return 0; | ||
586 | } | ||
587 | |||
588 | static int ak4671_set_bias_level(struct snd_soc_codec *codec, | ||
589 | enum snd_soc_bias_level level) | ||
590 | { | ||
591 | u8 reg; | ||
592 | |||
593 | switch (level) { | ||
594 | case SND_SOC_BIAS_ON: | ||
595 | case SND_SOC_BIAS_PREPARE: | ||
596 | case SND_SOC_BIAS_STANDBY: | ||
597 | reg = snd_soc_read(codec, AK4671_AD_DA_POWER_MANAGEMENT); | ||
598 | snd_soc_write(codec, AK4671_AD_DA_POWER_MANAGEMENT, | ||
599 | reg | AK4671_PMVCM); | ||
600 | break; | ||
601 | case SND_SOC_BIAS_OFF: | ||
602 | snd_soc_write(codec, AK4671_AD_DA_POWER_MANAGEMENT, 0x00); | ||
603 | break; | ||
604 | } | ||
605 | codec->bias_level = level; | ||
606 | return 0; | ||
607 | } | ||
608 | |||
609 | #define AK4671_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | ||
610 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ | ||
611 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\ | ||
612 | SNDRV_PCM_RATE_48000) | ||
613 | |||
614 | #define AK4671_FORMATS SNDRV_PCM_FMTBIT_S16_LE | ||
615 | |||
616 | static struct snd_soc_dai_ops ak4671_dai_ops = { | ||
617 | .hw_params = ak4671_hw_params, | ||
618 | .set_sysclk = ak4671_set_dai_sysclk, | ||
619 | .set_fmt = ak4671_set_dai_fmt, | ||
620 | }; | ||
621 | |||
622 | struct snd_soc_dai ak4671_dai = { | ||
623 | .name = "AK4671", | ||
624 | .playback = { | ||
625 | .stream_name = "Playback", | ||
626 | .channels_min = 1, | ||
627 | .channels_max = 2, | ||
628 | .rates = AK4671_RATES, | ||
629 | .formats = AK4671_FORMATS,}, | ||
630 | .capture = { | ||
631 | .stream_name = "Capture", | ||
632 | .channels_min = 1, | ||
633 | .channels_max = 2, | ||
634 | .rates = AK4671_RATES, | ||
635 | .formats = AK4671_FORMATS,}, | ||
636 | .ops = &ak4671_dai_ops, | ||
637 | }; | ||
638 | EXPORT_SYMBOL_GPL(ak4671_dai); | ||
639 | |||
640 | static int ak4671_probe(struct platform_device *pdev) | ||
641 | { | ||
642 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
643 | struct snd_soc_codec *codec; | ||
644 | int ret = 0; | ||
645 | |||
646 | if (ak4671_codec == NULL) { | ||
647 | dev_err(&pdev->dev, "Codec device not registered\n"); | ||
648 | return -ENODEV; | ||
649 | } | ||
650 | |||
651 | socdev->card->codec = ak4671_codec; | ||
652 | codec = ak4671_codec; | ||
653 | |||
654 | /* register pcms */ | ||
655 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
656 | if (ret < 0) { | ||
657 | dev_err(codec->dev, "failed to create pcms: %d\n", ret); | ||
658 | goto pcm_err; | ||
659 | } | ||
660 | |||
661 | snd_soc_add_controls(codec, ak4671_snd_controls, | ||
662 | ARRAY_SIZE(ak4671_snd_controls)); | ||
663 | ak4671_add_widgets(codec); | ||
664 | |||
665 | ret = snd_soc_init_card(socdev); | ||
666 | if (ret < 0) { | ||
667 | dev_err(codec->dev, "failed to register card: %d\n", ret); | ||
668 | goto card_err; | ||
669 | } | ||
670 | |||
671 | ak4671_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
672 | |||
673 | return ret; | ||
674 | |||
675 | card_err: | ||
676 | snd_soc_free_pcms(socdev); | ||
677 | snd_soc_dapm_free(socdev); | ||
678 | pcm_err: | ||
679 | return ret; | ||
680 | } | ||
681 | |||
682 | static int ak4671_remove(struct platform_device *pdev) | ||
683 | { | ||
684 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
685 | |||
686 | snd_soc_free_pcms(socdev); | ||
687 | snd_soc_dapm_free(socdev); | ||
688 | |||
689 | return 0; | ||
690 | } | ||
691 | |||
692 | struct snd_soc_codec_device soc_codec_dev_ak4671 = { | ||
693 | .probe = ak4671_probe, | ||
694 | .remove = ak4671_remove, | ||
695 | }; | ||
696 | EXPORT_SYMBOL_GPL(soc_codec_dev_ak4671); | ||
697 | |||
698 | static int ak4671_register(struct ak4671_priv *ak4671, | ||
699 | enum snd_soc_control_type control) | ||
700 | { | ||
701 | int ret; | ||
702 | struct snd_soc_codec *codec = &ak4671->codec; | ||
703 | |||
704 | if (ak4671_codec) { | ||
705 | dev_err(codec->dev, "Another AK4671 is registered\n"); | ||
706 | ret = -EINVAL; | ||
707 | goto err; | ||
708 | } | ||
709 | |||
710 | mutex_init(&codec->mutex); | ||
711 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
712 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
713 | |||
714 | codec->private_data = ak4671; | ||
715 | codec->name = "AK4671"; | ||
716 | codec->owner = THIS_MODULE; | ||
717 | codec->bias_level = SND_SOC_BIAS_OFF; | ||
718 | codec->set_bias_level = ak4671_set_bias_level; | ||
719 | codec->dai = &ak4671_dai; | ||
720 | codec->num_dai = 1; | ||
721 | codec->reg_cache_size = AK4671_CACHEREGNUM; | ||
722 | codec->reg_cache = &ak4671->reg_cache; | ||
723 | |||
724 | memcpy(codec->reg_cache, ak4671_reg, sizeof(ak4671_reg)); | ||
725 | |||
726 | ret = snd_soc_codec_set_cache_io(codec, 8, 8, control); | ||
727 | if (ret < 0) { | ||
728 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | ||
729 | goto err; | ||
730 | } | ||
731 | |||
732 | ak4671_dai.dev = codec->dev; | ||
733 | ak4671_codec = codec; | ||
734 | |||
735 | ret = snd_soc_register_codec(codec); | ||
736 | if (ret != 0) { | ||
737 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | ||
738 | goto err; | ||
739 | } | ||
740 | |||
741 | ret = snd_soc_register_dai(&ak4671_dai); | ||
742 | if (ret != 0) { | ||
743 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); | ||
744 | goto err_codec; | ||
745 | } | ||
746 | |||
747 | return 0; | ||
748 | |||
749 | err_codec: | ||
750 | snd_soc_unregister_codec(codec); | ||
751 | err: | ||
752 | kfree(ak4671); | ||
753 | return ret; | ||
754 | } | ||
755 | |||
756 | static void ak4671_unregister(struct ak4671_priv *ak4671) | ||
757 | { | ||
758 | ak4671_set_bias_level(&ak4671->codec, SND_SOC_BIAS_OFF); | ||
759 | snd_soc_unregister_dai(&ak4671_dai); | ||
760 | snd_soc_unregister_codec(&ak4671->codec); | ||
761 | kfree(ak4671); | ||
762 | ak4671_codec = NULL; | ||
763 | } | ||
764 | |||
765 | static int __devinit ak4671_i2c_probe(struct i2c_client *client, | ||
766 | const struct i2c_device_id *id) | ||
767 | { | ||
768 | struct ak4671_priv *ak4671; | ||
769 | struct snd_soc_codec *codec; | ||
770 | |||
771 | ak4671 = kzalloc(sizeof(struct ak4671_priv), GFP_KERNEL); | ||
772 | if (ak4671 == NULL) | ||
773 | return -ENOMEM; | ||
774 | |||
775 | codec = &ak4671->codec; | ||
776 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
777 | |||
778 | i2c_set_clientdata(client, ak4671); | ||
779 | codec->control_data = client; | ||
780 | |||
781 | codec->dev = &client->dev; | ||
782 | |||
783 | return ak4671_register(ak4671, SND_SOC_I2C); | ||
784 | } | ||
785 | |||
786 | static __devexit int ak4671_i2c_remove(struct i2c_client *client) | ||
787 | { | ||
788 | struct ak4671_priv *ak4671 = i2c_get_clientdata(client); | ||
789 | |||
790 | ak4671_unregister(ak4671); | ||
791 | |||
792 | return 0; | ||
793 | } | ||
794 | |||
795 | static const struct i2c_device_id ak4671_i2c_id[] = { | ||
796 | { "ak4671", 0 }, | ||
797 | { } | ||
798 | }; | ||
799 | MODULE_DEVICE_TABLE(i2c, ak4671_i2c_id); | ||
800 | |||
801 | static struct i2c_driver ak4671_i2c_driver = { | ||
802 | .driver = { | ||
803 | .name = "ak4671", | ||
804 | .owner = THIS_MODULE, | ||
805 | }, | ||
806 | .probe = ak4671_i2c_probe, | ||
807 | .remove = __devexit_p(ak4671_i2c_remove), | ||
808 | .id_table = ak4671_i2c_id, | ||
809 | }; | ||
810 | |||
811 | static int __init ak4671_modinit(void) | ||
812 | { | ||
813 | return i2c_add_driver(&ak4671_i2c_driver); | ||
814 | } | ||
815 | module_init(ak4671_modinit); | ||
816 | |||
817 | static void __exit ak4671_exit(void) | ||
818 | { | ||
819 | i2c_del_driver(&ak4671_i2c_driver); | ||
820 | } | ||
821 | module_exit(ak4671_exit); | ||
822 | |||
823 | MODULE_DESCRIPTION("ASoC AK4671 codec driver"); | ||
824 | MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>"); | ||
825 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/ak4671.h b/sound/soc/codecs/ak4671.h new file mode 100644 index 000000000000..e2fad964e88b --- /dev/null +++ b/sound/soc/codecs/ak4671.h | |||
@@ -0,0 +1,156 @@ | |||
1 | /* | ||
2 | * ak4671.h -- audio driver for AK4671 | ||
3 | * | ||
4 | * Copyright (C) 2009 Samsung Electronics Co.Ltd | ||
5 | * Author: Joonyoung Shim <jy0922.shim@samsung.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #ifndef _AK4671_H | ||
15 | #define _AK4671_H | ||
16 | |||
17 | #define AK4671_AD_DA_POWER_MANAGEMENT 0x00 | ||
18 | #define AK4671_PLL_MODE_SELECT0 0x01 | ||
19 | #define AK4671_PLL_MODE_SELECT1 0x02 | ||
20 | #define AK4671_FORMAT_SELECT 0x03 | ||
21 | #define AK4671_MIC_SIGNAL_SELECT 0x04 | ||
22 | #define AK4671_MIC_AMP_GAIN 0x05 | ||
23 | #define AK4671_MIXING_POWER_MANAGEMENT0 0x06 | ||
24 | #define AK4671_MIXING_POWER_MANAGEMENT1 0x07 | ||
25 | #define AK4671_OUTPUT_VOLUME_CONTROL 0x08 | ||
26 | #define AK4671_LOUT1_SIGNAL_SELECT 0x09 | ||
27 | #define AK4671_ROUT1_SIGNAL_SELECT 0x0a | ||
28 | #define AK4671_LOUT2_SIGNAL_SELECT 0x0b | ||
29 | #define AK4671_ROUT2_SIGNAL_SELECT 0x0c | ||
30 | #define AK4671_LOUT3_SIGNAL_SELECT 0x0d | ||
31 | #define AK4671_ROUT3_SIGNAL_SELECT 0x0e | ||
32 | #define AK4671_LOUT1_POWER_MANAGERMENT 0x0f | ||
33 | #define AK4671_LOUT2_POWER_MANAGERMENT 0x10 | ||
34 | #define AK4671_LOUT3_POWER_MANAGERMENT 0x11 | ||
35 | #define AK4671_LCH_INPUT_VOLUME_CONTROL 0x12 | ||
36 | #define AK4671_RCH_INPUT_VOLUME_CONTROL 0x13 | ||
37 | #define AK4671_ALC_REFERENCE_SELECT 0x14 | ||
38 | #define AK4671_DIGITAL_MIXING_CONTROL 0x15 | ||
39 | #define AK4671_ALC_TIMER_SELECT 0x16 | ||
40 | #define AK4671_ALC_MODE_CONTROL 0x17 | ||
41 | #define AK4671_MODE_CONTROL1 0x18 | ||
42 | #define AK4671_MODE_CONTROL2 0x19 | ||
43 | #define AK4671_LCH_OUTPUT_VOLUME_CONTROL 0x1a | ||
44 | #define AK4671_RCH_OUTPUT_VOLUME_CONTROL 0x1b | ||
45 | #define AK4671_SIDETONE_A_CONTROL 0x1c | ||
46 | #define AK4671_DIGITAL_FILTER_SELECT 0x1d | ||
47 | #define AK4671_FIL3_COEFFICIENT0 0x1e | ||
48 | #define AK4671_FIL3_COEFFICIENT1 0x1f | ||
49 | #define AK4671_FIL3_COEFFICIENT2 0x20 | ||
50 | #define AK4671_FIL3_COEFFICIENT3 0x21 | ||
51 | #define AK4671_EQ_COEFFICIENT0 0x22 | ||
52 | #define AK4671_EQ_COEFFICIENT1 0x23 | ||
53 | #define AK4671_EQ_COEFFICIENT2 0x24 | ||
54 | #define AK4671_EQ_COEFFICIENT3 0x25 | ||
55 | #define AK4671_EQ_COEFFICIENT4 0x26 | ||
56 | #define AK4671_EQ_COEFFICIENT5 0x27 | ||
57 | #define AK4671_FIL1_COEFFICIENT0 0x28 | ||
58 | #define AK4671_FIL1_COEFFICIENT1 0x29 | ||
59 | #define AK4671_FIL1_COEFFICIENT2 0x2a | ||
60 | #define AK4671_FIL1_COEFFICIENT3 0x2b | ||
61 | #define AK4671_FIL2_COEFFICIENT0 0x2c | ||
62 | #define AK4671_FIL2_COEFFICIENT1 0x2d | ||
63 | #define AK4671_FIL2_COEFFICIENT2 0x2e | ||
64 | #define AK4671_FIL2_COEFFICIENT3 0x2f | ||
65 | #define AK4671_DIGITAL_FILTER_SELECT2 0x30 | ||
66 | #define AK4671_E1_COEFFICIENT0 0x32 | ||
67 | #define AK4671_E1_COEFFICIENT1 0x33 | ||
68 | #define AK4671_E1_COEFFICIENT2 0x34 | ||
69 | #define AK4671_E1_COEFFICIENT3 0x35 | ||
70 | #define AK4671_E1_COEFFICIENT4 0x36 | ||
71 | #define AK4671_E1_COEFFICIENT5 0x37 | ||
72 | #define AK4671_E2_COEFFICIENT0 0x38 | ||
73 | #define AK4671_E2_COEFFICIENT1 0x39 | ||
74 | #define AK4671_E2_COEFFICIENT2 0x3a | ||
75 | #define AK4671_E2_COEFFICIENT3 0x3b | ||
76 | #define AK4671_E2_COEFFICIENT4 0x3c | ||
77 | #define AK4671_E2_COEFFICIENT5 0x3d | ||
78 | #define AK4671_E3_COEFFICIENT0 0x3e | ||
79 | #define AK4671_E3_COEFFICIENT1 0x3f | ||
80 | #define AK4671_E3_COEFFICIENT2 0x40 | ||
81 | #define AK4671_E3_COEFFICIENT3 0x41 | ||
82 | #define AK4671_E3_COEFFICIENT4 0x42 | ||
83 | #define AK4671_E3_COEFFICIENT5 0x43 | ||
84 | #define AK4671_E4_COEFFICIENT0 0x44 | ||
85 | #define AK4671_E4_COEFFICIENT1 0x45 | ||
86 | #define AK4671_E4_COEFFICIENT2 0x46 | ||
87 | #define AK4671_E4_COEFFICIENT3 0x47 | ||
88 | #define AK4671_E4_COEFFICIENT4 0x48 | ||
89 | #define AK4671_E4_COEFFICIENT5 0x49 | ||
90 | #define AK4671_E5_COEFFICIENT0 0x4a | ||
91 | #define AK4671_E5_COEFFICIENT1 0x4b | ||
92 | #define AK4671_E5_COEFFICIENT2 0x4c | ||
93 | #define AK4671_E5_COEFFICIENT3 0x4d | ||
94 | #define AK4671_E5_COEFFICIENT4 0x4e | ||
95 | #define AK4671_E5_COEFFICIENT5 0x4f | ||
96 | #define AK4671_EQ_CONTROL_250HZ_100HZ 0x50 | ||
97 | #define AK4671_EQ_CONTROL_3500HZ_1KHZ 0x51 | ||
98 | #define AK4671_EQ_CONTRO_10KHZ 0x52 | ||
99 | #define AK4671_PCM_IF_CONTROL0 0x53 | ||
100 | #define AK4671_PCM_IF_CONTROL1 0x54 | ||
101 | #define AK4671_PCM_IF_CONTROL2 0x55 | ||
102 | #define AK4671_DIGITAL_VOLUME_B_CONTROL 0x56 | ||
103 | #define AK4671_DIGITAL_VOLUME_C_CONTROL 0x57 | ||
104 | #define AK4671_SIDETONE_VOLUME_CONTROL 0x58 | ||
105 | #define AK4671_DIGITAL_MIXING_CONTROL2 0x59 | ||
106 | #define AK4671_SAR_ADC_CONTROL 0x5a | ||
107 | |||
108 | #define AK4671_CACHEREGNUM (AK4671_SAR_ADC_CONTROL + 1) | ||
109 | |||
110 | /* Bitfield Definitions */ | ||
111 | |||
112 | /* AK4671_AD_DA_POWER_MANAGEMENT (0x00) Fields */ | ||
113 | #define AK4671_PMVCM 0x01 | ||
114 | |||
115 | /* AK4671_PLL_MODE_SELECT0 (0x01) Fields */ | ||
116 | #define AK4671_PLL 0x0f | ||
117 | #define AK4671_PLL_11_2896MHZ (4 << 0) | ||
118 | #define AK4671_PLL_12_288MHZ (5 << 0) | ||
119 | #define AK4671_PLL_12MHZ (6 << 0) | ||
120 | #define AK4671_PLL_24MHZ (7 << 0) | ||
121 | #define AK4671_PLL_19_2MHZ (8 << 0) | ||
122 | #define AK4671_PLL_13_5MHZ (12 << 0) | ||
123 | #define AK4671_PLL_27MHZ (13 << 0) | ||
124 | #define AK4671_PLL_13MHZ (14 << 0) | ||
125 | #define AK4671_PLL_26MHZ (15 << 0) | ||
126 | #define AK4671_FS 0xf0 | ||
127 | #define AK4671_FS_8KHZ (0 << 4) | ||
128 | #define AK4671_FS_12KHZ (1 << 4) | ||
129 | #define AK4671_FS_16KHZ (2 << 4) | ||
130 | #define AK4671_FS_24KHZ (3 << 4) | ||
131 | #define AK4671_FS_11_025KHZ (5 << 4) | ||
132 | #define AK4671_FS_22_05KHZ (7 << 4) | ||
133 | #define AK4671_FS_32KHZ (10 << 4) | ||
134 | #define AK4671_FS_48KHZ (11 << 4) | ||
135 | #define AK4671_FS_44_1KHZ (15 << 4) | ||
136 | |||
137 | /* AK4671_PLL_MODE_SELECT1 (0x02) Fields */ | ||
138 | #define AK4671_PMPLL 0x01 | ||
139 | #define AK4671_M_S 0x02 | ||
140 | |||
141 | /* AK4671_FORMAT_SELECT (0x03) Fields */ | ||
142 | #define AK4671_DIF 0x03 | ||
143 | #define AK4671_DIF_DSP_MODE (0 << 0) | ||
144 | #define AK4671_DIF_MSB_MODE (2 << 0) | ||
145 | #define AK4671_DIF_I2S_MODE (3 << 0) | ||
146 | #define AK4671_BCKP 0x04 | ||
147 | #define AK4671_MSBS 0x08 | ||
148 | #define AK4671_SDOD 0x10 | ||
149 | |||
150 | /* AK4671_LOUT2_POWER_MANAGEMENT (0x10) Fields */ | ||
151 | #define AK4671_MUTEN 0x04 | ||
152 | |||
153 | extern struct snd_soc_dai ak4671_dai; | ||
154 | extern struct snd_soc_codec_device soc_codec_dev_ak4671; | ||
155 | |||
156 | #endif | ||
diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index 3ff0373dff89..3f7e8a8b387e 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c | |||
@@ -1101,7 +1101,7 @@ static inline int fll_factors(struct _fll_div *fll_div, unsigned int input, | |||
1101 | } | 1101 | } |
1102 | 1102 | ||
1103 | static int wm8350_set_fll(struct snd_soc_dai *codec_dai, | 1103 | static int wm8350_set_fll(struct snd_soc_dai *codec_dai, |
1104 | int pll_id, unsigned int freq_in, | 1104 | int pll_id, int source, unsigned int freq_in, |
1105 | unsigned int freq_out) | 1105 | unsigned int freq_out) |
1106 | { | 1106 | { |
1107 | struct snd_soc_codec *codec = codec_dai->codec; | 1107 | struct snd_soc_codec *codec = codec_dai->codec; |
diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c index b9ef4d915221..9cb8e50f0fbb 100644 --- a/sound/soc/codecs/wm8400.c +++ b/sound/soc/codecs/wm8400.c | |||
@@ -1011,7 +1011,8 @@ static int fll_factors(struct wm8400_priv *wm8400, struct fll_factors *factors, | |||
1011 | } | 1011 | } |
1012 | 1012 | ||
1013 | static int wm8400_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, | 1013 | static int wm8400_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, |
1014 | unsigned int freq_in, unsigned int freq_out) | 1014 | int source, unsigned int freq_in, |
1015 | unsigned int freq_out) | ||
1015 | { | 1016 | { |
1016 | struct snd_soc_codec *codec = codec_dai->codec; | 1017 | struct snd_soc_codec *codec = codec_dai->codec; |
1017 | struct wm8400_priv *wm8400 = codec->private_data; | 1018 | struct wm8400_priv *wm8400 = codec->private_data; |
diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c index 060d5d06ba95..5702435af81b 100644 --- a/sound/soc/codecs/wm8510.c +++ b/sound/soc/codecs/wm8510.c | |||
@@ -271,8 +271,8 @@ static void pll_factors(unsigned int target, unsigned int source) | |||
271 | pll_div.k = K; | 271 | pll_div.k = K; |
272 | } | 272 | } |
273 | 273 | ||
274 | static int wm8510_set_dai_pll(struct snd_soc_dai *codec_dai, | 274 | static int wm8510_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, |
275 | int pll_id, unsigned int freq_in, unsigned int freq_out) | 275 | int source, unsigned int freq_in, unsigned int freq_out) |
276 | { | 276 | { |
277 | struct snd_soc_codec *codec = codec_dai->codec; | 277 | struct snd_soc_codec *codec = codec_dai->codec; |
278 | u16 reg; | 278 | u16 reg; |
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index 6bded8c78150..3be5c0b2552c 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c | |||
@@ -407,8 +407,8 @@ static int pll_factors(struct _pll_div *pll_div, unsigned int target, | |||
407 | return 0; | 407 | return 0; |
408 | } | 408 | } |
409 | 409 | ||
410 | static int wm8580_set_dai_pll(struct snd_soc_dai *codec_dai, | 410 | static int wm8580_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, |
411 | int pll_id, unsigned int freq_in, unsigned int freq_out) | 411 | int source, unsigned int freq_in, unsigned int freq_out) |
412 | { | 412 | { |
413 | int offset; | 413 | int offset; |
414 | struct snd_soc_codec *codec = codec_dai->codec; | 414 | struct snd_soc_codec *codec = codec_dai->codec; |
diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c new file mode 100644 index 000000000000..90ec8c58e2f4 --- /dev/null +++ b/sound/soc/codecs/wm8711.c | |||
@@ -0,0 +1,659 @@ | |||
1 | /* | ||
2 | * wm8711.c -- WM8711 ALSA SoC Audio driver | ||
3 | * | ||
4 | * Copyright 2006 Wolfson Microelectronics | ||
5 | * | ||
6 | * Author: Mike Arthur <linux@wolfsonmicro.com> | ||
7 | * | ||
8 | * Based on wm8731.c by Richard Purdie | ||
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 <linux/spi/spi.h> | ||
23 | #include <sound/core.h> | ||
24 | #include <sound/pcm.h> | ||
25 | #include <sound/pcm_params.h> | ||
26 | #include <sound/soc.h> | ||
27 | #include <sound/soc-dapm.h> | ||
28 | #include <sound/tlv.h> | ||
29 | #include <sound/initval.h> | ||
30 | |||
31 | #include "wm8711.h" | ||
32 | |||
33 | static struct snd_soc_codec *wm8711_codec; | ||
34 | |||
35 | /* codec private data */ | ||
36 | struct wm8711_priv { | ||
37 | struct snd_soc_codec codec; | ||
38 | u16 reg_cache[WM8711_CACHEREGNUM]; | ||
39 | unsigned int sysclk; | ||
40 | }; | ||
41 | |||
42 | /* | ||
43 | * wm8711 register cache | ||
44 | * We can't read the WM8711 register space when we are | ||
45 | * using 2 wire for device control, so we cache them instead. | ||
46 | * There is no point in caching the reset register | ||
47 | */ | ||
48 | static const u16 wm8711_reg[WM8711_CACHEREGNUM] = { | ||
49 | 0x0079, 0x0079, 0x000a, 0x0008, | ||
50 | 0x009f, 0x000a, 0x0000, 0x0000 | ||
51 | }; | ||
52 | |||
53 | #define wm8711_reset(c) snd_soc_write(c, WM8711_RESET, 0) | ||
54 | |||
55 | static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1); | ||
56 | |||
57 | static const struct snd_kcontrol_new wm8711_snd_controls[] = { | ||
58 | |||
59 | SOC_DOUBLE_R_TLV("Master Playback Volume", WM8711_LOUT1V, WM8711_ROUT1V, | ||
60 | 0, 127, 0, out_tlv), | ||
61 | SOC_DOUBLE_R("Master Playback ZC Switch", WM8711_LOUT1V, WM8711_ROUT1V, | ||
62 | 7, 1, 0), | ||
63 | |||
64 | }; | ||
65 | |||
66 | /* Output Mixer */ | ||
67 | static const struct snd_kcontrol_new wm8711_output_mixer_controls[] = { | ||
68 | SOC_DAPM_SINGLE("Line Bypass Switch", WM8711_APANA, 3, 1, 0), | ||
69 | SOC_DAPM_SINGLE("HiFi Playback Switch", WM8711_APANA, 4, 1, 0), | ||
70 | }; | ||
71 | |||
72 | static const struct snd_soc_dapm_widget wm8711_dapm_widgets[] = { | ||
73 | SND_SOC_DAPM_MIXER("Output Mixer", WM8711_PWR, 4, 1, | ||
74 | &wm8711_output_mixer_controls[0], | ||
75 | ARRAY_SIZE(wm8711_output_mixer_controls)), | ||
76 | SND_SOC_DAPM_DAC("DAC", "HiFi Playback", WM8711_PWR, 3, 1), | ||
77 | SND_SOC_DAPM_OUTPUT("LOUT"), | ||
78 | SND_SOC_DAPM_OUTPUT("LHPOUT"), | ||
79 | SND_SOC_DAPM_OUTPUT("ROUT"), | ||
80 | SND_SOC_DAPM_OUTPUT("RHPOUT"), | ||
81 | }; | ||
82 | |||
83 | static const struct snd_soc_dapm_route intercon[] = { | ||
84 | /* output mixer */ | ||
85 | {"Output Mixer", "Line Bypass Switch", "Line Input"}, | ||
86 | {"Output Mixer", "HiFi Playback Switch", "DAC"}, | ||
87 | |||
88 | /* outputs */ | ||
89 | {"RHPOUT", NULL, "Output Mixer"}, | ||
90 | {"ROUT", NULL, "Output Mixer"}, | ||
91 | {"LHPOUT", NULL, "Output Mixer"}, | ||
92 | {"LOUT", NULL, "Output Mixer"}, | ||
93 | }; | ||
94 | |||
95 | static int wm8711_add_widgets(struct snd_soc_codec *codec) | ||
96 | { | ||
97 | snd_soc_dapm_new_controls(codec, wm8711_dapm_widgets, | ||
98 | ARRAY_SIZE(wm8711_dapm_widgets)); | ||
99 | |||
100 | snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); | ||
101 | |||
102 | snd_soc_dapm_new_widgets(codec); | ||
103 | return 0; | ||
104 | } | ||
105 | |||
106 | struct _coeff_div { | ||
107 | u32 mclk; | ||
108 | u32 rate; | ||
109 | u16 fs; | ||
110 | u8 sr:4; | ||
111 | u8 bosr:1; | ||
112 | u8 usb:1; | ||
113 | }; | ||
114 | |||
115 | /* codec mclk clock divider coefficients */ | ||
116 | static const struct _coeff_div coeff_div[] = { | ||
117 | /* 48k */ | ||
118 | {12288000, 48000, 256, 0x0, 0x0, 0x0}, | ||
119 | {18432000, 48000, 384, 0x0, 0x1, 0x0}, | ||
120 | {12000000, 48000, 250, 0x0, 0x0, 0x1}, | ||
121 | |||
122 | /* 32k */ | ||
123 | {12288000, 32000, 384, 0x6, 0x0, 0x0}, | ||
124 | {18432000, 32000, 576, 0x6, 0x1, 0x0}, | ||
125 | {12000000, 32000, 375, 0x6, 0x0, 0x1}, | ||
126 | |||
127 | /* 8k */ | ||
128 | {12288000, 8000, 1536, 0x3, 0x0, 0x0}, | ||
129 | {18432000, 8000, 2304, 0x3, 0x1, 0x0}, | ||
130 | {11289600, 8000, 1408, 0xb, 0x0, 0x0}, | ||
131 | {16934400, 8000, 2112, 0xb, 0x1, 0x0}, | ||
132 | {12000000, 8000, 1500, 0x3, 0x0, 0x1}, | ||
133 | |||
134 | /* 96k */ | ||
135 | {12288000, 96000, 128, 0x7, 0x0, 0x0}, | ||
136 | {18432000, 96000, 192, 0x7, 0x1, 0x0}, | ||
137 | {12000000, 96000, 125, 0x7, 0x0, 0x1}, | ||
138 | |||
139 | /* 44.1k */ | ||
140 | {11289600, 44100, 256, 0x8, 0x0, 0x0}, | ||
141 | {16934400, 44100, 384, 0x8, 0x1, 0x0}, | ||
142 | {12000000, 44100, 272, 0x8, 0x1, 0x1}, | ||
143 | |||
144 | /* 88.2k */ | ||
145 | {11289600, 88200, 128, 0xf, 0x0, 0x0}, | ||
146 | {16934400, 88200, 192, 0xf, 0x1, 0x0}, | ||
147 | {12000000, 88200, 136, 0xf, 0x1, 0x1}, | ||
148 | }; | ||
149 | |||
150 | static inline int get_coeff(int mclk, int rate) | ||
151 | { | ||
152 | int i; | ||
153 | |||
154 | for (i = 0; i < ARRAY_SIZE(coeff_div); i++) { | ||
155 | if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk) | ||
156 | return i; | ||
157 | } | ||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | static int wm8711_hw_params(struct snd_pcm_substream *substream, | ||
162 | struct snd_pcm_hw_params *params, | ||
163 | struct snd_soc_dai *dai) | ||
164 | { | ||
165 | struct snd_soc_codec *codec = dai->codec; | ||
166 | struct wm8711_priv *wm8711 = codec->private_data; | ||
167 | u16 iface = snd_soc_read(codec, WM8711_IFACE) & 0xfffc; | ||
168 | int i = get_coeff(wm8711->sysclk, params_rate(params)); | ||
169 | u16 srate = (coeff_div[i].sr << 2) | | ||
170 | (coeff_div[i].bosr << 1) | coeff_div[i].usb; | ||
171 | |||
172 | snd_soc_write(codec, WM8711_SRATE, srate); | ||
173 | |||
174 | /* bit size */ | ||
175 | switch (params_format(params)) { | ||
176 | case SNDRV_PCM_FORMAT_S16_LE: | ||
177 | break; | ||
178 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
179 | iface |= 0x0004; | ||
180 | break; | ||
181 | case SNDRV_PCM_FORMAT_S24_LE: | ||
182 | iface |= 0x0008; | ||
183 | break; | ||
184 | } | ||
185 | |||
186 | snd_soc_write(codec, WM8711_IFACE, iface); | ||
187 | return 0; | ||
188 | } | ||
189 | |||
190 | static int wm8711_pcm_prepare(struct snd_pcm_substream *substream, | ||
191 | struct snd_soc_dai *dai) | ||
192 | { | ||
193 | struct snd_soc_codec *codec = dai->codec; | ||
194 | |||
195 | /* set active */ | ||
196 | snd_soc_write(codec, WM8711_ACTIVE, 0x0001); | ||
197 | |||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | static void wm8711_shutdown(struct snd_pcm_substream *substream, | ||
202 | struct snd_soc_dai *dai) | ||
203 | { | ||
204 | struct snd_soc_codec *codec = dai->codec; | ||
205 | |||
206 | /* deactivate */ | ||
207 | if (!codec->active) { | ||
208 | udelay(50); | ||
209 | snd_soc_write(codec, WM8711_ACTIVE, 0x0); | ||
210 | } | ||
211 | } | ||
212 | |||
213 | static int wm8711_mute(struct snd_soc_dai *dai, int mute) | ||
214 | { | ||
215 | struct snd_soc_codec *codec = dai->codec; | ||
216 | u16 mute_reg = snd_soc_read(codec, WM8711_APDIGI) & 0xfff7; | ||
217 | |||
218 | if (mute) | ||
219 | snd_soc_write(codec, WM8711_APDIGI, mute_reg | 0x8); | ||
220 | else | ||
221 | snd_soc_write(codec, WM8711_APDIGI, mute_reg); | ||
222 | |||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | static int wm8711_set_dai_sysclk(struct snd_soc_dai *codec_dai, | ||
227 | int clk_id, unsigned int freq, int dir) | ||
228 | { | ||
229 | struct snd_soc_codec *codec = codec_dai->codec; | ||
230 | struct wm8711_priv *wm8711 = codec->private_data; | ||
231 | |||
232 | switch (freq) { | ||
233 | case 11289600: | ||
234 | case 12000000: | ||
235 | case 12288000: | ||
236 | case 16934400: | ||
237 | case 18432000: | ||
238 | wm8711->sysclk = freq; | ||
239 | return 0; | ||
240 | } | ||
241 | return -EINVAL; | ||
242 | } | ||
243 | |||
244 | static int wm8711_set_dai_fmt(struct snd_soc_dai *codec_dai, | ||
245 | unsigned int fmt) | ||
246 | { | ||
247 | struct snd_soc_codec *codec = codec_dai->codec; | ||
248 | u16 iface = 0; | ||
249 | |||
250 | /* set master/slave audio interface */ | ||
251 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
252 | case SND_SOC_DAIFMT_CBM_CFM: | ||
253 | iface |= 0x0040; | ||
254 | break; | ||
255 | case SND_SOC_DAIFMT_CBS_CFS: | ||
256 | break; | ||
257 | default: | ||
258 | return -EINVAL; | ||
259 | } | ||
260 | |||
261 | /* interface format */ | ||
262 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
263 | case SND_SOC_DAIFMT_I2S: | ||
264 | iface |= 0x0002; | ||
265 | break; | ||
266 | case SND_SOC_DAIFMT_RIGHT_J: | ||
267 | break; | ||
268 | case SND_SOC_DAIFMT_LEFT_J: | ||
269 | iface |= 0x0001; | ||
270 | break; | ||
271 | case SND_SOC_DAIFMT_DSP_A: | ||
272 | iface |= 0x0003; | ||
273 | break; | ||
274 | case SND_SOC_DAIFMT_DSP_B: | ||
275 | iface |= 0x0013; | ||
276 | break; | ||
277 | default: | ||
278 | return -EINVAL; | ||
279 | } | ||
280 | |||
281 | /* clock inversion */ | ||
282 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
283 | case SND_SOC_DAIFMT_NB_NF: | ||
284 | break; | ||
285 | case SND_SOC_DAIFMT_IB_IF: | ||
286 | iface |= 0x0090; | ||
287 | break; | ||
288 | case SND_SOC_DAIFMT_IB_NF: | ||
289 | iface |= 0x0080; | ||
290 | break; | ||
291 | case SND_SOC_DAIFMT_NB_IF: | ||
292 | iface |= 0x0010; | ||
293 | break; | ||
294 | default: | ||
295 | return -EINVAL; | ||
296 | } | ||
297 | |||
298 | /* set iface */ | ||
299 | snd_soc_write(codec, WM8711_IFACE, iface); | ||
300 | return 0; | ||
301 | } | ||
302 | |||
303 | |||
304 | static int wm8711_set_bias_level(struct snd_soc_codec *codec, | ||
305 | enum snd_soc_bias_level level) | ||
306 | { | ||
307 | u16 reg = snd_soc_read(codec, WM8711_PWR) & 0xff7f; | ||
308 | |||
309 | switch (level) { | ||
310 | case SND_SOC_BIAS_ON: | ||
311 | snd_soc_write(codec, WM8711_PWR, reg); | ||
312 | break; | ||
313 | case SND_SOC_BIAS_PREPARE: | ||
314 | break; | ||
315 | case SND_SOC_BIAS_STANDBY: | ||
316 | snd_soc_write(codec, WM8711_PWR, reg | 0x0040); | ||
317 | break; | ||
318 | case SND_SOC_BIAS_OFF: | ||
319 | snd_soc_write(codec, WM8711_ACTIVE, 0x0); | ||
320 | snd_soc_write(codec, WM8711_PWR, 0xffff); | ||
321 | break; | ||
322 | } | ||
323 | codec->bias_level = level; | ||
324 | return 0; | ||
325 | } | ||
326 | |||
327 | #define WM8711_RATES SNDRV_PCM_RATE_8000_96000 | ||
328 | |||
329 | #define WM8711_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | ||
330 | SNDRV_PCM_FMTBIT_S24_LE) | ||
331 | |||
332 | static struct snd_soc_dai_ops wm8711_ops = { | ||
333 | .prepare = wm8711_pcm_prepare, | ||
334 | .hw_params = wm8711_hw_params, | ||
335 | .shutdown = wm8711_shutdown, | ||
336 | .digital_mute = wm8711_mute, | ||
337 | .set_sysclk = wm8711_set_dai_sysclk, | ||
338 | .set_fmt = wm8711_set_dai_fmt, | ||
339 | }; | ||
340 | |||
341 | struct snd_soc_dai wm8711_dai = { | ||
342 | .name = "WM8711", | ||
343 | .playback = { | ||
344 | .stream_name = "Playback", | ||
345 | .channels_min = 1, | ||
346 | .channels_max = 2, | ||
347 | .rates = WM8711_RATES, | ||
348 | .formats = WM8711_FORMATS, | ||
349 | }, | ||
350 | .ops = &wm8711_ops, | ||
351 | }; | ||
352 | EXPORT_SYMBOL_GPL(wm8711_dai); | ||
353 | |||
354 | static int wm8711_suspend(struct platform_device *pdev, pm_message_t state) | ||
355 | { | ||
356 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
357 | struct snd_soc_codec *codec = socdev->card->codec; | ||
358 | |||
359 | snd_soc_write(codec, WM8711_ACTIVE, 0x0); | ||
360 | wm8711_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
361 | return 0; | ||
362 | } | ||
363 | |||
364 | static int wm8711_resume(struct platform_device *pdev) | ||
365 | { | ||
366 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
367 | struct snd_soc_codec *codec = socdev->card->codec; | ||
368 | int i; | ||
369 | u8 data[2]; | ||
370 | u16 *cache = codec->reg_cache; | ||
371 | |||
372 | /* Sync reg_cache with the hardware */ | ||
373 | for (i = 0; i < ARRAY_SIZE(wm8711_reg); i++) { | ||
374 | data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); | ||
375 | data[1] = cache[i] & 0x00ff; | ||
376 | codec->hw_write(codec->control_data, data, 2); | ||
377 | } | ||
378 | wm8711_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
379 | wm8711_set_bias_level(codec, codec->suspend_bias_level); | ||
380 | return 0; | ||
381 | } | ||
382 | |||
383 | static int wm8711_probe(struct platform_device *pdev) | ||
384 | { | ||
385 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
386 | struct snd_soc_codec *codec; | ||
387 | int ret = 0; | ||
388 | |||
389 | if (wm8711_codec == NULL) { | ||
390 | dev_err(&pdev->dev, "Codec device not registered\n"); | ||
391 | return -ENODEV; | ||
392 | } | ||
393 | |||
394 | socdev->card->codec = wm8711_codec; | ||
395 | codec = wm8711_codec; | ||
396 | |||
397 | /* register pcms */ | ||
398 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
399 | if (ret < 0) { | ||
400 | dev_err(codec->dev, "failed to create pcms: %d\n", ret); | ||
401 | goto pcm_err; | ||
402 | } | ||
403 | |||
404 | snd_soc_add_controls(codec, wm8711_snd_controls, | ||
405 | ARRAY_SIZE(wm8711_snd_controls)); | ||
406 | wm8711_add_widgets(codec); | ||
407 | ret = snd_soc_init_card(socdev); | ||
408 | if (ret < 0) { | ||
409 | dev_err(codec->dev, "failed to register card: %d\n", ret); | ||
410 | goto card_err; | ||
411 | } | ||
412 | |||
413 | return ret; | ||
414 | |||
415 | card_err: | ||
416 | snd_soc_free_pcms(socdev); | ||
417 | snd_soc_dapm_free(socdev); | ||
418 | pcm_err: | ||
419 | return ret; | ||
420 | } | ||
421 | |||
422 | /* power down chip */ | ||
423 | static int wm8711_remove(struct platform_device *pdev) | ||
424 | { | ||
425 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
426 | |||
427 | snd_soc_free_pcms(socdev); | ||
428 | snd_soc_dapm_free(socdev); | ||
429 | |||
430 | return 0; | ||
431 | } | ||
432 | |||
433 | struct snd_soc_codec_device soc_codec_dev_wm8711 = { | ||
434 | .probe = wm8711_probe, | ||
435 | .remove = wm8711_remove, | ||
436 | .suspend = wm8711_suspend, | ||
437 | .resume = wm8711_resume, | ||
438 | }; | ||
439 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8711); | ||
440 | |||
441 | static int wm8711_register(struct wm8711_priv *wm8711, | ||
442 | enum snd_soc_control_type control) | ||
443 | { | ||
444 | int ret; | ||
445 | struct snd_soc_codec *codec = &wm8711->codec; | ||
446 | u16 reg; | ||
447 | |||
448 | if (wm8711_codec) { | ||
449 | dev_err(codec->dev, "Another WM8711 is registered\n"); | ||
450 | return -EINVAL; | ||
451 | } | ||
452 | |||
453 | mutex_init(&codec->mutex); | ||
454 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
455 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
456 | |||
457 | codec->private_data = wm8711; | ||
458 | codec->name = "WM8711"; | ||
459 | codec->owner = THIS_MODULE; | ||
460 | codec->bias_level = SND_SOC_BIAS_OFF; | ||
461 | codec->set_bias_level = wm8711_set_bias_level; | ||
462 | codec->dai = &wm8711_dai; | ||
463 | codec->num_dai = 1; | ||
464 | codec->reg_cache_size = WM8711_CACHEREGNUM; | ||
465 | codec->reg_cache = &wm8711->reg_cache; | ||
466 | |||
467 | memcpy(codec->reg_cache, wm8711_reg, sizeof(wm8711_reg)); | ||
468 | |||
469 | ret = snd_soc_codec_set_cache_io(codec, 7, 9, control); | ||
470 | if (ret < 0) { | ||
471 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | ||
472 | goto err; | ||
473 | } | ||
474 | |||
475 | ret = wm8711_reset(codec); | ||
476 | if (ret < 0) { | ||
477 | dev_err(codec->dev, "Failed to issue reset\n"); | ||
478 | goto err; | ||
479 | } | ||
480 | |||
481 | wm8711_dai.dev = codec->dev; | ||
482 | |||
483 | wm8711_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
484 | |||
485 | /* Latch the update bits */ | ||
486 | reg = snd_soc_read(codec, WM8711_LOUT1V); | ||
487 | snd_soc_write(codec, WM8711_LOUT1V, reg | 0x0100); | ||
488 | reg = snd_soc_read(codec, WM8711_ROUT1V); | ||
489 | snd_soc_write(codec, WM8711_ROUT1V, reg | 0x0100); | ||
490 | |||
491 | wm8711_codec = codec; | ||
492 | |||
493 | ret = snd_soc_register_codec(codec); | ||
494 | if (ret != 0) { | ||
495 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | ||
496 | goto err; | ||
497 | } | ||
498 | |||
499 | ret = snd_soc_register_dai(&wm8711_dai); | ||
500 | if (ret != 0) { | ||
501 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); | ||
502 | goto err_codec; | ||
503 | } | ||
504 | |||
505 | return 0; | ||
506 | |||
507 | err_codec: | ||
508 | snd_soc_unregister_codec(codec); | ||
509 | err: | ||
510 | kfree(wm8711); | ||
511 | return ret; | ||
512 | } | ||
513 | |||
514 | static void wm8711_unregister(struct wm8711_priv *wm8711) | ||
515 | { | ||
516 | wm8711_set_bias_level(&wm8711->codec, SND_SOC_BIAS_OFF); | ||
517 | snd_soc_unregister_dai(&wm8711_dai); | ||
518 | snd_soc_unregister_codec(&wm8711->codec); | ||
519 | kfree(wm8711); | ||
520 | wm8711_codec = NULL; | ||
521 | } | ||
522 | |||
523 | #if defined(CONFIG_SPI_MASTER) | ||
524 | static int __devinit wm8711_spi_probe(struct spi_device *spi) | ||
525 | { | ||
526 | struct snd_soc_codec *codec; | ||
527 | struct wm8711_priv *wm8711; | ||
528 | |||
529 | wm8711 = kzalloc(sizeof(struct wm8711_priv), GFP_KERNEL); | ||
530 | if (wm8711 == NULL) | ||
531 | return -ENOMEM; | ||
532 | |||
533 | codec = &wm8711->codec; | ||
534 | codec->control_data = spi; | ||
535 | codec->dev = &spi->dev; | ||
536 | |||
537 | dev_set_drvdata(&spi->dev, wm8711); | ||
538 | |||
539 | return wm8711_register(wm8711, SND_SOC_SPI); | ||
540 | } | ||
541 | |||
542 | static int __devexit wm8711_spi_remove(struct spi_device *spi) | ||
543 | { | ||
544 | struct wm8711_priv *wm8711 = dev_get_drvdata(&spi->dev); | ||
545 | |||
546 | wm8711_unregister(wm8711); | ||
547 | |||
548 | return 0; | ||
549 | } | ||
550 | |||
551 | #ifdef CONFIG_PM | ||
552 | static int wm8711_spi_suspend(struct spi_device *spi, pm_message_t msg) | ||
553 | { | ||
554 | return snd_soc_suspend_device(&spi->dev); | ||
555 | } | ||
556 | |||
557 | static int wm8711_spi_resume(struct spi_device *spi) | ||
558 | { | ||
559 | return snd_soc_resume_device(&spi->dev); | ||
560 | } | ||
561 | #else | ||
562 | #define wm8711_spi_suspend NULL | ||
563 | #define wm8711_spi_resume NULL | ||
564 | #endif | ||
565 | |||
566 | static struct spi_driver wm8711_spi_driver = { | ||
567 | .driver = { | ||
568 | .name = "wm8711", | ||
569 | .bus = &spi_bus_type, | ||
570 | .owner = THIS_MODULE, | ||
571 | }, | ||
572 | .probe = wm8711_spi_probe, | ||
573 | .suspend = wm8711_spi_suspend, | ||
574 | .resume = wm8711_spi_resume, | ||
575 | .remove = __devexit_p(wm8711_spi_remove), | ||
576 | }; | ||
577 | #endif /* CONFIG_SPI_MASTER */ | ||
578 | |||
579 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
580 | static __devinit int wm8711_i2c_probe(struct i2c_client *i2c, | ||
581 | const struct i2c_device_id *id) | ||
582 | { | ||
583 | struct wm8711_priv *wm8711; | ||
584 | struct snd_soc_codec *codec; | ||
585 | |||
586 | wm8711 = kzalloc(sizeof(struct wm8711_priv), GFP_KERNEL); | ||
587 | if (wm8711 == NULL) | ||
588 | return -ENOMEM; | ||
589 | |||
590 | codec = &wm8711->codec; | ||
591 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
592 | |||
593 | i2c_set_clientdata(i2c, wm8711); | ||
594 | codec->control_data = i2c; | ||
595 | |||
596 | codec->dev = &i2c->dev; | ||
597 | |||
598 | return wm8711_register(wm8711, SND_SOC_I2C); | ||
599 | } | ||
600 | |||
601 | static __devexit int wm8711_i2c_remove(struct i2c_client *client) | ||
602 | { | ||
603 | struct wm8711_priv *wm8711 = i2c_get_clientdata(client); | ||
604 | wm8711_unregister(wm8711); | ||
605 | return 0; | ||
606 | } | ||
607 | |||
608 | static const struct i2c_device_id wm8711_i2c_id[] = { | ||
609 | { "wm8711", 0 }, | ||
610 | { } | ||
611 | }; | ||
612 | MODULE_DEVICE_TABLE(i2c, wm8711_i2c_id); | ||
613 | |||
614 | static struct i2c_driver wm8711_i2c_driver = { | ||
615 | .driver = { | ||
616 | .name = "WM8711 I2C Codec", | ||
617 | .owner = THIS_MODULE, | ||
618 | }, | ||
619 | .probe = wm8711_i2c_probe, | ||
620 | .remove = __devexit_p(wm8711_i2c_remove), | ||
621 | .id_table = wm8711_i2c_id, | ||
622 | }; | ||
623 | #endif | ||
624 | |||
625 | static int __init wm8711_modinit(void) | ||
626 | { | ||
627 | int ret; | ||
628 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
629 | ret = i2c_add_driver(&wm8711_i2c_driver); | ||
630 | if (ret != 0) { | ||
631 | printk(KERN_ERR "Failed to register WM8711 I2C driver: %d\n", | ||
632 | ret); | ||
633 | } | ||
634 | #endif | ||
635 | #if defined(CONFIG_SPI_MASTER) | ||
636 | ret = spi_register_driver(&wm8711_spi_driver); | ||
637 | if (ret != 0) { | ||
638 | printk(KERN_ERR "Failed to register WM8711 SPI driver: %d\n", | ||
639 | ret); | ||
640 | } | ||
641 | #endif | ||
642 | return 0; | ||
643 | } | ||
644 | module_init(wm8711_modinit); | ||
645 | |||
646 | static void __exit wm8711_exit(void) | ||
647 | { | ||
648 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
649 | i2c_del_driver(&wm8711_i2c_driver); | ||
650 | #endif | ||
651 | #if defined(CONFIG_SPI_MASTER) | ||
652 | spi_unregister_driver(&wm8711_spi_driver); | ||
653 | #endif | ||
654 | } | ||
655 | module_exit(wm8711_exit); | ||
656 | |||
657 | MODULE_DESCRIPTION("ASoC WM8711 driver"); | ||
658 | MODULE_AUTHOR("Mike Arthur"); | ||
659 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/wm8711.h b/sound/soc/codecs/wm8711.h new file mode 100644 index 000000000000..381e84a43816 --- /dev/null +++ b/sound/soc/codecs/wm8711.h | |||
@@ -0,0 +1,42 @@ | |||
1 | /* | ||
2 | * wm8711.h -- WM8711 Soc Audio driver | ||
3 | * | ||
4 | * Copyright 2006 Wolfson Microelectronics | ||
5 | * | ||
6 | * Author: Mike Arthur <linux@wolfsonmicro.com> | ||
7 | * | ||
8 | * Based on wm8731.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 _WM8711_H | ||
16 | #define _WM8711_H | ||
17 | |||
18 | /* WM8711 register space */ | ||
19 | |||
20 | #define WM8711_LOUT1V 0x02 | ||
21 | #define WM8711_ROUT1V 0x03 | ||
22 | #define WM8711_APANA 0x04 | ||
23 | #define WM8711_APDIGI 0x05 | ||
24 | #define WM8711_PWR 0x06 | ||
25 | #define WM8711_IFACE 0x07 | ||
26 | #define WM8711_SRATE 0x08 | ||
27 | #define WM8711_ACTIVE 0x09 | ||
28 | #define WM8711_RESET 0x0f | ||
29 | |||
30 | #define WM8711_CACHEREGNUM 8 | ||
31 | |||
32 | #define WM8711_SYSCLK 0 | ||
33 | #define WM8711_DAI 0 | ||
34 | |||
35 | struct wm8711_setup_data { | ||
36 | unsigned short i2c_address; | ||
37 | }; | ||
38 | |||
39 | extern struct snd_soc_dai wm8711_dai; | ||
40 | extern struct snd_soc_codec_device soc_codec_dev_wm8711; | ||
41 | |||
42 | #endif | ||
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index 5ad677ce80da..9b27efb052fe 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c | |||
@@ -724,8 +724,8 @@ static void pll_factors(struct _pll_div *pll_div, unsigned int target, | |||
724 | pll_div->k = K; | 724 | pll_div->k = K; |
725 | } | 725 | } |
726 | 726 | ||
727 | static int wm8753_set_dai_pll(struct snd_soc_dai *codec_dai, | 727 | static int wm8753_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, |
728 | int pll_id, unsigned int freq_in, unsigned int freq_out) | 728 | int source, unsigned int freq_in, unsigned int freq_out) |
729 | { | 729 | { |
730 | u16 reg, enable; | 730 | u16 reg, enable; |
731 | int offset; | 731 | int offset; |
diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index 5e9c855c0036..882604ef768c 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c | |||
@@ -814,8 +814,8 @@ reenable: | |||
814 | return 0; | 814 | return 0; |
815 | } | 815 | } |
816 | 816 | ||
817 | static int wm8900_set_dai_pll(struct snd_soc_dai *codec_dai, | 817 | static int wm8900_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, |
818 | int pll_id, unsigned int freq_in, unsigned int freq_out) | 818 | int source, unsigned int freq_in, unsigned int freq_out) |
819 | { | 819 | { |
820 | return wm8900_set_fll(codec_dai->codec, pll_id, freq_in, freq_out); | 820 | return wm8900_set_fll(codec_dai->codec, pll_id, freq_in, freq_out); |
821 | } | 821 | } |
diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c index 1ef2454c5205..1685cfb993c6 100644 --- a/sound/soc/codecs/wm8940.c +++ b/sound/soc/codecs/wm8940.c | |||
@@ -536,8 +536,8 @@ static void pll_factors(unsigned int target, unsigned int source) | |||
536 | } | 536 | } |
537 | 537 | ||
538 | /* Untested at the moment */ | 538 | /* Untested at the moment */ |
539 | static int wm8940_set_dai_pll(struct snd_soc_dai *codec_dai, | 539 | static int wm8940_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, |
540 | int pll_id, unsigned int freq_in, unsigned int freq_out) | 540 | int source, unsigned int freq_in, unsigned int freq_out) |
541 | { | 541 | { |
542 | struct snd_soc_codec *codec = codec_dai->codec; | 542 | struct snd_soc_codec *codec = codec_dai->codec; |
543 | u16 reg; | 543 | u16 reg; |
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index f59703be61c8..416fb3c17018 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c | |||
@@ -540,8 +540,8 @@ static int pll_factors(unsigned int source, unsigned int target, | |||
540 | return 0; | 540 | return 0; |
541 | } | 541 | } |
542 | 542 | ||
543 | static int wm8960_set_dai_pll(struct snd_soc_dai *codec_dai, | 543 | static int wm8960_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, |
544 | int pll_id, unsigned int freq_in, unsigned int freq_out) | 544 | int source, unsigned int freq_in, unsigned int freq_out) |
545 | { | 545 | { |
546 | struct snd_soc_codec *codec = codec_dai->codec; | 546 | struct snd_soc_codec *codec = codec_dai->codec; |
547 | u16 reg; | 547 | u16 reg; |
diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c index 98d663afc97d..eff29331235b 100644 --- a/sound/soc/codecs/wm8974.c +++ b/sound/soc/codecs/wm8974.c | |||
@@ -281,36 +281,38 @@ static int wm8974_add_widgets(struct snd_soc_codec *codec) | |||
281 | } | 281 | } |
282 | 282 | ||
283 | struct pll_ { | 283 | struct pll_ { |
284 | unsigned int pre_div:4; /* prescale - 1 */ | 284 | unsigned int pre_div:1; |
285 | unsigned int n:4; | 285 | unsigned int n:4; |
286 | unsigned int k; | 286 | unsigned int k; |
287 | }; | 287 | }; |
288 | 288 | ||
289 | static struct pll_ pll_div; | ||
290 | |||
291 | /* The size in bits of the pll divide multiplied by 10 | 289 | /* The size in bits of the pll divide multiplied by 10 |
292 | * to allow rounding later */ | 290 | * to allow rounding later */ |
293 | #define FIXED_PLL_SIZE ((1 << 24) * 10) | 291 | #define FIXED_PLL_SIZE ((1 << 24) * 10) |
294 | 292 | ||
295 | static void pll_factors(unsigned int target, unsigned int source) | 293 | static void pll_factors(struct pll_ *pll_div, |
294 | unsigned int target, unsigned int source) | ||
296 | { | 295 | { |
297 | unsigned long long Kpart; | 296 | unsigned long long Kpart; |
298 | unsigned int K, Ndiv, Nmod; | 297 | unsigned int K, Ndiv, Nmod; |
299 | 298 | ||
299 | /* There is a fixed divide by 4 in the output path */ | ||
300 | target *= 4; | ||
301 | |||
300 | Ndiv = target / source; | 302 | Ndiv = target / source; |
301 | if (Ndiv < 6) { | 303 | if (Ndiv < 6) { |
302 | source >>= 1; | 304 | source /= 2; |
303 | pll_div.pre_div = 1; | 305 | pll_div->pre_div = 1; |
304 | Ndiv = target / source; | 306 | Ndiv = target / source; |
305 | } else | 307 | } else |
306 | pll_div.pre_div = 0; | 308 | pll_div->pre_div = 0; |
307 | 309 | ||
308 | if ((Ndiv < 6) || (Ndiv > 12)) | 310 | if ((Ndiv < 6) || (Ndiv > 12)) |
309 | printk(KERN_WARNING | 311 | printk(KERN_WARNING |
310 | "WM8974 N value %u outwith recommended range!\n", | 312 | "WM8974 N value %u outwith recommended range!\n", |
311 | Ndiv); | 313 | Ndiv); |
312 | 314 | ||
313 | pll_div.n = Ndiv; | 315 | pll_div->n = Ndiv; |
314 | Nmod = target % source; | 316 | Nmod = target % source; |
315 | Kpart = FIXED_PLL_SIZE * (long long)Nmod; | 317 | Kpart = FIXED_PLL_SIZE * (long long)Nmod; |
316 | 318 | ||
@@ -325,13 +327,14 @@ static void pll_factors(unsigned int target, unsigned int source) | |||
325 | /* Move down to proper range now rounding is done */ | 327 | /* Move down to proper range now rounding is done */ |
326 | K /= 10; | 328 | K /= 10; |
327 | 329 | ||
328 | pll_div.k = K; | 330 | pll_div->k = K; |
329 | } | 331 | } |
330 | 332 | ||
331 | static int wm8974_set_dai_pll(struct snd_soc_dai *codec_dai, | 333 | static int wm8974_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, |
332 | int pll_id, unsigned int freq_in, unsigned int freq_out) | 334 | int source, unsigned int freq_in, unsigned int freq_out) |
333 | { | 335 | { |
334 | struct snd_soc_codec *codec = codec_dai->codec; | 336 | struct snd_soc_codec *codec = codec_dai->codec; |
337 | struct pll_ pll_div; | ||
335 | u16 reg; | 338 | u16 reg; |
336 | 339 | ||
337 | if (freq_in == 0 || freq_out == 0) { | 340 | if (freq_in == 0 || freq_out == 0) { |
@@ -345,7 +348,7 @@ static int wm8974_set_dai_pll(struct snd_soc_dai *codec_dai, | |||
345 | return 0; | 348 | return 0; |
346 | } | 349 | } |
347 | 350 | ||
348 | pll_factors(freq_out*4, freq_in); | 351 | pll_factors(&pll_div, freq_out, freq_in); |
349 | 352 | ||
350 | snd_soc_write(codec, WM8974_PLLN, (pll_div.pre_div << 4) | pll_div.n); | 353 | snd_soc_write(codec, WM8974_PLLN, (pll_div.pre_div << 4) | pll_div.n); |
351 | snd_soc_write(codec, WM8974_PLLK1, pll_div.k >> 18); | 354 | snd_soc_write(codec, WM8974_PLLK1, pll_div.k >> 18); |
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index 2d702db4131d..f657e9a5fe26 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c | |||
@@ -972,8 +972,8 @@ static void pll_factors(struct _pll_div *pll_div, unsigned int target, | |||
972 | pll_div->k = K; | 972 | pll_div->k = K; |
973 | } | 973 | } |
974 | 974 | ||
975 | static int wm8990_set_dai_pll(struct snd_soc_dai *codec_dai, | 975 | static int wm8990_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, |
976 | int pll_id, unsigned int freq_in, unsigned int freq_out) | 976 | int source, unsigned int freq_in, unsigned int freq_out) |
977 | { | 977 | { |
978 | u16 reg; | 978 | u16 reg; |
979 | struct snd_soc_codec *codec = codec_dai->codec; | 979 | struct snd_soc_codec *codec = codec_dai->codec; |
diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index d9987999e92c..dac397712147 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c | |||
@@ -422,7 +422,7 @@ static int fll_factors(struct _fll_div *fll_div, unsigned int Fref, | |||
422 | return 0; | 422 | return 0; |
423 | } | 423 | } |
424 | 424 | ||
425 | static int wm8993_set_fll(struct snd_soc_dai *dai, int fll_id, | 425 | static int wm8993_set_fll(struct snd_soc_dai *dai, int fll_id, int source, |
426 | unsigned int Fref, unsigned int Fout) | 426 | unsigned int Fref, unsigned int Fout) |
427 | { | 427 | { |
428 | struct snd_soc_codec *codec = dai->codec; | 428 | struct snd_soc_codec *codec = dai->codec; |
@@ -1572,33 +1572,15 @@ static int wm8993_i2c_probe(struct i2c_client *i2c, | |||
1572 | /* Use automatic clock configuration */ | 1572 | /* Use automatic clock configuration */ |
1573 | snd_soc_update_bits(codec, WM8993_CLOCKING_4, WM8993_SR_MODE, 0); | 1573 | snd_soc_update_bits(codec, WM8993_CLOCKING_4, WM8993_SR_MODE, 0); |
1574 | 1574 | ||
1575 | if (!wm8993->pdata.lineout1_diff) | 1575 | wm_hubs_handle_analogue_pdata(codec, wm8993->pdata.lineout1_diff, |
1576 | snd_soc_update_bits(codec, WM8993_LINE_MIXER1, | 1576 | wm8993->pdata.lineout2_diff, |
1577 | WM8993_LINEOUT1_MODE, | 1577 | wm8993->pdata.lineout1fb, |
1578 | WM8993_LINEOUT1_MODE); | 1578 | wm8993->pdata.lineout2fb, |
1579 | if (!wm8993->pdata.lineout2_diff) | 1579 | wm8993->pdata.jd_scthr, |
1580 | snd_soc_update_bits(codec, WM8993_LINE_MIXER2, | 1580 | wm8993->pdata.jd_thr, |
1581 | WM8993_LINEOUT2_MODE, | 1581 | wm8993->pdata.micbias1_lvl, |
1582 | WM8993_LINEOUT2_MODE); | 1582 | wm8993->pdata.micbias2_lvl); |
1583 | 1583 | ||
1584 | if (wm8993->pdata.lineout1fb) | ||
1585 | snd_soc_update_bits(codec, WM8993_ADDITIONAL_CONTROL, | ||
1586 | WM8993_LINEOUT1_FB, WM8993_LINEOUT1_FB); | ||
1587 | |||
1588 | if (wm8993->pdata.lineout2fb) | ||
1589 | snd_soc_update_bits(codec, WM8993_ADDITIONAL_CONTROL, | ||
1590 | WM8993_LINEOUT2_FB, WM8993_LINEOUT2_FB); | ||
1591 | |||
1592 | /* Apply the microphone bias/detection configuration - the | ||
1593 | * platform data is directly applicable to the register. */ | ||
1594 | snd_soc_update_bits(codec, WM8993_MICBIAS, | ||
1595 | WM8993_JD_SCTHR_MASK | WM8993_JD_THR_MASK | | ||
1596 | WM8993_MICB1_LVL | WM8993_MICB2_LVL, | ||
1597 | wm8993->pdata.jd_scthr << WM8993_JD_SCTHR_SHIFT | | ||
1598 | wm8993->pdata.jd_thr << WM8993_JD_THR_SHIFT | | ||
1599 | wm8993->pdata.micbias1_lvl | | ||
1600 | wm8993->pdata.micbias1_lvl << 1); | ||
1601 | |||
1602 | ret = wm8993_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 1584 | ret = wm8993_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
1603 | if (ret != 0) | 1585 | if (ret != 0) |
1604 | goto err; | 1586 | goto err; |
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index abed37acf787..ca3d449ed89e 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c | |||
@@ -800,8 +800,8 @@ static int wm9713_set_pll(struct snd_soc_codec *codec, | |||
800 | return 0; | 800 | return 0; |
801 | } | 801 | } |
802 | 802 | ||
803 | static int wm9713_set_dai_pll(struct snd_soc_dai *codec_dai, | 803 | static int wm9713_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, |
804 | int pll_id, unsigned int freq_in, unsigned int freq_out) | 804 | int source, unsigned int freq_in, unsigned int freq_out) |
805 | { | 805 | { |
806 | struct snd_soc_codec *codec = codec_dai->codec; | 806 | struct snd_soc_codec *codec = codec_dai->codec; |
807 | return wm9713_set_pll(codec, pll_id, freq_in, freq_out); | 807 | return wm9713_set_pll(codec, pll_id, freq_in, freq_out); |
diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c index e542027eea89..810a563d0ebf 100644 --- a/sound/soc/codecs/wm_hubs.c +++ b/sound/soc/codecs/wm_hubs.c | |||
@@ -738,6 +738,41 @@ int wm_hubs_add_analogue_routes(struct snd_soc_codec *codec, | |||
738 | } | 738 | } |
739 | EXPORT_SYMBOL_GPL(wm_hubs_add_analogue_routes); | 739 | EXPORT_SYMBOL_GPL(wm_hubs_add_analogue_routes); |
740 | 740 | ||
741 | int wm_hubs_handle_analogue_pdata(struct snd_soc_codec *codec, | ||
742 | int lineout1_diff, int lineout2_diff, | ||
743 | int lineout1fb, int lineout2fb, | ||
744 | int jd_scthr, int jd_thr, int micbias1_lvl, | ||
745 | int micbias2_lvl) | ||
746 | { | ||
747 | if (!lineout1_diff) | ||
748 | snd_soc_update_bits(codec, WM8993_LINE_MIXER1, | ||
749 | WM8993_LINEOUT1_MODE, | ||
750 | WM8993_LINEOUT1_MODE); | ||
751 | if (!lineout2_diff) | ||
752 | snd_soc_update_bits(codec, WM8993_LINE_MIXER2, | ||
753 | WM8993_LINEOUT2_MODE, | ||
754 | WM8993_LINEOUT2_MODE); | ||
755 | |||
756 | if (lineout1fb) | ||
757 | snd_soc_update_bits(codec, WM8993_ADDITIONAL_CONTROL, | ||
758 | WM8993_LINEOUT1_FB, WM8993_LINEOUT1_FB); | ||
759 | |||
760 | if (lineout2fb) | ||
761 | snd_soc_update_bits(codec, WM8993_ADDITIONAL_CONTROL, | ||
762 | WM8993_LINEOUT2_FB, WM8993_LINEOUT2_FB); | ||
763 | |||
764 | snd_soc_update_bits(codec, WM8993_MICBIAS, | ||
765 | WM8993_JD_SCTHR_MASK | WM8993_JD_THR_MASK | | ||
766 | WM8993_MICB1_LVL | WM8993_MICB2_LVL, | ||
767 | jd_scthr << WM8993_JD_SCTHR_SHIFT | | ||
768 | jd_thr << WM8993_JD_THR_SHIFT | | ||
769 | micbias1_lvl | | ||
770 | micbias2_lvl << WM8993_MICB2_LVL_SHIFT); | ||
771 | |||
772 | return 0; | ||
773 | } | ||
774 | EXPORT_SYMBOL_GPL(wm_hubs_handle_analogue_pdata); | ||
775 | |||
741 | MODULE_DESCRIPTION("Shared support for Wolfson hubs products"); | 776 | MODULE_DESCRIPTION("Shared support for Wolfson hubs products"); |
742 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); | 777 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); |
743 | MODULE_LICENSE("GPL"); | 778 | MODULE_LICENSE("GPL"); |
diff --git a/sound/soc/codecs/wm_hubs.h b/sound/soc/codecs/wm_hubs.h index ec09cb6a2939..36d3fba1de8b 100644 --- a/sound/soc/codecs/wm_hubs.h +++ b/sound/soc/codecs/wm_hubs.h | |||
@@ -20,5 +20,10 @@ extern const unsigned int wm_hubs_spkmix_tlv[]; | |||
20 | 20 | ||
21 | extern int wm_hubs_add_analogue_controls(struct snd_soc_codec *); | 21 | extern int wm_hubs_add_analogue_controls(struct snd_soc_codec *); |
22 | extern int wm_hubs_add_analogue_routes(struct snd_soc_codec *, int, int); | 22 | extern int wm_hubs_add_analogue_routes(struct snd_soc_codec *, int, int); |
23 | extern int wm_hubs_handle_analogue_pdata(struct snd_soc_codec *, | ||
24 | int lineout1_diff, int lineout2_diff, | ||
25 | int lineout1fb, int lineout2fb, | ||
26 | int jd_scthr, int jd_thr, | ||
27 | int micbias1_lvl, int micbias2_lvl); | ||
23 | 28 | ||
24 | #endif | 29 | #endif |
diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig index 4dfd4ad9d90e..047ee39418c0 100644 --- a/sound/soc/davinci/Kconfig +++ b/sound/soc/davinci/Kconfig | |||
@@ -13,9 +13,9 @@ config SND_DAVINCI_SOC_MCASP | |||
13 | tristate | 13 | tristate |
14 | 14 | ||
15 | config SND_DAVINCI_SOC_EVM | 15 | config SND_DAVINCI_SOC_EVM |
16 | tristate "SoC Audio support for DaVinci DM6446 or DM355 EVM" | 16 | tristate "SoC Audio support for DaVinci DM6446, DM355 or DM365 EVM" |
17 | depends on SND_DAVINCI_SOC | 17 | depends on SND_DAVINCI_SOC |
18 | depends on MACH_DAVINCI_EVM || MACH_DAVINCI_DM355_EVM | 18 | depends on MACH_DAVINCI_EVM || MACH_DAVINCI_DM355_EVM || MACH_DAVINCI_DM365_EVM |
19 | select SND_DAVINCI_SOC_I2S | 19 | select SND_DAVINCI_SOC_I2S |
20 | select SND_SOC_TLV320AIC3X | 20 | select SND_SOC_TLV320AIC3X |
21 | help | 21 | help |
diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c index 67414f659405..7ccbe6684fc2 100644 --- a/sound/soc/davinci/davinci-evm.c +++ b/sound/soc/davinci/davinci-evm.c | |||
@@ -45,7 +45,8 @@ static int evm_hw_params(struct snd_pcm_substream *substream, | |||
45 | unsigned sysclk; | 45 | unsigned sysclk; |
46 | 46 | ||
47 | /* ASP1 on DM355 EVM is clocked by an external oscillator */ | 47 | /* ASP1 on DM355 EVM is clocked by an external oscillator */ |
48 | if (machine_is_davinci_dm355_evm() || machine_is_davinci_dm6467_evm()) | 48 | if (machine_is_davinci_dm355_evm() || machine_is_davinci_dm6467_evm() || |
49 | machine_is_davinci_dm365_evm()) | ||
49 | sysclk = 27000000; | 50 | sysclk = 27000000; |
50 | 51 | ||
51 | /* ASP0 in DM6446 EVM is clocked by U55, as configured by | 52 | /* ASP0 in DM6446 EVM is clocked by U55, as configured by |
@@ -176,7 +177,7 @@ static struct snd_soc_dai_link da8xx_evm_dai = { | |||
176 | .ops = &evm_ops, | 177 | .ops = &evm_ops, |
177 | }; | 178 | }; |
178 | 179 | ||
179 | /* davinci-evm audio machine driver */ | 180 | /* davinci dm6446, dm355 or dm365 evm audio machine driver */ |
180 | static struct snd_soc_card snd_soc_card_evm = { | 181 | static struct snd_soc_card snd_soc_card_evm = { |
181 | .name = "DaVinci EVM", | 182 | .name = "DaVinci EVM", |
182 | .platform = &davinci_soc_platform, | 183 | .platform = &davinci_soc_platform, |
@@ -243,7 +244,7 @@ static int __init evm_init(void) | |||
243 | int index; | 244 | int index; |
244 | int ret; | 245 | int ret; |
245 | 246 | ||
246 | if (machine_is_davinci_evm()) { | 247 | if (machine_is_davinci_evm() || machine_is_davinci_dm365_evm()) { |
247 | evm_snd_dev_data = &evm_snd_devdata; | 248 | evm_snd_dev_data = &evm_snd_devdata; |
248 | index = 0; | 249 | index = 0; |
249 | } else if (machine_is_davinci_dm355_evm()) { | 250 | } else if (machine_is_davinci_dm355_evm()) { |
diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index 4ae707048021..2ab809359c08 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c | |||
@@ -397,6 +397,8 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, | |||
397 | } | 397 | } |
398 | 398 | ||
399 | dma_params->acnt = dma_params->data_type; | 399 | dma_params->acnt = dma_params->data_type; |
400 | dma_params->fifo_level = 0; | ||
401 | |||
400 | rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(1); | 402 | rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(1); |
401 | xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(1); | 403 | xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(1); |
402 | 404 | ||
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 5d1f98a4c978..50ad0519a8fa 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c | |||
@@ -714,16 +714,13 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, | |||
714 | struct davinci_pcm_dma_params *dma_params = | 714 | struct davinci_pcm_dma_params *dma_params = |
715 | &dev->dma_params[substream->stream]; | 715 | &dev->dma_params[substream->stream]; |
716 | int word_length; | 716 | int word_length; |
717 | u8 numevt; | 717 | u8 fifo_level; |
718 | 718 | ||
719 | davinci_hw_common_param(dev, substream->stream); | 719 | davinci_hw_common_param(dev, substream->stream); |
720 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 720 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
721 | numevt = dev->txnumevt; | 721 | fifo_level = dev->txnumevt; |
722 | else | 722 | else |
723 | numevt = dev->rxnumevt; | 723 | fifo_level = dev->rxnumevt; |
724 | |||
725 | if (!numevt) | ||
726 | numevt = 1; | ||
727 | 724 | ||
728 | if (dev->op_mode == DAVINCI_MCASP_DIT_MODE) | 725 | if (dev->op_mode == DAVINCI_MCASP_DIT_MODE) |
729 | davinci_hw_dit_param(dev); | 726 | davinci_hw_dit_param(dev); |
@@ -751,12 +748,12 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, | |||
751 | return -EINVAL; | 748 | return -EINVAL; |
752 | } | 749 | } |
753 | 750 | ||
754 | if (dev->version == MCASP_VERSION_2) { | 751 | if (dev->version == MCASP_VERSION_2 && !fifo_level) |
755 | dma_params->data_type *= numevt; | 752 | dma_params->acnt = 4; |
756 | dma_params->acnt = 4 * numevt; | 753 | else |
757 | } else | ||
758 | dma_params->acnt = dma_params->data_type; | 754 | dma_params->acnt = dma_params->data_type; |
759 | 755 | ||
756 | dma_params->fifo_level = fifo_level; | ||
760 | davinci_config_channel_size(dev, word_length); | 757 | davinci_config_channel_size(dev, word_length); |
761 | 758 | ||
762 | return 0; | 759 | return 0; |
diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c index c73a915f233f..fb10f1d63fdb 100644 --- a/sound/soc/davinci/davinci-pcm.c +++ b/sound/soc/davinci/davinci-pcm.c | |||
@@ -66,38 +66,53 @@ static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream) | |||
66 | dma_addr_t dma_pos; | 66 | dma_addr_t dma_pos; |
67 | dma_addr_t src, dst; | 67 | dma_addr_t src, dst; |
68 | unsigned short src_bidx, dst_bidx; | 68 | unsigned short src_bidx, dst_bidx; |
69 | unsigned short src_cidx, dst_cidx; | ||
69 | unsigned int data_type; | 70 | unsigned int data_type; |
70 | unsigned short acnt; | 71 | unsigned short acnt; |
71 | unsigned int count; | 72 | unsigned int count; |
73 | unsigned int fifo_level; | ||
72 | 74 | ||
73 | period_size = snd_pcm_lib_period_bytes(substream); | 75 | period_size = snd_pcm_lib_period_bytes(substream); |
74 | dma_offset = prtd->period * period_size; | 76 | dma_offset = prtd->period * period_size; |
75 | dma_pos = runtime->dma_addr + dma_offset; | 77 | dma_pos = runtime->dma_addr + dma_offset; |
78 | fifo_level = prtd->params->fifo_level; | ||
76 | 79 | ||
77 | pr_debug("davinci_pcm: audio_set_dma_params_play channel = %d " | 80 | pr_debug("davinci_pcm: audio_set_dma_params_play channel = %d " |
78 | "dma_ptr = %x period_size=%x\n", lch, dma_pos, period_size); | 81 | "dma_ptr = %x period_size=%x\n", lch, dma_pos, period_size); |
79 | 82 | ||
80 | data_type = prtd->params->data_type; | 83 | data_type = prtd->params->data_type; |
81 | count = period_size / data_type; | 84 | count = period_size / data_type; |
85 | if (fifo_level) | ||
86 | count /= fifo_level; | ||
82 | 87 | ||
83 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 88 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
84 | src = dma_pos; | 89 | src = dma_pos; |
85 | dst = prtd->params->dma_addr; | 90 | dst = prtd->params->dma_addr; |
86 | src_bidx = data_type; | 91 | src_bidx = data_type; |
87 | dst_bidx = 0; | 92 | dst_bidx = 0; |
93 | src_cidx = data_type * fifo_level; | ||
94 | dst_cidx = 0; | ||
88 | } else { | 95 | } else { |
89 | src = prtd->params->dma_addr; | 96 | src = prtd->params->dma_addr; |
90 | dst = dma_pos; | 97 | dst = dma_pos; |
91 | src_bidx = 0; | 98 | src_bidx = 0; |
92 | dst_bidx = data_type; | 99 | dst_bidx = data_type; |
100 | src_cidx = 0; | ||
101 | dst_cidx = data_type * fifo_level; | ||
93 | } | 102 | } |
94 | 103 | ||
95 | acnt = prtd->params->acnt; | 104 | acnt = prtd->params->acnt; |
96 | edma_set_src(lch, src, INCR, W8BIT); | 105 | edma_set_src(lch, src, INCR, W8BIT); |
97 | edma_set_dest(lch, dst, INCR, W8BIT); | 106 | edma_set_dest(lch, dst, INCR, W8BIT); |
98 | edma_set_src_index(lch, src_bidx, 0); | 107 | |
99 | edma_set_dest_index(lch, dst_bidx, 0); | 108 | edma_set_src_index(lch, src_bidx, src_cidx); |
100 | edma_set_transfer_params(lch, acnt, count, 1, 0, ASYNC); | 109 | edma_set_dest_index(lch, dst_bidx, dst_cidx); |
110 | |||
111 | if (!fifo_level) | ||
112 | edma_set_transfer_params(lch, acnt, count, 1, 0, ASYNC); | ||
113 | else | ||
114 | edma_set_transfer_params(lch, acnt, fifo_level, count, | ||
115 | fifo_level, ABSYNC); | ||
101 | 116 | ||
102 | prtd->period++; | 117 | prtd->period++; |
103 | if (unlikely(prtd->period >= runtime->periods)) | 118 | if (unlikely(prtd->period >= runtime->periods)) |
diff --git a/sound/soc/davinci/davinci-pcm.h b/sound/soc/davinci/davinci-pcm.h index 8746606efc89..c8b0d2baf05a 100644 --- a/sound/soc/davinci/davinci-pcm.h +++ b/sound/soc/davinci/davinci-pcm.h | |||
@@ -23,6 +23,7 @@ struct davinci_pcm_dma_params { | |||
23 | enum dma_event_q eventq_no; /* event queue number */ | 23 | enum dma_event_q eventq_no; /* event queue number */ |
24 | unsigned char data_type; /* xfer data type */ | 24 | unsigned char data_type; /* xfer data type */ |
25 | unsigned char convert_mono_stereo; | 25 | unsigned char convert_mono_stereo; |
26 | unsigned int fifo_level; | ||
26 | }; | 27 | }; |
27 | 28 | ||
28 | 29 | ||
diff --git a/sound/soc/imx/mx27vis_wm8974.c b/sound/soc/imx/mx27vis_wm8974.c index e4dcb539108a..0267d2d91685 100644 --- a/sound/soc/imx/mx27vis_wm8974.c +++ b/sound/soc/imx/mx27vis_wm8974.c | |||
@@ -157,7 +157,7 @@ static int mx27vis_hifi_hw_params(struct snd_pcm_substream *substream, | |||
157 | 157 | ||
158 | 158 | ||
159 | /* codec PLL input is 25 MHz */ | 159 | /* codec PLL input is 25 MHz */ |
160 | ret = codec_dai->ops->set_pll(codec_dai, IGNORED_ARG, | 160 | ret = codec_dai->ops->set_pll(codec_dai, IGNORED_ARG, IGNORED_ARG, |
161 | 25000000, pll_out); | 161 | 25000000, pll_out); |
162 | if (ret < 0) { | 162 | if (ret < 0) { |
163 | printk(KERN_ERR "Error when setting PLL input\n"); | 163 | printk(KERN_ERR "Error when setting PLL input\n"); |
diff --git a/sound/soc/pxa/magician.c b/sound/soc/pxa/magician.c index 9f7c61e23daf..4c8d99a8d386 100644 --- a/sound/soc/pxa/magician.c +++ b/sound/soc/pxa/magician.c | |||
@@ -213,7 +213,7 @@ static int magician_playback_hw_params(struct snd_pcm_substream *substream, | |||
213 | return ret; | 213 | return ret; |
214 | 214 | ||
215 | /* set SSP audio pll clock */ | 215 | /* set SSP audio pll clock */ |
216 | ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, acps); | 216 | ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, 0, acps); |
217 | if (ret < 0) | 217 | if (ret < 0) |
218 | return ret; | 218 | return ret; |
219 | 219 | ||
diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index d11a6d7e384a..3bd7712f029b 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c | |||
@@ -305,8 +305,8 @@ static int pxa_ssp_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, | |||
305 | /* | 305 | /* |
306 | * Configure the PLL frequency pxa27x and (afaik - pxa320 only) | 306 | * Configure the PLL frequency pxa27x and (afaik - pxa320 only) |
307 | */ | 307 | */ |
308 | static int pxa_ssp_set_dai_pll(struct snd_soc_dai *cpu_dai, | 308 | static int pxa_ssp_set_dai_pll(struct snd_soc_dai *cpu_dai, int pll_id, |
309 | int pll_id, unsigned int freq_in, unsigned int freq_out) | 309 | int source, unsigned int freq_in, unsigned int freq_out) |
310 | { | 310 | { |
311 | struct ssp_priv *priv = cpu_dai->private_data; | 311 | struct ssp_priv *priv = cpu_dai->private_data; |
312 | struct ssp_device *ssp = priv->dev.ssp; | 312 | struct ssp_device *ssp = priv->dev.ssp; |
@@ -760,13 +760,13 @@ struct snd_soc_dai pxa_ssp_dai[] = { | |||
760 | .resume = pxa_ssp_resume, | 760 | .resume = pxa_ssp_resume, |
761 | .playback = { | 761 | .playback = { |
762 | .channels_min = 1, | 762 | .channels_min = 1, |
763 | .channels_max = 2, | 763 | .channels_max = 8, |
764 | .rates = PXA_SSP_RATES, | 764 | .rates = PXA_SSP_RATES, |
765 | .formats = PXA_SSP_FORMATS, | 765 | .formats = PXA_SSP_FORMATS, |
766 | }, | 766 | }, |
767 | .capture = { | 767 | .capture = { |
768 | .channels_min = 1, | 768 | .channels_min = 1, |
769 | .channels_max = 2, | 769 | .channels_max = 8, |
770 | .rates = PXA_SSP_RATES, | 770 | .rates = PXA_SSP_RATES, |
771 | .formats = PXA_SSP_FORMATS, | 771 | .formats = PXA_SSP_FORMATS, |
772 | }, | 772 | }, |
@@ -780,13 +780,13 @@ struct snd_soc_dai pxa_ssp_dai[] = { | |||
780 | .resume = pxa_ssp_resume, | 780 | .resume = pxa_ssp_resume, |
781 | .playback = { | 781 | .playback = { |
782 | .channels_min = 1, | 782 | .channels_min = 1, |
783 | .channels_max = 2, | 783 | .channels_max = 8, |
784 | .rates = PXA_SSP_RATES, | 784 | .rates = PXA_SSP_RATES, |
785 | .formats = PXA_SSP_FORMATS, | 785 | .formats = PXA_SSP_FORMATS, |
786 | }, | 786 | }, |
787 | .capture = { | 787 | .capture = { |
788 | .channels_min = 1, | 788 | .channels_min = 1, |
789 | .channels_max = 2, | 789 | .channels_max = 8, |
790 | .rates = PXA_SSP_RATES, | 790 | .rates = PXA_SSP_RATES, |
791 | .formats = PXA_SSP_FORMATS, | 791 | .formats = PXA_SSP_FORMATS, |
792 | }, | 792 | }, |
@@ -801,13 +801,13 @@ struct snd_soc_dai pxa_ssp_dai[] = { | |||
801 | .resume = pxa_ssp_resume, | 801 | .resume = pxa_ssp_resume, |
802 | .playback = { | 802 | .playback = { |
803 | .channels_min = 1, | 803 | .channels_min = 1, |
804 | .channels_max = 2, | 804 | .channels_max = 8, |
805 | .rates = PXA_SSP_RATES, | 805 | .rates = PXA_SSP_RATES, |
806 | .formats = PXA_SSP_FORMATS, | 806 | .formats = PXA_SSP_FORMATS, |
807 | }, | 807 | }, |
808 | .capture = { | 808 | .capture = { |
809 | .channels_min = 1, | 809 | .channels_min = 1, |
810 | .channels_max = 2, | 810 | .channels_max = 8, |
811 | .rates = PXA_SSP_RATES, | 811 | .rates = PXA_SSP_RATES, |
812 | .formats = PXA_SSP_FORMATS, | 812 | .formats = PXA_SSP_FORMATS, |
813 | }, | 813 | }, |
@@ -822,13 +822,13 @@ struct snd_soc_dai pxa_ssp_dai[] = { | |||
822 | .resume = pxa_ssp_resume, | 822 | .resume = pxa_ssp_resume, |
823 | .playback = { | 823 | .playback = { |
824 | .channels_min = 1, | 824 | .channels_min = 1, |
825 | .channels_max = 2, | 825 | .channels_max = 8, |
826 | .rates = PXA_SSP_RATES, | 826 | .rates = PXA_SSP_RATES, |
827 | .formats = PXA_SSP_FORMATS, | 827 | .formats = PXA_SSP_FORMATS, |
828 | }, | 828 | }, |
829 | .capture = { | 829 | .capture = { |
830 | .channels_min = 1, | 830 | .channels_min = 1, |
831 | .channels_max = 2, | 831 | .channels_max = 8, |
832 | .rates = PXA_SSP_RATES, | 832 | .rates = PXA_SSP_RATES, |
833 | .formats = PXA_SSP_FORMATS, | 833 | .formats = PXA_SSP_FORMATS, |
834 | }, | 834 | }, |
diff --git a/sound/soc/pxa/zylonite.c b/sound/soc/pxa/zylonite.c index 9a386b4c4ed1..dd678ae24398 100644 --- a/sound/soc/pxa/zylonite.c +++ b/sound/soc/pxa/zylonite.c | |||
@@ -74,7 +74,8 @@ static const struct snd_soc_dapm_route audio_map[] = { | |||
74 | static int zylonite_wm9713_init(struct snd_soc_codec *codec) | 74 | static int zylonite_wm9713_init(struct snd_soc_codec *codec) |
75 | { | 75 | { |
76 | if (clk_pout) | 76 | if (clk_pout) |
77 | snd_soc_dai_set_pll(&codec->dai[0], 0, clk_get_rate(pout), 0); | 77 | snd_soc_dai_set_pll(&codec->dai[0], 0, 0, |
78 | clk_get_rate(pout), 0); | ||
78 | 79 | ||
79 | snd_soc_dapm_new_controls(codec, zylonite_dapm_widgets, | 80 | snd_soc_dapm_new_controls(codec, zylonite_dapm_widgets, |
80 | ARRAY_SIZE(zylonite_dapm_widgets)); | 81 | ARRAY_SIZE(zylonite_dapm_widgets)); |
@@ -128,7 +129,7 @@ static int zylonite_voice_hw_params(struct snd_pcm_substream *substream, | |||
128 | if (ret < 0) | 129 | if (ret < 0) |
129 | return ret; | 130 | return ret; |
130 | 131 | ||
131 | ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, pll_out); | 132 | ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, 0, pll_out); |
132 | if (ret < 0) | 133 | if (ret < 0) |
133 | return ret; | 134 | return ret; |
134 | 135 | ||
diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig index 923428fc1adb..d7912f1e4627 100644 --- a/sound/soc/s3c24xx/Kconfig +++ b/sound/soc/s3c24xx/Kconfig | |||
@@ -56,6 +56,15 @@ config SND_S3C24XX_SOC_JIVE_WM8750 | |||
56 | help | 56 | help |
57 | Sat Y if you want to add support for SoC audio on the Jive. | 57 | Sat Y if you want to add support for SoC audio on the Jive. |
58 | 58 | ||
59 | config SND_S3C64XX_SOC_WM8580 | ||
60 | tristate "SoC I2S Audio support for WM8580 on SMDK64XX" | ||
61 | depends on SND_S3C24XX_SOC && (MACH_SMDK6400 || MACH_SMDK6410) | ||
62 | depends on BROKEN | ||
63 | select SND_SOC_WM8580 | ||
64 | select SND_S3C64XX_SOC_I2S | ||
65 | help | ||
66 | Sat Y if you want to add support for SoC audio on the SMDK64XX. | ||
67 | |||
59 | config SND_S3C24XX_SOC_SMDK2443_WM9710 | 68 | config SND_S3C24XX_SOC_SMDK2443_WM9710 |
60 | tristate "SoC AC97 Audio support for SMDK2443 - WM9710" | 69 | tristate "SoC AC97 Audio support for SMDK2443 - WM9710" |
61 | depends on SND_S3C24XX_SOC && MACH_SMDK2443 | 70 | depends on SND_S3C24XX_SOC && MACH_SMDK2443 |
diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile index 99f5a7dd3fc6..7790406f90b7 100644 --- a/sound/soc/s3c24xx/Makefile +++ b/sound/soc/s3c24xx/Makefile | |||
@@ -23,6 +23,7 @@ snd-soc-s3c24xx-uda134x-objs := s3c24xx_uda134x.o | |||
23 | snd-soc-s3c24xx-simtec-objs := s3c24xx_simtec.o | 23 | snd-soc-s3c24xx-simtec-objs := s3c24xx_simtec.o |
24 | snd-soc-s3c24xx-simtec-hermes-objs := s3c24xx_simtec_hermes.o | 24 | snd-soc-s3c24xx-simtec-hermes-objs := s3c24xx_simtec_hermes.o |
25 | snd-soc-s3c24xx-simtec-tlv320aic23-objs := s3c24xx_simtec_tlv320aic23.o | 25 | snd-soc-s3c24xx-simtec-tlv320aic23-objs := s3c24xx_simtec_tlv320aic23.o |
26 | snd-soc-smdk64xx-wm8580-objs := smdk64xx_wm8580.o | ||
26 | 27 | ||
27 | obj-$(CONFIG_SND_S3C24XX_SOC_JIVE_WM8750) += snd-soc-jive-wm8750.o | 28 | obj-$(CONFIG_SND_S3C24XX_SOC_JIVE_WM8750) += snd-soc-jive-wm8750.o |
28 | obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o | 29 | obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o |
@@ -33,4 +34,5 @@ obj-$(CONFIG_SND_S3C24XX_SOC_S3C24XX_UDA134X) += snd-soc-s3c24xx-uda134x.o | |||
33 | obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC) += snd-soc-s3c24xx-simtec.o | 34 | obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC) += snd-soc-s3c24xx-simtec.o |
34 | obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_HERMES) += snd-soc-s3c24xx-simtec-hermes.o | 35 | obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_HERMES) += snd-soc-s3c24xx-simtec-hermes.o |
35 | obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_TLV320AIC23) += snd-soc-s3c24xx-simtec-tlv320aic23.o | 36 | obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_TLV320AIC23) += snd-soc-s3c24xx-simtec-tlv320aic23.o |
37 | obj-$(CONFIG_SND_S3C64XX_SOC_WM8580) += snd-soc-smdk64xx-wm8580.o | ||
36 | 38 | ||
diff --git a/sound/soc/s3c24xx/neo1973_gta02_wm8753.c b/sound/soc/s3c24xx/neo1973_gta02_wm8753.c index 0c52e36ddd87..26409a9cef9e 100644 --- a/sound/soc/s3c24xx/neo1973_gta02_wm8753.c +++ b/sound/soc/s3c24xx/neo1973_gta02_wm8753.c | |||
@@ -119,7 +119,7 @@ static int neo1973_gta02_hifi_hw_params(struct snd_pcm_substream *substream, | |||
119 | return ret; | 119 | return ret; |
120 | 120 | ||
121 | /* codec PLL input is PCLK/4 */ | 121 | /* codec PLL input is PCLK/4 */ |
122 | ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, | 122 | ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, |
123 | iis_clkrate / 4, pll_out); | 123 | iis_clkrate / 4, pll_out); |
124 | if (ret < 0) | 124 | if (ret < 0) |
125 | return ret; | 125 | return ret; |
@@ -133,7 +133,7 @@ static int neo1973_gta02_hifi_hw_free(struct snd_pcm_substream *substream) | |||
133 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; | 133 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; |
134 | 134 | ||
135 | /* disable the PLL */ | 135 | /* disable the PLL */ |
136 | return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0); | 136 | return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0, 0); |
137 | } | 137 | } |
138 | 138 | ||
139 | /* | 139 | /* |
@@ -183,7 +183,7 @@ static int neo1973_gta02_voice_hw_params( | |||
183 | return ret; | 183 | return ret; |
184 | 184 | ||
185 | /* configue and enable PLL for 12.288MHz output */ | 185 | /* configue and enable PLL for 12.288MHz output */ |
186 | ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, | 186 | ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, |
187 | iis_clkrate / 4, 12288000); | 187 | iis_clkrate / 4, 12288000); |
188 | if (ret < 0) | 188 | if (ret < 0) |
189 | return ret; | 189 | return ret; |
@@ -197,7 +197,7 @@ static int neo1973_gta02_voice_hw_free(struct snd_pcm_substream *substream) | |||
197 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; | 197 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; |
198 | 198 | ||
199 | /* disable the PLL */ | 199 | /* disable the PLL */ |
200 | return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0); | 200 | return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0, 0); |
201 | } | 201 | } |
202 | 202 | ||
203 | static struct snd_soc_ops neo1973_gta02_voice_ops = { | 203 | static struct snd_soc_ops neo1973_gta02_voice_ops = { |
diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c index 906709e6dd5f..c9b794843a70 100644 --- a/sound/soc/s3c24xx/neo1973_wm8753.c +++ b/sound/soc/s3c24xx/neo1973_wm8753.c | |||
@@ -137,7 +137,7 @@ static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream, | |||
137 | return ret; | 137 | return ret; |
138 | 138 | ||
139 | /* codec PLL input is PCLK/4 */ | 139 | /* codec PLL input is PCLK/4 */ |
140 | ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, | 140 | ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, |
141 | iis_clkrate / 4, pll_out); | 141 | iis_clkrate / 4, pll_out); |
142 | if (ret < 0) | 142 | if (ret < 0) |
143 | return ret; | 143 | return ret; |
@@ -153,7 +153,7 @@ static int neo1973_hifi_hw_free(struct snd_pcm_substream *substream) | |||
153 | pr_debug("Entered %s\n", __func__); | 153 | pr_debug("Entered %s\n", __func__); |
154 | 154 | ||
155 | /* disable the PLL */ | 155 | /* disable the PLL */ |
156 | return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0); | 156 | return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0, 0); |
157 | } | 157 | } |
158 | 158 | ||
159 | /* | 159 | /* |
@@ -203,7 +203,7 @@ static int neo1973_voice_hw_params(struct snd_pcm_substream *substream, | |||
203 | return ret; | 203 | return ret; |
204 | 204 | ||
205 | /* configue and enable PLL for 12.288MHz output */ | 205 | /* configue and enable PLL for 12.288MHz output */ |
206 | ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, | 206 | ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, |
207 | iis_clkrate / 4, 12288000); | 207 | iis_clkrate / 4, 12288000); |
208 | if (ret < 0) | 208 | if (ret < 0) |
209 | return ret; | 209 | return ret; |
@@ -219,7 +219,7 @@ static int neo1973_voice_hw_free(struct snd_pcm_substream *substream) | |||
219 | pr_debug("Entered %s\n", __func__); | 219 | pr_debug("Entered %s\n", __func__); |
220 | 220 | ||
221 | /* disable the PLL */ | 221 | /* disable the PLL */ |
222 | return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0); | 222 | return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0, 0); |
223 | } | 223 | } |
224 | 224 | ||
225 | static struct snd_soc_ops neo1973_voice_ops = { | 225 | static struct snd_soc_ops neo1973_voice_ops = { |
diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.c b/sound/soc/s3c24xx/s3c-i2s-v2.c index 9bc4aa35caab..11c45a37c631 100644 --- a/sound/soc/s3c24xx/s3c-i2s-v2.c +++ b/sound/soc/s3c24xx/s3c-i2s-v2.c | |||
@@ -312,12 +312,15 @@ static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai, | |||
312 | 312 | ||
313 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | 313 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
314 | case SND_SOC_DAIFMT_RIGHT_J: | 314 | case SND_SOC_DAIFMT_RIGHT_J: |
315 | iismod |= S3C2412_IISMOD_LR_RLOW; | ||
315 | iismod |= S3C2412_IISMOD_SDF_MSB; | 316 | iismod |= S3C2412_IISMOD_SDF_MSB; |
316 | break; | 317 | break; |
317 | case SND_SOC_DAIFMT_LEFT_J: | 318 | case SND_SOC_DAIFMT_LEFT_J: |
319 | iismod |= S3C2412_IISMOD_LR_RLOW; | ||
318 | iismod |= S3C2412_IISMOD_SDF_LSB; | 320 | iismod |= S3C2412_IISMOD_SDF_LSB; |
319 | break; | 321 | break; |
320 | case SND_SOC_DAIFMT_I2S: | 322 | case SND_SOC_DAIFMT_I2S: |
323 | iismod &= ~S3C2412_IISMOD_LR_RLOW; | ||
321 | iismod |= S3C2412_IISMOD_SDF_IIS; | 324 | iismod |= S3C2412_IISMOD_SDF_IIS; |
322 | break; | 325 | break; |
323 | default: | 326 | default: |
@@ -467,6 +470,31 @@ static int s3c2412_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai, | |||
467 | 470 | ||
468 | switch (div_id) { | 471 | switch (div_id) { |
469 | case S3C_I2SV2_DIV_BCLK: | 472 | case S3C_I2SV2_DIV_BCLK: |
473 | if (div > 3) { | ||
474 | /* convert value to bit field */ | ||
475 | |||
476 | switch (div) { | ||
477 | case 16: | ||
478 | div = S3C2412_IISMOD_BCLK_16FS; | ||
479 | break; | ||
480 | |||
481 | case 32: | ||
482 | div = S3C2412_IISMOD_BCLK_32FS; | ||
483 | break; | ||
484 | |||
485 | case 24: | ||
486 | div = S3C2412_IISMOD_BCLK_24FS; | ||
487 | break; | ||
488 | |||
489 | case 48: | ||
490 | div = S3C2412_IISMOD_BCLK_48FS; | ||
491 | break; | ||
492 | |||
493 | default: | ||
494 | return -EINVAL; | ||
495 | } | ||
496 | } | ||
497 | |||
470 | reg = readl(i2s->regs + S3C2412_IISMOD); | 498 | reg = readl(i2s->regs + S3C2412_IISMOD); |
471 | reg &= ~S3C2412_IISMOD_BCLK_MASK; | 499 | reg &= ~S3C2412_IISMOD_BCLK_MASK; |
472 | writel(reg | div, i2s->regs + S3C2412_IISMOD); | 500 | writel(reg | div, i2s->regs + S3C2412_IISMOD); |
@@ -626,7 +654,7 @@ int s3c_i2sv2_probe(struct platform_device *pdev, | |||
626 | } | 654 | } |
627 | 655 | ||
628 | i2s->iis_pclk = clk_get(dev, "iis"); | 656 | i2s->iis_pclk = clk_get(dev, "iis"); |
629 | if (i2s->iis_pclk == NULL) { | 657 | if (IS_ERR(i2s->iis_pclk)) { |
630 | dev_err(dev, "failed to get iis_clock\n"); | 658 | dev_err(dev, "failed to get iis_clock\n"); |
631 | iounmap(i2s->regs); | 659 | iounmap(i2s->regs); |
632 | return -ENOENT; | 660 | return -ENOENT; |
diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.c b/sound/soc/s3c24xx/s3c64xx-i2s.c index 3c06c401d0fb..43fb253a3429 100644 --- a/sound/soc/s3c24xx/s3c64xx-i2s.c +++ b/sound/soc/s3c24xx/s3c64xx-i2s.c | |||
@@ -99,6 +99,19 @@ static int s3c64xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, | |||
99 | iismod |= S3C64XX_IISMOD_IMS_SYSMUX; | 99 | iismod |= S3C64XX_IISMOD_IMS_SYSMUX; |
100 | break; | 100 | break; |
101 | 101 | ||
102 | case S3C64XX_CLKSRC_CDCLK: | ||
103 | switch (dir) { | ||
104 | case SND_SOC_CLOCK_IN: | ||
105 | iismod |= S3C64XX_IISMOD_CDCLKCON; | ||
106 | break; | ||
107 | case SND_SOC_CLOCK_OUT: | ||
108 | iismod &= ~S3C64XX_IISMOD_CDCLKCON; | ||
109 | break; | ||
110 | default: | ||
111 | return -EINVAL; | ||
112 | } | ||
113 | break; | ||
114 | |||
102 | default: | 115 | default: |
103 | return -EINVAL; | 116 | return -EINVAL; |
104 | } | 117 | } |
@@ -111,8 +124,12 @@ static int s3c64xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, | |||
111 | struct clk *s3c64xx_i2s_get_clock(struct snd_soc_dai *dai) | 124 | struct clk *s3c64xx_i2s_get_clock(struct snd_soc_dai *dai) |
112 | { | 125 | { |
113 | struct s3c_i2sv2_info *i2s = to_info(dai); | 126 | struct s3c_i2sv2_info *i2s = to_info(dai); |
127 | u32 iismod = readl(i2s->regs + S3C2412_IISMOD); | ||
114 | 128 | ||
115 | return i2s->iis_cclk; | 129 | if (iismod & S3C64XX_IISMOD_IMS_SYSMUX) |
130 | return i2s->iis_cclk; | ||
131 | else | ||
132 | return i2s->iis_pclk; | ||
116 | } | 133 | } |
117 | EXPORT_SYMBOL_GPL(s3c64xx_i2s_get_clock); | 134 | EXPORT_SYMBOL_GPL(s3c64xx_i2s_get_clock); |
118 | 135 | ||
diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.h b/sound/soc/s3c24xx/s3c64xx-i2s.h index 02148cee2613..abe7253b55fc 100644 --- a/sound/soc/s3c24xx/s3c64xx-i2s.h +++ b/sound/soc/s3c24xx/s3c64xx-i2s.h | |||
@@ -25,6 +25,7 @@ struct clk; | |||
25 | 25 | ||
26 | #define S3C64XX_CLKSRC_PCLK (0) | 26 | #define S3C64XX_CLKSRC_PCLK (0) |
27 | #define S3C64XX_CLKSRC_MUX (1) | 27 | #define S3C64XX_CLKSRC_MUX (1) |
28 | #define S3C64XX_CLKSRC_CDCLK (2) | ||
28 | 29 | ||
29 | extern struct snd_soc_dai s3c64xx_i2s_dai[]; | 30 | extern struct snd_soc_dai s3c64xx_i2s_dai[]; |
30 | 31 | ||
diff --git a/sound/soc/s3c24xx/smdk64xx_wm8580.c b/sound/soc/s3c24xx/smdk64xx_wm8580.c new file mode 100644 index 000000000000..482aaf10eff6 --- /dev/null +++ b/sound/soc/s3c24xx/smdk64xx_wm8580.c | |||
@@ -0,0 +1,273 @@ | |||
1 | /* | ||
2 | * smdk64xx_wm8580.c | ||
3 | * | ||
4 | * Copyright (c) 2009 Samsung Electronics Co. Ltd | ||
5 | * Author: Jaswinder Singh <jassi.brar@samsung.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | */ | ||
12 | |||
13 | #include <linux/platform_device.h> | ||
14 | #include <linux/clk.h> | ||
15 | #include <sound/core.h> | ||
16 | #include <sound/pcm.h> | ||
17 | #include <sound/pcm_params.h> | ||
18 | #include <sound/soc.h> | ||
19 | #include <sound/soc-dapm.h> | ||
20 | |||
21 | #include "../codecs/wm8580.h" | ||
22 | #include "s3c24xx-pcm.h" | ||
23 | #include "s3c64xx-i2s.h" | ||
24 | |||
25 | #define S3C64XX_I2S_V4 2 | ||
26 | |||
27 | /* SMDK64XX has a 12MHZ crystal attached to WM8580 */ | ||
28 | #define SMDK64XX_WM8580_FREQ 12000000 | ||
29 | |||
30 | static int smdk64xx_hw_params(struct snd_pcm_substream *substream, | ||
31 | struct snd_pcm_hw_params *params) | ||
32 | { | ||
33 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
34 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
35 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; | ||
36 | unsigned int pll_out; | ||
37 | int bfs, rfs, ret; | ||
38 | |||
39 | switch (params_format(params)) { | ||
40 | case SNDRV_PCM_FORMAT_U8: | ||
41 | case SNDRV_PCM_FORMAT_S8: | ||
42 | bfs = 16; | ||
43 | break; | ||
44 | case SNDRV_PCM_FORMAT_U16_LE: | ||
45 | case SNDRV_PCM_FORMAT_S16_LE: | ||
46 | bfs = 32; | ||
47 | break; | ||
48 | default: | ||
49 | return -EINVAL; | ||
50 | } | ||
51 | |||
52 | /* The Fvco for WM8580 PLLs must fall within [90,100]MHz. | ||
53 | * This criterion can't be met if we request PLL output | ||
54 | * as {8000x256, 64000x256, 11025x256}Hz. | ||
55 | * As a wayout, we rather change rfs to a minimum value that | ||
56 | * results in (params_rate(params) * rfs), and itself, acceptable | ||
57 | * to both - the CODEC and the CPU. | ||
58 | */ | ||
59 | switch (params_rate(params)) { | ||
60 | case 16000: | ||
61 | case 22050: | ||
62 | case 32000: | ||
63 | case 44100: | ||
64 | case 48000: | ||
65 | case 88200: | ||
66 | case 96000: | ||
67 | rfs = 256; | ||
68 | break; | ||
69 | case 64000: | ||
70 | rfs = 384; | ||
71 | break; | ||
72 | case 8000: | ||
73 | case 11025: | ||
74 | rfs = 512; | ||
75 | break; | ||
76 | default: | ||
77 | return -EINVAL; | ||
78 | } | ||
79 | pll_out = params_rate(params) * rfs; | ||
80 | |||
81 | /* Set the Codec DAI configuration */ | ||
82 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | ||
83 | | SND_SOC_DAIFMT_NB_NF | ||
84 | | SND_SOC_DAIFMT_CBM_CFM); | ||
85 | if (ret < 0) | ||
86 | return ret; | ||
87 | |||
88 | /* Set the AP DAI configuration */ | ||
89 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | ||
90 | | SND_SOC_DAIFMT_NB_NF | ||
91 | | SND_SOC_DAIFMT_CBM_CFM); | ||
92 | if (ret < 0) | ||
93 | return ret; | ||
94 | |||
95 | ret = snd_soc_dai_set_sysclk(cpu_dai, S3C64XX_CLKSRC_CDCLK, | ||
96 | 0, SND_SOC_CLOCK_IN); | ||
97 | if (ret < 0) | ||
98 | return ret; | ||
99 | |||
100 | /* We use PCLK for basic ops in SoC-Slave mode */ | ||
101 | ret = snd_soc_dai_set_sysclk(cpu_dai, S3C64XX_CLKSRC_PCLK, | ||
102 | 0, SND_SOC_CLOCK_IN); | ||
103 | if (ret < 0) | ||
104 | return ret; | ||
105 | |||
106 | /* Set WM8580 to drive MCLK from it's PLLA */ | ||
107 | ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_MCLK, | ||
108 | WM8580_CLKSRC_PLLA); | ||
109 | if (ret < 0) | ||
110 | return ret; | ||
111 | |||
112 | /* Explicitly set WM8580-DAC to source from MCLK */ | ||
113 | ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_DAC_CLKSEL, | ||
114 | WM8580_CLKSRC_MCLK); | ||
115 | if (ret < 0) | ||
116 | return ret; | ||
117 | |||
118 | /* Assuming the CODEC driver evaluates it's rfs too from this call */ | ||
119 | ret = snd_soc_dai_set_pll(codec_dai, 0, WM8580_PLLA, | ||
120 | SMDK64XX_WM8580_FREQ, pll_out); | ||
121 | if (ret < 0) | ||
122 | return ret; | ||
123 | |||
124 | ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C_I2SV2_DIV_BCLK, bfs); | ||
125 | if (ret < 0) | ||
126 | return ret; | ||
127 | |||
128 | ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C_I2SV2_DIV_RCLK, rfs); | ||
129 | if (ret < 0) | ||
130 | return ret; | ||
131 | |||
132 | return 0; | ||
133 | } | ||
134 | |||
135 | /* | ||
136 | * SMDK64XX WM8580 DAI operations. | ||
137 | */ | ||
138 | static struct snd_soc_ops smdk64xx_ops = { | ||
139 | .hw_params = smdk64xx_hw_params, | ||
140 | }; | ||
141 | |||
142 | /* SMDK64xx Playback widgets */ | ||
143 | static const struct snd_soc_dapm_widget wm8580_dapm_widgets_pbk[] = { | ||
144 | SND_SOC_DAPM_HP("Front-L/R", NULL), | ||
145 | SND_SOC_DAPM_HP("Center/Sub", NULL), | ||
146 | SND_SOC_DAPM_HP("Rear-L/R", NULL), | ||
147 | }; | ||
148 | |||
149 | /* SMDK64xx Capture widgets */ | ||
150 | static const struct snd_soc_dapm_widget wm8580_dapm_widgets_cpt[] = { | ||
151 | SND_SOC_DAPM_MIC("MicIn", NULL), | ||
152 | SND_SOC_DAPM_LINE("LineIn", NULL), | ||
153 | }; | ||
154 | |||
155 | /* SMDK-PAIFTX connections */ | ||
156 | static const struct snd_soc_dapm_route audio_map_tx[] = { | ||
157 | /* MicIn feeds AINL */ | ||
158 | {"AINL", NULL, "MicIn"}, | ||
159 | |||
160 | /* LineIn feeds AINL/R */ | ||
161 | {"AINL", NULL, "LineIn"}, | ||
162 | {"AINR", NULL, "LineIn"}, | ||
163 | }; | ||
164 | |||
165 | /* SMDK-PAIFRX connections */ | ||
166 | static const struct snd_soc_dapm_route audio_map_rx[] = { | ||
167 | /* Front Left/Right are fed VOUT1L/R */ | ||
168 | {"Front-L/R", NULL, "VOUT1L"}, | ||
169 | {"Front-L/R", NULL, "VOUT1R"}, | ||
170 | |||
171 | /* Center/Sub are fed VOUT2L/R */ | ||
172 | {"Center/Sub", NULL, "VOUT2L"}, | ||
173 | {"Center/Sub", NULL, "VOUT2R"}, | ||
174 | |||
175 | /* Rear Left/Right are fed VOUT3L/R */ | ||
176 | {"Rear-L/R", NULL, "VOUT3L"}, | ||
177 | {"Rear-L/R", NULL, "VOUT3R"}, | ||
178 | }; | ||
179 | |||
180 | static int smdk64xx_wm8580_init_paiftx(struct snd_soc_codec *codec) | ||
181 | { | ||
182 | /* Add smdk64xx specific Capture widgets */ | ||
183 | snd_soc_dapm_new_controls(codec, wm8580_dapm_widgets_cpt, | ||
184 | ARRAY_SIZE(wm8580_dapm_widgets_cpt)); | ||
185 | |||
186 | /* Set up PAIFTX audio path */ | ||
187 | snd_soc_dapm_add_routes(codec, audio_map_tx, ARRAY_SIZE(audio_map_tx)); | ||
188 | |||
189 | /* All enabled by default */ | ||
190 | snd_soc_dapm_enable_pin(codec, "MicIn"); | ||
191 | snd_soc_dapm_enable_pin(codec, "LineIn"); | ||
192 | |||
193 | /* signal a DAPM event */ | ||
194 | snd_soc_dapm_sync(codec); | ||
195 | |||
196 | return 0; | ||
197 | } | ||
198 | |||
199 | static int smdk64xx_wm8580_init_paifrx(struct snd_soc_codec *codec) | ||
200 | { | ||
201 | /* Add smdk64xx specific Playback widgets */ | ||
202 | snd_soc_dapm_new_controls(codec, wm8580_dapm_widgets_pbk, | ||
203 | ARRAY_SIZE(wm8580_dapm_widgets_pbk)); | ||
204 | |||
205 | /* Set up PAIFRX audio path */ | ||
206 | snd_soc_dapm_add_routes(codec, audio_map_rx, ARRAY_SIZE(audio_map_rx)); | ||
207 | |||
208 | /* All enabled by default */ | ||
209 | snd_soc_dapm_enable_pin(codec, "Front-L/R"); | ||
210 | snd_soc_dapm_enable_pin(codec, "Center/Sub"); | ||
211 | snd_soc_dapm_enable_pin(codec, "Rear-L/R"); | ||
212 | |||
213 | /* signal a DAPM event */ | ||
214 | snd_soc_dapm_sync(codec); | ||
215 | |||
216 | return 0; | ||
217 | } | ||
218 | |||
219 | static struct snd_soc_dai_link smdk64xx_dai[] = { | ||
220 | { /* Primary Playback i/f */ | ||
221 | .name = "WM8580 PAIF RX", | ||
222 | .stream_name = "Playback", | ||
223 | .cpu_dai = &s3c64xx_i2s_dai[S3C64XX_I2S_V4], | ||
224 | .codec_dai = &wm8580_dai[WM8580_DAI_PAIFRX], | ||
225 | .init = smdk64xx_wm8580_init_paifrx, | ||
226 | .ops = &smdk64xx_ops, | ||
227 | }, | ||
228 | { /* Primary Capture i/f */ | ||
229 | .name = "WM8580 PAIF TX", | ||
230 | .stream_name = "Capture", | ||
231 | .cpu_dai = &s3c64xx_i2s_dai[S3C64XX_I2S_V4], | ||
232 | .codec_dai = &wm8580_dai[WM8580_DAI_PAIFTX], | ||
233 | .init = smdk64xx_wm8580_init_paiftx, | ||
234 | .ops = &smdk64xx_ops, | ||
235 | }, | ||
236 | }; | ||
237 | |||
238 | static struct snd_soc_card smdk64xx = { | ||
239 | .name = "smdk64xx", | ||
240 | .platform = &s3c24xx_soc_platform, | ||
241 | .dai_link = smdk64xx_dai, | ||
242 | .num_links = ARRAY_SIZE(smdk64xx_dai), | ||
243 | }; | ||
244 | |||
245 | static struct snd_soc_device smdk64xx_snd_devdata = { | ||
246 | .card = &smdk64xx, | ||
247 | .codec_dev = &soc_codec_dev_wm8580, | ||
248 | }; | ||
249 | |||
250 | static struct platform_device *smdk64xx_snd_device; | ||
251 | |||
252 | static int __init smdk64xx_audio_init(void) | ||
253 | { | ||
254 | int ret; | ||
255 | |||
256 | smdk64xx_snd_device = platform_device_alloc("soc-audio", -1); | ||
257 | if (!smdk64xx_snd_device) | ||
258 | return -ENOMEM; | ||
259 | |||
260 | platform_set_drvdata(smdk64xx_snd_device, &smdk64xx_snd_devdata); | ||
261 | smdk64xx_snd_devdata.dev = &smdk64xx_snd_device->dev; | ||
262 | ret = platform_device_add(smdk64xx_snd_device); | ||
263 | |||
264 | if (ret) | ||
265 | platform_device_put(smdk64xx_snd_device); | ||
266 | |||
267 | return ret; | ||
268 | } | ||
269 | module_init(smdk64xx_audio_init); | ||
270 | |||
271 | MODULE_AUTHOR("Jaswinder Singh, jassi.brar@samsung.com"); | ||
272 | MODULE_DESCRIPTION("ALSA SoC SMDK64XX WM8580"); | ||
273 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index c8ceddc2a26c..d2505e8b06c9 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c | |||
@@ -77,6 +77,35 @@ static int snd_soc_7_9_spi_write(void *control_data, const char *data, | |||
77 | #define snd_soc_7_9_spi_write NULL | 77 | #define snd_soc_7_9_spi_write NULL |
78 | #endif | 78 | #endif |
79 | 79 | ||
80 | static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg, | ||
81 | unsigned int value) | ||
82 | { | ||
83 | u8 *cache = codec->reg_cache; | ||
84 | u8 data[2]; | ||
85 | |||
86 | BUG_ON(codec->volatile_register); | ||
87 | |||
88 | data[0] = reg & 0xff; | ||
89 | data[1] = value & 0xff; | ||
90 | |||
91 | if (reg < codec->reg_cache_size) | ||
92 | cache[reg] = value; | ||
93 | |||
94 | if (codec->hw_write(codec->control_data, data, 2) == 2) | ||
95 | return 0; | ||
96 | else | ||
97 | return -EIO; | ||
98 | } | ||
99 | |||
100 | static unsigned int snd_soc_8_8_read(struct snd_soc_codec *codec, | ||
101 | unsigned int reg) | ||
102 | { | ||
103 | u8 *cache = codec->reg_cache; | ||
104 | if (reg >= codec->reg_cache_size) | ||
105 | return -1; | ||
106 | return cache[reg]; | ||
107 | } | ||
108 | |||
80 | static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg, | 109 | static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg, |
81 | unsigned int value) | 110 | unsigned int value) |
82 | { | 111 | { |
@@ -150,9 +179,20 @@ static struct { | |||
150 | unsigned int (*read)(struct snd_soc_codec *, unsigned int); | 179 | unsigned int (*read)(struct snd_soc_codec *, unsigned int); |
151 | unsigned int (*i2c_read)(struct snd_soc_codec *, unsigned int); | 180 | unsigned int (*i2c_read)(struct snd_soc_codec *, unsigned int); |
152 | } io_types[] = { | 181 | } io_types[] = { |
153 | { 7, 9, snd_soc_7_9_write, snd_soc_7_9_spi_write, snd_soc_7_9_read }, | 182 | { |
154 | { 8, 16, snd_soc_8_16_write, NULL, snd_soc_8_16_read, | 183 | .addr_bits = 7, .data_bits = 9, |
155 | snd_soc_8_16_read_i2c }, | 184 | .write = snd_soc_7_9_write, .read = snd_soc_7_9_read, |
185 | .spi_write = snd_soc_7_9_spi_write | ||
186 | }, | ||
187 | { | ||
188 | .addr_bits = 8, .data_bits = 8, | ||
189 | .write = snd_soc_8_8_write, .read = snd_soc_8_8_read, | ||
190 | }, | ||
191 | { | ||
192 | .addr_bits = 8, .data_bits = 16, | ||
193 | .write = snd_soc_8_16_write, .read = snd_soc_8_16_read, | ||
194 | .i2c_read = snd_soc_8_16_read_i2c, | ||
195 | }, | ||
156 | }; | 196 | }; |
157 | 197 | ||
158 | /** | 198 | /** |
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 7ff04ad2a97e..1dec9d21c55e 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c | |||
@@ -1254,21 +1254,39 @@ static const struct file_operations codec_reg_fops = { | |||
1254 | 1254 | ||
1255 | static void soc_init_codec_debugfs(struct snd_soc_codec *codec) | 1255 | static void soc_init_codec_debugfs(struct snd_soc_codec *codec) |
1256 | { | 1256 | { |
1257 | char codec_root[128]; | ||
1258 | |||
1259 | if (codec->dev) | ||
1260 | snprintf(codec_root, sizeof(codec_root), | ||
1261 | "%s.%s", codec->name, dev_name(codec->dev)); | ||
1262 | else | ||
1263 | snprintf(codec_root, sizeof(codec_root), | ||
1264 | "%s", codec->name); | ||
1265 | |||
1266 | codec->debugfs_codec_root = debugfs_create_dir(codec_root, | ||
1267 | debugfs_root); | ||
1268 | if (!codec->debugfs_codec_root) { | ||
1269 | printk(KERN_WARNING | ||
1270 | "ASoC: Failed to create codec debugfs directory\n"); | ||
1271 | return; | ||
1272 | } | ||
1273 | |||
1257 | codec->debugfs_reg = debugfs_create_file("codec_reg", 0644, | 1274 | codec->debugfs_reg = debugfs_create_file("codec_reg", 0644, |
1258 | debugfs_root, codec, | 1275 | codec->debugfs_codec_root, |
1259 | &codec_reg_fops); | 1276 | codec, &codec_reg_fops); |
1260 | if (!codec->debugfs_reg) | 1277 | if (!codec->debugfs_reg) |
1261 | printk(KERN_WARNING | 1278 | printk(KERN_WARNING |
1262 | "ASoC: Failed to create codec register debugfs file\n"); | 1279 | "ASoC: Failed to create codec register debugfs file\n"); |
1263 | 1280 | ||
1264 | codec->debugfs_pop_time = debugfs_create_u32("dapm_pop_time", 0744, | 1281 | codec->debugfs_pop_time = debugfs_create_u32("dapm_pop_time", 0744, |
1265 | debugfs_root, | 1282 | codec->debugfs_codec_root, |
1266 | &codec->pop_time); | 1283 | &codec->pop_time); |
1267 | if (!codec->debugfs_pop_time) | 1284 | if (!codec->debugfs_pop_time) |
1268 | printk(KERN_WARNING | 1285 | printk(KERN_WARNING |
1269 | "Failed to create pop time debugfs file\n"); | 1286 | "Failed to create pop time debugfs file\n"); |
1270 | 1287 | ||
1271 | codec->debugfs_dapm = debugfs_create_dir("dapm", debugfs_root); | 1288 | codec->debugfs_dapm = debugfs_create_dir("dapm", |
1289 | codec->debugfs_codec_root); | ||
1272 | if (!codec->debugfs_dapm) | 1290 | if (!codec->debugfs_dapm) |
1273 | printk(KERN_WARNING | 1291 | printk(KERN_WARNING |
1274 | "Failed to create DAPM debugfs directory\n"); | 1292 | "Failed to create DAPM debugfs directory\n"); |
@@ -1278,9 +1296,7 @@ static void soc_init_codec_debugfs(struct snd_soc_codec *codec) | |||
1278 | 1296 | ||
1279 | static void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec) | 1297 | static void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec) |
1280 | { | 1298 | { |
1281 | debugfs_remove_recursive(codec->debugfs_dapm); | 1299 | debugfs_remove_recursive(codec->debugfs_codec_root); |
1282 | debugfs_remove(codec->debugfs_pop_time); | ||
1283 | debugfs_remove(codec->debugfs_reg); | ||
1284 | } | 1300 | } |
1285 | 1301 | ||
1286 | #else | 1302 | #else |
@@ -2197,16 +2213,18 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_clkdiv); | |||
2197 | * snd_soc_dai_set_pll - configure DAI PLL. | 2213 | * snd_soc_dai_set_pll - configure DAI PLL. |
2198 | * @dai: DAI | 2214 | * @dai: DAI |
2199 | * @pll_id: DAI specific PLL ID | 2215 | * @pll_id: DAI specific PLL ID |
2216 | * @source: DAI specific source for the PLL | ||
2200 | * @freq_in: PLL input clock frequency in Hz | 2217 | * @freq_in: PLL input clock frequency in Hz |
2201 | * @freq_out: requested PLL output clock frequency in Hz | 2218 | * @freq_out: requested PLL output clock frequency in Hz |
2202 | * | 2219 | * |
2203 | * Configures and enables PLL to generate output clock based on input clock. | 2220 | * Configures and enables PLL to generate output clock based on input clock. |
2204 | */ | 2221 | */ |
2205 | int snd_soc_dai_set_pll(struct snd_soc_dai *dai, | 2222 | int snd_soc_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source, |
2206 | int pll_id, unsigned int freq_in, unsigned int freq_out) | 2223 | unsigned int freq_in, unsigned int freq_out) |
2207 | { | 2224 | { |
2208 | if (dai->ops && dai->ops->set_pll) | 2225 | if (dai->ops && dai->ops->set_pll) |
2209 | return dai->ops->set_pll(dai, pll_id, freq_in, freq_out); | 2226 | return dai->ops->set_pll(dai, pll_id, source, |
2227 | freq_in, freq_out); | ||
2210 | else | 2228 | else |
2211 | return -EINVAL; | 2229 | return -EINVAL; |
2212 | } | 2230 | } |
@@ -2251,6 +2269,30 @@ int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, | |||
2251 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot); | 2269 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot); |
2252 | 2270 | ||
2253 | /** | 2271 | /** |
2272 | * snd_soc_dai_set_channel_map - configure DAI audio channel map | ||
2273 | * @dai: DAI | ||
2274 | * @tx_num: how many TX channels | ||
2275 | * @tx_slot: pointer to an array which imply the TX slot number channel | ||
2276 | * 0~num-1 uses | ||
2277 | * @rx_num: how many RX channels | ||
2278 | * @rx_slot: pointer to an array which imply the RX slot number channel | ||
2279 | * 0~num-1 uses | ||
2280 | * | ||
2281 | * configure the relationship between channel number and TDM slot number. | ||
2282 | */ | ||
2283 | int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai, | ||
2284 | unsigned int tx_num, unsigned int *tx_slot, | ||
2285 | unsigned int rx_num, unsigned int *rx_slot) | ||
2286 | { | ||
2287 | if (dai->ops && dai->ops->set_channel_map) | ||
2288 | return dai->ops->set_channel_map(dai, tx_num, tx_slot, | ||
2289 | rx_num, rx_slot); | ||
2290 | else | ||
2291 | return -EINVAL; | ||
2292 | } | ||
2293 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_channel_map); | ||
2294 | |||
2295 | /** | ||
2254 | * snd_soc_dai_set_tristate - configure DAI system or master clock. | 2296 | * snd_soc_dai_set_tristate - configure DAI system or master clock. |
2255 | * @dai: DAI | 2297 | * @dai: DAI |
2256 | * @tristate: tristate enable | 2298 | * @tristate: tristate enable |
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 8de6f9dec4a2..d2af872e4771 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c | |||
@@ -719,6 +719,10 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w) | |||
719 | 719 | ||
720 | /* Check if one of our outputs is connected */ | 720 | /* Check if one of our outputs is connected */ |
721 | list_for_each_entry(path, &w->sinks, list_source) { | 721 | list_for_each_entry(path, &w->sinks, list_source) { |
722 | if (path->connected && | ||
723 | !path->connected(path->source, path->sink)) | ||
724 | continue; | ||
725 | |||
722 | if (path->sink && path->sink->power_check && | 726 | if (path->sink && path->sink->power_check && |
723 | path->sink->power_check(path->sink)) { | 727 | path->sink->power_check(path->sink)) { |
724 | power = 1; | 728 | power = 1; |
@@ -1138,6 +1142,9 @@ static ssize_t dapm_widget_power_read_file(struct file *file, | |||
1138 | w->active ? "active" : "inactive"); | 1142 | w->active ? "active" : "inactive"); |
1139 | 1143 | ||
1140 | list_for_each_entry(p, &w->sources, list_sink) { | 1144 | list_for_each_entry(p, &w->sources, list_sink) { |
1145 | if (p->connected && !p->connected(w, p->sink)) | ||
1146 | continue; | ||
1147 | |||
1141 | if (p->connect) | 1148 | if (p->connect) |
1142 | ret += snprintf(buf + ret, PAGE_SIZE - ret, | 1149 | ret += snprintf(buf + ret, PAGE_SIZE - ret, |
1143 | " in %s %s\n", | 1150 | " in %s %s\n", |
@@ -1145,6 +1152,9 @@ static ssize_t dapm_widget_power_read_file(struct file *file, | |||
1145 | p->source->name); | 1152 | p->source->name); |
1146 | } | 1153 | } |
1147 | list_for_each_entry(p, &w->sinks, list_source) { | 1154 | list_for_each_entry(p, &w->sinks, list_source) { |
1155 | if (p->connected && !p->connected(w, p->sink)) | ||
1156 | continue; | ||
1157 | |||
1148 | if (p->connect) | 1158 | if (p->connect) |
1149 | ret += snprintf(buf + ret, PAGE_SIZE - ret, | 1159 | ret += snprintf(buf + ret, PAGE_SIZE - ret, |
1150 | " out %s %s\n", | 1160 | " out %s %s\n", |
@@ -1192,8 +1202,8 @@ void snd_soc_dapm_debugfs_init(struct snd_soc_codec *codec) | |||
1192 | 1202 | ||
1193 | /* test and update the power status of a mux widget */ | 1203 | /* test and update the power status of a mux widget */ |
1194 | static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, | 1204 | static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, |
1195 | struct snd_kcontrol *kcontrol, int mask, | 1205 | struct snd_kcontrol *kcontrol, int change, |
1196 | int mux, int val, struct soc_enum *e) | 1206 | int mux, struct soc_enum *e) |
1197 | { | 1207 | { |
1198 | struct snd_soc_dapm_path *path; | 1208 | struct snd_soc_dapm_path *path; |
1199 | int found = 0; | 1209 | int found = 0; |
@@ -1202,7 +1212,7 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, | |||
1202 | widget->id != snd_soc_dapm_value_mux) | 1212 | widget->id != snd_soc_dapm_value_mux) |
1203 | return -ENODEV; | 1213 | return -ENODEV; |
1204 | 1214 | ||
1205 | if (!snd_soc_test_bits(widget->codec, e->reg, mask, val)) | 1215 | if (!change) |
1206 | return 0; | 1216 | return 0; |
1207 | 1217 | ||
1208 | /* find dapm widget path assoc with kcontrol */ | 1218 | /* find dapm widget path assoc with kcontrol */ |
@@ -1387,10 +1397,13 @@ int snd_soc_dapm_sync(struct snd_soc_codec *codec) | |||
1387 | EXPORT_SYMBOL_GPL(snd_soc_dapm_sync); | 1397 | EXPORT_SYMBOL_GPL(snd_soc_dapm_sync); |
1388 | 1398 | ||
1389 | static int snd_soc_dapm_add_route(struct snd_soc_codec *codec, | 1399 | static int snd_soc_dapm_add_route(struct snd_soc_codec *codec, |
1390 | const char *sink, const char *control, const char *source) | 1400 | const struct snd_soc_dapm_route *route) |
1391 | { | 1401 | { |
1392 | struct snd_soc_dapm_path *path; | 1402 | struct snd_soc_dapm_path *path; |
1393 | struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w; | 1403 | struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w; |
1404 | const char *sink = route->sink; | ||
1405 | const char *control = route->control; | ||
1406 | const char *source = route->source; | ||
1394 | int ret = 0; | 1407 | int ret = 0; |
1395 | 1408 | ||
1396 | /* find src and dest widgets */ | 1409 | /* find src and dest widgets */ |
@@ -1414,6 +1427,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_codec *codec, | |||
1414 | 1427 | ||
1415 | path->source = wsource; | 1428 | path->source = wsource; |
1416 | path->sink = wsink; | 1429 | path->sink = wsink; |
1430 | path->connected = route->connected; | ||
1417 | INIT_LIST_HEAD(&path->list); | 1431 | INIT_LIST_HEAD(&path->list); |
1418 | INIT_LIST_HEAD(&path->list_source); | 1432 | INIT_LIST_HEAD(&path->list_source); |
1419 | INIT_LIST_HEAD(&path->list_sink); | 1433 | INIT_LIST_HEAD(&path->list_sink); |
@@ -1514,8 +1528,7 @@ int snd_soc_dapm_add_routes(struct snd_soc_codec *codec, | |||
1514 | int i, ret; | 1528 | int i, ret; |
1515 | 1529 | ||
1516 | for (i = 0; i < num; i++) { | 1530 | for (i = 0; i < num; i++) { |
1517 | ret = snd_soc_dapm_add_route(codec, route->sink, | 1531 | ret = snd_soc_dapm_add_route(codec, route); |
1518 | route->control, route->source); | ||
1519 | if (ret < 0) { | 1532 | if (ret < 0) { |
1520 | printk(KERN_ERR "Failed to add route %s->%s\n", | 1533 | printk(KERN_ERR "Failed to add route %s->%s\n", |
1521 | route->source, | 1534 | route->source, |
@@ -1752,7 +1765,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, | |||
1752 | { | 1765 | { |
1753 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); | 1766 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); |
1754 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 1767 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
1755 | unsigned int val, mux; | 1768 | unsigned int val, mux, change; |
1756 | unsigned int mask, bitmask; | 1769 | unsigned int mask, bitmask; |
1757 | int ret = 0; | 1770 | int ret = 0; |
1758 | 1771 | ||
@@ -1772,20 +1785,21 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, | |||
1772 | 1785 | ||
1773 | mutex_lock(&widget->codec->mutex); | 1786 | mutex_lock(&widget->codec->mutex); |
1774 | widget->value = val; | 1787 | widget->value = val; |
1775 | dapm_mux_update_power(widget, kcontrol, mask, mux, val, e); | 1788 | change = snd_soc_test_bits(widget->codec, e->reg, mask, val); |
1776 | if (widget->event) { | 1789 | dapm_mux_update_power(widget, kcontrol, change, mux, e); |
1777 | if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { | 1790 | |
1778 | ret = widget->event(widget, | 1791 | if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { |
1779 | kcontrol, SND_SOC_DAPM_PRE_REG); | 1792 | ret = widget->event(widget, |
1780 | if (ret < 0) | 1793 | kcontrol, SND_SOC_DAPM_PRE_REG); |
1781 | goto out; | 1794 | if (ret < 0) |
1782 | } | 1795 | goto out; |
1783 | ret = snd_soc_update_bits(widget->codec, e->reg, mask, val); | 1796 | } |
1784 | if (widget->event_flags & SND_SOC_DAPM_POST_REG) | 1797 | |
1785 | ret = widget->event(widget, | 1798 | ret = snd_soc_update_bits(widget->codec, e->reg, mask, val); |
1786 | kcontrol, SND_SOC_DAPM_POST_REG); | 1799 | |
1787 | } else | 1800 | if (widget->event_flags & SND_SOC_DAPM_POST_REG) |
1788 | ret = snd_soc_update_bits(widget->codec, e->reg, mask, val); | 1801 | ret = widget->event(widget, |
1802 | kcontrol, SND_SOC_DAPM_POST_REG); | ||
1789 | 1803 | ||
1790 | out: | 1804 | out: |
1791 | mutex_unlock(&widget->codec->mutex); | 1805 | mutex_unlock(&widget->codec->mutex); |
@@ -1794,6 +1808,54 @@ out: | |||
1794 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double); | 1808 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double); |
1795 | 1809 | ||
1796 | /** | 1810 | /** |
1811 | * snd_soc_dapm_get_enum_virt - Get virtual DAPM mux | ||
1812 | * @kcontrol: mixer control | ||
1813 | * @ucontrol: control element information | ||
1814 | * | ||
1815 | * Returns 0 for success. | ||
1816 | */ | ||
1817 | int snd_soc_dapm_get_enum_virt(struct snd_kcontrol *kcontrol, | ||
1818 | struct snd_ctl_elem_value *ucontrol) | ||
1819 | { | ||
1820 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); | ||
1821 | |||
1822 | ucontrol->value.enumerated.item[0] = widget->value; | ||
1823 | |||
1824 | return 0; | ||
1825 | } | ||
1826 | EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_virt); | ||
1827 | |||
1828 | /** | ||
1829 | * snd_soc_dapm_put_enum_virt - Set virtual DAPM mux | ||
1830 | * @kcontrol: mixer control | ||
1831 | * @ucontrol: control element information | ||
1832 | * | ||
1833 | * Returns 0 for success. | ||
1834 | */ | ||
1835 | int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol, | ||
1836 | struct snd_ctl_elem_value *ucontrol) | ||
1837 | { | ||
1838 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); | ||
1839 | struct soc_enum *e = | ||
1840 | (struct soc_enum *)kcontrol->private_value; | ||
1841 | int change; | ||
1842 | int ret = 0; | ||
1843 | |||
1844 | if (ucontrol->value.enumerated.item[0] >= e->max) | ||
1845 | return -EINVAL; | ||
1846 | |||
1847 | mutex_lock(&widget->codec->mutex); | ||
1848 | |||
1849 | change = widget->value != ucontrol->value.enumerated.item[0]; | ||
1850 | widget->value = ucontrol->value.enumerated.item[0]; | ||
1851 | dapm_mux_update_power(widget, kcontrol, change, widget->value, e); | ||
1852 | |||
1853 | mutex_unlock(&widget->codec->mutex); | ||
1854 | return ret; | ||
1855 | } | ||
1856 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt); | ||
1857 | |||
1858 | /** | ||
1797 | * snd_soc_dapm_get_value_enum_double - dapm semi enumerated double mixer get | 1859 | * snd_soc_dapm_get_value_enum_double - dapm semi enumerated double mixer get |
1798 | * callback | 1860 | * callback |
1799 | * @kcontrol: mixer control | 1861 | * @kcontrol: mixer control |
@@ -1851,7 +1913,7 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, | |||
1851 | { | 1913 | { |
1852 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); | 1914 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); |
1853 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 1915 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
1854 | unsigned int val, mux; | 1916 | unsigned int val, mux, change; |
1855 | unsigned int mask; | 1917 | unsigned int mask; |
1856 | int ret = 0; | 1918 | int ret = 0; |
1857 | 1919 | ||
@@ -1869,20 +1931,21 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, | |||
1869 | 1931 | ||
1870 | mutex_lock(&widget->codec->mutex); | 1932 | mutex_lock(&widget->codec->mutex); |
1871 | widget->value = val; | 1933 | widget->value = val; |
1872 | dapm_mux_update_power(widget, kcontrol, mask, mux, val, e); | 1934 | change = snd_soc_test_bits(widget->codec, e->reg, mask, val); |
1873 | if (widget->event) { | 1935 | dapm_mux_update_power(widget, kcontrol, change, mux, e); |
1874 | if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { | 1936 | |
1875 | ret = widget->event(widget, | 1937 | if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { |
1876 | kcontrol, SND_SOC_DAPM_PRE_REG); | 1938 | ret = widget->event(widget, |
1877 | if (ret < 0) | 1939 | kcontrol, SND_SOC_DAPM_PRE_REG); |
1878 | goto out; | 1940 | if (ret < 0) |
1879 | } | 1941 | goto out; |
1880 | ret = snd_soc_update_bits(widget->codec, e->reg, mask, val); | 1942 | } |
1881 | if (widget->event_flags & SND_SOC_DAPM_POST_REG) | 1943 | |
1882 | ret = widget->event(widget, | 1944 | ret = snd_soc_update_bits(widget->codec, e->reg, mask, val); |
1883 | kcontrol, SND_SOC_DAPM_POST_REG); | 1945 | |
1884 | } else | 1946 | if (widget->event_flags & SND_SOC_DAPM_POST_REG) |
1885 | ret = snd_soc_update_bits(widget->codec, e->reg, mask, val); | 1947 | ret = widget->event(widget, |
1948 | kcontrol, SND_SOC_DAPM_POST_REG); | ||
1886 | 1949 | ||
1887 | out: | 1950 | out: |
1888 | mutex_unlock(&widget->codec->mutex); | 1951 | mutex_unlock(&widget->codec->mutex); |