ASoC: Declare 2 channels for WM8974
[linux-2.6-block.git] / sound / soc / codecs / wm8974.c
CommitLineData
0a1bf553
MB
1/*
2 * wm8974.c -- WM8974 ALSA Soc Audio driver
3 *
4 * Copyright 2006 Wolfson Microelectronics PLC.
5 *
4fcbbb67 6 * Author: Liam Girdwood <linux@wolfsonmicro.com>
0a1bf553
MB
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/version.h>
16#include <linux/kernel.h>
17#include <linux/init.h>
18#include <linux/delay.h>
19#include <linux/pm.h>
20#include <linux/i2c.h>
21#include <linux/platform_device.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 "wm8974.h"
30
0a1bf553 31static const u16 wm8974_reg[WM8974_CACHEREGNUM] = {
1a55b3f6
MB
32 0x0000, 0x0000, 0x0000, 0x0000,
33 0x0050, 0x0000, 0x0140, 0x0000,
34 0x0000, 0x0000, 0x0000, 0x00ff,
35 0x0000, 0x0000, 0x0100, 0x00ff,
36 0x0000, 0x0000, 0x012c, 0x002c,
37 0x002c, 0x002c, 0x002c, 0x0000,
38 0x0032, 0x0000, 0x0000, 0x0000,
39 0x0000, 0x0000, 0x0000, 0x0000,
40 0x0038, 0x000b, 0x0032, 0x0000,
41 0x0008, 0x000c, 0x0093, 0x00e9,
42 0x0000, 0x0000, 0x0000, 0x0000,
43 0x0003, 0x0010, 0x0000, 0x0000,
44 0x0000, 0x0002, 0x0000, 0x0000,
45 0x0000, 0x0000, 0x0039, 0x0000,
46 0x0000,
0a1bf553
MB
47};
48
df1ef7a3
MB
49#define WM8974_POWER1_BIASEN 0x08
50#define WM8974_POWER1_BUFIOEN 0x10
51
4fcbbb67
MB
52struct wm8974_priv {
53 struct snd_soc_codec codec;
54 u16 reg_cache[WM8974_CACHEREGNUM];
55};
56
57static struct snd_soc_codec *wm8974_codec;
58
0a1bf553
MB
59/*
60 * read wm8974 register cache
61 */
1a55b3f6 62static inline unsigned int wm8974_read_reg_cache(struct snd_soc_codec *codec,
0a1bf553
MB
63 unsigned int reg)
64{
65 u16 *cache = codec->reg_cache;
66 if (reg == WM8974_RESET)
67 return 0;
68 if (reg >= WM8974_CACHEREGNUM)
69 return -1;
70 return cache[reg];
71}
72
73/*
74 * write wm8974 register cache
75 */
76static inline void wm8974_write_reg_cache(struct snd_soc_codec *codec,
77 u16 reg, unsigned int value)
78{
79 u16 *cache = codec->reg_cache;
80 if (reg >= WM8974_CACHEREGNUM)
81 return;
82 cache[reg] = value;
83}
84
85/*
86 * write to the WM8974 register space
87 */
88static int wm8974_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 WM8974 register offset
95 * D8...D0 register data
96 */
97 data[0] = (reg << 1) | ((value >> 8) & 0x0001);
98 data[1] = value & 0x00ff;
99
1a55b3f6 100 wm8974_write_reg_cache(codec, reg, value);
0a1bf553
MB
101 if (codec->hw_write(codec->control_data, data, 2) == 2)
102 return 0;
103 else
104 return -EIO;
105}
106
107#define wm8974_reset(c) wm8974_write(c, WM8974_RESET, 0)
108
109static const char *wm8974_companding[] = {"Off", "NC", "u-law", "A-law" };
110static const char *wm8974_deemp[] = {"None", "32kHz", "44.1kHz", "48kHz" };
111static const char *wm8974_eqmode[] = {"Capture", "Playback" };
112static const char *wm8974_bw[] = {"Narrow", "Wide" };
113static const char *wm8974_eq1[] = {"80Hz", "105Hz", "135Hz", "175Hz" };
114static const char *wm8974_eq2[] = {"230Hz", "300Hz", "385Hz", "500Hz" };
115static const char *wm8974_eq3[] = {"650Hz", "850Hz", "1.1kHz", "1.4kHz" };
116static const char *wm8974_eq4[] = {"1.8kHz", "2.4kHz", "3.2kHz", "4.1kHz" };
117static const char *wm8974_eq5[] = {"5.3kHz", "6.9kHz", "9kHz", "11.7kHz" };
118static const char *wm8974_alc[] = {"ALC", "Limiter" };
119
120static const struct soc_enum wm8974_enum[] = {
121 SOC_ENUM_SINGLE(WM8974_COMP, 1, 4, wm8974_companding), /* adc */
122 SOC_ENUM_SINGLE(WM8974_COMP, 3, 4, wm8974_companding), /* dac */
123 SOC_ENUM_SINGLE(WM8974_DAC, 4, 4, wm8974_deemp),
124 SOC_ENUM_SINGLE(WM8974_EQ1, 8, 2, wm8974_eqmode),
125
126 SOC_ENUM_SINGLE(WM8974_EQ1, 5, 4, wm8974_eq1),
127 SOC_ENUM_SINGLE(WM8974_EQ2, 8, 2, wm8974_bw),
128 SOC_ENUM_SINGLE(WM8974_EQ2, 5, 4, wm8974_eq2),
129 SOC_ENUM_SINGLE(WM8974_EQ3, 8, 2, wm8974_bw),
130
131 SOC_ENUM_SINGLE(WM8974_EQ3, 5, 4, wm8974_eq3),
132 SOC_ENUM_SINGLE(WM8974_EQ4, 8, 2, wm8974_bw),
133 SOC_ENUM_SINGLE(WM8974_EQ4, 5, 4, wm8974_eq4),
134 SOC_ENUM_SINGLE(WM8974_EQ5, 8, 2, wm8974_bw),
135
136 SOC_ENUM_SINGLE(WM8974_EQ5, 5, 4, wm8974_eq5),
137 SOC_ENUM_SINGLE(WM8974_ALC3, 8, 2, wm8974_alc),
138};
139
140static const struct snd_kcontrol_new wm8974_snd_controls[] = {
141
142SOC_SINGLE("Digital Loopback Switch", WM8974_COMP, 0, 1, 0),
143
144SOC_ENUM("DAC Companding", wm8974_enum[1]),
145SOC_ENUM("ADC Companding", wm8974_enum[0]),
146
147SOC_ENUM("Playback De-emphasis", wm8974_enum[2]),
148SOC_SINGLE("DAC Inversion Switch", WM8974_DAC, 0, 1, 0),
149
150SOC_SINGLE("PCM Volume", WM8974_DACVOL, 0, 127, 0),
151
152SOC_SINGLE("High Pass Filter Switch", WM8974_ADC, 8, 1, 0),
153SOC_SINGLE("High Pass Cut Off", WM8974_ADC, 4, 7, 0),
154SOC_SINGLE("ADC Inversion Switch", WM8974_COMP, 0, 1, 0),
155
156SOC_SINGLE("Capture Volume", WM8974_ADCVOL, 0, 127, 0),
157
158SOC_ENUM("Equaliser Function", wm8974_enum[3]),
159SOC_ENUM("EQ1 Cut Off", wm8974_enum[4]),
160SOC_SINGLE("EQ1 Volume", WM8974_EQ1, 0, 31, 1),
161
162SOC_ENUM("Equaliser EQ2 Bandwith", wm8974_enum[5]),
163SOC_ENUM("EQ2 Cut Off", wm8974_enum[6]),
164SOC_SINGLE("EQ2 Volume", WM8974_EQ2, 0, 31, 1),
165
166SOC_ENUM("Equaliser EQ3 Bandwith", wm8974_enum[7]),
167SOC_ENUM("EQ3 Cut Off", wm8974_enum[8]),
168SOC_SINGLE("EQ3 Volume", WM8974_EQ3, 0, 31, 1),
169
170SOC_ENUM("Equaliser EQ4 Bandwith", wm8974_enum[9]),
171SOC_ENUM("EQ4 Cut Off", wm8974_enum[10]),
172SOC_SINGLE("EQ4 Volume", WM8974_EQ4, 0, 31, 1),
173
174SOC_ENUM("Equaliser EQ5 Bandwith", wm8974_enum[11]),
175SOC_ENUM("EQ5 Cut Off", wm8974_enum[12]),
176SOC_SINGLE("EQ5 Volume", WM8974_EQ5, 0, 31, 1),
177
178SOC_SINGLE("DAC Playback Limiter Switch", WM8974_DACLIM1, 8, 1, 0),
179SOC_SINGLE("DAC Playback Limiter Decay", WM8974_DACLIM1, 4, 15, 0),
180SOC_SINGLE("DAC Playback Limiter Attack", WM8974_DACLIM1, 0, 15, 0),
181
182SOC_SINGLE("DAC Playback Limiter Threshold", WM8974_DACLIM2, 4, 7, 0),
183SOC_SINGLE("DAC Playback Limiter Boost", WM8974_DACLIM2, 0, 15, 0),
184
185SOC_SINGLE("ALC Enable Switch", WM8974_ALC1, 8, 1, 0),
186SOC_SINGLE("ALC Capture Max Gain", WM8974_ALC1, 3, 7, 0),
187SOC_SINGLE("ALC Capture Min Gain", WM8974_ALC1, 0, 7, 0),
188
189SOC_SINGLE("ALC Capture ZC Switch", WM8974_ALC2, 8, 1, 0),
190SOC_SINGLE("ALC Capture Hold", WM8974_ALC2, 4, 7, 0),
191SOC_SINGLE("ALC Capture Target", WM8974_ALC2, 0, 15, 0),
192
193SOC_ENUM("ALC Capture Mode", wm8974_enum[13]),
194SOC_SINGLE("ALC Capture Decay", WM8974_ALC3, 4, 15, 0),
195SOC_SINGLE("ALC Capture Attack", WM8974_ALC3, 0, 15, 0),
196
197SOC_SINGLE("ALC Capture Noise Gate Switch", WM8974_NGATE, 3, 1, 0),
198SOC_SINGLE("ALC Capture Noise Gate Threshold", WM8974_NGATE, 0, 7, 0),
199
200SOC_SINGLE("Capture PGA ZC Switch", WM8974_INPPGA, 7, 1, 0),
201SOC_SINGLE("Capture PGA Volume", WM8974_INPPGA, 0, 63, 0),
202
203SOC_SINGLE("Speaker Playback ZC Switch", WM8974_SPKVOL, 7, 1, 0),
204SOC_SINGLE("Speaker Playback Switch", WM8974_SPKVOL, 6, 1, 1),
205SOC_SINGLE("Speaker Playback Volume", WM8974_SPKVOL, 0, 63, 0),
206
207SOC_SINGLE("Capture Boost(+20dB)", WM8974_ADCBOOST, 8, 1, 0),
208SOC_SINGLE("Mono Playback Switch", WM8974_MONOMIX, 6, 1, 0),
209};
210
0a1bf553
MB
211/* Speaker Output Mixer */
212static const struct snd_kcontrol_new wm8974_speaker_mixer_controls[] = {
213SOC_DAPM_SINGLE("Line Bypass Switch", WM8974_SPKMIX, 1, 1, 0),
214SOC_DAPM_SINGLE("Aux Playback Switch", WM8974_SPKMIX, 5, 1, 0),
215SOC_DAPM_SINGLE("PCM Playback Switch", WM8974_SPKMIX, 0, 1, 1),
216};
217
218/* Mono Output Mixer */
219static const struct snd_kcontrol_new wm8974_mono_mixer_controls[] = {
220SOC_DAPM_SINGLE("Line Bypass Switch", WM8974_MONOMIX, 1, 1, 0),
221SOC_DAPM_SINGLE("Aux Playback Switch", WM8974_MONOMIX, 2, 1, 0),
222SOC_DAPM_SINGLE("PCM Playback Switch", WM8974_MONOMIX, 0, 1, 1),
223};
224
225/* AUX Input boost vol */
226static const struct snd_kcontrol_new wm8974_aux_boost_controls =
227SOC_DAPM_SINGLE("Aux Volume", WM8974_ADCBOOST, 0, 7, 0);
228
229/* Mic Input boost vol */
230static const struct snd_kcontrol_new wm8974_mic_boost_controls =
231SOC_DAPM_SINGLE("Mic Volume", WM8974_ADCBOOST, 4, 7, 0);
232
233/* Capture boost switch */
234static const struct snd_kcontrol_new wm8974_capture_boost_controls =
235SOC_DAPM_SINGLE("Capture Boost Switch", WM8974_INPPGA, 6, 1, 0);
236
237/* Aux In to PGA */
238static const struct snd_kcontrol_new wm8974_aux_capture_boost_controls =
239SOC_DAPM_SINGLE("Aux Capture Boost Switch", WM8974_INPPGA, 2, 1, 0);
240
241/* Mic P In to PGA */
242static const struct snd_kcontrol_new wm8974_micp_capture_boost_controls =
243SOC_DAPM_SINGLE("Mic P Capture Boost Switch", WM8974_INPPGA, 0, 1, 0);
244
245/* Mic N In to PGA */
246static const struct snd_kcontrol_new wm8974_micn_capture_boost_controls =
247SOC_DAPM_SINGLE("Mic N Capture Boost Switch", WM8974_INPPGA, 1, 1, 0);
248
249static const struct snd_soc_dapm_widget wm8974_dapm_widgets[] = {
250SND_SOC_DAPM_MIXER("Speaker Mixer", WM8974_POWER3, 2, 0,
251 &wm8974_speaker_mixer_controls[0],
252 ARRAY_SIZE(wm8974_speaker_mixer_controls)),
253SND_SOC_DAPM_MIXER("Mono Mixer", WM8974_POWER3, 3, 0,
254 &wm8974_mono_mixer_controls[0],
255 ARRAY_SIZE(wm8974_mono_mixer_controls)),
256SND_SOC_DAPM_DAC("DAC", "HiFi Playback", WM8974_POWER3, 0, 0),
257SND_SOC_DAPM_ADC("ADC", "HiFi Capture", WM8974_POWER3, 0, 0),
258SND_SOC_DAPM_PGA("Aux Input", WM8974_POWER1, 6, 0, NULL, 0),
259SND_SOC_DAPM_PGA("SpkN Out", WM8974_POWER3, 5, 0, NULL, 0),
260SND_SOC_DAPM_PGA("SpkP Out", WM8974_POWER3, 6, 0, NULL, 0),
261SND_SOC_DAPM_PGA("Mono Out", WM8974_POWER3, 7, 0, NULL, 0),
262SND_SOC_DAPM_PGA("Mic PGA", WM8974_POWER2, 2, 0, NULL, 0),
263
264SND_SOC_DAPM_PGA("Aux Boost", SND_SOC_NOPM, 0, 0,
265 &wm8974_aux_boost_controls, 1),
266SND_SOC_DAPM_PGA("Mic Boost", SND_SOC_NOPM, 0, 0,
267 &wm8974_mic_boost_controls, 1),
268SND_SOC_DAPM_SWITCH("Capture Boost", SND_SOC_NOPM, 0, 0,
269 &wm8974_capture_boost_controls),
270
271SND_SOC_DAPM_MIXER("Boost Mixer", WM8974_POWER2, 4, 0, NULL, 0),
272
273SND_SOC_DAPM_MICBIAS("Mic Bias", WM8974_POWER1, 4, 0),
274
275SND_SOC_DAPM_INPUT("MICN"),
276SND_SOC_DAPM_INPUT("MICP"),
277SND_SOC_DAPM_INPUT("AUX"),
278SND_SOC_DAPM_OUTPUT("MONOOUT"),
279SND_SOC_DAPM_OUTPUT("SPKOUTP"),
280SND_SOC_DAPM_OUTPUT("SPKOUTN"),
281};
282
283static const struct snd_soc_dapm_route audio_map[] = {
284 /* Mono output mixer */
285 {"Mono Mixer", "PCM Playback Switch", "DAC"},
286 {"Mono Mixer", "Aux Playback Switch", "Aux Input"},
287 {"Mono Mixer", "Line Bypass Switch", "Boost Mixer"},
288
289 /* Speaker output mixer */
290 {"Speaker Mixer", "PCM Playback Switch", "DAC"},
291 {"Speaker Mixer", "Aux Playback Switch", "Aux Input"},
292 {"Speaker Mixer", "Line Bypass Switch", "Boost Mixer"},
293
294 /* Outputs */
295 {"Mono Out", NULL, "Mono Mixer"},
296 {"MONOOUT", NULL, "Mono Out"},
297 {"SpkN Out", NULL, "Speaker Mixer"},
298 {"SpkP Out", NULL, "Speaker Mixer"},
299 {"SPKOUTN", NULL, "SpkN Out"},
300 {"SPKOUTP", NULL, "SpkP Out"},
301
302 /* Boost Mixer */
303 {"Boost Mixer", NULL, "ADC"},
304 {"Capture Boost Switch", "Aux Capture Boost Switch", "AUX"},
305 {"Aux Boost", "Aux Volume", "Boost Mixer"},
306 {"Capture Boost", "Capture Switch", "Boost Mixer"},
307 {"Mic Boost", "Mic Volume", "Boost Mixer"},
308
309 /* Inputs */
310 {"MICP", NULL, "Mic Boost"},
311 {"MICN", NULL, "Mic PGA"},
312 {"Mic PGA", NULL, "Capture Boost"},
313 {"AUX", NULL, "Aux Input"},
314};
315
316static int wm8974_add_widgets(struct snd_soc_codec *codec)
317{
318 snd_soc_dapm_new_controls(codec, wm8974_dapm_widgets,
319 ARRAY_SIZE(wm8974_dapm_widgets));
320
321 snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
322
323 snd_soc_dapm_new_widgets(codec);
324 return 0;
325}
326
327struct pll_ {
328 unsigned int in_hz, out_hz;
329 unsigned int pre:4; /* prescale - 1 */
330 unsigned int n:4;
331 unsigned int k;
332};
333
334static struct pll_ pll[] = {
1a55b3f6
MB
335 { 12000000, 11289600, 0, 7, 0x86c220 },
336 { 12000000, 12288000, 0, 8, 0x3126e8 },
337 { 13000000, 11289600, 0, 6, 0xf28bd4 },
338 { 13000000, 12288000, 0, 7, 0x8fd525 },
339 { 12288000, 11289600, 0, 7, 0x59999a },
340 { 11289600, 12288000, 0, 8, 0x80dee9 },
341 { 25000000, 11289600, 1, 7, 0x39B024 },
342 { 25000000, 24576000, 1, 7, 0xdd4413 }
0a1bf553
MB
343};
344
345static int wm8974_set_dai_pll(struct snd_soc_dai *codec_dai,
346 int pll_id, unsigned int freq_in, unsigned int freq_out)
347{
348 struct snd_soc_codec *codec = codec_dai->codec;
349 int i;
350 u16 reg;
351
1a55b3f6 352 if (freq_in == 0 || freq_out == 0) {
0a1bf553
MB
353 reg = wm8974_read_reg_cache(codec, WM8974_POWER1);
354 wm8974_write(codec, WM8974_POWER1, reg & 0x1df);
355 return 0;
356 }
357
1a55b3f6 358 for (i = 0; i < ARRAY_SIZE(pll); i++) {
0a1bf553 359 if (freq_in == pll[i].in_hz && freq_out == pll[i].out_hz) {
1a55b3f6
MB
360 wm8974_write(codec, WM8974_PLLN,
361 (pll[i].pre << 4) | pll[i].n);
0a1bf553 362 wm8974_write(codec, WM8974_PLLK1, pll[i].k >> 18);
1a55b3f6
MB
363 wm8974_write(codec, WM8974_PLLK2,
364 (pll[i].k >> 9) & 0x1ff);
0a1bf553
MB
365 wm8974_write(codec, WM8974_PLLK3, pll[i].k & 0x1ff);
366 reg = wm8974_read_reg_cache(codec, WM8974_POWER1);
367 wm8974_write(codec, WM8974_POWER1, reg | 0x020);
368 return 0;
369 }
370 }
1a55b3f6 371
0a1bf553
MB
372 return -EINVAL;
373}
374
375/*
376 * Configure WM8974 clock dividers.
377 */
378static int wm8974_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
379 int div_id, int div)
380{
381 struct snd_soc_codec *codec = codec_dai->codec;
382 u16 reg;
383
384 switch (div_id) {
385 case WM8974_OPCLKDIV:
1a55b3f6 386 reg = wm8974_read_reg_cache(codec, WM8974_GPIO) & 0x1cf;
0a1bf553
MB
387 wm8974_write(codec, WM8974_GPIO, reg | div);
388 break;
389 case WM8974_MCLKDIV:
390 reg = wm8974_read_reg_cache(codec, WM8974_CLOCK) & 0x11f;
391 wm8974_write(codec, WM8974_CLOCK, reg | div);
392 break;
393 case WM8974_ADCCLK:
394 reg = wm8974_read_reg_cache(codec, WM8974_ADC) & 0x1f7;
395 wm8974_write(codec, WM8974_ADC, reg | div);
396 break;
397 case WM8974_DACCLK:
398 reg = wm8974_read_reg_cache(codec, WM8974_DAC) & 0x1f7;
399 wm8974_write(codec, WM8974_DAC, reg | div);
400 break;
401 case WM8974_BCLKDIV:
402 reg = wm8974_read_reg_cache(codec, WM8974_CLOCK) & 0x1e3;
403 wm8974_write(codec, WM8974_CLOCK, reg | div);
404 break;
405 default:
406 return -EINVAL;
407 }
408
409 return 0;
410}
411
412static int wm8974_set_dai_fmt(struct snd_soc_dai *codec_dai,
413 unsigned int fmt)
414{
415 struct snd_soc_codec *codec = codec_dai->codec;
416 u16 iface = 0;
417 u16 clk = wm8974_read_reg_cache(codec, WM8974_CLOCK) & 0x1fe;
418
419 /* set master/slave audio interface */
420 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
421 case SND_SOC_DAIFMT_CBM_CFM:
422 clk |= 0x0001;
423 break;
424 case SND_SOC_DAIFMT_CBS_CFS:
425 break;
426 default:
427 return -EINVAL;
428 }
429
430 /* interface format */
431 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
432 case SND_SOC_DAIFMT_I2S:
433 iface |= 0x0010;
434 break;
435 case SND_SOC_DAIFMT_RIGHT_J:
436 break;
437 case SND_SOC_DAIFMT_LEFT_J:
438 iface |= 0x0008;
439 break;
440 case SND_SOC_DAIFMT_DSP_A:
441 iface |= 0x00018;
442 break;
443 default:
444 return -EINVAL;
445 }
446
447 /* clock inversion */
448 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
449 case SND_SOC_DAIFMT_NB_NF:
450 break;
451 case SND_SOC_DAIFMT_IB_IF:
452 iface |= 0x0180;
453 break;
454 case SND_SOC_DAIFMT_IB_NF:
455 iface |= 0x0100;
456 break;
457 case SND_SOC_DAIFMT_NB_IF:
458 iface |= 0x0080;
459 break;
460 default:
461 return -EINVAL;
462 }
463
464 wm8974_write(codec, WM8974_IFACE, iface);
465 wm8974_write(codec, WM8974_CLOCK, clk);
466 return 0;
467}
468
469static int wm8974_pcm_hw_params(struct snd_pcm_substream *substream,
470 struct snd_pcm_hw_params *params,
471 struct snd_soc_dai *dai)
472{
473 struct snd_soc_codec *codec = dai->codec;
474 u16 iface = wm8974_read_reg_cache(codec, WM8974_IFACE) & 0x19f;
475 u16 adn = wm8974_read_reg_cache(codec, WM8974_ADD) & 0x1f1;
476
477 /* bit size */
478 switch (params_format(params)) {
479 case SNDRV_PCM_FORMAT_S16_LE:
480 break;
481 case SNDRV_PCM_FORMAT_S20_3LE:
482 iface |= 0x0020;
483 break;
484 case SNDRV_PCM_FORMAT_S24_LE:
485 iface |= 0x0040;
486 break;
487 case SNDRV_PCM_FORMAT_S32_LE:
488 iface |= 0x0060;
489 break;
490 }
491
492 /* filter coefficient */
493 switch (params_rate(params)) {
494 case SNDRV_PCM_RATE_8000:
495 adn |= 0x5 << 1;
496 break;
497 case SNDRV_PCM_RATE_11025:
498 adn |= 0x4 << 1;
499 break;
500 case SNDRV_PCM_RATE_16000:
501 adn |= 0x3 << 1;
502 break;
503 case SNDRV_PCM_RATE_22050:
504 adn |= 0x2 << 1;
505 break;
506 case SNDRV_PCM_RATE_32000:
507 adn |= 0x1 << 1;
508 break;
509 case SNDRV_PCM_RATE_44100:
510 break;
511 }
512
513 wm8974_write(codec, WM8974_IFACE, iface);
514 wm8974_write(codec, WM8974_ADD, adn);
515 return 0;
516}
517
518static int wm8974_mute(struct snd_soc_dai *dai, int mute)
519{
520 struct snd_soc_codec *codec = dai->codec;
521 u16 mute_reg = wm8974_read_reg_cache(codec, WM8974_DAC) & 0xffbf;
522
1a55b3f6 523 if (mute)
0a1bf553
MB
524 wm8974_write(codec, WM8974_DAC, mute_reg | 0x40);
525 else
526 wm8974_write(codec, WM8974_DAC, mute_reg);
527 return 0;
528}
529
530/* liam need to make this lower power with dapm */
531static int wm8974_set_bias_level(struct snd_soc_codec *codec,
532 enum snd_soc_bias_level level)
533{
df1ef7a3
MB
534 u16 power1 = wm8974_read_reg_cache(codec, WM8974_POWER1) & ~0x3;
535
0a1bf553
MB
536 switch (level) {
537 case SND_SOC_BIAS_ON:
0a1bf553 538 case SND_SOC_BIAS_PREPARE:
df1ef7a3
MB
539 power1 |= 0x1; /* VMID 50k */
540 wm8974_write(codec, WM8974_POWER1, power1);
0a1bf553 541 break;
df1ef7a3 542
0a1bf553 543 case SND_SOC_BIAS_STANDBY:
df1ef7a3
MB
544 power1 |= WM8974_POWER1_BIASEN | WM8974_POWER1_BUFIOEN;
545
546 if (codec->bias_level == SND_SOC_BIAS_OFF) {
547 /* Initial cap charge at VMID 5k */
548 wm8974_write(codec, WM8974_POWER1, power1 | 0x3);
549 mdelay(100);
550 }
551
552 power1 |= 0x2; /* VMID 500k */
553 wm8974_write(codec, WM8974_POWER1, power1);
0a1bf553 554 break;
df1ef7a3 555
0a1bf553 556 case SND_SOC_BIAS_OFF:
df1ef7a3
MB
557 wm8974_write(codec, WM8974_POWER1, 0);
558 wm8974_write(codec, WM8974_POWER2, 0);
559 wm8974_write(codec, WM8974_POWER3, 0);
0a1bf553
MB
560 break;
561 }
df1ef7a3 562
0a1bf553
MB
563 codec->bias_level = level;
564 return 0;
565}
566
1a55b3f6 567#define WM8974_RATES (SNDRV_PCM_RATE_8000_48000)
0a1bf553
MB
568
569#define WM8974_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
570 SNDRV_PCM_FMTBIT_S24_LE)
571
572static struct snd_soc_dai_ops wm8974_ops = {
573 .hw_params = wm8974_pcm_hw_params,
574 .digital_mute = wm8974_mute,
575 .set_fmt = wm8974_set_dai_fmt,
576 .set_clkdiv = wm8974_set_dai_clkdiv,
577 .set_pll = wm8974_set_dai_pll,
578};
579
580struct snd_soc_dai wm8974_dai = {
581 .name = "WM8974 HiFi",
582 .playback = {
583 .stream_name = "Playback",
584 .channels_min = 1,
33d81af4 585 .channels_max = 2, /* Only 1 channel of data */
0a1bf553
MB
586 .rates = WM8974_RATES,
587 .formats = WM8974_FORMATS,},
588 .capture = {
589 .stream_name = "Capture",
590 .channels_min = 1,
33d81af4 591 .channels_max = 2, /* Only 1 channel of data */
0a1bf553
MB
592 .rates = WM8974_RATES,
593 .formats = WM8974_FORMATS,},
594 .ops = &wm8974_ops,
595};
596EXPORT_SYMBOL_GPL(wm8974_dai);
597
598static int wm8974_suspend(struct platform_device *pdev, pm_message_t state)
599{
600 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
601 struct snd_soc_codec *codec = socdev->card->codec;
602
603 wm8974_set_bias_level(codec, SND_SOC_BIAS_OFF);
604 return 0;
605}
606
607static int wm8974_resume(struct platform_device *pdev)
608{
609 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
610 struct snd_soc_codec *codec = socdev->card->codec;
611 int i;
612 u8 data[2];
613 u16 *cache = codec->reg_cache;
614
615 /* Sync reg_cache with the hardware */
616 for (i = 0; i < ARRAY_SIZE(wm8974_reg); i++) {
617 data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
618 data[1] = cache[i] & 0x00ff;
619 codec->hw_write(codec->control_data, data, 2);
620 }
621 wm8974_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
622 wm8974_set_bias_level(codec, codec->suspend_bias_level);
623 return 0;
624}
625
4fcbbb67 626static int wm8974_probe(struct platform_device *pdev)
0a1bf553 627{
4fcbbb67
MB
628 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
629 struct snd_soc_codec *codec;
0a1bf553
MB
630 int ret = 0;
631
4fcbbb67
MB
632 if (wm8974_codec == NULL) {
633 dev_err(&pdev->dev, "Codec device not registered\n");
634 return -ENODEV;
635 }
0a1bf553 636
4fcbbb67
MB
637 socdev->card->codec = wm8974_codec;
638 codec = wm8974_codec;
0a1bf553
MB
639
640 /* register pcms */
641 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
1a55b3f6 642 if (ret < 0) {
4fcbbb67 643 dev_err(codec->dev, "failed to create pcms: %d\n", ret);
0a1bf553
MB
644 goto pcm_err;
645 }
646
4fcbbb67
MB
647 snd_soc_add_controls(codec, wm8974_snd_controls,
648 ARRAY_SIZE(wm8974_snd_controls));
0a1bf553
MB
649 wm8974_add_widgets(codec);
650 ret = snd_soc_init_card(socdev);
651 if (ret < 0) {
4fcbbb67 652 dev_err(codec->dev, "failed to register card: %d\n", ret);
0a1bf553
MB
653 goto card_err;
654 }
4fcbbb67 655
0a1bf553
MB
656 return ret;
657
658card_err:
659 snd_soc_free_pcms(socdev);
660 snd_soc_dapm_free(socdev);
661pcm_err:
0a1bf553
MB
662 return ret;
663}
664
4fcbbb67
MB
665/* power down chip */
666static int wm8974_remove(struct platform_device *pdev)
667{
668 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
0a1bf553 669
4fcbbb67
MB
670 snd_soc_free_pcms(socdev);
671 snd_soc_dapm_free(socdev);
0a1bf553 672
4fcbbb67
MB
673 return 0;
674}
0a1bf553 675
4fcbbb67
MB
676struct snd_soc_codec_device soc_codec_dev_wm8974 = {
677 .probe = wm8974_probe,
678 .remove = wm8974_remove,
679 .suspend = wm8974_suspend,
680 .resume = wm8974_resume,
681};
682EXPORT_SYMBOL_GPL(soc_codec_dev_wm8974);
0a1bf553 683
4fcbbb67 684static __devinit int wm8974_register(struct wm8974_priv *wm8974)
0a1bf553 685{
0a1bf553 686 int ret;
4fcbbb67 687 struct snd_soc_codec *codec = &wm8974->codec;
0a1bf553 688
4fcbbb67
MB
689 if (wm8974_codec) {
690 dev_err(codec->dev, "Another WM8974 is registered\n");
691 return -EINVAL;
692 }
0a1bf553 693
4fcbbb67
MB
694 mutex_init(&codec->mutex);
695 INIT_LIST_HEAD(&codec->dapm_widgets);
696 INIT_LIST_HEAD(&codec->dapm_paths);
0a1bf553 697
4fcbbb67
MB
698 codec->private_data = wm8974;
699 codec->name = "WM8974";
700 codec->owner = THIS_MODULE;
701 codec->read = wm8974_read_reg_cache;
702 codec->write = wm8974_write;
703 codec->bias_level = SND_SOC_BIAS_OFF;
704 codec->set_bias_level = wm8974_set_bias_level;
705 codec->dai = &wm8974_dai;
706 codec->num_dai = 1;
707 codec->reg_cache_size = WM8974_CACHEREGNUM;
708 codec->reg_cache = &wm8974->reg_cache;
0a1bf553 709
4fcbbb67
MB
710 memcpy(codec->reg_cache, wm8974_reg, sizeof(wm8974_reg));
711
712 ret = wm8974_reset(codec);
0a1bf553 713 if (ret < 0) {
4fcbbb67
MB
714 dev_err(codec->dev, "Failed to issue reset\n");
715 return ret;
0a1bf553
MB
716 }
717
4fcbbb67
MB
718 wm8974_dai.dev = codec->dev;
719
720 wm8974_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
721
722 wm8974_codec = codec;
723
724 ret = snd_soc_register_codec(codec);
725 if (ret != 0) {
726 dev_err(codec->dev, "Failed to register codec: %d\n", ret);
727 return ret;
0a1bf553 728 }
0a1bf553 729
4fcbbb67
MB
730 ret = snd_soc_register_dai(&wm8974_dai);
731 if (ret != 0) {
732 dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
733 snd_soc_unregister_codec(codec);
734 return ret;
735 }
0a1bf553 736
0a1bf553
MB
737 return 0;
738}
739
4fcbbb67 740static __devexit void wm8974_unregister(struct wm8974_priv *wm8974)
0a1bf553 741{
4fcbbb67
MB
742 wm8974_set_bias_level(&wm8974->codec, SND_SOC_BIAS_OFF);
743 snd_soc_unregister_dai(&wm8974_dai);
744 snd_soc_unregister_codec(&wm8974->codec);
745 kfree(wm8974);
746 wm8974_codec = NULL;
0a1bf553
MB
747}
748
4fcbbb67
MB
749static __devinit int wm8974_i2c_probe(struct i2c_client *i2c,
750 const struct i2c_device_id *id)
0a1bf553 751{
4fcbbb67 752 struct wm8974_priv *wm8974;
0a1bf553 753 struct snd_soc_codec *codec;
0a1bf553 754
4fcbbb67
MB
755 wm8974 = kzalloc(sizeof(struct wm8974_priv), GFP_KERNEL);
756 if (wm8974 == NULL)
0a1bf553
MB
757 return -ENOMEM;
758
4fcbbb67
MB
759 codec = &wm8974->codec;
760 codec->hw_write = (hw_write_t)i2c_master_send;
0a1bf553 761
4fcbbb67
MB
762 i2c_set_clientdata(i2c, wm8974);
763 codec->control_data = i2c;
0a1bf553 764
4fcbbb67 765 codec->dev = &i2c->dev;
0a1bf553 766
4fcbbb67
MB
767 return wm8974_register(wm8974);
768}
0a1bf553 769
4fcbbb67
MB
770static __devexit int wm8974_i2c_remove(struct i2c_client *client)
771{
772 struct wm8974_priv *wm8974 = i2c_get_clientdata(client);
773 wm8974_unregister(wm8974);
0a1bf553
MB
774 return 0;
775}
776
4fcbbb67
MB
777static const struct i2c_device_id wm8974_i2c_id[] = {
778 { "wm8974", 0 },
779 { }
780};
781MODULE_DEVICE_TABLE(i2c, wm8974_i2c_id);
782
783static struct i2c_driver wm8974_i2c_driver = {
784 .driver = {
785 .name = "WM8974 I2C Codec",
786 .owner = THIS_MODULE,
787 },
788 .probe = wm8974_i2c_probe,
789 .remove = __devexit_p(wm8974_i2c_remove),
790 .id_table = wm8974_i2c_id,
0a1bf553 791};
0a1bf553
MB
792
793static int __init wm8974_modinit(void)
794{
4fcbbb67 795 return i2c_add_driver(&wm8974_i2c_driver);
0a1bf553
MB
796}
797module_init(wm8974_modinit);
798
799static void __exit wm8974_exit(void)
800{
4fcbbb67 801 i2c_del_driver(&wm8974_i2c_driver);
0a1bf553
MB
802}
803module_exit(wm8974_exit);
804
805MODULE_DESCRIPTION("ASoC WM8974 driver");
806MODULE_AUTHOR("Liam Girdwood");
807MODULE_LICENSE("GPL");