1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24#include <linux/module.h>
25#include <linux/moduleparam.h>
26#include <linux/kernel.h>
27#include <linux/init.h>
28#include <linux/delay.h>
29#include <linux/pm.h>
30#include <linux/i2c.h>
31#include <linux/platform_device.h>
32#include <linux/spi/spi.h>
33#include <linux/slab.h>
34#include <sound/core.h>
35#include <sound/pcm.h>
36#include <sound/pcm_params.h>
37#include <sound/soc.h>
38#include <sound/initval.h>
39#include <sound/tlv.h>
40
41#include "wm8940.h"
42
43struct wm8940_priv {
44 unsigned int sysclk;
45 enum snd_soc_control_type control_type;
46};
47
48static int wm8940_volatile_register(struct snd_soc_codec *codec,
49 unsigned int reg)
50{
51 switch (reg) {
52 case WM8940_SOFTRESET:
53 return 1;
54 default:
55 return 0;
56 }
57}
58
59static u16 wm8940_reg_defaults[] = {
60 0x8940,
61 0x0000,
62 0x0000,
63 0x0000,
64 0x0010,
65 0x0000,
66 0x0140,
67 0x0000,
68 0x0000,
69 0x0002,
70 0x0000,
71 0x00FF,
72 0,
73 0,
74 0x0100,
75 0x00FF,
76 0x0000,
77 0x0000,
78 0x0000,
79 0x0000,
80 0x0000,
81 0x0000,
82 0x0000,
83 0x0000,
84 0x0032,
85 0x0000,
86 0,
87 0,
88 0,
89 0,
90 0,
91 0,
92 0x0038,
93 0x000B,
94 0x0032,
95 0x0000,
96 0x0041,
97 0x000C,
98 0x0093,
99 0x00E9,
100 0,
101 0,
102 0x0030,
103 0,
104 0x0002,
105 0x0050,
106 0,
107 0x0002,
108 0,
109 0x0002,
110 0x0000,
111 0,
112 0,
113 0,
114 0x0079,
115 0,
116 0x0000,
117};
118
119static const char *wm8940_companding[] = { "Off", "NC", "u-law", "A-law" };
120static const struct soc_enum wm8940_adc_companding_enum
121= SOC_ENUM_SINGLE(WM8940_COMPANDINGCTL, 1, 4, wm8940_companding);
122static const struct soc_enum wm8940_dac_companding_enum
123= SOC_ENUM_SINGLE(WM8940_COMPANDINGCTL, 3, 4, wm8940_companding);
124
125static const char *wm8940_alc_mode_text[] = {"ALC", "Limiter"};
126static const struct soc_enum wm8940_alc_mode_enum
127= SOC_ENUM_SINGLE(WM8940_ALC3, 8, 2, wm8940_alc_mode_text);
128
129static const char *wm8940_mic_bias_level_text[] = {"0.9", "0.65"};
130static const struct soc_enum wm8940_mic_bias_level_enum
131= SOC_ENUM_SINGLE(WM8940_INPUTCTL, 8, 2, wm8940_mic_bias_level_text);
132
133static const char *wm8940_filter_mode_text[] = {"Audio", "Application"};
134static const struct soc_enum wm8940_filter_mode_enum
135= SOC_ENUM_SINGLE(WM8940_ADC, 7, 2, wm8940_filter_mode_text);
136
137static DECLARE_TLV_DB_SCALE(wm8940_spk_vol_tlv, -5700, 100, 1);
138static DECLARE_TLV_DB_SCALE(wm8940_att_tlv, -1000, 1000, 0);
139static DECLARE_TLV_DB_SCALE(wm8940_pga_vol_tlv, -1200, 75, 0);
140static DECLARE_TLV_DB_SCALE(wm8940_alc_min_tlv, -1200, 600, 0);
141static DECLARE_TLV_DB_SCALE(wm8940_alc_max_tlv, 675, 600, 0);
142static DECLARE_TLV_DB_SCALE(wm8940_alc_tar_tlv, -2250, 50, 0);
143static DECLARE_TLV_DB_SCALE(wm8940_lim_boost_tlv, 0, 100, 0);
144static DECLARE_TLV_DB_SCALE(wm8940_lim_thresh_tlv, -600, 100, 0);
145static DECLARE_TLV_DB_SCALE(wm8940_adc_tlv, -12750, 50, 1);
146static DECLARE_TLV_DB_SCALE(wm8940_capture_boost_vol_tlv, 0, 2000, 0);
147
148static const struct snd_kcontrol_new wm8940_snd_controls[] = {
149 SOC_SINGLE("Digital Loopback Switch", WM8940_COMPANDINGCTL,
150 6, 1, 0),
151 SOC_ENUM("DAC Companding", wm8940_dac_companding_enum),
152 SOC_ENUM("ADC Companding", wm8940_adc_companding_enum),
153
154 SOC_ENUM("ALC Mode", wm8940_alc_mode_enum),
155 SOC_SINGLE("ALC Switch", WM8940_ALC1, 8, 1, 0),
156 SOC_SINGLE_TLV("ALC Capture Max Gain", WM8940_ALC1,
157 3, 7, 1, wm8940_alc_max_tlv),
158 SOC_SINGLE_TLV("ALC Capture Min Gain", WM8940_ALC1,
159 0, 7, 0, wm8940_alc_min_tlv),
160 SOC_SINGLE_TLV("ALC Capture Target", WM8940_ALC2,
161 0, 14, 0, wm8940_alc_tar_tlv),
162 SOC_SINGLE("ALC Capture Hold", WM8940_ALC2, 4, 10, 0),
163 SOC_SINGLE("ALC Capture Decay", WM8940_ALC3, 4, 10, 0),
164 SOC_SINGLE("ALC Capture Attach", WM8940_ALC3, 0, 10, 0),
165 SOC_SINGLE("ALC ZC Switch", WM8940_ALC4, 1, 1, 0),
166 SOC_SINGLE("ALC Capture Noise Gate Switch", WM8940_NOISEGATE,
167 3, 1, 0),
168 SOC_SINGLE("ALC Capture Noise Gate Threshold", WM8940_NOISEGATE,
169 0, 7, 0),
170
171 SOC_SINGLE("DAC Playback Limiter Switch", WM8940_DACLIM1, 8, 1, 0),
172 SOC_SINGLE("DAC Playback Limiter Attack", WM8940_DACLIM1, 0, 9, 0),
173 SOC_SINGLE("DAC Playback Limiter Decay", WM8940_DACLIM1, 4, 11, 0),
174 SOC_SINGLE_TLV("DAC Playback Limiter Threshold", WM8940_DACLIM2,
175 4, 9, 1, wm8940_lim_thresh_tlv),
176 SOC_SINGLE_TLV("DAC Playback Limiter Boost", WM8940_DACLIM2,
177 0, 12, 0, wm8940_lim_boost_tlv),
178
179 SOC_SINGLE("Capture PGA ZC Switch", WM8940_PGAGAIN, 7, 1, 0),
180 SOC_SINGLE_TLV("Capture PGA Volume", WM8940_PGAGAIN,
181 0, 63, 0, wm8940_pga_vol_tlv),
182 SOC_SINGLE_TLV("Digital Playback Volume", WM8940_DACVOL,
183 0, 255, 0, wm8940_adc_tlv),
184 SOC_SINGLE_TLV("Digital Capture Volume", WM8940_ADCVOL,
185 0, 255, 0, wm8940_adc_tlv),
186 SOC_ENUM("Mic Bias Level", wm8940_mic_bias_level_enum),
187 SOC_SINGLE_TLV("Capture Boost Volue", WM8940_ADCBOOST,
188 8, 1, 0, wm8940_capture_boost_vol_tlv),
189 SOC_SINGLE_TLV("Speaker Playback Volume", WM8940_SPKVOL,
190 0, 63, 0, wm8940_spk_vol_tlv),
191 SOC_SINGLE("Speaker Playback Switch", WM8940_SPKVOL, 6, 1, 1),
192
193 SOC_SINGLE_TLV("Speaker Mixer Line Bypass Volume", WM8940_SPKVOL,
194 8, 1, 1, wm8940_att_tlv),
195 SOC_SINGLE("Speaker Playback ZC Switch", WM8940_SPKVOL, 7, 1, 0),
196
197 SOC_SINGLE("Mono Out Switch", WM8940_MONOMIX, 6, 1, 1),
198 SOC_SINGLE_TLV("Mono Mixer Line Bypass Volume", WM8940_MONOMIX,
199 7, 1, 1, wm8940_att_tlv),
200
201 SOC_SINGLE("High Pass Filter Switch", WM8940_ADC, 8, 1, 0),
202 SOC_ENUM("High Pass Filter Mode", wm8940_filter_mode_enum),
203 SOC_SINGLE("High Pass Filter Cut Off", WM8940_ADC, 4, 7, 0),
204 SOC_SINGLE("ADC Inversion Switch", WM8940_ADC, 0, 1, 0),
205 SOC_SINGLE("DAC Inversion Switch", WM8940_DAC, 0, 1, 0),
206 SOC_SINGLE("DAC Auto Mute Switch", WM8940_DAC, 2, 1, 0),
207 SOC_SINGLE("ZC Timeout Clock Switch", WM8940_ADDCNTRL, 0, 1, 0),
208};
209
210static const struct snd_kcontrol_new wm8940_speaker_mixer_controls[] = {
211 SOC_DAPM_SINGLE("Line Bypass Switch", WM8940_SPKMIX, 1, 1, 0),
212 SOC_DAPM_SINGLE("Aux Playback Switch", WM8940_SPKMIX, 5, 1, 0),
213 SOC_DAPM_SINGLE("PCM Playback Switch", WM8940_SPKMIX, 0, 1, 0),
214};
215
216static const struct snd_kcontrol_new wm8940_mono_mixer_controls[] = {
217 SOC_DAPM_SINGLE("Line Bypass Switch", WM8940_MONOMIX, 1, 1, 0),
218 SOC_DAPM_SINGLE("Aux Playback Switch", WM8940_MONOMIX, 2, 1, 0),
219 SOC_DAPM_SINGLE("PCM Playback Switch", WM8940_MONOMIX, 0, 1, 0),
220};
221
222static DECLARE_TLV_DB_SCALE(wm8940_boost_vol_tlv, -1500, 300, 1);
223static const struct snd_kcontrol_new wm8940_input_boost_controls[] = {
224 SOC_DAPM_SINGLE("Mic PGA Switch", WM8940_PGAGAIN, 6, 1, 1),
225 SOC_DAPM_SINGLE_TLV("Aux Volume", WM8940_ADCBOOST,
226 0, 7, 0, wm8940_boost_vol_tlv),
227 SOC_DAPM_SINGLE_TLV("Mic Volume", WM8940_ADCBOOST,
228 4, 7, 0, wm8940_boost_vol_tlv),
229};
230
231static const struct snd_kcontrol_new wm8940_micpga_controls[] = {
232 SOC_DAPM_SINGLE("AUX Switch", WM8940_INPUTCTL, 2, 1, 0),
233 SOC_DAPM_SINGLE("MICP Switch", WM8940_INPUTCTL, 0, 1, 0),
234 SOC_DAPM_SINGLE("MICN Switch", WM8940_INPUTCTL, 1, 1, 0),
235};
236
237static const struct snd_soc_dapm_widget wm8940_dapm_widgets[] = {
238 SND_SOC_DAPM_MIXER("Speaker Mixer", WM8940_POWER3, 2, 0,
239 &wm8940_speaker_mixer_controls[0],
240 ARRAY_SIZE(wm8940_speaker_mixer_controls)),
241 SND_SOC_DAPM_MIXER("Mono Mixer", WM8940_POWER3, 3, 0,
242 &wm8940_mono_mixer_controls[0],
243 ARRAY_SIZE(wm8940_mono_mixer_controls)),
244 SND_SOC_DAPM_DAC("DAC", "HiFi Playback", WM8940_POWER3, 0, 0),
245
246 SND_SOC_DAPM_PGA("SpkN Out", WM8940_POWER3, 5, 0, NULL, 0),
247 SND_SOC_DAPM_PGA("SpkP Out", WM8940_POWER3, 6, 0, NULL, 0),
248 SND_SOC_DAPM_PGA("Mono Out", WM8940_POWER3, 7, 0, NULL, 0),
249 SND_SOC_DAPM_OUTPUT("MONOOUT"),
250 SND_SOC_DAPM_OUTPUT("SPKOUTP"),
251 SND_SOC_DAPM_OUTPUT("SPKOUTN"),
252
253 SND_SOC_DAPM_PGA("Aux Input", WM8940_POWER1, 6, 0, NULL, 0),
254 SND_SOC_DAPM_ADC("ADC", "HiFi Capture", WM8940_POWER2, 0, 0),
255 SND_SOC_DAPM_MIXER("Mic PGA", WM8940_POWER2, 2, 0,
256 &wm8940_micpga_controls[0],
257 ARRAY_SIZE(wm8940_micpga_controls)),
258 SND_SOC_DAPM_MIXER("Boost Mixer", WM8940_POWER2, 4, 0,
259 &wm8940_input_boost_controls[0],
260 ARRAY_SIZE(wm8940_input_boost_controls)),
261 SND_SOC_DAPM_MICBIAS("Mic Bias", WM8940_POWER1, 4, 0),
262
263 SND_SOC_DAPM_INPUT("MICN"),
264 SND_SOC_DAPM_INPUT("MICP"),
265 SND_SOC_DAPM_INPUT("AUX"),
266};
267
268static const struct snd_soc_dapm_route audio_map[] = {
269
270 {"Mono Mixer", "PCM Playback Switch", "DAC"},
271 {"Mono Mixer", "Aux Playback Switch", "Aux Input"},
272 {"Mono Mixer", "Line Bypass Switch", "Boost Mixer"},
273
274
275 {"Speaker Mixer", "PCM Playback Switch", "DAC"},
276 {"Speaker Mixer", "Aux Playback Switch", "Aux Input"},
277 {"Speaker Mixer", "Line Bypass Switch", "Boost Mixer"},
278
279
280 {"Mono Out", NULL, "Mono Mixer"},
281 {"MONOOUT", NULL, "Mono Out"},
282 {"SpkN Out", NULL, "Speaker Mixer"},
283 {"SpkP Out", NULL, "Speaker Mixer"},
284 {"SPKOUTN", NULL, "SpkN Out"},
285 {"SPKOUTP", NULL, "SpkP Out"},
286
287
288 {"Mic PGA", "MICN Switch", "MICN"},
289 {"Mic PGA", "MICP Switch", "MICP"},
290 {"Mic PGA", "AUX Switch", "AUX"},
291
292
293 {"Boost Mixer", "Mic PGA Switch", "Mic PGA"},
294 {"Boost Mixer", "Mic Volume", "MICP"},
295 {"Boost Mixer", "Aux Volume", "Aux Input"},
296
297 {"ADC", NULL, "Boost Mixer"},
298};
299
300static int wm8940_add_widgets(struct snd_soc_codec *codec)
301{
302 struct snd_soc_dapm_context *dapm = &codec->dapm;
303 int ret;
304
305 ret = snd_soc_dapm_new_controls(dapm, wm8940_dapm_widgets,
306 ARRAY_SIZE(wm8940_dapm_widgets));
307 if (ret)
308 goto error_ret;
309 ret = snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
310
311error_ret:
312 return ret;
313}
314
315#define wm8940_reset(c) snd_soc_write(c, WM8940_SOFTRESET, 0);
316
317static int wm8940_set_dai_fmt(struct snd_soc_dai *codec_dai,
318 unsigned int fmt)
319{
320 struct snd_soc_codec *codec = codec_dai->codec;
321 u16 iface = snd_soc_read(codec, WM8940_IFACE) & 0xFE67;
322 u16 clk = snd_soc_read(codec, WM8940_CLOCK) & 0x1fe;
323
324 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
325 case SND_SOC_DAIFMT_CBM_CFM:
326 clk |= 1;
327 break;
328 case SND_SOC_DAIFMT_CBS_CFS:
329 break;
330 default:
331 return -EINVAL;
332 }
333 snd_soc_write(codec, WM8940_CLOCK, clk);
334
335 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
336 case SND_SOC_DAIFMT_I2S:
337 iface |= (2 << 3);
338 break;
339 case SND_SOC_DAIFMT_LEFT_J:
340 iface |= (1 << 3);
341 break;
342 case SND_SOC_DAIFMT_RIGHT_J:
343 break;
344 case SND_SOC_DAIFMT_DSP_A:
345 iface |= (3 << 3);
346 break;
347 case SND_SOC_DAIFMT_DSP_B:
348 iface |= (3 << 3) | (1 << 7);
349 break;
350 }
351
352 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
353 case SND_SOC_DAIFMT_NB_NF:
354 break;
355 case SND_SOC_DAIFMT_NB_IF:
356 iface |= (1 << 7);
357 break;
358 case SND_SOC_DAIFMT_IB_NF:
359 iface |= (1 << 8);
360 break;
361 case SND_SOC_DAIFMT_IB_IF:
362 iface |= (1 << 8) | (1 << 7);
363 break;
364 }
365
366 snd_soc_write(codec, WM8940_IFACE, iface);
367
368 return 0;
369}
370
371static int wm8940_i2s_hw_params(struct snd_pcm_substream *substream,
372 struct snd_pcm_hw_params *params,
373 struct snd_soc_dai *dai)
374{
375 struct snd_soc_pcm_runtime *rtd = substream->private_data;
376 struct snd_soc_codec *codec = rtd->codec;
377 u16 iface = snd_soc_read(codec, WM8940_IFACE) & 0xFD9F;
378 u16 addcntrl = snd_soc_read(codec, WM8940_ADDCNTRL) & 0xFFF1;
379 u16 companding = snd_soc_read(codec,
380 WM8940_COMPANDINGCTL) & 0xFFDF;
381 int ret;
382
383
384 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE
385 && params_channels(params) == 2)
386 iface |= (1 << 9);
387
388 switch (params_rate(params)) {
389 case 8000:
390 addcntrl |= (0x5 << 1);
391 break;
392 case 11025:
393 addcntrl |= (0x4 << 1);
394 break;
395 case 16000:
396 addcntrl |= (0x3 << 1);
397 break;
398 case 22050:
399 addcntrl |= (0x2 << 1);
400 break;
401 case 32000:
402 addcntrl |= (0x1 << 1);
403 break;
404 case 44100:
405 case 48000:
406 break;
407 }
408 ret = snd_soc_write(codec, WM8940_ADDCNTRL, addcntrl);
409 if (ret)
410 goto error_ret;
411
412 switch (params_format(params)) {
413 case SNDRV_PCM_FORMAT_S8:
414 companding = companding | (1 << 5);
415 break;
416 case SNDRV_PCM_FORMAT_S16_LE:
417 break;
418 case SNDRV_PCM_FORMAT_S20_3LE:
419 iface |= (1 << 5);
420 break;
421 case SNDRV_PCM_FORMAT_S24_LE:
422 iface |= (2 << 5);
423 break;
424 case SNDRV_PCM_FORMAT_S32_LE:
425 iface |= (3 << 5);
426 break;
427 }
428 ret = snd_soc_write(codec, WM8940_COMPANDINGCTL, companding);
429 if (ret)
430 goto error_ret;
431 ret = snd_soc_write(codec, WM8940_IFACE, iface);
432
433error_ret:
434 return ret;
435}
436
437static int wm8940_mute(struct snd_soc_dai *dai, int mute)
438{
439 struct snd_soc_codec *codec = dai->codec;
440 u16 mute_reg = snd_soc_read(codec, WM8940_DAC) & 0xffbf;
441
442 if (mute)
443 mute_reg |= 0x40;
444
445 return snd_soc_write(codec, WM8940_DAC, mute_reg);
446}
447
448static int wm8940_set_bias_level(struct snd_soc_codec *codec,
449 enum snd_soc_bias_level level)
450{
451 u16 val;
452 u16 pwr_reg = snd_soc_read(codec, WM8940_POWER1) & 0x1F0;
453 int ret = 0;
454
455 switch (level) {
456 case SND_SOC_BIAS_ON:
457
458 pwr_reg |= (1 << 2) | (1 << 3);
459
460 val = snd_soc_read(codec, WM8940_OUTPUTCTL);
461 ret = snd_soc_write(codec, WM8940_OUTPUTCTL, val | 0x2);
462 if (ret)
463 break;
464
465 ret = snd_soc_write(codec, WM8940_POWER1, pwr_reg | 0x1);
466 break;
467 case SND_SOC_BIAS_PREPARE:
468
469 pwr_reg |= (1 << 2) | (1 << 3);
470 ret = snd_soc_write(codec, WM8940_POWER1, pwr_reg | 0x1);
471 break;
472 case SND_SOC_BIAS_STANDBY:
473 if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
474 ret = snd_soc_cache_sync(codec);
475 if (ret < 0) {
476 dev_err(codec->dev, "Failed to sync cache: %d\n", ret);
477 return ret;
478 }
479 }
480
481
482 pwr_reg |= (1 << 2) | (1 << 3);
483
484 ret = snd_soc_write(codec, WM8940_POWER1, pwr_reg | 0x2);
485 break;
486 case SND_SOC_BIAS_OFF:
487 ret = snd_soc_write(codec, WM8940_POWER1, pwr_reg);
488 break;
489 }
490
491 codec->dapm.bias_level = level;
492
493 return ret;
494}
495
496struct pll_ {
497 unsigned int pre_scale:2;
498 unsigned int n:4;
499 unsigned int k;
500};
501
502static struct pll_ pll_div;
503
504
505
506#define FIXED_PLL_SIZE ((1 << 24) * 10)
507static void pll_factors(unsigned int target, unsigned int source)
508{
509 unsigned long long Kpart;
510 unsigned int K, Ndiv, Nmod;
511
512 Ndiv = target / source;
513
514 if (Ndiv > 12) {
515 source <<= 1;
516
517 pll_div.pre_scale = 0;
518 Ndiv = target / source;
519 } else if (Ndiv < 3) {
520 source >>= 2;
521
522 pll_div.pre_scale = 3;
523 Ndiv = target / source;
524 } else if (Ndiv < 6) {
525 source >>= 1;
526
527 pll_div.pre_scale = 2;
528 Ndiv = target / source;
529 } else
530 pll_div.pre_scale = 1;
531
532 if ((Ndiv < 6) || (Ndiv > 12))
533 printk(KERN_WARNING
534 "WM8940 N value %d outwith recommended range!d\n",
535 Ndiv);
536
537 pll_div.n = Ndiv;
538 Nmod = target % source;
539 Kpart = FIXED_PLL_SIZE * (long long)Nmod;
540
541 do_div(Kpart, source);
542
543 K = Kpart & 0xFFFFFFFF;
544
545
546 if ((K % 10) >= 5)
547 K += 5;
548
549
550 K /= 10;
551
552 pll_div.k = K;
553}
554
555
556static int wm8940_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
557 int source, unsigned int freq_in, unsigned int freq_out)
558{
559 struct snd_soc_codec *codec = codec_dai->codec;
560 u16 reg;
561
562
563 reg = snd_soc_read(codec, WM8940_POWER1);
564 snd_soc_write(codec, WM8940_POWER1, reg & 0x1df);
565
566 if (freq_in == 0 || freq_out == 0) {
567
568 reg = snd_soc_read(codec, WM8940_CLOCK);
569 snd_soc_write(codec, WM8940_CLOCK, reg & 0x0ff);
570
571 snd_soc_write(codec, WM8940_PLLN, (1 << 7));
572 return 0;
573 }
574
575
576 pll_factors(freq_out*4, freq_in);
577 if (pll_div.k)
578 snd_soc_write(codec, WM8940_PLLN,
579 (pll_div.pre_scale << 4) | pll_div.n | (1 << 6));
580 else
581 snd_soc_write(codec, WM8940_PLLN,
582 (pll_div.pre_scale << 4) | pll_div.n);
583 snd_soc_write(codec, WM8940_PLLK1, pll_div.k >> 18);
584 snd_soc_write(codec, WM8940_PLLK2, (pll_div.k >> 9) & 0x1ff);
585 snd_soc_write(codec, WM8940_PLLK3, pll_div.k & 0x1ff);
586
587 reg = snd_soc_read(codec, WM8940_POWER1);
588 snd_soc_write(codec, WM8940_POWER1, reg | 0x020);
589
590
591 reg = snd_soc_read(codec, WM8940_CLOCK);
592 snd_soc_write(codec, WM8940_CLOCK, reg | 0x100);
593
594 return 0;
595}
596
597static int wm8940_set_dai_sysclk(struct snd_soc_dai *codec_dai,
598 int clk_id, unsigned int freq, int dir)
599{
600 struct snd_soc_codec *codec = codec_dai->codec;
601 struct wm8940_priv *wm8940 = snd_soc_codec_get_drvdata(codec);
602
603 switch (freq) {
604 case 11289600:
605 case 12000000:
606 case 12288000:
607 case 16934400:
608 case 18432000:
609 wm8940->sysclk = freq;
610 return 0;
611 }
612 return -EINVAL;
613}
614
615static int wm8940_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
616 int div_id, int div)
617{
618 struct snd_soc_codec *codec = codec_dai->codec;
619 u16 reg;
620 int ret = 0;
621
622 switch (div_id) {
623 case WM8940_BCLKDIV:
624 reg = snd_soc_read(codec, WM8940_CLOCK) & 0xFFE3;
625 ret = snd_soc_write(codec, WM8940_CLOCK, reg | (div << 2));
626 break;
627 case WM8940_MCLKDIV:
628 reg = snd_soc_read(codec, WM8940_CLOCK) & 0xFF1F;
629 ret = snd_soc_write(codec, WM8940_CLOCK, reg | (div << 5));
630 break;
631 case WM8940_OPCLKDIV:
632 reg = snd_soc_read(codec, WM8940_ADDCNTRL) & 0xFFCF;
633 ret = snd_soc_write(codec, WM8940_ADDCNTRL, reg | (div << 4));
634 break;
635 }
636 return ret;
637}
638
639#define WM8940_RATES SNDRV_PCM_RATE_8000_48000
640
641#define WM8940_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
642 SNDRV_PCM_FMTBIT_S16_LE | \
643 SNDRV_PCM_FMTBIT_S20_3LE | \
644 SNDRV_PCM_FMTBIT_S24_LE | \
645 SNDRV_PCM_FMTBIT_S32_LE)
646
647static struct snd_soc_dai_ops wm8940_dai_ops = {
648 .hw_params = wm8940_i2s_hw_params,
649 .set_sysclk = wm8940_set_dai_sysclk,
650 .digital_mute = wm8940_mute,
651 .set_fmt = wm8940_set_dai_fmt,
652 .set_clkdiv = wm8940_set_dai_clkdiv,
653 .set_pll = wm8940_set_dai_pll,
654};
655
656static struct snd_soc_dai_driver wm8940_dai = {
657 .name = "wm8940-hifi",
658 .playback = {
659 .stream_name = "Playback",
660 .channels_min = 1,
661 .channels_max = 2,
662 .rates = WM8940_RATES,
663 .formats = WM8940_FORMATS,
664 },
665 .capture = {
666 .stream_name = "Capture",
667 .channels_min = 1,
668 .channels_max = 2,
669 .rates = WM8940_RATES,
670 .formats = WM8940_FORMATS,
671 },
672 .ops = &wm8940_dai_ops,
673 .symmetric_rates = 1,
674};
675
676static int wm8940_suspend(struct snd_soc_codec *codec, pm_message_t state)
677{
678 return wm8940_set_bias_level(codec, SND_SOC_BIAS_OFF);
679}
680
681static int wm8940_resume(struct snd_soc_codec *codec)
682{
683 wm8940_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
684 return 0;
685}
686
687static int wm8940_probe(struct snd_soc_codec *codec)
688{
689 struct wm8940_priv *wm8940 = snd_soc_codec_get_drvdata(codec);
690 struct wm8940_setup_data *pdata = codec->dev->platform_data;
691 int ret;
692 u16 reg;
693
694 ret = snd_soc_codec_set_cache_io(codec, 8, 16, wm8940->control_type);
695 if (ret < 0) {
696 dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
697 return ret;
698 }
699
700 ret = wm8940_reset(codec);
701 if (ret < 0) {
702 dev_err(codec->dev, "Failed to issue reset\n");
703 return ret;
704 }
705
706 wm8940_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
707
708 ret = snd_soc_write(codec, WM8940_POWER1, 0x180);
709 if (ret < 0)
710 return ret;
711
712 if (!pdata)
713 dev_warn(codec->dev, "No platform data supplied\n");
714 else {
715 reg = snd_soc_read(codec, WM8940_OUTPUTCTL);
716 ret = snd_soc_write(codec, WM8940_OUTPUTCTL, reg | pdata->vroi);
717 if (ret < 0)
718 return ret;
719 }
720
721 ret = snd_soc_add_controls(codec, wm8940_snd_controls,
722 ARRAY_SIZE(wm8940_snd_controls));
723 if (ret)
724 return ret;
725 ret = wm8940_add_widgets(codec);
726 return ret;
727}
728
729static int wm8940_remove(struct snd_soc_codec *codec)
730{
731 wm8940_set_bias_level(codec, SND_SOC_BIAS_OFF);
732 return 0;
733}
734
735static struct snd_soc_codec_driver soc_codec_dev_wm8940 = {
736 .probe = wm8940_probe,
737 .remove = wm8940_remove,
738 .suspend = wm8940_suspend,
739 .resume = wm8940_resume,
740 .set_bias_level = wm8940_set_bias_level,
741 .reg_cache_size = ARRAY_SIZE(wm8940_reg_defaults),
742 .reg_word_size = sizeof(u16),
743 .reg_cache_default = wm8940_reg_defaults,
744 .volatile_register = wm8940_volatile_register,
745};
746
747#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
748static __devinit int wm8940_i2c_probe(struct i2c_client *i2c,
749 const struct i2c_device_id *id)
750{
751 struct wm8940_priv *wm8940;
752 int ret;
753
754 wm8940 = kzalloc(sizeof(struct wm8940_priv), GFP_KERNEL);
755 if (wm8940 == NULL)
756 return -ENOMEM;
757
758 i2c_set_clientdata(i2c, wm8940);
759 wm8940->control_type = SND_SOC_I2C;
760
761 ret = snd_soc_register_codec(&i2c->dev,
762 &soc_codec_dev_wm8940, &wm8940_dai, 1);
763 if (ret < 0)
764 kfree(wm8940);
765 return ret;
766}
767
768static __devexit int wm8940_i2c_remove(struct i2c_client *client)
769{
770 snd_soc_unregister_codec(&client->dev);
771 kfree(i2c_get_clientdata(client));
772 return 0;
773}
774
775static const struct i2c_device_id wm8940_i2c_id[] = {
776 { "wm8940", 0 },
777 { }
778};
779MODULE_DEVICE_TABLE(i2c, wm8940_i2c_id);
780
781static struct i2c_driver wm8940_i2c_driver = {
782 .driver = {
783 .name = "wm8940-codec",
784 .owner = THIS_MODULE,
785 },
786 .probe = wm8940_i2c_probe,
787 .remove = __devexit_p(wm8940_i2c_remove),
788 .id_table = wm8940_i2c_id,
789};
790#endif
791
792static int __init wm8940_modinit(void)
793{
794 int ret = 0;
795#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
796 ret = i2c_add_driver(&wm8940_i2c_driver);
797 if (ret != 0) {
798 printk(KERN_ERR "Failed to register wm8940 I2C driver: %d\n",
799 ret);
800 }
801#endif
802 return ret;
803}
804module_init(wm8940_modinit);
805
806static void __exit wm8940_exit(void)
807{
808#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
809 i2c_del_driver(&wm8940_i2c_driver);
810#endif
811}
812module_exit(wm8940_exit);
813
814MODULE_DESCRIPTION("ASoC WM8940 driver");
815MODULE_AUTHOR("Jonathan Cameron");
816MODULE_LICENSE("GPL");
817