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