aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorLiam Girdwood <lg@opensource.wolfsonmicro.com>2007-02-02 11:15:33 -0500
committerJaroslav Kysela <perex@suse.cz>2007-02-09 03:03:39 -0500
commit4422b606bc04eab01dd5cb6f8e6dd0608d65bb11 (patch)
tree85920f9a1d11c685ec410f3c069546ff567b12ca /sound
parentb36d61d45654104c04ff71055ef09c696fea5f89 (diff)
[ALSA] soc - ASoC 0.13 WM8750 codec driver
This patch updates the WM8750 codec driver to the new API in ASoC 0.13. Changes:- o Removed DAI capabilities matching code in favour of manual matching in the machine drivers. o Added DAI operations for codec and CPU interfaces. o Removed config_sysclk() function and struct snd_soc_clock_info. No longer needed as clocking is now configured manually in the machine drivers. Also removed other clocking data from structures. Signed-off-by: Liam Girdwood <lg@opensource.wolfsonmicro.com> Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Jaroslav Kysela <perex@suse.cz>
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/codecs/wm8750.c446
-rw-r--r--sound/soc/codecs/wm8750.h3
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 */
55struct 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
94static 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 */ 568static int wm8750_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai,
838static 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
845static int wm8750_pcm_prepare(struct snd_pcm_substream *substream) 586static 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
644static 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
940static int wm8750_mute(struct snd_soc_codec *codec, 679static 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
977struct snd_soc_codec_dai wm8750_dai = { 724struct 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};
999EXPORT_SYMBOL_GPL(wm8750_dai); 747EXPORT_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 */
1008static 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 */
1250static int wm8750_remove(struct platform_device *pdev) 1025static 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
58struct wm8750_setup_data { 60struct wm8750_setup_data {
59 unsigned short i2c_address; 61 unsigned short i2c_address;
60 unsigned int mclk;
61}; 62};
62 63
63extern struct snd_soc_codec_dai wm8750_dai; 64extern struct snd_soc_codec_dai wm8750_dai;