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