diff options
-rw-r--r-- | sound/soc/codecs/wm8750.c | 446 | ||||
-rw-r--r-- | sound/soc/codecs/wm8750.h | 3 |
2 files changed, 113 insertions, 336 deletions
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index d4a288ba644b..c1ffb61ef7f7 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c | |||
@@ -30,7 +30,7 @@ | |||
30 | #include "wm8750.h" | 30 | #include "wm8750.h" |
31 | 31 | ||
32 | #define AUDIO_NAME "WM8750" | 32 | #define AUDIO_NAME "WM8750" |
33 | #define WM8750_VERSION "0.11" | 33 | #define WM8750_VERSION "0.12" |
34 | 34 | ||
35 | /* | 35 | /* |
36 | * Debug | 36 | * Debug |
@@ -51,6 +51,11 @@ | |||
51 | #define warn(format, arg...) \ | 51 | #define warn(format, arg...) \ |
52 | printk(KERN_WARNING AUDIO_NAME ": " format "\n" , ## arg) | 52 | printk(KERN_WARNING AUDIO_NAME ": " format "\n" , ## arg) |
53 | 53 | ||
54 | /* codec private data */ | ||
55 | struct wm8750_priv { | ||
56 | unsigned int sysclk; | ||
57 | }; | ||
58 | |||
54 | /* | 59 | /* |
55 | * wm8750 register cache | 60 | * wm8750 register cache |
56 | * We can't read the WM8750 register space when we | 61 | * We can't read the WM8750 register space when we |
@@ -70,280 +75,6 @@ static const u16 wm8750_reg[] = { | |||
70 | 0x0079, 0x0079, 0x0079, /* 40 */ | 75 | 0x0079, 0x0079, 0x0079, /* 40 */ |
71 | }; | 76 | }; |
72 | 77 | ||
73 | #define WM8750_HIFI_DAIFMT \ | ||
74 | (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_RIGHT_J | \ | ||
75 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_NB_IF | SND_SOC_DAIFMT_IB_NF | \ | ||
76 | SND_SOC_DAIFMT_IB_IF) | ||
77 | |||
78 | #define WM8750_DIR \ | ||
79 | (SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE) | ||
80 | |||
81 | #define WM8750_HIFI_FSB \ | ||
82 | (SND_SOC_FSBD(1) | SND_SOC_FSBD(2) | SND_SOC_FSBD(4) | \ | ||
83 | SND_SOC_FSBD(8) | SND_SOC_FSBD(16)) | ||
84 | |||
85 | #define WM8750_HIFI_RATES \ | ||
86 | (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \ | ||
87 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ | ||
88 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) | ||
89 | |||
90 | #define WM8750_HIFI_BITS \ | ||
91 | (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ | ||
92 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) | ||
93 | |||
94 | static struct snd_soc_dai_mode wm8750_modes[] = { | ||
95 | /* common codec frame and clock master modes */ | ||
96 | /* 8k */ | ||
97 | { | ||
98 | .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, | ||
99 | .pcmfmt = WM8750_HIFI_BITS, | ||
100 | .pcmrate = SNDRV_PCM_RATE_8000, | ||
101 | .pcmdir = WM8750_DIR, | ||
102 | .flags = SND_SOC_DAI_BFS_DIV, | ||
103 | .fs = 1536, | ||
104 | .bfs = WM8750_HIFI_FSB, | ||
105 | }, | ||
106 | { | ||
107 | .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, | ||
108 | .pcmfmt = WM8750_HIFI_BITS, | ||
109 | .pcmrate = SNDRV_PCM_RATE_8000, | ||
110 | .pcmdir = WM8750_DIR, | ||
111 | .flags = SND_SOC_DAI_BFS_DIV, | ||
112 | .fs = 1408, | ||
113 | .bfs = WM8750_HIFI_FSB, | ||
114 | }, | ||
115 | { | ||
116 | .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, | ||
117 | .pcmfmt = WM8750_HIFI_BITS, | ||
118 | .pcmrate = SNDRV_PCM_RATE_8000, | ||
119 | .pcmdir = WM8750_DIR, | ||
120 | .flags = SND_SOC_DAI_BFS_DIV, | ||
121 | .fs = 2304, | ||
122 | .bfs = WM8750_HIFI_FSB, | ||
123 | }, | ||
124 | { | ||
125 | .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, | ||
126 | .pcmfmt = WM8750_HIFI_BITS, | ||
127 | .pcmrate = SNDRV_PCM_RATE_8000, | ||
128 | .pcmdir = WM8750_DIR, | ||
129 | .flags = SND_SOC_DAI_BFS_DIV, | ||
130 | .fs = 2112, | ||
131 | .bfs = WM8750_HIFI_FSB, | ||
132 | }, | ||
133 | { | ||
134 | .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, | ||
135 | .pcmfmt = WM8750_HIFI_BITS, | ||
136 | .pcmrate = SNDRV_PCM_RATE_8000, | ||
137 | .pcmdir = WM8750_DIR, | ||
138 | .flags = SND_SOC_DAI_BFS_DIV, | ||
139 | .fs = 1500, | ||
140 | .bfs = WM8750_HIFI_FSB, | ||
141 | }, | ||
142 | |||
143 | /* 11.025k */ | ||
144 | { | ||
145 | .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, | ||
146 | .pcmfmt = WM8750_HIFI_BITS, | ||
147 | .pcmrate = SNDRV_PCM_RATE_11025, | ||
148 | .pcmdir = WM8750_DIR, | ||
149 | .flags = SND_SOC_DAI_BFS_DIV, | ||
150 | .fs = 1024, | ||
151 | .bfs = WM8750_HIFI_FSB, | ||
152 | }, | ||
153 | { | ||
154 | .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, | ||
155 | .pcmfmt = WM8750_HIFI_BITS, | ||
156 | .pcmrate = SNDRV_PCM_RATE_11025, | ||
157 | .pcmdir = WM8750_DIR, | ||
158 | .flags = SND_SOC_DAI_BFS_DIV, | ||
159 | .fs = 1536, | ||
160 | .bfs = WM8750_HIFI_FSB, | ||
161 | }, | ||
162 | { | ||
163 | .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, | ||
164 | .pcmfmt = WM8750_HIFI_BITS, | ||
165 | .pcmrate = SNDRV_PCM_RATE_11025, | ||
166 | .pcmdir = WM8750_DIR, | ||
167 | .flags = SND_SOC_DAI_BFS_DIV, | ||
168 | .fs = 1088, | ||
169 | .bfs = WM8750_HIFI_FSB, | ||
170 | }, | ||
171 | |||
172 | /* 16k */ | ||
173 | { | ||
174 | .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, | ||
175 | .pcmfmt = WM8750_HIFI_BITS, | ||
176 | .pcmrate = SNDRV_PCM_RATE_16000, | ||
177 | .pcmdir = WM8750_DIR, | ||
178 | .flags = SND_SOC_DAI_BFS_DIV, | ||
179 | .fs = 768, | ||
180 | .bfs = WM8750_HIFI_FSB, | ||
181 | }, | ||
182 | { | ||
183 | .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, | ||
184 | .pcmfmt = WM8750_HIFI_BITS, | ||
185 | .pcmrate = SNDRV_PCM_RATE_16000, | ||
186 | .pcmdir = WM8750_DIR, | ||
187 | .flags = SND_SOC_DAI_BFS_DIV, | ||
188 | .fs = 1152, | ||
189 | .bfs = WM8750_HIFI_FSB | ||
190 | }, | ||
191 | { | ||
192 | .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, | ||
193 | .pcmfmt = WM8750_HIFI_BITS, | ||
194 | .pcmrate = SNDRV_PCM_RATE_16000, | ||
195 | .pcmdir = WM8750_DIR, | ||
196 | .flags = SND_SOC_DAI_BFS_DIV, | ||
197 | .fs = 750, | ||
198 | .bfs = WM8750_HIFI_FSB, | ||
199 | }, | ||
200 | |||
201 | /* 22.05k */ | ||
202 | { | ||
203 | .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, | ||
204 | .pcmfmt = WM8750_HIFI_BITS, | ||
205 | .pcmrate = SNDRV_PCM_RATE_22050, | ||
206 | .pcmdir = WM8750_DIR, | ||
207 | .flags = SND_SOC_DAI_BFS_DIV, | ||
208 | .fs = 512, | ||
209 | .bfs = WM8750_HIFI_FSB, | ||
210 | }, | ||
211 | { | ||
212 | .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, | ||
213 | .pcmfmt = WM8750_HIFI_BITS, | ||
214 | .pcmrate = SNDRV_PCM_RATE_22050, | ||
215 | .pcmdir = WM8750_DIR, | ||
216 | .flags = SND_SOC_DAI_BFS_DIV, | ||
217 | .fs = 768, | ||
218 | .bfs = WM8750_HIFI_FSB, | ||
219 | }, | ||
220 | { | ||
221 | .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, | ||
222 | .pcmfmt = WM8750_HIFI_BITS, | ||
223 | .pcmrate = SNDRV_PCM_RATE_22050, | ||
224 | .pcmdir = WM8750_DIR, | ||
225 | .flags = SND_SOC_DAI_BFS_DIV, | ||
226 | .fs = 544, | ||
227 | .bfs = WM8750_HIFI_FSB, | ||
228 | }, | ||
229 | |||
230 | /* 32k */ | ||
231 | { | ||
232 | .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, | ||
233 | .pcmfmt = WM8750_HIFI_BITS, | ||
234 | .pcmrate = SNDRV_PCM_RATE_32000, | ||
235 | .pcmdir = WM8750_DIR, | ||
236 | .flags = SND_SOC_DAI_BFS_DIV, | ||
237 | .fs = 384, | ||
238 | .bfs = WM8750_HIFI_FSB, | ||
239 | }, | ||
240 | { | ||
241 | .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, | ||
242 | .pcmfmt = WM8750_HIFI_BITS, | ||
243 | .pcmrate = SNDRV_PCM_RATE_32000, | ||
244 | .pcmdir = WM8750_DIR, | ||
245 | .flags = SND_SOC_DAI_BFS_DIV, | ||
246 | .fs = 576, | ||
247 | .bfs = WM8750_HIFI_FSB, | ||
248 | }, | ||
249 | { | ||
250 | .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, | ||
251 | .pcmfmt = WM8750_HIFI_BITS, | ||
252 | .pcmrate = SNDRV_PCM_RATE_32000, | ||
253 | .pcmdir = WM8750_DIR, | ||
254 | .flags = SND_SOC_DAI_BFS_DIV, | ||
255 | .fs = 375, | ||
256 | .bfs = WM8750_HIFI_FSB, | ||
257 | }, | ||
258 | |||
259 | /* 44.1k & 48k */ | ||
260 | { | ||
261 | .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, | ||
262 | .pcmfmt = WM8750_HIFI_BITS, | ||
263 | .pcmrate = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, | ||
264 | .pcmdir = WM8750_DIR, | ||
265 | .flags = SND_SOC_DAI_BFS_DIV, | ||
266 | .fs = 256, | ||
267 | .bfs = WM8750_HIFI_FSB, | ||
268 | }, | ||
269 | { | ||
270 | .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, | ||
271 | .pcmfmt = WM8750_HIFI_BITS, | ||
272 | .pcmrate = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, | ||
273 | .pcmdir = WM8750_DIR, | ||
274 | .flags = SND_SOC_DAI_BFS_DIV, | ||
275 | .fs = 384, | ||
276 | .bfs = WM8750_HIFI_FSB, | ||
277 | }, | ||
278 | { | ||
279 | .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, | ||
280 | .pcmfmt = WM8750_HIFI_BITS, | ||
281 | .pcmrate = SNDRV_PCM_RATE_44100, | ||
282 | .pcmdir = WM8750_DIR, | ||
283 | .flags = SND_SOC_DAI_BFS_DIV, | ||
284 | .fs = 272, | ||
285 | .bfs = WM8750_HIFI_FSB, | ||
286 | }, | ||
287 | { | ||
288 | .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, | ||
289 | .pcmfmt = WM8750_HIFI_BITS, | ||
290 | .pcmrate = SNDRV_PCM_RATE_48000, | ||
291 | .pcmdir = WM8750_DIR, | ||
292 | .flags = SND_SOC_DAI_BFS_DIV, | ||
293 | .fs = 250, | ||
294 | .bfs = WM8750_HIFI_FSB, | ||
295 | }, | ||
296 | |||
297 | /* 88.2k & 96k */ | ||
298 | { | ||
299 | .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, | ||
300 | .pcmfmt = WM8750_HIFI_BITS, | ||
301 | .pcmrate = SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000, | ||
302 | .pcmdir = WM8750_DIR, | ||
303 | .flags = SND_SOC_DAI_BFS_DIV, | ||
304 | .fs = 128, | ||
305 | .bfs = WM8750_HIFI_FSB, | ||
306 | }, | ||
307 | { | ||
308 | .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, | ||
309 | .pcmfmt = WM8750_HIFI_BITS, | ||
310 | .pcmrate = SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000, | ||
311 | .pcmdir = WM8750_DIR, | ||
312 | .flags = SND_SOC_DAI_BFS_DIV, | ||
313 | .fs = 192, | ||
314 | .bfs = WM8750_HIFI_FSB, | ||
315 | }, | ||
316 | { | ||
317 | .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, | ||
318 | .pcmfmt = WM8750_HIFI_BITS, | ||
319 | .pcmrate = SNDRV_PCM_RATE_88200, | ||
320 | .pcmdir = WM8750_DIR, | ||
321 | .flags = SND_SOC_DAI_BFS_DIV, | ||
322 | .fs = 136, | ||
323 | .bfs = WM8750_HIFI_FSB, | ||
324 | }, | ||
325 | { | ||
326 | .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, | ||
327 | .pcmfmt = WM8750_HIFI_BITS, | ||
328 | .pcmrate = SNDRV_PCM_RATE_96000, | ||
329 | .pcmdir = WM8750_DIR, | ||
330 | .flags = SND_SOC_DAI_BFS_DIV, | ||
331 | .fs = 125, | ||
332 | .bfs = WM8750_HIFI_FSB, | ||
333 | }, | ||
334 | |||
335 | /* codec frame and clock slave modes */ | ||
336 | { | ||
337 | .fmt = WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, | ||
338 | .pcmfmt = WM8750_HIFI_BITS, | ||
339 | .pcmrate = WM8750_HIFI_RATES, | ||
340 | .pcmdir = WM8750_DIR, | ||
341 | .flags = SND_SOC_DAI_BFS_DIV, | ||
342 | .fs = SND_SOC_FS_ALL, | ||
343 | .bfs = SND_SOC_FSB_ALL, | ||
344 | }, | ||
345 | }; | ||
346 | |||
347 | /* | 78 | /* |
348 | * read wm8750 register cache | 79 | * read wm8750 register cache |
349 | */ | 80 | */ |
@@ -834,40 +565,43 @@ static inline int get_coeff(int mclk, int rate) | |||
834 | return -EINVAL; | 565 | return -EINVAL; |
835 | } | 566 | } |
836 | 567 | ||
837 | /* WM8750 supports numerous input clocks per sample rate */ | 568 | static int wm8750_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai, |
838 | static unsigned int wm8750_config_sysclk(struct snd_soc_codec_dai *dai, | 569 | int clk_id, unsigned int freq, int dir) |
839 | struct snd_soc_clock_info *info, unsigned int clk) | ||
840 | { | 570 | { |
841 | dai->mclk = clk; | 571 | struct snd_soc_codec *codec = codec_dai->codec; |
842 | return dai->mclk; | 572 | struct wm8750_priv *wm8750 = codec->private_data; |
573 | |||
574 | switch (freq) { | ||
575 | case 11289600: | ||
576 | case 12000000: | ||
577 | case 12288000: | ||
578 | case 16934400: | ||
579 | case 18432000: | ||
580 | wm8750->sysclk = freq; | ||
581 | return 0; | ||
582 | } | ||
583 | return -EINVAL; | ||
843 | } | 584 | } |
844 | 585 | ||
845 | static int wm8750_pcm_prepare(struct snd_pcm_substream *substream) | 586 | static int wm8750_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, |
587 | unsigned int fmt) | ||
846 | { | 588 | { |
847 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 589 | struct snd_soc_codec *codec = codec_dai->codec; |
848 | struct snd_soc_device *socdev = rtd->socdev; | 590 | u16 iface = 0; |
849 | struct snd_soc_codec *codec = socdev->codec; | ||
850 | u16 iface = 0, bfs, srate = 0; | ||
851 | int i = get_coeff(rtd->codec_dai->mclk, | ||
852 | snd_soc_get_rate(rtd->codec_dai->dai_runtime.pcmrate)); | ||
853 | |||
854 | /* is coefficient valid ? */ | ||
855 | if (i < 0) | ||
856 | return i; | ||
857 | |||
858 | bfs = SND_SOC_FSBD_REAL(rtd->codec_dai->dai_runtime.bfs); | ||
859 | 591 | ||
860 | /* set master/slave audio interface */ | 592 | /* set master/slave audio interface */ |
861 | switch (rtd->codec_dai->dai_runtime.fmt & SND_SOC_DAIFMT_CLOCK_MASK) { | 593 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
862 | case SND_SOC_DAIFMT_CBM_CFM: | 594 | case SND_SOC_DAIFMT_CBM_CFM: |
863 | iface = 0x0040; | 595 | iface = 0x0040; |
864 | break; | 596 | break; |
865 | case SND_SOC_DAIFMT_CBS_CFS: | 597 | case SND_SOC_DAIFMT_CBS_CFS: |
866 | break; | 598 | break; |
599 | default: | ||
600 | return -EINVAL; | ||
867 | } | 601 | } |
868 | 602 | ||
869 | /* interface format */ | 603 | /* interface format */ |
870 | switch (rtd->codec_dai->dai_runtime.fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | 604 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
871 | case SND_SOC_DAIFMT_I2S: | 605 | case SND_SOC_DAIFMT_I2S: |
872 | iface |= 0x0002; | 606 | iface |= 0x0002; |
873 | break; | 607 | break; |
@@ -882,25 +616,12 @@ static int wm8750_pcm_prepare(struct snd_pcm_substream *substream) | |||
882 | case SND_SOC_DAIFMT_DSP_B: | 616 | case SND_SOC_DAIFMT_DSP_B: |
883 | iface |= 0x0013; | 617 | iface |= 0x0013; |
884 | break; | 618 | break; |
885 | } | 619 | default: |
886 | 620 | return -EINVAL; | |
887 | /* bit size */ | ||
888 | switch (rtd->codec_dai->dai_runtime.pcmfmt) { | ||
889 | case SNDRV_PCM_FMTBIT_S16_LE: | ||
890 | break; | ||
891 | case SNDRV_PCM_FMTBIT_S20_3LE: | ||
892 | iface |= 0x0004; | ||
893 | break; | ||
894 | case SNDRV_PCM_FMTBIT_S24_LE: | ||
895 | iface |= 0x0008; | ||
896 | break; | ||
897 | case SNDRV_PCM_FMTBIT_S32_LE: | ||
898 | iface |= 0x000c; | ||
899 | break; | ||
900 | } | 621 | } |
901 | 622 | ||
902 | /* clock inversion */ | 623 | /* clock inversion */ |
903 | switch (rtd->codec_dai->dai_runtime.fmt & SND_SOC_DAIFMT_INV_MASK) { | 624 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { |
904 | case SND_SOC_DAIFMT_NB_NF: | 625 | case SND_SOC_DAIFMT_NB_NF: |
905 | break; | 626 | break; |
906 | case SND_SOC_DAIFMT_IB_IF: | 627 | case SND_SOC_DAIFMT_IB_IF: |
@@ -912,35 +633,54 @@ static int wm8750_pcm_prepare(struct snd_pcm_substream *substream) | |||
912 | case SND_SOC_DAIFMT_NB_IF: | 633 | case SND_SOC_DAIFMT_NB_IF: |
913 | iface |= 0x0010; | 634 | iface |= 0x0010; |
914 | break; | 635 | break; |
636 | default: | ||
637 | return -EINVAL; | ||
915 | } | 638 | } |
916 | 639 | ||
917 | /* set bclk divisor rate */ | 640 | wm8750_write(codec, WM8750_IFACE, iface); |
918 | switch (bfs) { | 641 | return 0; |
919 | case 1: | 642 | } |
643 | |||
644 | static int wm8750_pcm_hw_params(struct snd_pcm_substream *substream, | ||
645 | struct snd_pcm_hw_params *params) | ||
646 | { | ||
647 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
648 | struct snd_soc_device *socdev = rtd->socdev; | ||
649 | struct snd_soc_codec *codec = socdev->codec; | ||
650 | struct wm8750_priv *wm8750 = codec->private_data; | ||
651 | u16 iface = wm8750_read_reg_cache(codec, WM8750_IFACE) & 0x1f3; | ||
652 | u16 srate = wm8750_read_reg_cache(codec, WM8750_SRATE) & 0x1c0; | ||
653 | int coeff = get_coeff(wm8750->sysclk, params_rate(params)); | ||
654 | |||
655 | /* bit size */ | ||
656 | switch (params_format(params)) { | ||
657 | case SNDRV_PCM_FORMAT_S16_LE: | ||
920 | break; | 658 | break; |
921 | case 4: | 659 | case SNDRV_PCM_FORMAT_S20_3LE: |
922 | srate |= (0x1 << 7); | 660 | iface |= 0x0004; |
923 | break; | 661 | break; |
924 | case 8: | 662 | case SNDRV_PCM_FORMAT_S24_LE: |
925 | srate |= (0x2 << 7); | 663 | iface |= 0x0008; |
926 | break; | 664 | break; |
927 | case 16: | 665 | case SNDRV_PCM_FORMAT_S32_LE: |
928 | srate |= (0x3 << 7); | 666 | iface |= 0x000c; |
929 | break; | 667 | break; |
930 | } | 668 | } |
931 | 669 | ||
932 | /* set iface & srate */ | 670 | /* set iface & srate */ |
933 | wm8750_write(codec, WM8750_IFACE, iface); | 671 | wm8750_write(codec, WM8750_IFACE, iface); |
934 | wm8750_write(codec, WM8750_SRATE, srate | | 672 | if (coeff >= 0) |
935 | (coeff_div[i].sr << 1) | coeff_div[i].usb); | 673 | wm8750_write(codec, WM8750_SRATE, srate | |
674 | (coeff_div[coeff].sr << 1) | coeff_div[coeff].usb); | ||
936 | 675 | ||
937 | return 0; | 676 | return 0; |
938 | } | 677 | } |
939 | 678 | ||
940 | static int wm8750_mute(struct snd_soc_codec *codec, | 679 | static int wm8750_mute(struct snd_soc_codec_dai *dai, int mute) |
941 | struct snd_soc_codec_dai *dai, int mute) | ||
942 | { | 680 | { |
681 | struct snd_soc_codec *codec = dai->codec; | ||
943 | u16 mute_reg = wm8750_read_reg_cache(codec, WM8750_ADCDAC) & 0xfff7; | 682 | u16 mute_reg = wm8750_read_reg_cache(codec, WM8750_ADCDAC) & 0xfff7; |
683 | |||
944 | if (mute) | 684 | if (mute) |
945 | wm8750_write(codec, WM8750_ADCDAC, mute_reg | 0x8); | 685 | wm8750_write(codec, WM8750_ADCDAC, mute_reg | 0x8); |
946 | else | 686 | else |
@@ -974,26 +714,34 @@ static int wm8750_dapm_event(struct snd_soc_codec *codec, int event) | |||
974 | return 0; | 714 | return 0; |
975 | } | 715 | } |
976 | 716 | ||
717 | #define WM8750_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | ||
718 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \ | ||
719 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) | ||
720 | |||
721 | #define WM8750_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | ||
722 | SNDRV_PCM_FMTBIT_S24_LE) | ||
723 | |||
977 | struct snd_soc_codec_dai wm8750_dai = { | 724 | struct snd_soc_codec_dai wm8750_dai = { |
978 | .name = "WM8750", | 725 | .name = "WM8750", |
979 | .playback = { | 726 | .playback = { |
980 | .stream_name = "Playback", | 727 | .stream_name = "Playback", |
981 | .channels_min = 1, | 728 | .channels_min = 1, |
982 | .channels_max = 2, | 729 | .channels_max = 2, |
983 | }, | 730 | .rates = WM8750_RATES, |
731 | .formats = WM8750_FORMATS,}, | ||
984 | .capture = { | 732 | .capture = { |
985 | .stream_name = "Capture", | 733 | .stream_name = "Capture", |
986 | .channels_min = 1, | 734 | .channels_min = 1, |
987 | .channels_max = 2, | 735 | .channels_max = 2, |
988 | }, | 736 | .rates = WM8750_RATES, |
989 | .config_sysclk = wm8750_config_sysclk, | 737 | .formats = WM8750_FORMATS,}, |
990 | .digital_mute = wm8750_mute, | ||
991 | .ops = { | 738 | .ops = { |
992 | .prepare = wm8750_pcm_prepare, | 739 | .hw_params = wm8750_pcm_hw_params, |
993 | }, | 740 | }, |
994 | .caps = { | 741 | .dai_ops = { |
995 | .num_modes = ARRAY_SIZE(wm8750_modes), | 742 | .digital_mute = wm8750_mute, |
996 | .mode = wm8750_modes, | 743 | .set_fmt = wm8750_set_dai_fmt, |
744 | .set_sysclk = wm8750_set_dai_sysclk, | ||
997 | }, | 745 | }, |
998 | }; | 746 | }; |
999 | EXPORT_SYMBOL_GPL(wm8750_dai); | 747 | EXPORT_SYMBOL_GPL(wm8750_dai); |
@@ -1037,8 +785,7 @@ static int wm8750_resume(struct platform_device *pdev) | |||
1037 | if (codec->suspend_dapm_state == SNDRV_CTL_POWER_D0) { | 785 | if (codec->suspend_dapm_state == SNDRV_CTL_POWER_D0) { |
1038 | wm8750_dapm_event(codec, SNDRV_CTL_POWER_D2); | 786 | wm8750_dapm_event(codec, SNDRV_CTL_POWER_D2); |
1039 | codec->dapm_state = SNDRV_CTL_POWER_D0; | 787 | codec->dapm_state = SNDRV_CTL_POWER_D0; |
1040 | schedule_delayed_work(&codec->delayed_work, | 788 | schedule_delayed_work(&codec->delayed_work, msecs_to_jiffies(1000)); |
1041 | msecs_to_jiffies(1000)); | ||
1042 | } | 789 | } |
1043 | 790 | ||
1044 | return 0; | 791 | return 0; |
@@ -1218,6 +965,7 @@ static int wm8750_probe(struct platform_device *pdev) | |||
1218 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 965 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
1219 | struct wm8750_setup_data *setup = socdev->codec_data; | 966 | struct wm8750_setup_data *setup = socdev->codec_data; |
1220 | struct snd_soc_codec *codec; | 967 | struct snd_soc_codec *codec; |
968 | struct wm8750_priv *wm8750; | ||
1221 | int ret = 0; | 969 | int ret = 0; |
1222 | 970 | ||
1223 | info("WM8750 Audio Codec %s", WM8750_VERSION); | 971 | info("WM8750 Audio Codec %s", WM8750_VERSION); |
@@ -1225,12 +973,20 @@ static int wm8750_probe(struct platform_device *pdev) | |||
1225 | if (codec == NULL) | 973 | if (codec == NULL) |
1226 | return -ENOMEM; | 974 | return -ENOMEM; |
1227 | 975 | ||
976 | wm8750 = kzalloc(sizeof(struct wm8750_priv), GFP_KERNEL); | ||
977 | if (wm8750 == NULL) { | ||
978 | kfree(codec); | ||
979 | return -ENOMEM; | ||
980 | } | ||
981 | |||
982 | codec->private_data = wm8750; | ||
1228 | socdev->codec = codec; | 983 | socdev->codec = codec; |
1229 | mutex_init(&codec->mutex); | 984 | mutex_init(&codec->mutex); |
1230 | INIT_LIST_HEAD(&codec->dapm_widgets); | 985 | INIT_LIST_HEAD(&codec->dapm_widgets); |
1231 | INIT_LIST_HEAD(&codec->dapm_paths); | 986 | INIT_LIST_HEAD(&codec->dapm_paths); |
1232 | wm8750_socdev = socdev; | 987 | wm8750_socdev = socdev; |
1233 | INIT_DELAYED_WORK(&codec->delayed_work, wm8750_work); | 988 | INIT_DELAYED_WORK(&codec->delayed_work, wm8750_work); |
989 | |||
1234 | #if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) | 990 | #if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) |
1235 | if (setup->i2c_address) { | 991 | if (setup->i2c_address) { |
1236 | normal_i2c[0] = setup->i2c_address; | 992 | normal_i2c[0] = setup->i2c_address; |
@@ -1246,6 +1002,25 @@ static int wm8750_probe(struct platform_device *pdev) | |||
1246 | return ret; | 1002 | return ret; |
1247 | } | 1003 | } |
1248 | 1004 | ||
1005 | /* | ||
1006 | * This function forces any delayed work to be queued and run. | ||
1007 | */ | ||
1008 | static int run_delayed_work(struct delayed_work *dwork) | ||
1009 | { | ||
1010 | int ret; | ||
1011 | |||
1012 | /* cancel any work waiting to be queued. */ | ||
1013 | ret = cancel_delayed_work(dwork); | ||
1014 | |||
1015 | /* if there was any work waiting then we run it now and | ||
1016 | * wait for it's completion */ | ||
1017 | if (ret) { | ||
1018 | schedule_delayed_work(dwork, 0); | ||
1019 | flush_scheduled_work(); | ||
1020 | } | ||
1021 | return ret; | ||
1022 | } | ||
1023 | |||
1249 | /* power down chip */ | 1024 | /* power down chip */ |
1250 | static int wm8750_remove(struct platform_device *pdev) | 1025 | static int wm8750_remove(struct platform_device *pdev) |
1251 | { | 1026 | { |
@@ -1254,12 +1029,13 @@ static int wm8750_remove(struct platform_device *pdev) | |||
1254 | 1029 | ||
1255 | if (codec->control_data) | 1030 | if (codec->control_data) |
1256 | wm8750_dapm_event(codec, SNDRV_CTL_POWER_D3cold); | 1031 | wm8750_dapm_event(codec, SNDRV_CTL_POWER_D3cold); |
1257 | flush_scheduled_work(); | 1032 | run_delayed_work(&codec->delayed_work); |
1258 | snd_soc_free_pcms(socdev); | 1033 | snd_soc_free_pcms(socdev); |
1259 | snd_soc_dapm_free(socdev); | 1034 | snd_soc_dapm_free(socdev); |
1260 | #if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) | 1035 | #if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) |
1261 | i2c_del_driver(&wm8750_i2c_driver); | 1036 | i2c_del_driver(&wm8750_i2c_driver); |
1262 | #endif | 1037 | #endif |
1038 | kfree(codec->private_data); | ||
1263 | kfree(codec); | 1039 | kfree(codec); |
1264 | 1040 | ||
1265 | return 0; | 1041 | return 0; |
diff --git a/sound/soc/codecs/wm8750.h b/sound/soc/codecs/wm8750.h index ee5eea4a2d34..a97a54a6348e 100644 --- a/sound/soc/codecs/wm8750.h +++ b/sound/soc/codecs/wm8750.h | |||
@@ -55,9 +55,10 @@ | |||
55 | 55 | ||
56 | #define WM8750_CACHE_REGNUM 0x2a | 56 | #define WM8750_CACHE_REGNUM 0x2a |
57 | 57 | ||
58 | #define WM8750_SYSCLK 0 | ||
59 | |||
58 | struct wm8750_setup_data { | 60 | struct wm8750_setup_data { |
59 | unsigned short i2c_address; | 61 | unsigned short i2c_address; |
60 | unsigned int mclk; | ||
61 | }; | 62 | }; |
62 | 63 | ||
63 | extern struct snd_soc_codec_dai wm8750_dai; | 64 | extern struct snd_soc_codec_dai wm8750_dai; |