]> pilppa.org Git - linux-2.6-omap-h63xx.git/blob - sound/soc/codecs/wm8510.c
16768a5acc4c99e7830c3a6e3e9365cd25ae2ed4
[linux-2.6-omap-h63xx.git] / sound / soc / codecs / wm8510.c
1 /*
2  * wm8510.c  --  WM8510 ALSA Soc Audio driver
3  *
4  * Copyright 2006 Wolfson Microelectronics PLC.
5  *
6  * Author: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  */
12
13 #include <linux/module.h>
14 #include <linux/moduleparam.h>
15 #include <linux/kernel.h>
16 #include <linux/init.h>
17 #include <linux/delay.h>
18 #include <linux/pm.h>
19 #include <linux/i2c.h>
20 #include <linux/platform_device.h>
21 #include <linux/spi/spi.h>
22 #include <sound/core.h>
23 #include <sound/pcm.h>
24 #include <sound/pcm_params.h>
25 #include <sound/soc.h>
26 #include <sound/soc-dapm.h>
27 #include <sound/initval.h>
28
29 #include "wm8510.h"
30
31 #define AUDIO_NAME "wm8510"
32 #define WM8510_VERSION "0.6"
33
34 struct snd_soc_codec_device soc_codec_dev_wm8510;
35
36 /*
37  * wm8510 register cache
38  * We can't read the WM8510 register space when we are
39  * using 2 wire for device control, so we cache them instead.
40  */
41 static const u16 wm8510_reg[WM8510_CACHEREGNUM] = {
42         0x0000, 0x0000, 0x0000, 0x0000,
43         0x0050, 0x0000, 0x0140, 0x0000,
44         0x0000, 0x0000, 0x0000, 0x00ff,
45         0x0000, 0x0000, 0x0100, 0x00ff,
46         0x0000, 0x0000, 0x012c, 0x002c,
47         0x002c, 0x002c, 0x002c, 0x0000,
48         0x0032, 0x0000, 0x0000, 0x0000,
49         0x0000, 0x0000, 0x0000, 0x0000,
50         0x0038, 0x000b, 0x0032, 0x0000,
51         0x0008, 0x000c, 0x0093, 0x00e9,
52         0x0000, 0x0000, 0x0000, 0x0000,
53         0x0003, 0x0010, 0x0000, 0x0000,
54         0x0000, 0x0002, 0x0001, 0x0000,
55         0x0000, 0x0000, 0x0039, 0x0000,
56         0x0001,
57 };
58
59 /*
60  * read wm8510 register cache
61  */
62 static inline unsigned int wm8510_read_reg_cache(struct snd_soc_codec *codec,
63         unsigned int reg)
64 {
65         u16 *cache = codec->reg_cache;
66         if (reg == WM8510_RESET)
67                 return 0;
68         if (reg >= WM8510_CACHEREGNUM)
69                 return -1;
70         return cache[reg];
71 }
72
73 /*
74  * write wm8510 register cache
75  */
76 static inline void wm8510_write_reg_cache(struct snd_soc_codec *codec,
77         u16 reg, unsigned int value)
78 {
79         u16 *cache = codec->reg_cache;
80         if (reg >= WM8510_CACHEREGNUM)
81                 return;
82         cache[reg] = value;
83 }
84
85 /*
86  * write to the WM8510 register space
87  */
88 static int wm8510_write(struct snd_soc_codec *codec, unsigned int reg,
89         unsigned int value)
90 {
91         u8 data[2];
92
93         /* data is
94          *   D15..D9 WM8510 register offset
95          *   D8...D0 register data
96          */
97         data[0] = (reg << 1) | ((value >> 8) & 0x0001);
98         data[1] = value & 0x00ff;
99
100         wm8510_write_reg_cache(codec, reg, value);
101         if (codec->hw_write(codec->control_data, data, 2) == 2)
102                 return 0;
103         else
104                 return -EIO;
105 }
106
107 #define wm8510_reset(c) wm8510_write(c, WM8510_RESET, 0)
108
109 static const char *wm8510_companding[] = { "Off", "NC", "u-law", "A-law" };
110 static const char *wm8510_deemp[] = { "None", "32kHz", "44.1kHz", "48kHz" };
111 static const char *wm8510_alc[] = { "ALC", "Limiter" };
112
113 static const struct soc_enum wm8510_enum[] = {
114         SOC_ENUM_SINGLE(WM8510_COMP, 1, 4, wm8510_companding), /* adc */
115         SOC_ENUM_SINGLE(WM8510_COMP, 3, 4, wm8510_companding), /* dac */
116         SOC_ENUM_SINGLE(WM8510_DAC,  4, 4, wm8510_deemp),
117         SOC_ENUM_SINGLE(WM8510_ALC3,  8, 2, wm8510_alc),
118 };
119
120 static const struct snd_kcontrol_new wm8510_snd_controls[] = {
121
122 SOC_SINGLE("Digital Loopback Switch", WM8510_COMP, 0, 1, 0),
123
124 SOC_ENUM("DAC Companding", wm8510_enum[1]),
125 SOC_ENUM("ADC Companding", wm8510_enum[0]),
126
127 SOC_ENUM("Playback De-emphasis", wm8510_enum[2]),
128 SOC_SINGLE("DAC Inversion Switch", WM8510_DAC, 0, 1, 0),
129
130 SOC_SINGLE("Master Playback Volume", WM8510_DACVOL, 0, 127, 0),
131
132 SOC_SINGLE("High Pass Filter Switch", WM8510_ADC, 8, 1, 0),
133 SOC_SINGLE("High Pass Cut Off", WM8510_ADC, 4, 7, 0),
134 SOC_SINGLE("ADC Inversion Switch", WM8510_COMP, 0, 1, 0),
135
136 SOC_SINGLE("Capture Volume", WM8510_ADCVOL,  0, 127, 0),
137
138 SOC_SINGLE("DAC Playback Limiter Switch", WM8510_DACLIM1,  8, 1, 0),
139 SOC_SINGLE("DAC Playback Limiter Decay", WM8510_DACLIM1,  4, 15, 0),
140 SOC_SINGLE("DAC Playback Limiter Attack", WM8510_DACLIM1,  0, 15, 0),
141
142 SOC_SINGLE("DAC Playback Limiter Threshold", WM8510_DACLIM2,  4, 7, 0),
143 SOC_SINGLE("DAC Playback Limiter Boost", WM8510_DACLIM2,  0, 15, 0),
144
145 SOC_SINGLE("ALC Enable Switch", WM8510_ALC1,  8, 1, 0),
146 SOC_SINGLE("ALC Capture Max Gain", WM8510_ALC1,  3, 7, 0),
147 SOC_SINGLE("ALC Capture Min Gain", WM8510_ALC1,  0, 7, 0),
148
149 SOC_SINGLE("ALC Capture ZC Switch", WM8510_ALC2,  8, 1, 0),
150 SOC_SINGLE("ALC Capture Hold", WM8510_ALC2,  4, 7, 0),
151 SOC_SINGLE("ALC Capture Target", WM8510_ALC2,  0, 15, 0),
152
153 SOC_ENUM("ALC Capture Mode", wm8510_enum[3]),
154 SOC_SINGLE("ALC Capture Decay", WM8510_ALC3,  4, 15, 0),
155 SOC_SINGLE("ALC Capture Attack", WM8510_ALC3,  0, 15, 0),
156
157 SOC_SINGLE("ALC Capture Noise Gate Switch", WM8510_NGATE,  3, 1, 0),
158 SOC_SINGLE("ALC Capture Noise Gate Threshold", WM8510_NGATE,  0, 7, 0),
159
160 SOC_SINGLE("Capture PGA ZC Switch", WM8510_INPPGA,  7, 1, 0),
161 SOC_SINGLE("Capture PGA Volume", WM8510_INPPGA,  0, 63, 0),
162
163 SOC_SINGLE("Speaker Playback ZC Switch", WM8510_SPKVOL,  7, 1, 0),
164 SOC_SINGLE("Speaker Playback Switch", WM8510_SPKVOL,  6, 1, 1),
165 SOC_SINGLE("Speaker Playback Volume", WM8510_SPKVOL,  0, 63, 0),
166 SOC_SINGLE("Speaker Boost", WM8510_OUTPUT, 2, 1, 0),
167
168 SOC_SINGLE("Capture Boost(+20dB)", WM8510_ADCBOOST,  8, 1, 0),
169 SOC_SINGLE("Mono Playback Switch", WM8510_MONOMIX, 6, 1, 1),
170 };
171
172 /* add non dapm controls */
173 static int wm8510_add_controls(struct snd_soc_codec *codec)
174 {
175         int err, i;
176
177         for (i = 0; i < ARRAY_SIZE(wm8510_snd_controls); i++) {
178                 err = snd_ctl_add(codec->card,
179                                 snd_soc_cnew(&wm8510_snd_controls[i], codec,
180                                         NULL));
181                 if (err < 0)
182                         return err;
183         }
184
185         return 0;
186 }
187
188 /* Speaker Output Mixer */
189 static const struct snd_kcontrol_new wm8510_speaker_mixer_controls[] = {
190 SOC_DAPM_SINGLE("Line Bypass Switch", WM8510_SPKMIX, 1, 1, 0),
191 SOC_DAPM_SINGLE("Aux Playback Switch", WM8510_SPKMIX, 5, 1, 0),
192 SOC_DAPM_SINGLE("PCM Playback Switch", WM8510_SPKMIX, 0, 1, 0),
193 };
194
195 /* Mono Output Mixer */
196 static const struct snd_kcontrol_new wm8510_mono_mixer_controls[] = {
197 SOC_DAPM_SINGLE("Line Bypass Switch", WM8510_MONOMIX, 1, 1, 0),
198 SOC_DAPM_SINGLE("Aux Playback Switch", WM8510_MONOMIX, 2, 1, 0),
199 SOC_DAPM_SINGLE("PCM Playback Switch", WM8510_MONOMIX, 0, 1, 0),
200 };
201
202 static const struct snd_kcontrol_new wm8510_boost_controls[] = {
203 SOC_DAPM_SINGLE("Mic PGA Switch", WM8510_INPPGA,  6, 1, 1),
204 SOC_DAPM_SINGLE("Aux Volume", WM8510_ADCBOOST, 0, 7, 0),
205 SOC_DAPM_SINGLE("Mic Volume", WM8510_ADCBOOST, 4, 7, 0),
206 };
207
208 static const struct snd_kcontrol_new wm8510_micpga_controls[] = {
209 SOC_DAPM_SINGLE("MICP Switch", WM8510_INPUT, 0, 1, 0),
210 SOC_DAPM_SINGLE("MICN Switch", WM8510_INPUT, 1, 1, 0),
211 SOC_DAPM_SINGLE("AUX Switch", WM8510_INPUT, 2, 1, 0),
212 };
213
214 static const struct snd_soc_dapm_widget wm8510_dapm_widgets[] = {
215 SND_SOC_DAPM_MIXER("Speaker Mixer", WM8510_POWER3, 2, 0,
216         &wm8510_speaker_mixer_controls[0],
217         ARRAY_SIZE(wm8510_speaker_mixer_controls)),
218 SND_SOC_DAPM_MIXER("Mono Mixer", WM8510_POWER3, 3, 0,
219         &wm8510_mono_mixer_controls[0],
220         ARRAY_SIZE(wm8510_mono_mixer_controls)),
221 SND_SOC_DAPM_DAC("DAC", "HiFi Playback", WM8510_POWER3, 0, 0),
222 SND_SOC_DAPM_ADC("ADC", "HiFi Capture", WM8510_POWER2, 0, 0),
223 SND_SOC_DAPM_PGA("Aux Input", WM8510_POWER1, 6, 0, NULL, 0),
224 SND_SOC_DAPM_PGA("SpkN Out", WM8510_POWER3, 5, 0, NULL, 0),
225 SND_SOC_DAPM_PGA("SpkP Out", WM8510_POWER3, 6, 0, NULL, 0),
226 SND_SOC_DAPM_PGA("Mono Out", WM8510_POWER3, 7, 0, NULL, 0),
227
228 SND_SOC_DAPM_PGA("Mic PGA", WM8510_POWER2, 2, 0,
229                  &wm8510_micpga_controls[0],
230                  ARRAY_SIZE(wm8510_micpga_controls)),
231 SND_SOC_DAPM_MIXER("Boost Mixer", WM8510_POWER2, 4, 0,
232         &wm8510_boost_controls[0],
233         ARRAY_SIZE(wm8510_boost_controls)),
234
235 SND_SOC_DAPM_MICBIAS("Mic Bias", WM8510_POWER1, 4, 0),
236
237 SND_SOC_DAPM_INPUT("MICN"),
238 SND_SOC_DAPM_INPUT("MICP"),
239 SND_SOC_DAPM_INPUT("AUX"),
240 SND_SOC_DAPM_OUTPUT("MONOOUT"),
241 SND_SOC_DAPM_OUTPUT("SPKOUTP"),
242 SND_SOC_DAPM_OUTPUT("SPKOUTN"),
243 };
244
245 static const struct snd_soc_dapm_route audio_map[] = {
246         /* Mono output mixer */
247         {"Mono Mixer", "PCM Playback Switch", "DAC"},
248         {"Mono Mixer", "Aux Playback Switch", "Aux Input"},
249         {"Mono Mixer", "Line Bypass Switch", "Boost Mixer"},
250
251         /* Speaker output mixer */
252         {"Speaker Mixer", "PCM Playback Switch", "DAC"},
253         {"Speaker Mixer", "Aux Playback Switch", "Aux Input"},
254         {"Speaker Mixer", "Line Bypass Switch", "Boost Mixer"},
255
256         /* Outputs */
257         {"Mono Out", NULL, "Mono Mixer"},
258         {"MONOOUT", NULL, "Mono Out"},
259         {"SpkN Out", NULL, "Speaker Mixer"},
260         {"SpkP Out", NULL, "Speaker Mixer"},
261         {"SPKOUTN", NULL, "SpkN Out"},
262         {"SPKOUTP", NULL, "SpkP Out"},
263
264         /* Microphone PGA */
265         {"Mic PGA", "MICN Switch", "MICN"},
266         {"Mic PGA", "MICP Switch", "MICP"},
267         { "Mic PGA", "AUX Switch", "Aux Input" },
268
269         /* Boost Mixer */
270         {"Boost Mixer", "Mic PGA Switch", "Mic PGA"},
271         {"Boost Mixer", "Mic Volume", "MICP"},
272         {"Boost Mixer", "Aux Volume", "Aux Input"},
273
274         {"ADC", NULL, "Boost Mixer"},
275 };
276
277 static int wm8510_add_widgets(struct snd_soc_codec *codec)
278 {
279         snd_soc_dapm_new_controls(codec, wm8510_dapm_widgets,
280                                   ARRAY_SIZE(wm8510_dapm_widgets));
281
282         snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
283
284         snd_soc_dapm_new_widgets(codec);
285         return 0;
286 }
287
288 struct pll_ {
289         unsigned int pre_div:4; /* prescale - 1 */
290         unsigned int n:4;
291         unsigned int k;
292 };
293
294 static struct pll_ pll_div;
295
296 /* The size in bits of the pll divide multiplied by 10
297  * to allow rounding later */
298 #define FIXED_PLL_SIZE ((1 << 24) * 10)
299
300 static void pll_factors(unsigned int target, unsigned int source)
301 {
302         unsigned long long Kpart;
303         unsigned int K, Ndiv, Nmod;
304
305         Ndiv = target / source;
306         if (Ndiv < 6) {
307                 source >>= 1;
308                 pll_div.pre_div = 1;
309                 Ndiv = target / source;
310         } else
311                 pll_div.pre_div = 0;
312
313         if ((Ndiv < 6) || (Ndiv > 12))
314                 printk(KERN_WARNING
315                         "WM8510 N value %d outwith recommended range!d\n",
316                         Ndiv);
317
318         pll_div.n = Ndiv;
319         Nmod = target % source;
320         Kpart = FIXED_PLL_SIZE * (long long)Nmod;
321
322         do_div(Kpart, source);
323
324         K = Kpart & 0xFFFFFFFF;
325
326         /* Check if we need to round */
327         if ((K % 10) >= 5)
328                 K += 5;
329
330         /* Move down to proper range now rounding is done */
331         K /= 10;
332
333         pll_div.k = K;
334 }
335
336 static int wm8510_set_dai_pll(struct snd_soc_dai *codec_dai,
337                 int pll_id, unsigned int freq_in, unsigned int freq_out)
338 {
339         struct snd_soc_codec *codec = codec_dai->codec;
340         u16 reg;
341
342         if (freq_in == 0 || freq_out == 0) {
343                 /* Clock CODEC directly from MCLK */
344                 reg = wm8510_read_reg_cache(codec, WM8510_CLOCK);
345                 wm8510_write(codec, WM8510_CLOCK, reg & 0x0ff);
346
347                 /* Turn off PLL */
348                 reg = wm8510_read_reg_cache(codec, WM8510_POWER1);
349                 wm8510_write(codec, WM8510_POWER1, reg & 0x1df);
350                 return 0;
351         }
352
353         pll_factors(freq_out*8, freq_in);
354
355         wm8510_write(codec, WM8510_PLLN, (pll_div.pre_div << 4) | pll_div.n);
356         wm8510_write(codec, WM8510_PLLK1, pll_div.k >> 18);
357         wm8510_write(codec, WM8510_PLLK2, (pll_div.k >> 9) & 0x1ff);
358         wm8510_write(codec, WM8510_PLLK3, pll_div.k & 0x1ff);
359         reg = wm8510_read_reg_cache(codec, WM8510_POWER1);
360         wm8510_write(codec, WM8510_POWER1, reg | 0x020);
361
362         /* Run CODEC from PLL instead of MCLK */
363         reg = wm8510_read_reg_cache(codec, WM8510_CLOCK);
364         wm8510_write(codec, WM8510_CLOCK, reg | 0x100);
365
366         return 0;
367 }
368
369 /*
370  * Configure WM8510 clock dividers.
371  */
372 static int wm8510_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
373                 int div_id, int div)
374 {
375         struct snd_soc_codec *codec = codec_dai->codec;
376         u16 reg;
377
378         switch (div_id) {
379         case WM8510_OPCLKDIV:
380                 reg = wm8510_read_reg_cache(codec, WM8510_GPIO) & 0x1cf;
381                 wm8510_write(codec, WM8510_GPIO, reg | div);
382                 break;
383         case WM8510_MCLKDIV:
384                 reg = wm8510_read_reg_cache(codec, WM8510_CLOCK) & 0x1f;
385                 wm8510_write(codec, WM8510_CLOCK, reg | div);
386                 break;
387         case WM8510_ADCCLK:
388                 reg = wm8510_read_reg_cache(codec, WM8510_ADC) & 0x1f7;
389                 wm8510_write(codec, WM8510_ADC, reg | div);
390                 break;
391         case WM8510_DACCLK:
392                 reg = wm8510_read_reg_cache(codec, WM8510_DAC) & 0x1f7;
393                 wm8510_write(codec, WM8510_DAC, reg | div);
394                 break;
395         case WM8510_BCLKDIV:
396                 reg = wm8510_read_reg_cache(codec, WM8510_CLOCK) & 0x1e3;
397                 wm8510_write(codec, WM8510_CLOCK, reg | div);
398                 break;
399         default:
400                 return -EINVAL;
401         }
402
403         return 0;
404 }
405
406 static int wm8510_set_dai_fmt(struct snd_soc_dai *codec_dai,
407                 unsigned int fmt)
408 {
409         struct snd_soc_codec *codec = codec_dai->codec;
410         u16 iface = 0;
411         u16 clk = wm8510_read_reg_cache(codec, WM8510_CLOCK) & 0x1fe;
412
413         /* set master/slave audio interface */
414         switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
415         case SND_SOC_DAIFMT_CBM_CFM:
416                 clk |= 0x0001;
417                 break;
418         case SND_SOC_DAIFMT_CBS_CFS:
419                 break;
420         default:
421                 return -EINVAL;
422         }
423
424         /* interface format */
425         switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
426         case SND_SOC_DAIFMT_I2S:
427                 iface |= 0x0010;
428                 break;
429         case SND_SOC_DAIFMT_RIGHT_J:
430                 break;
431         case SND_SOC_DAIFMT_LEFT_J:
432                 iface |= 0x0008;
433                 break;
434         case SND_SOC_DAIFMT_DSP_A:
435                 iface |= 0x00018;
436                 break;
437         default:
438                 return -EINVAL;
439         }
440
441         /* clock inversion */
442         switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
443         case SND_SOC_DAIFMT_NB_NF:
444                 break;
445         case SND_SOC_DAIFMT_IB_IF:
446                 iface |= 0x0180;
447                 break;
448         case SND_SOC_DAIFMT_IB_NF:
449                 iface |= 0x0100;
450                 break;
451         case SND_SOC_DAIFMT_NB_IF:
452                 iface |= 0x0080;
453                 break;
454         default:
455                 return -EINVAL;
456         }
457
458         wm8510_write(codec, WM8510_IFACE, iface);
459         wm8510_write(codec, WM8510_CLOCK, clk);
460         return 0;
461 }
462
463 static int wm8510_pcm_hw_params(struct snd_pcm_substream *substream,
464         struct snd_pcm_hw_params *params)
465 {
466         struct snd_soc_pcm_runtime *rtd = substream->private_data;
467         struct snd_soc_device *socdev = rtd->socdev;
468         struct snd_soc_codec *codec = socdev->codec;
469         u16 iface = wm8510_read_reg_cache(codec, WM8510_IFACE) & 0x19f;
470         u16 adn = wm8510_read_reg_cache(codec, WM8510_ADD) & 0x1f1;
471
472         /* bit size */
473         switch (params_format(params)) {
474         case SNDRV_PCM_FORMAT_S16_LE:
475                 break;
476         case SNDRV_PCM_FORMAT_S20_3LE:
477                 iface |= 0x0020;
478                 break;
479         case SNDRV_PCM_FORMAT_S24_LE:
480                 iface |= 0x0040;
481                 break;
482         case SNDRV_PCM_FORMAT_S32_LE:
483                 iface |= 0x0060;
484                 break;
485         }
486
487         /* filter coefficient */
488         switch (params_rate(params)) {
489         case SNDRV_PCM_RATE_8000:
490                 adn |= 0x5 << 1;
491                 break;
492         case SNDRV_PCM_RATE_11025:
493                 adn |= 0x4 << 1;
494                 break;
495         case SNDRV_PCM_RATE_16000:
496                 adn |= 0x3 << 1;
497                 break;
498         case SNDRV_PCM_RATE_22050:
499                 adn |= 0x2 << 1;
500                 break;
501         case SNDRV_PCM_RATE_32000:
502                 adn |= 0x1 << 1;
503                 break;
504         case SNDRV_PCM_RATE_44100:
505         case SNDRV_PCM_RATE_48000:
506                 break;
507         }
508
509         wm8510_write(codec, WM8510_IFACE, iface);
510         wm8510_write(codec, WM8510_ADD, adn);
511         return 0;
512 }
513
514 static int wm8510_mute(struct snd_soc_dai *dai, int mute)
515 {
516         struct snd_soc_codec *codec = dai->codec;
517         u16 mute_reg = wm8510_read_reg_cache(codec, WM8510_DAC) & 0xffbf;
518
519         if (mute)
520                 wm8510_write(codec, WM8510_DAC, mute_reg | 0x40);
521         else
522                 wm8510_write(codec, WM8510_DAC, mute_reg);
523         return 0;
524 }
525
526 /* liam need to make this lower power with dapm */
527 static int wm8510_set_bias_level(struct snd_soc_codec *codec,
528         enum snd_soc_bias_level level)
529 {
530
531         switch (level) {
532         case SND_SOC_BIAS_ON:
533                 wm8510_write(codec, WM8510_POWER1, 0x1ff);
534                 wm8510_write(codec, WM8510_POWER2, 0x1ff);
535                 wm8510_write(codec, WM8510_POWER3, 0x1ff);
536                 break;
537         case SND_SOC_BIAS_PREPARE:
538         case SND_SOC_BIAS_STANDBY:
539                 break;
540         case SND_SOC_BIAS_OFF:
541                 /* everything off, dac mute, inactive */
542                 wm8510_write(codec, WM8510_POWER1, 0x0);
543                 wm8510_write(codec, WM8510_POWER2, 0x0);
544                 wm8510_write(codec, WM8510_POWER3, 0x0);
545                 break;
546         }
547         codec->bias_level = level;
548         return 0;
549 }
550
551 #define WM8510_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
552                 SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
553                 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
554
555 #define WM8510_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
556         SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
557
558 struct snd_soc_dai wm8510_dai = {
559         .name = "WM8510 HiFi",
560         .playback = {
561                 .stream_name = "Playback",
562                 .channels_min = 2,
563                 .channels_max = 2,
564                 .rates = WM8510_RATES,
565                 .formats = WM8510_FORMATS,},
566         .capture = {
567                 .stream_name = "Capture",
568                 .channels_min = 2,
569                 .channels_max = 2,
570                 .rates = WM8510_RATES,
571                 .formats = WM8510_FORMATS,},
572         .ops = {
573                 .hw_params = wm8510_pcm_hw_params,
574         },
575         .dai_ops = {
576                 .digital_mute = wm8510_mute,
577                 .set_fmt = wm8510_set_dai_fmt,
578                 .set_clkdiv = wm8510_set_dai_clkdiv,
579                 .set_pll = wm8510_set_dai_pll,
580         },
581 };
582 EXPORT_SYMBOL_GPL(wm8510_dai);
583
584 static int wm8510_suspend(struct platform_device *pdev, pm_message_t state)
585 {
586         struct snd_soc_device *socdev = platform_get_drvdata(pdev);
587         struct snd_soc_codec *codec = socdev->codec;
588
589         wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF);
590         return 0;
591 }
592
593 static int wm8510_resume(struct platform_device *pdev)
594 {
595         struct snd_soc_device *socdev = platform_get_drvdata(pdev);
596         struct snd_soc_codec *codec = socdev->codec;
597         int i;
598         u8 data[2];
599         u16 *cache = codec->reg_cache;
600
601         /* Sync reg_cache with the hardware */
602         for (i = 0; i < ARRAY_SIZE(wm8510_reg); i++) {
603                 data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
604                 data[1] = cache[i] & 0x00ff;
605                 codec->hw_write(codec->control_data, data, 2);
606         }
607         wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
608         wm8510_set_bias_level(codec, codec->suspend_bias_level);
609         return 0;
610 }
611
612 /*
613  * initialise the WM8510 driver
614  * register the mixer and dsp interfaces with the kernel
615  */
616 static int wm8510_init(struct snd_soc_device *socdev)
617 {
618         struct snd_soc_codec *codec = socdev->codec;
619         int ret = 0;
620
621         codec->name = "WM8510";
622         codec->owner = THIS_MODULE;
623         codec->read = wm8510_read_reg_cache;
624         codec->write = wm8510_write;
625         codec->set_bias_level = wm8510_set_bias_level;
626         codec->dai = &wm8510_dai;
627         codec->num_dai = 1;
628         codec->reg_cache_size = ARRAY_SIZE(wm8510_reg);
629         codec->reg_cache = kmemdup(wm8510_reg, sizeof(wm8510_reg), GFP_KERNEL);
630
631         if (codec->reg_cache == NULL)
632                 return -ENOMEM;
633
634         wm8510_reset(codec);
635
636         /* register pcms */
637         ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
638         if (ret < 0) {
639                 printk(KERN_ERR "wm8510: failed to create pcms\n");
640                 goto pcm_err;
641         }
642
643         /* power on device */
644         wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
645         wm8510_add_controls(codec);
646         wm8510_add_widgets(codec);
647         ret = snd_soc_register_card(socdev);
648         if (ret < 0) {
649                 printk(KERN_ERR "wm8510: failed to register card\n");
650                 goto card_err;
651         }
652         return ret;
653
654 card_err:
655         snd_soc_free_pcms(socdev);
656         snd_soc_dapm_free(socdev);
657 pcm_err:
658         kfree(codec->reg_cache);
659         return ret;
660 }
661
662 static struct snd_soc_device *wm8510_socdev;
663
664 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
665
666 /*
667  * WM8510 2 wire address is 0x1a
668  */
669
670 static int wm8510_i2c_probe(struct i2c_client *i2c,
671                             const struct i2c_device_id *id)
672 {
673         struct snd_soc_device *socdev = wm8510_socdev;
674         struct snd_soc_codec *codec = socdev->codec;
675         int ret;
676
677         i2c_set_clientdata(i2c, codec);
678         codec->control_data = i2c;
679
680         ret = wm8510_init(socdev);
681         if (ret < 0)
682                 pr_err("failed to initialise WM8510\n");
683
684         return ret;
685 }
686
687 static int wm8510_i2c_remove(struct i2c_client *client)
688 {
689         struct snd_soc_codec *codec = i2c_get_clientdata(client);
690         kfree(codec->reg_cache);
691         return 0;
692 }
693
694 static const struct i2c_device_id wm8510_i2c_id[] = {
695         { "wm8510", 0 },
696         { }
697 };
698 MODULE_DEVICE_TABLE(i2c, wm8510_i2c_id);
699
700 static struct i2c_driver wm8510_i2c_driver = {
701         .driver = {
702                 .name = "WM8510 I2C Codec",
703                 .owner = THIS_MODULE,
704         },
705         .probe =    wm8510_i2c_probe,
706         .remove =   wm8510_i2c_remove,
707         .id_table = wm8510_i2c_id,
708 };
709
710 static int wm8510_add_i2c_device(struct platform_device *pdev,
711                                  const struct wm8510_setup_data *setup)
712 {
713         struct i2c_board_info info;
714         struct i2c_adapter *adapter;
715         struct i2c_client *client;
716         int ret;
717
718         ret = i2c_add_driver(&wm8510_i2c_driver);
719         if (ret != 0) {
720                 dev_err(&pdev->dev, "can't add i2c driver\n");
721                 return ret;
722         }
723
724         memset(&info, 0, sizeof(struct i2c_board_info));
725         info.addr = setup->i2c_address;
726         strlcpy(info.type, "wm8510", I2C_NAME_SIZE);
727
728         adapter = i2c_get_adapter(setup->i2c_bus);
729         if (!adapter) {
730                 dev_err(&pdev->dev, "can't get i2c adapter %d\n",
731                         setup->i2c_bus);
732                 goto err_driver;
733         }
734
735         client = i2c_new_device(adapter, &info);
736         i2c_put_adapter(adapter);
737         if (!client) {
738                 dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
739                         (unsigned int)info.addr);
740                 goto err_driver;
741         }
742
743         return 0;
744
745 err_driver:
746         i2c_del_driver(&wm8510_i2c_driver);
747         return -ENODEV;
748 }
749 #endif
750
751 #if defined(CONFIG_SPI_MASTER)
752 static int __devinit wm8510_spi_probe(struct spi_device *spi)
753 {
754         struct snd_soc_device *socdev = wm8510_socdev;
755         struct snd_soc_codec *codec = socdev->codec;
756         int ret;
757
758         codec->control_data = spi;
759
760         ret = wm8510_init(socdev);
761         if (ret < 0)
762                 dev_err(&spi->dev, "failed to initialise WM8510\n");
763
764         return ret;
765 }
766
767 static int __devexit wm8510_spi_remove(struct spi_device *spi)
768 {
769         return 0;
770 }
771
772 static struct spi_driver wm8510_spi_driver = {
773         .driver = {
774                 .name   = "wm8510",
775                 .bus    = &spi_bus_type,
776                 .owner  = THIS_MODULE,
777         },
778         .probe          = wm8510_spi_probe,
779         .remove         = __devexit_p(wm8510_spi_remove),
780 };
781
782 static int wm8510_spi_write(struct spi_device *spi, const char *data, int len)
783 {
784         struct spi_transfer t;
785         struct spi_message m;
786         u8 msg[2];
787
788         if (len <= 0)
789                 return 0;
790
791         msg[0] = data[0];
792         msg[1] = data[1];
793
794         spi_message_init(&m);
795         memset(&t, 0, (sizeof t));
796
797         t.tx_buf = &msg[0];
798         t.len = len;
799
800         spi_message_add_tail(&t, &m);
801         spi_sync(spi, &m);
802
803         return len;
804 }
805 #endif /* CONFIG_SPI_MASTER */
806
807 static int wm8510_probe(struct platform_device *pdev)
808 {
809         struct snd_soc_device *socdev = platform_get_drvdata(pdev);
810         struct wm8510_setup_data *setup;
811         struct snd_soc_codec *codec;
812         int ret = 0;
813
814         pr_info("WM8510 Audio Codec %s", WM8510_VERSION);
815
816         setup = socdev->codec_data;
817         codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
818         if (codec == NULL)
819                 return -ENOMEM;
820
821         socdev->codec = codec;
822         mutex_init(&codec->mutex);
823         INIT_LIST_HEAD(&codec->dapm_widgets);
824         INIT_LIST_HEAD(&codec->dapm_paths);
825
826         wm8510_socdev = socdev;
827 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
828         if (setup->i2c_address) {
829                 codec->hw_write = (hw_write_t)i2c_master_send;
830                 ret = wm8510_add_i2c_device(pdev, setup);
831         }
832 #endif
833 #if defined(CONFIG_SPI_MASTER)
834         if (setup->spi) {
835                 codec->hw_write = (hw_write_t)wm8510_spi_write;
836                 ret = spi_register_driver(&wm8510_spi_driver);
837                 if (ret != 0)
838                         printk(KERN_ERR "can't add spi driver");
839         }
840 #endif
841
842         if (ret != 0)
843                 kfree(codec);
844         return ret;
845 }
846
847 /* power down chip */
848 static int wm8510_remove(struct platform_device *pdev)
849 {
850         struct snd_soc_device *socdev = platform_get_drvdata(pdev);
851         struct snd_soc_codec *codec = socdev->codec;
852
853         if (codec->control_data)
854                 wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF);
855
856         snd_soc_free_pcms(socdev);
857         snd_soc_dapm_free(socdev);
858 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
859         i2c_unregister_device(codec->control_data);
860         i2c_del_driver(&wm8510_i2c_driver);
861 #endif
862 #if defined(CONFIG_SPI_MASTER)
863         spi_unregister_driver(&wm8510_spi_driver);
864 #endif
865         kfree(codec);
866
867         return 0;
868 }
869
870 struct snd_soc_codec_device soc_codec_dev_wm8510 = {
871         .probe =        wm8510_probe,
872         .remove =       wm8510_remove,
873         .suspend =      wm8510_suspend,
874         .resume =       wm8510_resume,
875 };
876 EXPORT_SYMBOL_GPL(soc_codec_dev_wm8510);
877
878 MODULE_DESCRIPTION("ASoC WM8510 driver");
879 MODULE_AUTHOR("Liam Girdwood");
880 MODULE_LICENSE("GPL");