ASoC: dapm: Allow regulators to bypass as well as disable when idle
[linux-2.6-block.git] / sound / soc / codecs / wm8974.c
CommitLineData
0a1bf553
MB
1/*
2 * wm8974.c -- WM8974 ALSA Soc Audio driver
3 *
8b83a193 4 * Copyright 2006-2009 Wolfson Microelectronics PLC.
0a1bf553 5 *
9a185b9a 6 * Author: Liam Girdwood <Liam.Girdwood@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>
0a1bf553
MB
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>
5a0e3ad6 20#include <linux/slab.h>
0a1bf553
MB
21#include <sound/core.h>
22#include <sound/pcm.h>
23#include <sound/pcm_params.h>
24#include <sound/soc.h>
0a1bf553 25#include <sound/initval.h>
a5f8d2f1 26#include <sound/tlv.h>
0a1bf553
MB
27
28#include "wm8974.h"
29
0a1bf553 30static const u16 wm8974_reg[WM8974_CACHEREGNUM] = {
1a55b3f6
MB
31 0x0000, 0x0000, 0x0000, 0x0000,
32 0x0050, 0x0000, 0x0140, 0x0000,
33 0x0000, 0x0000, 0x0000, 0x00ff,
34 0x0000, 0x0000, 0x0100, 0x00ff,
35 0x0000, 0x0000, 0x012c, 0x002c,
36 0x002c, 0x002c, 0x002c, 0x0000,
37 0x0032, 0x0000, 0x0000, 0x0000,
38 0x0000, 0x0000, 0x0000, 0x0000,
39 0x0038, 0x000b, 0x0032, 0x0000,
40 0x0008, 0x000c, 0x0093, 0x00e9,
41 0x0000, 0x0000, 0x0000, 0x0000,
42 0x0003, 0x0010, 0x0000, 0x0000,
43 0x0000, 0x0002, 0x0000, 0x0000,
44 0x0000, 0x0000, 0x0039, 0x0000,
45 0x0000,
0a1bf553
MB
46};
47
df1ef7a3 48#define WM8974_POWER1_BIASEN 0x08
48c03ce7 49#define WM8974_POWER1_BUFIOEN 0x04
df1ef7a3 50
1e97f50b 51#define wm8974_reset(c) snd_soc_write(c, WM8974_RESET, 0)
0a1bf553
MB
52
53static const char *wm8974_companding[] = {"Off", "NC", "u-law", "A-law" };
54static const char *wm8974_deemp[] = {"None", "32kHz", "44.1kHz", "48kHz" };
55static const char *wm8974_eqmode[] = {"Capture", "Playback" };
56static const char *wm8974_bw[] = {"Narrow", "Wide" };
57static const char *wm8974_eq1[] = {"80Hz", "105Hz", "135Hz", "175Hz" };
58static const char *wm8974_eq2[] = {"230Hz", "300Hz", "385Hz", "500Hz" };
59static const char *wm8974_eq3[] = {"650Hz", "850Hz", "1.1kHz", "1.4kHz" };
60static const char *wm8974_eq4[] = {"1.8kHz", "2.4kHz", "3.2kHz", "4.1kHz" };
61static const char *wm8974_eq5[] = {"5.3kHz", "6.9kHz", "9kHz", "11.7kHz" };
62static const char *wm8974_alc[] = {"ALC", "Limiter" };
63
64static const struct soc_enum wm8974_enum[] = {
65 SOC_ENUM_SINGLE(WM8974_COMP, 1, 4, wm8974_companding), /* adc */
66 SOC_ENUM_SINGLE(WM8974_COMP, 3, 4, wm8974_companding), /* dac */
67 SOC_ENUM_SINGLE(WM8974_DAC, 4, 4, wm8974_deemp),
68 SOC_ENUM_SINGLE(WM8974_EQ1, 8, 2, wm8974_eqmode),
69
70 SOC_ENUM_SINGLE(WM8974_EQ1, 5, 4, wm8974_eq1),
71 SOC_ENUM_SINGLE(WM8974_EQ2, 8, 2, wm8974_bw),
72 SOC_ENUM_SINGLE(WM8974_EQ2, 5, 4, wm8974_eq2),
73 SOC_ENUM_SINGLE(WM8974_EQ3, 8, 2, wm8974_bw),
74
75 SOC_ENUM_SINGLE(WM8974_EQ3, 5, 4, wm8974_eq3),
76 SOC_ENUM_SINGLE(WM8974_EQ4, 8, 2, wm8974_bw),
77 SOC_ENUM_SINGLE(WM8974_EQ4, 5, 4, wm8974_eq4),
78 SOC_ENUM_SINGLE(WM8974_EQ5, 8, 2, wm8974_bw),
79
80 SOC_ENUM_SINGLE(WM8974_EQ5, 5, 4, wm8974_eq5),
81 SOC_ENUM_SINGLE(WM8974_ALC3, 8, 2, wm8974_alc),
82};
83
8a123ee2
MB
84static const char *wm8974_auxmode_text[] = { "Buffer", "Mixer" };
85
86static const struct soc_enum wm8974_auxmode =
87 SOC_ENUM_SINGLE(WM8974_INPUT, 3, 2, wm8974_auxmode_text);
88
a5f8d2f1
MB
89static const DECLARE_TLV_DB_SCALE(digital_tlv, -12750, 50, 1);
90static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
91static const DECLARE_TLV_DB_SCALE(inpga_tlv, -1200, 75, 0);
92static const DECLARE_TLV_DB_SCALE(spk_tlv, -5700, 100, 0);
93
0a1bf553
MB
94static const struct snd_kcontrol_new wm8974_snd_controls[] = {
95
96SOC_SINGLE("Digital Loopback Switch", WM8974_COMP, 0, 1, 0),
97
98SOC_ENUM("DAC Companding", wm8974_enum[1]),
99SOC_ENUM("ADC Companding", wm8974_enum[0]),
100
101SOC_ENUM("Playback De-emphasis", wm8974_enum[2]),
102SOC_SINGLE("DAC Inversion Switch", WM8974_DAC, 0, 1, 0),
103
a5f8d2f1 104SOC_SINGLE_TLV("PCM Volume", WM8974_DACVOL, 0, 255, 0, digital_tlv),
0a1bf553
MB
105
106SOC_SINGLE("High Pass Filter Switch", WM8974_ADC, 8, 1, 0),
107SOC_SINGLE("High Pass Cut Off", WM8974_ADC, 4, 7, 0),
25cbf465 108SOC_SINGLE("ADC Inversion Switch", WM8974_ADC, 0, 1, 0),
0a1bf553 109
a5f8d2f1 110SOC_SINGLE_TLV("Capture Volume", WM8974_ADCVOL, 0, 255, 0, digital_tlv),
0a1bf553
MB
111
112SOC_ENUM("Equaliser Function", wm8974_enum[3]),
113SOC_ENUM("EQ1 Cut Off", wm8974_enum[4]),
a5f8d2f1 114SOC_SINGLE_TLV("EQ1 Volume", WM8974_EQ1, 0, 24, 1, eq_tlv),
0a1bf553
MB
115
116SOC_ENUM("Equaliser EQ2 Bandwith", wm8974_enum[5]),
117SOC_ENUM("EQ2 Cut Off", wm8974_enum[6]),
a5f8d2f1 118SOC_SINGLE_TLV("EQ2 Volume", WM8974_EQ2, 0, 24, 1, eq_tlv),
0a1bf553
MB
119
120SOC_ENUM("Equaliser EQ3 Bandwith", wm8974_enum[7]),
121SOC_ENUM("EQ3 Cut Off", wm8974_enum[8]),
a5f8d2f1 122SOC_SINGLE_TLV("EQ3 Volume", WM8974_EQ3, 0, 24, 1, eq_tlv),
0a1bf553
MB
123
124SOC_ENUM("Equaliser EQ4 Bandwith", wm8974_enum[9]),
125SOC_ENUM("EQ4 Cut Off", wm8974_enum[10]),
a5f8d2f1 126SOC_SINGLE_TLV("EQ4 Volume", WM8974_EQ4, 0, 24, 1, eq_tlv),
0a1bf553
MB
127
128SOC_ENUM("Equaliser EQ5 Bandwith", wm8974_enum[11]),
129SOC_ENUM("EQ5 Cut Off", wm8974_enum[12]),
a5f8d2f1 130SOC_SINGLE_TLV("EQ5 Volume", WM8974_EQ5, 0, 24, 1, eq_tlv),
0a1bf553
MB
131
132SOC_SINGLE("DAC Playback Limiter Switch", WM8974_DACLIM1, 8, 1, 0),
133SOC_SINGLE("DAC Playback Limiter Decay", WM8974_DACLIM1, 4, 15, 0),
134SOC_SINGLE("DAC Playback Limiter Attack", WM8974_DACLIM1, 0, 15, 0),
135
136SOC_SINGLE("DAC Playback Limiter Threshold", WM8974_DACLIM2, 4, 7, 0),
137SOC_SINGLE("DAC Playback Limiter Boost", WM8974_DACLIM2, 0, 15, 0),
138
139SOC_SINGLE("ALC Enable Switch", WM8974_ALC1, 8, 1, 0),
140SOC_SINGLE("ALC Capture Max Gain", WM8974_ALC1, 3, 7, 0),
141SOC_SINGLE("ALC Capture Min Gain", WM8974_ALC1, 0, 7, 0),
142
143SOC_SINGLE("ALC Capture ZC Switch", WM8974_ALC2, 8, 1, 0),
144SOC_SINGLE("ALC Capture Hold", WM8974_ALC2, 4, 7, 0),
145SOC_SINGLE("ALC Capture Target", WM8974_ALC2, 0, 15, 0),
146
147SOC_ENUM("ALC Capture Mode", wm8974_enum[13]),
148SOC_SINGLE("ALC Capture Decay", WM8974_ALC3, 4, 15, 0),
149SOC_SINGLE("ALC Capture Attack", WM8974_ALC3, 0, 15, 0),
150
151SOC_SINGLE("ALC Capture Noise Gate Switch", WM8974_NGATE, 3, 1, 0),
152SOC_SINGLE("ALC Capture Noise Gate Threshold", WM8974_NGATE, 0, 7, 0),
153
154SOC_SINGLE("Capture PGA ZC Switch", WM8974_INPPGA, 7, 1, 0),
a5f8d2f1 155SOC_SINGLE_TLV("Capture PGA Volume", WM8974_INPPGA, 0, 63, 0, inpga_tlv),
0a1bf553
MB
156
157SOC_SINGLE("Speaker Playback ZC Switch", WM8974_SPKVOL, 7, 1, 0),
158SOC_SINGLE("Speaker Playback Switch", WM8974_SPKVOL, 6, 1, 1),
8a123ee2
MB
159SOC_SINGLE_TLV("Speaker Playback Volume", WM8974_SPKVOL, 0, 63, 0, spk_tlv),
160
161SOC_ENUM("Aux Mode", wm8974_auxmode),
0a1bf553
MB
162
163SOC_SINGLE("Capture Boost(+20dB)", WM8974_ADCBOOST, 8, 1, 0),
8a123ee2 164SOC_SINGLE("Mono Playback Switch", WM8974_MONOMIX, 6, 1, 1),
b2c3e923
GL
165
166/* DAC / ADC oversampling */
167SOC_SINGLE("DAC 128x Oversampling Switch", WM8974_DAC, 8, 1, 0),
168SOC_SINGLE("ADC 128x Oversampling Switch", WM8974_ADC, 8, 1, 0),
0a1bf553
MB
169};
170
0a1bf553
MB
171/* Speaker Output Mixer */
172static const struct snd_kcontrol_new wm8974_speaker_mixer_controls[] = {
173SOC_DAPM_SINGLE("Line Bypass Switch", WM8974_SPKMIX, 1, 1, 0),
174SOC_DAPM_SINGLE("Aux Playback Switch", WM8974_SPKMIX, 5, 1, 0),
759512fb 175SOC_DAPM_SINGLE("PCM Playback Switch", WM8974_SPKMIX, 0, 1, 0),
0a1bf553
MB
176};
177
178/* Mono Output Mixer */
179static const struct snd_kcontrol_new wm8974_mono_mixer_controls[] = {
180SOC_DAPM_SINGLE("Line Bypass Switch", WM8974_MONOMIX, 1, 1, 0),
181SOC_DAPM_SINGLE("Aux Playback Switch", WM8974_MONOMIX, 2, 1, 0),
8a123ee2
MB
182SOC_DAPM_SINGLE("PCM Playback Switch", WM8974_MONOMIX, 0, 1, 0),
183};
184
185/* Boost mixer */
186static const struct snd_kcontrol_new wm8974_boost_mixer[] = {
187SOC_DAPM_SINGLE("Aux Switch", WM8974_INPPGA, 6, 1, 0),
188};
189
190/* Input PGA */
191static const struct snd_kcontrol_new wm8974_inpga[] = {
192SOC_DAPM_SINGLE("Aux Switch", WM8974_INPUT, 2, 1, 0),
193SOC_DAPM_SINGLE("MicN Switch", WM8974_INPUT, 1, 1, 0),
194SOC_DAPM_SINGLE("MicP Switch", WM8974_INPUT, 0, 1, 0),
0a1bf553
MB
195};
196
197/* AUX Input boost vol */
198static const struct snd_kcontrol_new wm8974_aux_boost_controls =
199SOC_DAPM_SINGLE("Aux Volume", WM8974_ADCBOOST, 0, 7, 0);
200
201/* Mic Input boost vol */
202static const struct snd_kcontrol_new wm8974_mic_boost_controls =
203SOC_DAPM_SINGLE("Mic Volume", WM8974_ADCBOOST, 4, 7, 0);
204
0a1bf553
MB
205static const struct snd_soc_dapm_widget wm8974_dapm_widgets[] = {
206SND_SOC_DAPM_MIXER("Speaker Mixer", WM8974_POWER3, 2, 0,
207 &wm8974_speaker_mixer_controls[0],
208 ARRAY_SIZE(wm8974_speaker_mixer_controls)),
209SND_SOC_DAPM_MIXER("Mono Mixer", WM8974_POWER3, 3, 0,
210 &wm8974_mono_mixer_controls[0],
211 ARRAY_SIZE(wm8974_mono_mixer_controls)),
212SND_SOC_DAPM_DAC("DAC", "HiFi Playback", WM8974_POWER3, 0, 0),
8a123ee2 213SND_SOC_DAPM_ADC("ADC", "HiFi Capture", WM8974_POWER2, 0, 0),
0a1bf553
MB
214SND_SOC_DAPM_PGA("Aux Input", WM8974_POWER1, 6, 0, NULL, 0),
215SND_SOC_DAPM_PGA("SpkN Out", WM8974_POWER3, 5, 0, NULL, 0),
216SND_SOC_DAPM_PGA("SpkP Out", WM8974_POWER3, 6, 0, NULL, 0),
217SND_SOC_DAPM_PGA("Mono Out", WM8974_POWER3, 7, 0, NULL, 0),
0a1bf553 218
8a123ee2
MB
219SND_SOC_DAPM_MIXER("Input PGA", WM8974_POWER2, 2, 0, wm8974_inpga,
220 ARRAY_SIZE(wm8974_inpga)),
221SND_SOC_DAPM_MIXER("Boost Mixer", WM8974_POWER2, 4, 0,
222 wm8974_boost_mixer, ARRAY_SIZE(wm8974_boost_mixer)),
0a1bf553 223
48dd231b 224SND_SOC_DAPM_SUPPLY("Mic Bias", WM8974_POWER1, 4, 0, NULL, 0),
0a1bf553
MB
225
226SND_SOC_DAPM_INPUT("MICN"),
227SND_SOC_DAPM_INPUT("MICP"),
228SND_SOC_DAPM_INPUT("AUX"),
229SND_SOC_DAPM_OUTPUT("MONOOUT"),
230SND_SOC_DAPM_OUTPUT("SPKOUTP"),
231SND_SOC_DAPM_OUTPUT("SPKOUTN"),
232};
233
a2bd691c 234static const struct snd_soc_dapm_route wm8974_dapm_routes[] = {
0a1bf553
MB
235 /* Mono output mixer */
236 {"Mono Mixer", "PCM Playback Switch", "DAC"},
237 {"Mono Mixer", "Aux Playback Switch", "Aux Input"},
238 {"Mono Mixer", "Line Bypass Switch", "Boost Mixer"},
239
240 /* Speaker output mixer */
241 {"Speaker Mixer", "PCM Playback Switch", "DAC"},
242 {"Speaker Mixer", "Aux Playback Switch", "Aux Input"},
243 {"Speaker Mixer", "Line Bypass Switch", "Boost Mixer"},
244
245 /* Outputs */
246 {"Mono Out", NULL, "Mono Mixer"},
247 {"MONOOUT", NULL, "Mono Out"},
248 {"SpkN Out", NULL, "Speaker Mixer"},
249 {"SpkP Out", NULL, "Speaker Mixer"},
250 {"SPKOUTN", NULL, "SpkN Out"},
251 {"SPKOUTP", NULL, "SpkP Out"},
252
253 /* Boost Mixer */
8a123ee2
MB
254 {"ADC", NULL, "Boost Mixer"},
255 {"Boost Mixer", "Aux Switch", "Aux Input"},
256 {"Boost Mixer", NULL, "Input PGA"},
257 {"Boost Mixer", NULL, "MICP"},
258
259 /* Input PGA */
260 {"Input PGA", "Aux Switch", "Aux Input"},
261 {"Input PGA", "MicN Switch", "MICN"},
262 {"Input PGA", "MicP Switch", "MICP"},
0a1bf553
MB
263
264 /* Inputs */
8a123ee2 265 {"Aux Input", NULL, "AUX"},
0a1bf553
MB
266};
267
0a1bf553 268struct pll_ {
c36b2fc7 269 unsigned int pre_div:1;
0a1bf553
MB
270 unsigned int n:4;
271 unsigned int k;
272};
273
91d0c3ec
MB
274/* The size in bits of the pll divide multiplied by 10
275 * to allow rounding later */
276#define FIXED_PLL_SIZE ((1 << 24) * 10)
277
c36b2fc7
MB
278static void pll_factors(struct pll_ *pll_div,
279 unsigned int target, unsigned int source)
91d0c3ec
MB
280{
281 unsigned long long Kpart;
282 unsigned int K, Ndiv, Nmod;
283
c36b2fc7
MB
284 /* There is a fixed divide by 4 in the output path */
285 target *= 4;
286
91d0c3ec
MB
287 Ndiv = target / source;
288 if (Ndiv < 6) {
c36b2fc7
MB
289 source /= 2;
290 pll_div->pre_div = 1;
91d0c3ec
MB
291 Ndiv = target / source;
292 } else
c36b2fc7 293 pll_div->pre_div = 0;
91d0c3ec
MB
294
295 if ((Ndiv < 6) || (Ndiv > 12))
296 printk(KERN_WARNING
8b83a193 297 "WM8974 N value %u outwith recommended range!\n",
91d0c3ec
MB
298 Ndiv);
299
c36b2fc7 300 pll_div->n = Ndiv;
91d0c3ec
MB
301 Nmod = target % source;
302 Kpart = FIXED_PLL_SIZE * (long long)Nmod;
303
304 do_div(Kpart, source);
305
306 K = Kpart & 0xFFFFFFFF;
307
308 /* Check if we need to round */
309 if ((K % 10) >= 5)
310 K += 5;
311
312 /* Move down to proper range now rounding is done */
313 K /= 10;
314
c36b2fc7 315 pll_div->k = K;
91d0c3ec 316}
0a1bf553 317
85488037
MB
318static int wm8974_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
319 int source, unsigned int freq_in, unsigned int freq_out)
0a1bf553
MB
320{
321 struct snd_soc_codec *codec = codec_dai->codec;
c36b2fc7 322 struct pll_ pll_div;
0a1bf553
MB
323 u16 reg;
324
1a55b3f6 325 if (freq_in == 0 || freq_out == 0) {
91d0c3ec 326 /* Clock CODEC directly from MCLK */
1e97f50b
MB
327 reg = snd_soc_read(codec, WM8974_CLOCK);
328 snd_soc_write(codec, WM8974_CLOCK, reg & 0x0ff);
91d0c3ec
MB
329
330 /* Turn off PLL */
1e97f50b
MB
331 reg = snd_soc_read(codec, WM8974_POWER1);
332 snd_soc_write(codec, WM8974_POWER1, reg & 0x1df);
0a1bf553
MB
333 return 0;
334 }
335
c36b2fc7 336 pll_factors(&pll_div, freq_out, freq_in);
91d0c3ec 337
1e97f50b
MB
338 snd_soc_write(codec, WM8974_PLLN, (pll_div.pre_div << 4) | pll_div.n);
339 snd_soc_write(codec, WM8974_PLLK1, pll_div.k >> 18);
340 snd_soc_write(codec, WM8974_PLLK2, (pll_div.k >> 9) & 0x1ff);
341 snd_soc_write(codec, WM8974_PLLK3, pll_div.k & 0x1ff);
342 reg = snd_soc_read(codec, WM8974_POWER1);
343 snd_soc_write(codec, WM8974_POWER1, reg | 0x020);
1a55b3f6 344
91d0c3ec 345 /* Run CODEC from PLL instead of MCLK */
1e97f50b
MB
346 reg = snd_soc_read(codec, WM8974_CLOCK);
347 snd_soc_write(codec, WM8974_CLOCK, reg | 0x100);
91d0c3ec
MB
348
349 return 0;
0a1bf553
MB
350}
351
352/*
353 * Configure WM8974 clock dividers.
354 */
355static int wm8974_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
356 int div_id, int div)
357{
358 struct snd_soc_codec *codec = codec_dai->codec;
359 u16 reg;
360
361 switch (div_id) {
362 case WM8974_OPCLKDIV:
1e97f50b
MB
363 reg = snd_soc_read(codec, WM8974_GPIO) & 0x1cf;
364 snd_soc_write(codec, WM8974_GPIO, reg | div);
0a1bf553
MB
365 break;
366 case WM8974_MCLKDIV:
1e97f50b
MB
367 reg = snd_soc_read(codec, WM8974_CLOCK) & 0x11f;
368 snd_soc_write(codec, WM8974_CLOCK, reg | div);
0a1bf553 369 break;
0a1bf553 370 case WM8974_BCLKDIV:
1e97f50b
MB
371 reg = snd_soc_read(codec, WM8974_CLOCK) & 0x1e3;
372 snd_soc_write(codec, WM8974_CLOCK, reg | div);
0a1bf553
MB
373 break;
374 default:
375 return -EINVAL;
376 }
377
378 return 0;
379}
380
381static int wm8974_set_dai_fmt(struct snd_soc_dai *codec_dai,
382 unsigned int fmt)
383{
384 struct snd_soc_codec *codec = codec_dai->codec;
385 u16 iface = 0;
1e97f50b 386 u16 clk = snd_soc_read(codec, WM8974_CLOCK) & 0x1fe;
0a1bf553
MB
387
388 /* set master/slave audio interface */
389 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
390 case SND_SOC_DAIFMT_CBM_CFM:
391 clk |= 0x0001;
392 break;
393 case SND_SOC_DAIFMT_CBS_CFS:
394 break;
395 default:
396 return -EINVAL;
397 }
398
399 /* interface format */
400 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
401 case SND_SOC_DAIFMT_I2S:
402 iface |= 0x0010;
403 break;
404 case SND_SOC_DAIFMT_RIGHT_J:
405 break;
406 case SND_SOC_DAIFMT_LEFT_J:
407 iface |= 0x0008;
408 break;
409 case SND_SOC_DAIFMT_DSP_A:
410 iface |= 0x00018;
411 break;
412 default:
413 return -EINVAL;
414 }
415
416 /* clock inversion */
417 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
418 case SND_SOC_DAIFMT_NB_NF:
419 break;
420 case SND_SOC_DAIFMT_IB_IF:
421 iface |= 0x0180;
422 break;
423 case SND_SOC_DAIFMT_IB_NF:
424 iface |= 0x0100;
425 break;
426 case SND_SOC_DAIFMT_NB_IF:
427 iface |= 0x0080;
428 break;
429 default:
430 return -EINVAL;
431 }
432
1e97f50b
MB
433 snd_soc_write(codec, WM8974_IFACE, iface);
434 snd_soc_write(codec, WM8974_CLOCK, clk);
0a1bf553
MB
435 return 0;
436}
437
438static int wm8974_pcm_hw_params(struct snd_pcm_substream *substream,
439 struct snd_pcm_hw_params *params,
440 struct snd_soc_dai *dai)
441{
442 struct snd_soc_codec *codec = dai->codec;
1e97f50b
MB
443 u16 iface = snd_soc_read(codec, WM8974_IFACE) & 0x19f;
444 u16 adn = snd_soc_read(codec, WM8974_ADD) & 0x1f1;
0a1bf553
MB
445
446 /* bit size */
447 switch (params_format(params)) {
448 case SNDRV_PCM_FORMAT_S16_LE:
449 break;
450 case SNDRV_PCM_FORMAT_S20_3LE:
451 iface |= 0x0020;
452 break;
453 case SNDRV_PCM_FORMAT_S24_LE:
454 iface |= 0x0040;
455 break;
456 case SNDRV_PCM_FORMAT_S32_LE:
457 iface |= 0x0060;
458 break;
459 }
460
461 /* filter coefficient */
462 switch (params_rate(params)) {
b3172f22 463 case 8000:
0a1bf553
MB
464 adn |= 0x5 << 1;
465 break;
b3172f22 466 case 11025:
0a1bf553
MB
467 adn |= 0x4 << 1;
468 break;
b3172f22 469 case 16000:
0a1bf553
MB
470 adn |= 0x3 << 1;
471 break;
b3172f22 472 case 22050:
0a1bf553
MB
473 adn |= 0x2 << 1;
474 break;
b3172f22 475 case 32000:
0a1bf553
MB
476 adn |= 0x1 << 1;
477 break;
b3172f22
GL
478 case 44100:
479 case 48000:
0a1bf553
MB
480 break;
481 }
482
1e97f50b
MB
483 snd_soc_write(codec, WM8974_IFACE, iface);
484 snd_soc_write(codec, WM8974_ADD, adn);
0a1bf553
MB
485 return 0;
486}
487
488static int wm8974_mute(struct snd_soc_dai *dai, int mute)
489{
490 struct snd_soc_codec *codec = dai->codec;
1e97f50b 491 u16 mute_reg = snd_soc_read(codec, WM8974_DAC) & 0xffbf;
0a1bf553 492
1a55b3f6 493 if (mute)
1e97f50b 494 snd_soc_write(codec, WM8974_DAC, mute_reg | 0x40);
0a1bf553 495 else
1e97f50b 496 snd_soc_write(codec, WM8974_DAC, mute_reg);
0a1bf553
MB
497 return 0;
498}
499
500/* liam need to make this lower power with dapm */
501static int wm8974_set_bias_level(struct snd_soc_codec *codec,
502 enum snd_soc_bias_level level)
503{
1e97f50b 504 u16 power1 = snd_soc_read(codec, WM8974_POWER1) & ~0x3;
df1ef7a3 505
0a1bf553
MB
506 switch (level) {
507 case SND_SOC_BIAS_ON:
0a1bf553 508 case SND_SOC_BIAS_PREPARE:
df1ef7a3 509 power1 |= 0x1; /* VMID 50k */
1e97f50b 510 snd_soc_write(codec, WM8974_POWER1, power1);
0a1bf553 511 break;
df1ef7a3 512
0a1bf553 513 case SND_SOC_BIAS_STANDBY:
df1ef7a3
MB
514 power1 |= WM8974_POWER1_BIASEN | WM8974_POWER1_BUFIOEN;
515
ce6120cc 516 if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
0bad3d84
AL
517 snd_soc_cache_sync(codec);
518
df1ef7a3 519 /* Initial cap charge at VMID 5k */
1e97f50b 520 snd_soc_write(codec, WM8974_POWER1, power1 | 0x3);
df1ef7a3
MB
521 mdelay(100);
522 }
523
524 power1 |= 0x2; /* VMID 500k */
1e97f50b 525 snd_soc_write(codec, WM8974_POWER1, power1);
0a1bf553 526 break;
df1ef7a3 527
0a1bf553 528 case SND_SOC_BIAS_OFF:
1e97f50b
MB
529 snd_soc_write(codec, WM8974_POWER1, 0);
530 snd_soc_write(codec, WM8974_POWER2, 0);
531 snd_soc_write(codec, WM8974_POWER3, 0);
0a1bf553
MB
532 break;
533 }
df1ef7a3 534
ce6120cc 535 codec->dapm.bias_level = level;
0a1bf553
MB
536 return 0;
537}
538
1a55b3f6 539#define WM8974_RATES (SNDRV_PCM_RATE_8000_48000)
0a1bf553
MB
540
541#define WM8974_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
542 SNDRV_PCM_FMTBIT_S24_LE)
543
85e7652d 544static const struct snd_soc_dai_ops wm8974_ops = {
0a1bf553
MB
545 .hw_params = wm8974_pcm_hw_params,
546 .digital_mute = wm8974_mute,
547 .set_fmt = wm8974_set_dai_fmt,
548 .set_clkdiv = wm8974_set_dai_clkdiv,
549 .set_pll = wm8974_set_dai_pll,
550};
551
f0fba2ad
LG
552static struct snd_soc_dai_driver wm8974_dai = {
553 .name = "wm8974-hifi",
0a1bf553
MB
554 .playback = {
555 .stream_name = "Playback",
556 .channels_min = 1,
33d81af4 557 .channels_max = 2, /* Only 1 channel of data */
0a1bf553
MB
558 .rates = WM8974_RATES,
559 .formats = WM8974_FORMATS,},
560 .capture = {
561 .stream_name = "Capture",
562 .channels_min = 1,
33d81af4 563 .channels_max = 2, /* Only 1 channel of data */
0a1bf553
MB
564 .rates = WM8974_RATES,
565 .formats = WM8974_FORMATS,},
566 .ops = &wm8974_ops,
cb11d39e 567 .symmetric_rates = 1,
0a1bf553 568};
0a1bf553 569
84b315ee 570static int wm8974_suspend(struct snd_soc_codec *codec)
0a1bf553 571{
0a1bf553
MB
572 wm8974_set_bias_level(codec, SND_SOC_BIAS_OFF);
573 return 0;
574}
575
f0fba2ad 576static int wm8974_resume(struct snd_soc_codec *codec)
0a1bf553 577{
0a1bf553 578 wm8974_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
0a1bf553
MB
579 return 0;
580}
581
f0fba2ad 582static int wm8974_probe(struct snd_soc_codec *codec)
0a1bf553 583{
0a1bf553
MB
584 int ret = 0;
585
f0fba2ad
LG
586 ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_I2C);
587 if (ret < 0) {
588 dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
589 return ret;
4fcbbb67 590 }
0a1bf553 591
f0fba2ad 592 ret = wm8974_reset(codec);
1a55b3f6 593 if (ret < 0) {
f0fba2ad
LG
594 dev_err(codec->dev, "Failed to issue reset\n");
595 return ret;
0a1bf553
MB
596 }
597
f0fba2ad 598 wm8974_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
4fcbbb67 599
0a1bf553 600 return ret;
0a1bf553
MB
601}
602
4fcbbb67 603/* power down chip */
f0fba2ad 604static int wm8974_remove(struct snd_soc_codec *codec)
4fcbbb67 605{
f0fba2ad 606 wm8974_set_bias_level(codec, SND_SOC_BIAS_OFF);
4fcbbb67
MB
607 return 0;
608}
0a1bf553 609
f0fba2ad 610static struct snd_soc_codec_driver soc_codec_dev_wm8974 = {
4fcbbb67
MB
611 .probe = wm8974_probe,
612 .remove = wm8974_remove,
613 .suspend = wm8974_suspend,
614 .resume = wm8974_resume,
f0fba2ad
LG
615 .set_bias_level = wm8974_set_bias_level,
616 .reg_cache_size = ARRAY_SIZE(wm8974_reg),
617 .reg_word_size = sizeof(u16),
618 .reg_cache_default = wm8974_reg,
a2bd691c
MB
619
620 .controls = wm8974_snd_controls,
621 .num_controls = ARRAY_SIZE(wm8974_snd_controls),
622 .dapm_widgets = wm8974_dapm_widgets,
623 .num_dapm_widgets = ARRAY_SIZE(wm8974_dapm_widgets),
624 .dapm_routes = wm8974_dapm_routes,
625 .num_dapm_routes = ARRAY_SIZE(wm8974_dapm_routes),
4fcbbb67 626};
0a1bf553 627
4fcbbb67
MB
628static __devinit int wm8974_i2c_probe(struct i2c_client *i2c,
629 const struct i2c_device_id *id)
0a1bf553 630{
f0fba2ad 631 int ret;
0a1bf553 632
f0fba2ad
LG
633 ret = snd_soc_register_codec(&i2c->dev,
634 &soc_codec_dev_wm8974, &wm8974_dai, 1);
c2562a8e 635
f0fba2ad 636 return ret;
4fcbbb67 637}
0a1bf553 638
4fcbbb67
MB
639static __devexit int wm8974_i2c_remove(struct i2c_client *client)
640{
f0fba2ad 641 snd_soc_unregister_codec(&client->dev);
c2562a8e 642
0a1bf553
MB
643 return 0;
644}
645
4fcbbb67
MB
646static const struct i2c_device_id wm8974_i2c_id[] = {
647 { "wm8974", 0 },
648 { }
649};
650MODULE_DEVICE_TABLE(i2c, wm8974_i2c_id);
651
652static struct i2c_driver wm8974_i2c_driver = {
653 .driver = {
091edccf 654 .name = "wm8974",
4fcbbb67
MB
655 .owner = THIS_MODULE,
656 },
657 .probe = wm8974_i2c_probe,
658 .remove = __devexit_p(wm8974_i2c_remove),
659 .id_table = wm8974_i2c_id,
0a1bf553 660};
0a1bf553 661
2be59418 662module_i2c_driver(wm8974_i2c_driver);
0a1bf553
MB
663
664MODULE_DESCRIPTION("ASoC WM8974 driver");
665MODULE_AUTHOR("Liam Girdwood");
666MODULE_LICENSE("GPL");