blob: c32e6326be6cd972d6ab79a81fbfed86b66e56f5 [file] [log] [blame]
Liam Girdwood1f53aee2007-04-16 19:17:44 +02001/*
2 * wm8753.c -- WM8753 ALSA Soc Audio driver
3 *
4 * Copyright 2003 Wolfson Microelectronics PLC.
5 * Author: Liam Girdwood
6 * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 *
13 * Notes:
14 * The WM8753 is a low power, high quality stereo codec with integrated PCM
15 * codec designed for portable digital telephony applications.
16 *
17 * Dual DAI:-
18 *
19 * This driver support 2 DAI PCM's. This makes the default PCM available for
20 * HiFi audio (e.g. MP3, ogg) playback/capture and the other PCM available for
21 * voice.
22 *
23 * Please note that the voice PCM can be connected directly to a Bluetooth
24 * codec or GSM modem and thus cannot be read or written to, although it is
25 * available to be configured with snd_hw_params(), etc and kcontrols in the
26 * normal alsa manner.
27 *
28 * Fast DAI switching:-
29 *
30 * The driver can now fast switch between the DAI configurations via a
31 * an alsa kcontrol. This allows the PCM to remain open.
32 *
33 */
34
35#include <linux/module.h>
36#include <linux/moduleparam.h>
37#include <linux/version.h>
38#include <linux/kernel.h>
39#include <linux/init.h>
40#include <linux/delay.h>
41#include <linux/pm.h>
42#include <linux/i2c.h>
43#include <linux/platform_device.h>
Liam Girdwood1f53aee2007-04-16 19:17:44 +020044#include <sound/core.h>
45#include <sound/pcm.h>
46#include <sound/pcm_params.h>
47#include <sound/soc.h>
48#include <sound/soc-dapm.h>
49#include <sound/initval.h>
Liam Girdwood2d6a4ac2008-01-10 14:43:48 +010050#include <sound/tlv.h>
Liam Girdwood1f53aee2007-04-16 19:17:44 +020051#include <asm/div64.h>
52
53#include "wm8753.h"
54
55#define AUDIO_NAME "wm8753"
56#define WM8753_VERSION "0.16"
57
58/*
59 * Debug
60 */
61
62#define WM8753_DEBUG 0
63
64#ifdef WM8753_DEBUG
65#define dbg(format, arg...) \
66 printk(KERN_DEBUG AUDIO_NAME ": " format "\n" , ## arg)
67#else
68#define dbg(format, arg...) do {} while (0)
69#endif
70#define err(format, arg...) \
71 printk(KERN_ERR AUDIO_NAME ": " format "\n" , ## arg)
72#define info(format, arg...) \
73 printk(KERN_INFO AUDIO_NAME ": " format "\n" , ## arg)
74#define warn(format, arg...) \
75 printk(KERN_WARNING AUDIO_NAME ": " format "\n" , ## arg)
76
77static int caps_charge = 2000;
78module_param(caps_charge, int, 0);
79MODULE_PARM_DESC(caps_charge, "WM8753 cap charge time (msecs)");
80
81static void wm8753_set_dai_mode(struct snd_soc_codec *codec,
82 unsigned int mode);
83
84/* codec private data */
85struct wm8753_priv {
86 unsigned int sysclk;
87 unsigned int pcmclk;
88};
89
90/*
91 * wm8753 register cache
92 * We can't read the WM8753 register space when we
93 * are using 2 wire for device control, so we cache them instead.
94 */
95static const u16 wm8753_reg[] = {
96 0x0008, 0x0000, 0x000a, 0x000a,
97 0x0033, 0x0000, 0x0007, 0x00ff,
98 0x00ff, 0x000f, 0x000f, 0x007b,
99 0x0000, 0x0032, 0x0000, 0x00c3,
100 0x00c3, 0x00c0, 0x0000, 0x0000,
101 0x0000, 0x0000, 0x0000, 0x0000,
102 0x0000, 0x0000, 0x0000, 0x0000,
103 0x0000, 0x0000, 0x0000, 0x0055,
104 0x0005, 0x0050, 0x0055, 0x0050,
105 0x0055, 0x0050, 0x0055, 0x0079,
106 0x0079, 0x0079, 0x0079, 0x0079,
107 0x0000, 0x0000, 0x0000, 0x0000,
108 0x0097, 0x0097, 0x0000, 0x0004,
109 0x0000, 0x0083, 0x0024, 0x01ba,
110 0x0000, 0x0083, 0x0024, 0x01ba,
111 0x0000, 0x0000
112};
113
114/*
115 * read wm8753 register cache
116 */
117static inline unsigned int wm8753_read_reg_cache(struct snd_soc_codec *codec,
118 unsigned int reg)
119{
120 u16 *cache = codec->reg_cache;
121 if (reg < 1 || reg > (ARRAY_SIZE(wm8753_reg) + 1))
122 return -1;
123 return cache[reg - 1];
124}
125
126/*
127 * write wm8753 register cache
128 */
129static inline void wm8753_write_reg_cache(struct snd_soc_codec *codec,
130 unsigned int reg, unsigned int value)
131{
132 u16 *cache = codec->reg_cache;
133 if (reg < 1 || reg > 0x3f)
134 return;
135 cache[reg - 1] = value;
136}
137
138/*
139 * write to the WM8753 register space
140 */
141static int wm8753_write(struct snd_soc_codec *codec, unsigned int reg,
142 unsigned int value)
143{
144 u8 data[2];
145
146 /* data is
147 * D15..D9 WM8753 register offset
148 * D8...D0 register data
149 */
150 data[0] = (reg << 1) | ((value >> 8) & 0x0001);
151 data[1] = value & 0x00ff;
152
Mark Brown60fc6842008-04-30 17:18:43 +0200153 wm8753_write_reg_cache(codec, reg, value);
Liam Girdwood1f53aee2007-04-16 19:17:44 +0200154 if (codec->hw_write(codec->control_data, data, 2) == 2)
155 return 0;
156 else
157 return -EIO;
158}
159
160#define wm8753_reset(c) wm8753_write(c, WM8753_RESET, 0)
161
162/*
163 * WM8753 Controls
164 */
165static const char *wm8753_base[] = {"Linear Control", "Adaptive Boost"};
166static const char *wm8753_base_filter[] =
167 {"130Hz @ 48kHz", "200Hz @ 48kHz", "100Hz @ 16kHz", "400Hz @ 48kHz",
168 "100Hz @ 8kHz", "200Hz @ 8kHz"};
169static const char *wm8753_treble[] = {"8kHz", "4kHz"};
170static const char *wm8753_alc_func[] = {"Off", "Right", "Left", "Stereo"};
171static const char *wm8753_ng_type[] = {"Constant PGA Gain", "Mute ADC Output"};
172static const char *wm8753_3d_func[] = {"Capture", "Playback"};
173static const char *wm8753_3d_uc[] = {"2.2kHz", "1.5kHz"};
174static const char *wm8753_3d_lc[] = {"200Hz", "500Hz"};
175static const char *wm8753_deemp[] = {"None", "32kHz", "44.1kHz", "48kHz"};
176static const char *wm8753_mono_mix[] = {"Stereo", "Left", "Right", "Mono"};
177static const char *wm8753_dac_phase[] = {"Non Inverted", "Inverted"};
178static const char *wm8753_line_mix[] = {"Line 1 + 2", "Line 1 - 2",
179 "Line 1", "Line 2"};
180static const char *wm8753_mono_mux[] = {"Line Mix", "Rx Mix"};
181static const char *wm8753_right_mux[] = {"Line 2", "Rx Mix"};
182static const char *wm8753_left_mux[] = {"Line 1", "Rx Mix"};
183static const char *wm8753_rxmsel[] = {"RXP - RXN", "RXP + RXN", "RXP", "RXN"};
184static const char *wm8753_sidetone_mux[] = {"Left PGA", "Mic 1", "Mic 2",
185 "Right PGA"};
186static const char *wm8753_mono2_src[] = {"Inverted Mono 1", "Left", "Right",
187 "Left + Right"};
188static const char *wm8753_out3[] = {"VREF", "ROUT2", "Left + Right"};
189static const char *wm8753_out4[] = {"VREF", "Capture ST", "LOUT2"};
190static const char *wm8753_radcsel[] = {"PGA", "Line or RXP-RXN", "Sidetone"};
191static const char *wm8753_ladcsel[] = {"PGA", "Line or RXP-RXN", "Line"};
192static const char *wm8753_mono_adc[] = {"Stereo", "Analogue Mix Left",
193 "Analogue Mix Right", "Digital Mono Mix"};
194static const char *wm8753_adc_hp[] = {"3.4Hz @ 48kHz", "82Hz @ 16k",
195 "82Hz @ 8kHz", "170Hz @ 8kHz"};
196static const char *wm8753_adc_filter[] = {"HiFi", "Voice"};
197static const char *wm8753_mic_sel[] = {"Mic 1", "Mic 2", "Mic 3"};
198static const char *wm8753_dai_mode[] = {"DAI 0", "DAI 1", "DAI 2", "DAI 3"};
199static const char *wm8753_dat_sel[] = {"Stereo", "Left ADC", "Right ADC",
200 "Channel Swap"};
Graeme Gregoryae092c92008-03-03 17:19:45 +0100201static const char *wm8753_rout2_phase[] = {"Non Inverted", "Inverted"};
Liam Girdwood1f53aee2007-04-16 19:17:44 +0200202
203static const struct soc_enum wm8753_enum[] = {
204SOC_ENUM_SINGLE(WM8753_BASS, 7, 2, wm8753_base),
205SOC_ENUM_SINGLE(WM8753_BASS, 4, 6, wm8753_base_filter),
206SOC_ENUM_SINGLE(WM8753_TREBLE, 6, 2, wm8753_treble),
207SOC_ENUM_SINGLE(WM8753_ALC1, 7, 4, wm8753_alc_func),
208SOC_ENUM_SINGLE(WM8753_NGATE, 1, 2, wm8753_ng_type),
209SOC_ENUM_SINGLE(WM8753_3D, 7, 2, wm8753_3d_func),
210SOC_ENUM_SINGLE(WM8753_3D, 6, 2, wm8753_3d_uc),
211SOC_ENUM_SINGLE(WM8753_3D, 5, 2, wm8753_3d_lc),
212SOC_ENUM_SINGLE(WM8753_DAC, 1, 4, wm8753_deemp),
213SOC_ENUM_SINGLE(WM8753_DAC, 4, 4, wm8753_mono_mix),
214SOC_ENUM_SINGLE(WM8753_DAC, 6, 2, wm8753_dac_phase),
215SOC_ENUM_SINGLE(WM8753_INCTL1, 3, 4, wm8753_line_mix),
216SOC_ENUM_SINGLE(WM8753_INCTL1, 2, 2, wm8753_mono_mux),
217SOC_ENUM_SINGLE(WM8753_INCTL1, 1, 2, wm8753_right_mux),
218SOC_ENUM_SINGLE(WM8753_INCTL1, 0, 2, wm8753_left_mux),
219SOC_ENUM_SINGLE(WM8753_INCTL2, 6, 4, wm8753_rxmsel),
220SOC_ENUM_SINGLE(WM8753_INCTL2, 4, 4, wm8753_sidetone_mux),
221SOC_ENUM_SINGLE(WM8753_OUTCTL, 7, 4, wm8753_mono2_src),
222SOC_ENUM_SINGLE(WM8753_OUTCTL, 0, 3, wm8753_out3),
223SOC_ENUM_SINGLE(WM8753_ADCTL2, 7, 3, wm8753_out4),
224SOC_ENUM_SINGLE(WM8753_ADCIN, 2, 3, wm8753_radcsel),
225SOC_ENUM_SINGLE(WM8753_ADCIN, 0, 3, wm8753_ladcsel),
226SOC_ENUM_SINGLE(WM8753_ADCIN, 4, 4, wm8753_mono_adc),
227SOC_ENUM_SINGLE(WM8753_ADC, 2, 4, wm8753_adc_hp),
228SOC_ENUM_SINGLE(WM8753_ADC, 4, 2, wm8753_adc_filter),
229SOC_ENUM_SINGLE(WM8753_MICBIAS, 6, 3, wm8753_mic_sel),
230SOC_ENUM_SINGLE(WM8753_IOCTL, 2, 4, wm8753_dai_mode),
231SOC_ENUM_SINGLE(WM8753_ADC, 7, 4, wm8753_dat_sel),
Graeme Gregoryae092c92008-03-03 17:19:45 +0100232SOC_ENUM_SINGLE(WM8753_OUTCTL, 2, 2, wm8753_rout2_phase),
Liam Girdwood1f53aee2007-04-16 19:17:44 +0200233};
234
235
236static int wm8753_get_dai(struct snd_kcontrol *kcontrol,
237 struct snd_ctl_elem_value *ucontrol)
238{
239 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
240 int mode = wm8753_read_reg_cache(codec, WM8753_IOCTL);
241
242 ucontrol->value.integer.value[0] = (mode & 0xc) >> 2;
243 return 0;
244}
245
246static int wm8753_set_dai(struct snd_kcontrol *kcontrol,
247 struct snd_ctl_elem_value *ucontrol)
248{
249 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
250 int mode = wm8753_read_reg_cache(codec, WM8753_IOCTL);
251
Mark Brown60fc6842008-04-30 17:18:43 +0200252 if (((mode & 0xc) >> 2) == ucontrol->value.integer.value[0])
Liam Girdwood1f53aee2007-04-16 19:17:44 +0200253 return 0;
254
255 mode &= 0xfff3;
256 mode |= (ucontrol->value.integer.value[0] << 2);
257
258 wm8753_write(codec, WM8753_IOCTL, mode);
259 wm8753_set_dai_mode(codec, ucontrol->value.integer.value[0]);
260 return 1;
261}
262
Liam Girdwood2d6a4ac2008-01-10 14:43:48 +0100263static const DECLARE_TLV_DB_LINEAR(rec_mix_tlv, -1500, 600);
264
Liam Girdwood1f53aee2007-04-16 19:17:44 +0200265static const struct snd_kcontrol_new wm8753_snd_controls[] = {
266SOC_DOUBLE_R("PCM Volume", WM8753_LDAC, WM8753_RDAC, 0, 255, 0),
267
268SOC_DOUBLE_R("ADC Capture Volume", WM8753_LADC, WM8753_RADC, 0, 255, 0),
269
270SOC_DOUBLE_R("Headphone Playback Volume", WM8753_LOUT1V, WM8753_ROUT1V, 0, 127, 0),
271SOC_DOUBLE_R("Speaker Playback Volume", WM8753_LOUT2V, WM8753_ROUT2V, 0, 127, 0),
272
273SOC_SINGLE("Mono Playback Volume", WM8753_MOUTV, 0, 127, 0),
274
275SOC_DOUBLE_R("Bypass Playback Volume", WM8753_LOUTM1, WM8753_ROUTM1, 4, 7, 1),
276SOC_DOUBLE_R("Sidetone Playback Volume", WM8753_LOUTM2, WM8753_ROUTM2, 4, 7, 1),
277SOC_DOUBLE_R("Voice Playback Volume", WM8753_LOUTM2, WM8753_ROUTM2, 0, 7, 1),
278
279SOC_DOUBLE_R("Headphone Playback ZC Switch", WM8753_LOUT1V, WM8753_ROUT1V, 7, 1, 0),
280SOC_DOUBLE_R("Speaker Playback ZC Switch", WM8753_LOUT2V, WM8753_ROUT2V, 7, 1, 0),
281
282SOC_SINGLE("Mono Bypass Playback Volume", WM8753_MOUTM1, 4, 7, 1),
283SOC_SINGLE("Mono Sidetone Playback Volume", WM8753_MOUTM2, 4, 7, 1),
Mike Montour10264602008-02-01 13:12:12 +0100284SOC_SINGLE("Mono Voice Playback Volume", WM8753_MOUTM2, 0, 7, 1),
Liam Girdwood1f53aee2007-04-16 19:17:44 +0200285SOC_SINGLE("Mono Playback ZC Switch", WM8753_MOUTV, 7, 1, 0),
286
287SOC_ENUM("Bass Boost", wm8753_enum[0]),
288SOC_ENUM("Bass Filter", wm8753_enum[1]),
289SOC_SINGLE("Bass Volume", WM8753_BASS, 0, 15, 1),
290
291SOC_SINGLE("Treble Volume", WM8753_TREBLE, 0, 15, 1),
292SOC_ENUM("Treble Cut-off", wm8753_enum[2]),
293
Liam Girdwood2d6a4ac2008-01-10 14:43:48 +0100294SOC_DOUBLE_TLV("Sidetone Capture Volume", WM8753_RECMIX1, 0, 4, 7, 1, rec_mix_tlv),
295SOC_SINGLE_TLV("Voice Sidetone Capture Volume", WM8753_RECMIX2, 0, 7, 1, rec_mix_tlv),
Liam Girdwood1f53aee2007-04-16 19:17:44 +0200296
297SOC_DOUBLE_R("Capture Volume", WM8753_LINVOL, WM8753_RINVOL, 0, 63, 0),
298SOC_DOUBLE_R("Capture ZC Switch", WM8753_LINVOL, WM8753_RINVOL, 6, 1, 0),
299SOC_DOUBLE_R("Capture Switch", WM8753_LINVOL, WM8753_RINVOL, 7, 1, 1),
300
301SOC_ENUM("Capture Filter Select", wm8753_enum[23]),
302SOC_ENUM("Capture Filter Cut-off", wm8753_enum[24]),
303SOC_SINGLE("Capture Filter Switch", WM8753_ADC, 0, 1, 1),
304
305SOC_SINGLE("ALC Capture Target Volume", WM8753_ALC1, 0, 7, 0),
306SOC_SINGLE("ALC Capture Max Volume", WM8753_ALC1, 4, 7, 0),
307SOC_ENUM("ALC Capture Function", wm8753_enum[3]),
308SOC_SINGLE("ALC Capture ZC Switch", WM8753_ALC2, 8, 1, 0),
309SOC_SINGLE("ALC Capture Hold Time", WM8753_ALC2, 0, 15, 1),
310SOC_SINGLE("ALC Capture Decay Time", WM8753_ALC3, 4, 15, 1),
311SOC_SINGLE("ALC Capture Attack Time", WM8753_ALC3, 0, 15, 0),
312SOC_SINGLE("ALC Capture NG Threshold", WM8753_NGATE, 3, 31, 0),
313SOC_ENUM("ALC Capture NG Type", wm8753_enum[4]),
314SOC_SINGLE("ALC Capture NG Switch", WM8753_NGATE, 0, 1, 0),
315
316SOC_ENUM("3D Function", wm8753_enum[5]),
317SOC_ENUM("3D Upper Cut-off", wm8753_enum[6]),
318SOC_ENUM("3D Lower Cut-off", wm8753_enum[7]),
319SOC_SINGLE("3D Volume", WM8753_3D, 1, 15, 0),
320SOC_SINGLE("3D Switch", WM8753_3D, 0, 1, 0),
321
322SOC_SINGLE("Capture 6dB Attenuate", WM8753_ADCTL1, 2, 1, 0),
323SOC_SINGLE("Playback 6dB Attenuate", WM8753_ADCTL1, 1, 1, 0),
324
325SOC_ENUM("De-emphasis", wm8753_enum[8]),
326SOC_ENUM("Playback Mono Mix", wm8753_enum[9]),
327SOC_ENUM("Playback Phase", wm8753_enum[10]),
328
329SOC_SINGLE("Mic2 Capture Volume", WM8753_INCTL1, 7, 3, 0),
330SOC_SINGLE("Mic1 Capture Volume", WM8753_INCTL1, 5, 3, 0),
331
332SOC_ENUM_EXT("DAI Mode", wm8753_enum[26], wm8753_get_dai, wm8753_set_dai),
333
334SOC_ENUM("ADC Data Select", wm8753_enum[27]),
Graeme Gregoryae092c92008-03-03 17:19:45 +0100335SOC_ENUM("ROUT2 Phase", wm8753_enum[28]),
Liam Girdwood1f53aee2007-04-16 19:17:44 +0200336};
337
338/* add non dapm controls */
339static int wm8753_add_controls(struct snd_soc_codec *codec)
340{
341 int err, i;
342
343 for (i = 0; i < ARRAY_SIZE(wm8753_snd_controls); i++) {
344 err = snd_ctl_add(codec->card,
Mark Brown60fc6842008-04-30 17:18:43 +0200345 snd_soc_cnew(&wm8753_snd_controls[i],
346 codec, NULL));
Liam Girdwood1f53aee2007-04-16 19:17:44 +0200347 if (err < 0)
348 return err;
349 }
350 return 0;
351}
352
353/*
354 * _DAPM_ Controls
355 */
356
357/* Left Mixer */
358static const struct snd_kcontrol_new wm8753_left_mixer_controls[] = {
359SOC_DAPM_SINGLE("Voice Playback Switch", WM8753_LOUTM2, 8, 1, 0),
360SOC_DAPM_SINGLE("Sidetone Playback Switch", WM8753_LOUTM2, 7, 1, 0),
361SOC_DAPM_SINGLE("Left Playback Switch", WM8753_LOUTM1, 8, 1, 0),
362SOC_DAPM_SINGLE("Bypass Playback Switch", WM8753_LOUTM1, 7, 1, 0),
363};
364
365/* Right mixer */
366static const struct snd_kcontrol_new wm8753_right_mixer_controls[] = {
367SOC_DAPM_SINGLE("Voice Playback Switch", WM8753_ROUTM2, 8, 1, 0),
368SOC_DAPM_SINGLE("Sidetone Playback Switch", WM8753_ROUTM2, 7, 1, 0),
369SOC_DAPM_SINGLE("Right Playback Switch", WM8753_ROUTM1, 8, 1, 0),
370SOC_DAPM_SINGLE("Bypass Playback Switch", WM8753_ROUTM1, 7, 1, 0),
371};
372
373/* Mono mixer */
374static const struct snd_kcontrol_new wm8753_mono_mixer_controls[] = {
375SOC_DAPM_SINGLE("Left Playback Switch", WM8753_MOUTM1, 8, 1, 0),
376SOC_DAPM_SINGLE("Right Playback Switch", WM8753_MOUTM2, 8, 1, 0),
377SOC_DAPM_SINGLE("Voice Playback Switch", WM8753_MOUTM2, 3, 1, 0),
378SOC_DAPM_SINGLE("Sidetone Playback Switch", WM8753_MOUTM2, 7, 1, 0),
379SOC_DAPM_SINGLE("Bypass Playback Switch", WM8753_MOUTM1, 7, 1, 0),
380};
381
382/* Mono 2 Mux */
383static const struct snd_kcontrol_new wm8753_mono2_controls =
384SOC_DAPM_ENUM("Route", wm8753_enum[17]);
385
386/* Out 3 Mux */
387static const struct snd_kcontrol_new wm8753_out3_controls =
388SOC_DAPM_ENUM("Route", wm8753_enum[18]);
389
390/* Out 4 Mux */
391static const struct snd_kcontrol_new wm8753_out4_controls =
392SOC_DAPM_ENUM("Route", wm8753_enum[19]);
393
394/* ADC Mono Mix */
395static const struct snd_kcontrol_new wm8753_adc_mono_controls =
396SOC_DAPM_ENUM("Route", wm8753_enum[22]);
397
398/* Record mixer */
399static const struct snd_kcontrol_new wm8753_record_mixer_controls[] = {
400SOC_DAPM_SINGLE("Voice Capture Switch", WM8753_RECMIX2, 3, 1, 0),
401SOC_DAPM_SINGLE("Left Capture Switch", WM8753_RECMIX1, 3, 1, 0),
402SOC_DAPM_SINGLE("Right Capture Switch", WM8753_RECMIX1, 7, 1, 0),
403};
404
405/* Left ADC mux */
406static const struct snd_kcontrol_new wm8753_adc_left_controls =
407SOC_DAPM_ENUM("Route", wm8753_enum[21]);
408
409/* Right ADC mux */
410static const struct snd_kcontrol_new wm8753_adc_right_controls =
411SOC_DAPM_ENUM("Route", wm8753_enum[20]);
412
413/* MIC mux */
414static const struct snd_kcontrol_new wm8753_mic_mux_controls =
415SOC_DAPM_ENUM("Route", wm8753_enum[16]);
416
417/* ALC mixer */
418static const struct snd_kcontrol_new wm8753_alc_mixer_controls[] = {
419SOC_DAPM_SINGLE("Line Capture Switch", WM8753_INCTL2, 3, 1, 0),
420SOC_DAPM_SINGLE("Mic2 Capture Switch", WM8753_INCTL2, 2, 1, 0),
421SOC_DAPM_SINGLE("Mic1 Capture Switch", WM8753_INCTL2, 1, 1, 0),
422SOC_DAPM_SINGLE("Rx Capture Switch", WM8753_INCTL2, 0, 1, 0),
423};
424
425/* Left Line mux */
426static const struct snd_kcontrol_new wm8753_line_left_controls =
427SOC_DAPM_ENUM("Route", wm8753_enum[14]);
428
429/* Right Line mux */
430static const struct snd_kcontrol_new wm8753_line_right_controls =
431SOC_DAPM_ENUM("Route", wm8753_enum[13]);
432
433/* Mono Line mux */
434static const struct snd_kcontrol_new wm8753_line_mono_controls =
435SOC_DAPM_ENUM("Route", wm8753_enum[12]);
436
437/* Line mux and mixer */
438static const struct snd_kcontrol_new wm8753_line_mux_mix_controls =
439SOC_DAPM_ENUM("Route", wm8753_enum[11]);
440
441/* Rx mux and mixer */
442static const struct snd_kcontrol_new wm8753_rx_mux_mix_controls =
443SOC_DAPM_ENUM("Route", wm8753_enum[15]);
444
445/* Mic Selector Mux */
446static const struct snd_kcontrol_new wm8753_mic_sel_mux_controls =
447SOC_DAPM_ENUM("Route", wm8753_enum[25]);
448
449static const struct snd_soc_dapm_widget wm8753_dapm_widgets[] = {
450SND_SOC_DAPM_MICBIAS("Mic Bias", WM8753_PWR1, 5, 0),
451SND_SOC_DAPM_MIXER("Left Mixer", WM8753_PWR4, 0, 0,
452 &wm8753_left_mixer_controls[0], ARRAY_SIZE(wm8753_left_mixer_controls)),
453SND_SOC_DAPM_PGA("Left Out 1", WM8753_PWR3, 8, 0, NULL, 0),
454SND_SOC_DAPM_PGA("Left Out 2", WM8753_PWR3, 6, 0, NULL, 0),
455SND_SOC_DAPM_DAC("Left DAC", "Left HiFi Playback", WM8753_PWR1, 3, 0),
456SND_SOC_DAPM_OUTPUT("LOUT1"),
457SND_SOC_DAPM_OUTPUT("LOUT2"),
458SND_SOC_DAPM_MIXER("Right Mixer", WM8753_PWR4, 1, 0,
459 &wm8753_right_mixer_controls[0], ARRAY_SIZE(wm8753_right_mixer_controls)),
460SND_SOC_DAPM_PGA("Right Out 1", WM8753_PWR3, 7, 0, NULL, 0),
461SND_SOC_DAPM_PGA("Right Out 2", WM8753_PWR3, 5, 0, NULL, 0),
462SND_SOC_DAPM_DAC("Right DAC", "Right HiFi Playback", WM8753_PWR1, 2, 0),
463SND_SOC_DAPM_OUTPUT("ROUT1"),
464SND_SOC_DAPM_OUTPUT("ROUT2"),
465SND_SOC_DAPM_MIXER("Mono Mixer", WM8753_PWR4, 2, 0,
466 &wm8753_mono_mixer_controls[0], ARRAY_SIZE(wm8753_mono_mixer_controls)),
467SND_SOC_DAPM_PGA("Mono Out 1", WM8753_PWR3, 2, 0, NULL, 0),
468SND_SOC_DAPM_PGA("Mono Out 2", WM8753_PWR3, 1, 0, NULL, 0),
469SND_SOC_DAPM_DAC("Voice DAC", "Voice Playback", WM8753_PWR1, 4, 0),
470SND_SOC_DAPM_OUTPUT("MONO1"),
471SND_SOC_DAPM_MUX("Mono 2 Mux", SND_SOC_NOPM, 0, 0, &wm8753_mono2_controls),
472SND_SOC_DAPM_OUTPUT("MONO2"),
473SND_SOC_DAPM_MIXER("Out3 Left + Right", -1, 0, 0, NULL, 0),
474SND_SOC_DAPM_MUX("Out3 Mux", SND_SOC_NOPM, 0, 0, &wm8753_out3_controls),
475SND_SOC_DAPM_PGA("Out 3", WM8753_PWR3, 4, 0, NULL, 0),
476SND_SOC_DAPM_OUTPUT("OUT3"),
477SND_SOC_DAPM_MUX("Out4 Mux", SND_SOC_NOPM, 0, 0, &wm8753_out4_controls),
478SND_SOC_DAPM_PGA("Out 4", WM8753_PWR3, 3, 0, NULL, 0),
479SND_SOC_DAPM_OUTPUT("OUT4"),
480SND_SOC_DAPM_MIXER("Playback Mixer", WM8753_PWR4, 3, 0,
481 &wm8753_record_mixer_controls[0],
482 ARRAY_SIZE(wm8753_record_mixer_controls)),
483SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8753_PWR2, 3, 0),
484SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8753_PWR2, 2, 0),
485SND_SOC_DAPM_MUX("Capture Left Mixer", SND_SOC_NOPM, 0, 0,
486 &wm8753_adc_mono_controls),
487SND_SOC_DAPM_MUX("Capture Right Mixer", SND_SOC_NOPM, 0, 0,
488 &wm8753_adc_mono_controls),
489SND_SOC_DAPM_MUX("Capture Left Mux", SND_SOC_NOPM, 0, 0,
490 &wm8753_adc_left_controls),
491SND_SOC_DAPM_MUX("Capture Right Mux", SND_SOC_NOPM, 0, 0,
492 &wm8753_adc_right_controls),
493SND_SOC_DAPM_MUX("Mic Sidetone Mux", SND_SOC_NOPM, 0, 0,
494 &wm8753_mic_mux_controls),
495SND_SOC_DAPM_PGA("Left Capture Volume", WM8753_PWR2, 5, 0, NULL, 0),
496SND_SOC_DAPM_PGA("Right Capture Volume", WM8753_PWR2, 4, 0, NULL, 0),
497SND_SOC_DAPM_MIXER("ALC Mixer", WM8753_PWR2, 6, 0,
498 &wm8753_alc_mixer_controls[0], ARRAY_SIZE(wm8753_alc_mixer_controls)),
499SND_SOC_DAPM_MUX("Line Left Mux", SND_SOC_NOPM, 0, 0,
500 &wm8753_line_left_controls),
501SND_SOC_DAPM_MUX("Line Right Mux", SND_SOC_NOPM, 0, 0,
502 &wm8753_line_right_controls),
503SND_SOC_DAPM_MUX("Line Mono Mux", SND_SOC_NOPM, 0, 0,
504 &wm8753_line_mono_controls),
505SND_SOC_DAPM_MUX("Line Mixer", WM8753_PWR2, 0, 0,
506 &wm8753_line_mux_mix_controls),
507SND_SOC_DAPM_MUX("Rx Mixer", WM8753_PWR2, 1, 0,
508 &wm8753_rx_mux_mix_controls),
509SND_SOC_DAPM_PGA("Mic 1 Volume", WM8753_PWR2, 8, 0, NULL, 0),
510SND_SOC_DAPM_PGA("Mic 2 Volume", WM8753_PWR2, 7, 0, NULL, 0),
511SND_SOC_DAPM_MUX("Mic Selection Mux", SND_SOC_NOPM, 0, 0,
512 &wm8753_mic_sel_mux_controls),
513SND_SOC_DAPM_INPUT("LINE1"),
514SND_SOC_DAPM_INPUT("LINE2"),
515SND_SOC_DAPM_INPUT("RXP"),
516SND_SOC_DAPM_INPUT("RXN"),
517SND_SOC_DAPM_INPUT("ACIN"),
518SND_SOC_DAPM_OUTPUT("ACOP"),
519SND_SOC_DAPM_INPUT("MIC1N"),
520SND_SOC_DAPM_INPUT("MIC1"),
521SND_SOC_DAPM_INPUT("MIC2N"),
522SND_SOC_DAPM_INPUT("MIC2"),
523SND_SOC_DAPM_VMID("VREF"),
524};
525
Mark Browna65f0562008-05-13 14:54:43 +0200526static const struct snd_soc_dapm_route audio_map[] = {
Liam Girdwood1f53aee2007-04-16 19:17:44 +0200527 /* left mixer */
528 {"Left Mixer", "Left Playback Switch", "Left DAC"},
529 {"Left Mixer", "Voice Playback Switch", "Voice DAC"},
530 {"Left Mixer", "Sidetone Playback Switch", "Mic Sidetone Mux"},
531 {"Left Mixer", "Bypass Playback Switch", "Line Left Mux"},
532
533 /* right mixer */
534 {"Right Mixer", "Right Playback Switch", "Right DAC"},
535 {"Right Mixer", "Voice Playback Switch", "Voice DAC"},
536 {"Right Mixer", "Sidetone Playback Switch", "Mic Sidetone Mux"},
537 {"Right Mixer", "Bypass Playback Switch", "Line Right Mux"},
538
539 /* mono mixer */
540 {"Mono Mixer", "Voice Playback Switch", "Voice DAC"},
541 {"Mono Mixer", "Left Playback Switch", "Left DAC"},
542 {"Mono Mixer", "Right Playback Switch", "Right DAC"},
543 {"Mono Mixer", "Sidetone Playback Switch", "Mic Sidetone Mux"},
544 {"Mono Mixer", "Bypass Playback Switch", "Line Mono Mux"},
545
546 /* left out */
547 {"Left Out 1", NULL, "Left Mixer"},
548 {"Left Out 2", NULL, "Left Mixer"},
549 {"LOUT1", NULL, "Left Out 1"},
550 {"LOUT2", NULL, "Left Out 2"},
551
552 /* right out */
553 {"Right Out 1", NULL, "Right Mixer"},
554 {"Right Out 2", NULL, "Right Mixer"},
555 {"ROUT1", NULL, "Right Out 1"},
556 {"ROUT2", NULL, "Right Out 2"},
557
558 /* mono 1 out */
559 {"Mono Out 1", NULL, "Mono Mixer"},
560 {"MONO1", NULL, "Mono Out 1"},
561
562 /* mono 2 out */
563 {"Mono 2 Mux", "Left + Right", "Out3 Left + Right"},
564 {"Mono 2 Mux", "Inverted Mono 1", "MONO1"},
565 {"Mono 2 Mux", "Left", "Left Mixer"},
566 {"Mono 2 Mux", "Right", "Right Mixer"},
567 {"Mono Out 2", NULL, "Mono 2 Mux"},
568 {"MONO2", NULL, "Mono Out 2"},
569
570 /* out 3 */
571 {"Out3 Left + Right", NULL, "Left Mixer"},
572 {"Out3 Left + Right", NULL, "Right Mixer"},
573 {"Out3 Mux", "VREF", "VREF"},
574 {"Out3 Mux", "Left + Right", "Out3 Left + Right"},
575 {"Out3 Mux", "ROUT2", "ROUT2"},
576 {"Out 3", NULL, "Out3 Mux"},
577 {"OUT3", NULL, "Out 3"},
578
579 /* out 4 */
580 {"Out4 Mux", "VREF", "VREF"},
581 {"Out4 Mux", "Capture ST", "Capture ST Mixer"},
582 {"Out4 Mux", "LOUT2", "LOUT2"},
583 {"Out 4", NULL, "Out4 Mux"},
584 {"OUT4", NULL, "Out 4"},
585
586 /* record mixer */
587 {"Playback Mixer", "Left Capture Switch", "Left Mixer"},
588 {"Playback Mixer", "Voice Capture Switch", "Mono Mixer"},
589 {"Playback Mixer", "Right Capture Switch", "Right Mixer"},
590
591 /* Mic/SideTone Mux */
592 {"Mic Sidetone Mux", "Left PGA", "Left Capture Volume"},
593 {"Mic Sidetone Mux", "Right PGA", "Right Capture Volume"},
594 {"Mic Sidetone Mux", "Mic 1", "Mic 1 Volume"},
595 {"Mic Sidetone Mux", "Mic 2", "Mic 2 Volume"},
596
597 /* Capture Left Mux */
598 {"Capture Left Mux", "PGA", "Left Capture Volume"},
599 {"Capture Left Mux", "Line or RXP-RXN", "Line Left Mux"},
600 {"Capture Left Mux", "Line", "LINE1"},
601
602 /* Capture Right Mux */
603 {"Capture Right Mux", "PGA", "Right Capture Volume"},
604 {"Capture Right Mux", "Line or RXP-RXN", "Line Right Mux"},
605 {"Capture Right Mux", "Sidetone", "Capture ST Mixer"},
606
607 /* Mono Capture mixer-mux */
608 {"Capture Right Mixer", "Stereo", "Capture Right Mux"},
609 {"Capture Left Mixer", "Analogue Mix Left", "Capture Left Mux"},
610 {"Capture Left Mixer", "Analogue Mix Left", "Capture Right Mux"},
611 {"Capture Right Mixer", "Analogue Mix Right", "Capture Left Mux"},
612 {"Capture Right Mixer", "Analogue Mix Right", "Capture Right Mux"},
613 {"Capture Left Mixer", "Digital Mono Mix", "Capture Left Mux"},
614 {"Capture Left Mixer", "Digital Mono Mix", "Capture Right Mux"},
615 {"Capture Right Mixer", "Digital Mono Mix", "Capture Left Mux"},
616 {"Capture Right Mixer", "Digital Mono Mix", "Capture Right Mux"},
617
618 /* ADC */
619 {"Left ADC", NULL, "Capture Left Mixer"},
620 {"Right ADC", NULL, "Capture Right Mixer"},
621
622 /* Left Capture Volume */
623 {"Left Capture Volume", NULL, "ACIN"},
624
625 /* Right Capture Volume */
626 {"Right Capture Volume", NULL, "Mic 2 Volume"},
627
628 /* ALC Mixer */
629 {"ALC Mixer", "Line Capture Switch", "Line Mixer"},
630 {"ALC Mixer", "Mic2 Capture Switch", "Mic 2 Volume"},
631 {"ALC Mixer", "Mic1 Capture Switch", "Mic 1 Volume"},
632 {"ALC Mixer", "Rx Capture Switch", "Rx Mixer"},
633
634 /* Line Left Mux */
635 {"Line Left Mux", "Line 1", "LINE1"},
636 {"Line Left Mux", "Rx Mix", "Rx Mixer"},
637
638 /* Line Right Mux */
639 {"Line Right Mux", "Line 2", "LINE2"},
640 {"Line Right Mux", "Rx Mix", "Rx Mixer"},
641
642 /* Line Mono Mux */
643 {"Line Mono Mux", "Line Mix", "Line Mixer"},
644 {"Line Mono Mux", "Rx Mix", "Rx Mixer"},
645
646 /* Line Mixer/Mux */
647 {"Line Mixer", "Line 1 + 2", "LINE1"},
648 {"Line Mixer", "Line 1 - 2", "LINE1"},
649 {"Line Mixer", "Line 1 + 2", "LINE2"},
650 {"Line Mixer", "Line 1 - 2", "LINE2"},
651 {"Line Mixer", "Line 1", "LINE1"},
652 {"Line Mixer", "Line 2", "LINE2"},
653
654 /* Rx Mixer/Mux */
655 {"Rx Mixer", "RXP - RXN", "RXP"},
656 {"Rx Mixer", "RXP + RXN", "RXP"},
657 {"Rx Mixer", "RXP - RXN", "RXN"},
658 {"Rx Mixer", "RXP + RXN", "RXN"},
659 {"Rx Mixer", "RXP", "RXP"},
660 {"Rx Mixer", "RXN", "RXN"},
661
662 /* Mic 1 Volume */
663 {"Mic 1 Volume", NULL, "MIC1N"},
664 {"Mic 1 Volume", NULL, "Mic Selection Mux"},
665
666 /* Mic 2 Volume */
667 {"Mic 2 Volume", NULL, "MIC2N"},
668 {"Mic 2 Volume", NULL, "MIC2"},
669
670 /* Mic Selector Mux */
671 {"Mic Selection Mux", "Mic 1", "MIC1"},
672 {"Mic Selection Mux", "Mic 2", "MIC2N"},
673 {"Mic Selection Mux", "Mic 3", "MIC2"},
674
675 /* ACOP */
676 {"ACOP", NULL, "ALC Mixer"},
Liam Girdwood1f53aee2007-04-16 19:17:44 +0200677};
678
679static int wm8753_add_widgets(struct snd_soc_codec *codec)
680{
Mark Browna65f0562008-05-13 14:54:43 +0200681 snd_soc_dapm_new_controls(codec, wm8753_dapm_widgets,
682 ARRAY_SIZE(wm8753_dapm_widgets));
Liam Girdwood1f53aee2007-04-16 19:17:44 +0200683
Mark Browna65f0562008-05-13 14:54:43 +0200684 snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
Liam Girdwood1f53aee2007-04-16 19:17:44 +0200685
686 snd_soc_dapm_new_widgets(codec);
687 return 0;
688}
689
690/* PLL divisors */
691struct _pll_div {
692 u32 div2:1;
693 u32 n:4;
694 u32 k:24;
695};
696
697/* The size in bits of the pll divide multiplied by 10
698 * to allow rounding later */
699#define FIXED_PLL_SIZE ((1 << 22) * 10)
700
701static void pll_factors(struct _pll_div *pll_div, unsigned int target,
702 unsigned int source)
703{
704 u64 Kpart;
705 unsigned int K, Ndiv, Nmod;
706
707 Ndiv = target / source;
708 if (Ndiv < 6) {
709 source >>= 1;
710 pll_div->div2 = 1;
711 Ndiv = target / source;
712 } else
713 pll_div->div2 = 0;
714
715 if ((Ndiv < 6) || (Ndiv > 12))
716 printk(KERN_WARNING
Mark Brown60fc6842008-04-30 17:18:43 +0200717 "wm8753: unsupported N = %d\n", Ndiv);
Liam Girdwood1f53aee2007-04-16 19:17:44 +0200718
719 pll_div->n = Ndiv;
720 Nmod = target % source;
721 Kpart = FIXED_PLL_SIZE * (long long)Nmod;
722
723 do_div(Kpart, source);
724
725 K = Kpart & 0xFFFFFFFF;
726
727 /* Check if we need to round */
728 if ((K % 10) >= 5)
729 K += 5;
730
731 /* Move down to proper range now rounding is done */
732 K /= 10;
733
734 pll_div->k = K;
735}
736
737static int wm8753_set_dai_pll(struct snd_soc_codec_dai *codec_dai,
738 int pll_id, unsigned int freq_in, unsigned int freq_out)
739{
740 u16 reg, enable;
741 int offset;
742 struct snd_soc_codec *codec = codec_dai->codec;
743
744 if (pll_id < WM8753_PLL1 || pll_id > WM8753_PLL2)
745 return -ENODEV;
746
747 if (pll_id == WM8753_PLL1) {
748 offset = 0;
749 enable = 0x10;
750 reg = wm8753_read_reg_cache(codec, WM8753_CLOCK) & 0xffef;
751 } else {
752 offset = 4;
753 enable = 0x8;
754 reg = wm8753_read_reg_cache(codec, WM8753_CLOCK) & 0xfff7;
755 }
756
757 if (!freq_in || !freq_out) {
758 /* disable PLL */
759 wm8753_write(codec, WM8753_PLL1CTL1 + offset, 0x0026);
760 wm8753_write(codec, WM8753_CLOCK, reg);
761 return 0;
762 } else {
763 u16 value = 0;
764 struct _pll_div pll_div;
765
766 pll_factors(&pll_div, freq_out * 8, freq_in);
767
768 /* set up N and K PLL divisor ratios */
769 /* bits 8:5 = PLL_N, bits 3:0 = PLL_K[21:18] */
770 value = (pll_div.n << 5) + ((pll_div.k & 0x3c0000) >> 18);
771 wm8753_write(codec, WM8753_PLL1CTL2 + offset, value);
772
773 /* bits 8:0 = PLL_K[17:9] */
774 value = (pll_div.k & 0x03fe00) >> 9;
775 wm8753_write(codec, WM8753_PLL1CTL3 + offset, value);
776
777 /* bits 8:0 = PLL_K[8:0] */
778 value = pll_div.k & 0x0001ff;
779 wm8753_write(codec, WM8753_PLL1CTL4 + offset, value);
780
781 /* set PLL as input and enable */
782 wm8753_write(codec, WM8753_PLL1CTL1 + offset, 0x0027 |
783 (pll_div.div2 << 3));
784 wm8753_write(codec, WM8753_CLOCK, reg | enable);
785 }
786 return 0;
787}
788
789struct _coeff_div {
790 u32 mclk;
791 u32 rate;
792 u8 sr:5;
793 u8 usb:1;
794};
795
796/* codec hifi mclk (after PLL) clock divider coefficients */
797static const struct _coeff_div coeff_div[] = {
798 /* 8k */
799 {12288000, 8000, 0x6, 0x0},
800 {11289600, 8000, 0x16, 0x0},
801 {18432000, 8000, 0x7, 0x0},
802 {16934400, 8000, 0x17, 0x0},
803 {12000000, 8000, 0x6, 0x1},
804
805 /* 11.025k */
806 {11289600, 11025, 0x18, 0x0},
807 {16934400, 11025, 0x19, 0x0},
808 {12000000, 11025, 0x19, 0x1},
809
810 /* 16k */
811 {12288000, 16000, 0xa, 0x0},
812 {18432000, 16000, 0xb, 0x0},
813 {12000000, 16000, 0xa, 0x1},
814
815 /* 22.05k */
816 {11289600, 22050, 0x1a, 0x0},
817 {16934400, 22050, 0x1b, 0x0},
818 {12000000, 22050, 0x1b, 0x1},
819
820 /* 32k */
821 {12288000, 32000, 0xc, 0x0},
822 {18432000, 32000, 0xd, 0x0},
823 {12000000, 32000, 0xa, 0x1},
824
825 /* 44.1k */
826 {11289600, 44100, 0x10, 0x0},
827 {16934400, 44100, 0x11, 0x0},
828 {12000000, 44100, 0x11, 0x1},
829
830 /* 48k */
831 {12288000, 48000, 0x0, 0x0},
832 {18432000, 48000, 0x1, 0x0},
833 {12000000, 48000, 0x0, 0x1},
834
835 /* 88.2k */
836 {11289600, 88200, 0x1e, 0x0},
837 {16934400, 88200, 0x1f, 0x0},
838 {12000000, 88200, 0x1f, 0x1},
839
840 /* 96k */
841 {12288000, 96000, 0xe, 0x0},
842 {18432000, 96000, 0xf, 0x0},
843 {12000000, 96000, 0xe, 0x1},
844};
845
846static int get_coeff(int mclk, int rate)
847{
848 int i;
849
850 for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
851 if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
852 return i;
853 }
854 return -EINVAL;
855}
856
857/*
858 * Clock after PLL and dividers
859 */
860static int wm8753_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai,
861 int clk_id, unsigned int freq, int dir)
862{
863 struct snd_soc_codec *codec = codec_dai->codec;
864 struct wm8753_priv *wm8753 = codec->private_data;
865
866 switch (freq) {
867 case 11289600:
868 case 12000000:
869 case 12288000:
870 case 16934400:
871 case 18432000:
872 if (clk_id == WM8753_MCLK) {
873 wm8753->sysclk = freq;
874 return 0;
875 } else if (clk_id == WM8753_PCMCLK) {
876 wm8753->pcmclk = freq;
877 return 0;
878 }
879 break;
880 }
881 return -EINVAL;
882}
883
884/*
885 * Set's ADC and Voice DAC format.
886 */
887static int wm8753_vdac_adc_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,
888 unsigned int fmt)
889{
890 struct snd_soc_codec *codec = codec_dai->codec;
891 u16 voice = wm8753_read_reg_cache(codec, WM8753_PCM) & 0x01ec;
892
893 /* interface format */
894 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
895 case SND_SOC_DAIFMT_I2S:
896 voice |= 0x0002;
897 break;
898 case SND_SOC_DAIFMT_RIGHT_J:
899 break;
900 case SND_SOC_DAIFMT_LEFT_J:
901 voice |= 0x0001;
902 break;
903 case SND_SOC_DAIFMT_DSP_A:
904 voice |= 0x0003;
905 break;
906 case SND_SOC_DAIFMT_DSP_B:
907 voice |= 0x0013;
908 break;
909 default:
910 return -EINVAL;
911 }
912
913 wm8753_write(codec, WM8753_PCM, voice);
914 return 0;
915}
916
917/*
918 * Set PCM DAI bit size and sample rate.
919 */
920static int wm8753_pcm_hw_params(struct snd_pcm_substream *substream,
921 struct snd_pcm_hw_params *params)
922{
923 struct snd_soc_pcm_runtime *rtd = substream->private_data;
924 struct snd_soc_device *socdev = rtd->socdev;
925 struct snd_soc_codec *codec = socdev->codec;
926 struct wm8753_priv *wm8753 = codec->private_data;
927 u16 voice = wm8753_read_reg_cache(codec, WM8753_PCM) & 0x01f3;
928 u16 srate = wm8753_read_reg_cache(codec, WM8753_SRATE1) & 0x017f;
929
930 /* bit size */
931 switch (params_format(params)) {
932 case SNDRV_PCM_FORMAT_S16_LE:
933 break;
934 case SNDRV_PCM_FORMAT_S20_3LE:
935 voice |= 0x0004;
936 break;
937 case SNDRV_PCM_FORMAT_S24_LE:
938 voice |= 0x0008;
939 break;
940 case SNDRV_PCM_FORMAT_S32_LE:
941 voice |= 0x000c;
942 break;
943 }
944
945 /* sample rate */
946 if (params_rate(params) * 384 == wm8753->pcmclk)
947 srate |= 0x80;
948 wm8753_write(codec, WM8753_SRATE1, srate);
949
950 wm8753_write(codec, WM8753_PCM, voice);
951 return 0;
952}
953
954/*
955 * Set's PCM dai fmt and BCLK.
956 */
957static int wm8753_pcm_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,
958 unsigned int fmt)
959{
960 struct snd_soc_codec *codec = codec_dai->codec;
961 u16 voice, ioctl;
962
963 voice = wm8753_read_reg_cache(codec, WM8753_PCM) & 0x011f;
964 ioctl = wm8753_read_reg_cache(codec, WM8753_IOCTL) & 0x015d;
965
966 /* set master/slave audio interface */
967 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
968 case SND_SOC_DAIFMT_CBS_CFS:
969 break;
970 case SND_SOC_DAIFMT_CBM_CFM:
971 ioctl |= 0x2;
972 case SND_SOC_DAIFMT_CBM_CFS:
973 voice |= 0x0040;
974 break;
975 default:
976 return -EINVAL;
977 }
978
979 /* clock inversion */
980 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
981 case SND_SOC_DAIFMT_DSP_A:
982 case SND_SOC_DAIFMT_DSP_B:
983 /* frame inversion not valid for DSP modes */
984 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
985 case SND_SOC_DAIFMT_NB_NF:
986 break;
987 case SND_SOC_DAIFMT_IB_NF:
988 voice |= 0x0080;
989 break;
990 default:
991 return -EINVAL;
992 }
993 break;
994 case SND_SOC_DAIFMT_I2S:
995 case SND_SOC_DAIFMT_RIGHT_J:
996 case SND_SOC_DAIFMT_LEFT_J:
997 voice &= ~0x0010;
998 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
999 case SND_SOC_DAIFMT_NB_NF:
1000 break;
1001 case SND_SOC_DAIFMT_IB_IF:
1002 voice |= 0x0090;
1003 break;
1004 case SND_SOC_DAIFMT_IB_NF:
1005 voice |= 0x0080;
1006 break;
1007 case SND_SOC_DAIFMT_NB_IF:
1008 voice |= 0x0010;
1009 break;
1010 default:
1011 return -EINVAL;
1012 }
1013 break;
1014 default:
1015 return -EINVAL;
1016 }
1017
1018 wm8753_write(codec, WM8753_PCM, voice);
1019 wm8753_write(codec, WM8753_IOCTL, ioctl);
1020 return 0;
1021}
1022
1023static int wm8753_set_dai_clkdiv(struct snd_soc_codec_dai *codec_dai,
1024 int div_id, int div)
1025{
1026 struct snd_soc_codec *codec = codec_dai->codec;
1027 u16 reg;
1028
1029 switch (div_id) {
1030 case WM8753_PCMDIV:
1031 reg = wm8753_read_reg_cache(codec, WM8753_CLOCK) & 0x003f;
1032 wm8753_write(codec, WM8753_CLOCK, reg | div);
1033 break;
1034 case WM8753_BCLKDIV:
1035 reg = wm8753_read_reg_cache(codec, WM8753_SRATE2) & 0x01c7;
1036 wm8753_write(codec, WM8753_SRATE2, reg | div);
1037 break;
1038 case WM8753_VXCLKDIV:
1039 reg = wm8753_read_reg_cache(codec, WM8753_SRATE2) & 0x003f;
1040 wm8753_write(codec, WM8753_SRATE2, reg | div);
1041 break;
1042 default:
1043 return -EINVAL;
1044 }
1045 return 0;
1046}
1047
1048/*
1049 * Set's HiFi DAC format.
1050 */
1051static int wm8753_hdac_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,
1052 unsigned int fmt)
1053{
1054 struct snd_soc_codec *codec = codec_dai->codec;
1055 u16 hifi = wm8753_read_reg_cache(codec, WM8753_HIFI) & 0x01e0;
1056
1057 /* interface format */
1058 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
1059 case SND_SOC_DAIFMT_I2S:
1060 hifi |= 0x0002;
1061 break;
1062 case SND_SOC_DAIFMT_RIGHT_J:
1063 break;
1064 case SND_SOC_DAIFMT_LEFT_J:
1065 hifi |= 0x0001;
1066 break;
1067 case SND_SOC_DAIFMT_DSP_A:
1068 hifi |= 0x0003;
1069 break;
1070 case SND_SOC_DAIFMT_DSP_B:
1071 hifi |= 0x0013;
1072 break;
1073 default:
1074 return -EINVAL;
1075 }
1076
1077 wm8753_write(codec, WM8753_HIFI, hifi);
1078 return 0;
1079}
1080
1081/*
1082 * Set's I2S DAI format.
1083 */
1084static int wm8753_i2s_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,
1085 unsigned int fmt)
1086{
1087 struct snd_soc_codec *codec = codec_dai->codec;
1088 u16 ioctl, hifi;
1089
1090 hifi = wm8753_read_reg_cache(codec, WM8753_HIFI) & 0x011f;
1091 ioctl = wm8753_read_reg_cache(codec, WM8753_IOCTL) & 0x00ae;
1092
1093 /* set master/slave audio interface */
1094 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
1095 case SND_SOC_DAIFMT_CBS_CFS:
1096 break;
1097 case SND_SOC_DAIFMT_CBM_CFM:
1098 ioctl |= 0x1;
1099 case SND_SOC_DAIFMT_CBM_CFS:
1100 hifi |= 0x0040;
1101 break;
1102 default:
1103 return -EINVAL;
1104 }
1105
1106 /* clock inversion */
1107 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
1108 case SND_SOC_DAIFMT_DSP_A:
1109 case SND_SOC_DAIFMT_DSP_B:
1110 /* frame inversion not valid for DSP modes */
1111 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
1112 case SND_SOC_DAIFMT_NB_NF:
1113 break;
1114 case SND_SOC_DAIFMT_IB_NF:
1115 hifi |= 0x0080;
1116 break;
1117 default:
1118 return -EINVAL;
1119 }
1120 break;
1121 case SND_SOC_DAIFMT_I2S:
1122 case SND_SOC_DAIFMT_RIGHT_J:
1123 case SND_SOC_DAIFMT_LEFT_J:
1124 hifi &= ~0x0010;
1125 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
1126 case SND_SOC_DAIFMT_NB_NF:
1127 break;
1128 case SND_SOC_DAIFMT_IB_IF:
1129 hifi |= 0x0090;
1130 break;
1131 case SND_SOC_DAIFMT_IB_NF:
1132 hifi |= 0x0080;
1133 break;
1134 case SND_SOC_DAIFMT_NB_IF:
1135 hifi |= 0x0010;
1136 break;
1137 default:
1138 return -EINVAL;
1139 }
1140 break;
1141 default:
1142 return -EINVAL;
1143 }
1144
1145 wm8753_write(codec, WM8753_HIFI, hifi);
1146 wm8753_write(codec, WM8753_IOCTL, ioctl);
1147 return 0;
1148}
1149
1150/*
1151 * Set PCM DAI bit size and sample rate.
1152 */
1153static int wm8753_i2s_hw_params(struct snd_pcm_substream *substream,
1154 struct snd_pcm_hw_params *params)
1155{
1156 struct snd_soc_pcm_runtime *rtd = substream->private_data;
1157 struct snd_soc_device *socdev = rtd->socdev;
1158 struct snd_soc_codec *codec = socdev->codec;
1159 struct wm8753_priv *wm8753 = codec->private_data;
1160 u16 srate = wm8753_read_reg_cache(codec, WM8753_SRATE1) & 0x01c0;
1161 u16 hifi = wm8753_read_reg_cache(codec, WM8753_HIFI) & 0x01f3;
1162 int coeff;
1163
1164 /* is digital filter coefficient valid ? */
1165 coeff = get_coeff(wm8753->sysclk, params_rate(params));
1166 if (coeff < 0) {
1167 printk(KERN_ERR "wm8753 invalid MCLK or rate\n");
1168 return coeff;
1169 }
1170 wm8753_write(codec, WM8753_SRATE1, srate | (coeff_div[coeff].sr << 1) |
1171 coeff_div[coeff].usb);
1172
1173 /* bit size */
1174 switch (params_format(params)) {
1175 case SNDRV_PCM_FORMAT_S16_LE:
1176 break;
1177 case SNDRV_PCM_FORMAT_S20_3LE:
1178 hifi |= 0x0004;
1179 break;
1180 case SNDRV_PCM_FORMAT_S24_LE:
1181 hifi |= 0x0008;
1182 break;
1183 case SNDRV_PCM_FORMAT_S32_LE:
1184 hifi |= 0x000c;
1185 break;
1186 }
1187
1188 wm8753_write(codec, WM8753_HIFI, hifi);
1189 return 0;
1190}
1191
1192static int wm8753_mode1v_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,
1193 unsigned int fmt)
1194{
1195 struct snd_soc_codec *codec = codec_dai->codec;
1196 u16 clock;
1197
1198 /* set clk source as pcmclk */
1199 clock = wm8753_read_reg_cache(codec, WM8753_CLOCK) & 0xfffb;
1200 wm8753_write(codec, WM8753_CLOCK, clock);
1201
1202 if (wm8753_vdac_adc_set_dai_fmt(codec_dai, fmt) < 0)
1203 return -EINVAL;
1204 return wm8753_pcm_set_dai_fmt(codec_dai, fmt);
1205}
1206
1207static int wm8753_mode1h_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,
1208 unsigned int fmt)
1209{
1210 if (wm8753_hdac_set_dai_fmt(codec_dai, fmt) < 0)
1211 return -EINVAL;
1212 return wm8753_i2s_set_dai_fmt(codec_dai, fmt);
1213}
1214
1215static int wm8753_mode2_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,
1216 unsigned int fmt)
1217{
1218 struct snd_soc_codec *codec = codec_dai->codec;
1219 u16 clock;
1220
1221 /* set clk source as pcmclk */
1222 clock = wm8753_read_reg_cache(codec, WM8753_CLOCK) & 0xfffb;
1223 wm8753_write(codec, WM8753_CLOCK, clock);
1224
1225 if (wm8753_vdac_adc_set_dai_fmt(codec_dai, fmt) < 0)
1226 return -EINVAL;
1227 return wm8753_i2s_set_dai_fmt(codec_dai, fmt);
1228}
1229
1230static int wm8753_mode3_4_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,
1231 unsigned int fmt)
1232{
1233 struct snd_soc_codec *codec = codec_dai->codec;
1234 u16 clock;
1235
1236 /* set clk source as mclk */
1237 clock = wm8753_read_reg_cache(codec, WM8753_CLOCK) & 0xfffb;
1238 wm8753_write(codec, WM8753_CLOCK, clock | 0x4);
1239
1240 if (wm8753_hdac_set_dai_fmt(codec_dai, fmt) < 0)
1241 return -EINVAL;
1242 if (wm8753_vdac_adc_set_dai_fmt(codec_dai, fmt) < 0)
1243 return -EINVAL;
1244 return wm8753_i2s_set_dai_fmt(codec_dai, fmt);
1245}
1246
1247static int wm8753_mute(struct snd_soc_codec_dai *dai, int mute)
1248{
1249 struct snd_soc_codec *codec = dai->codec;
1250 u16 mute_reg = wm8753_read_reg_cache(codec, WM8753_DAC) & 0xfff7;
1251
1252 /* the digital mute covers the HiFi and Voice DAC's on the WM8753.
1253 * make sure we check if they are not both active when we mute */
1254 if (mute && dai->id == 1) {
1255 if (!wm8753_dai[WM8753_DAI_VOICE].playback.active ||
1256 !wm8753_dai[WM8753_DAI_HIFI].playback.active)
1257 wm8753_write(codec, WM8753_DAC, mute_reg | 0x8);
1258 } else {
1259 if (mute)
1260 wm8753_write(codec, WM8753_DAC, mute_reg | 0x8);
1261 else
1262 wm8753_write(codec, WM8753_DAC, mute_reg);
1263 }
1264
1265 return 0;
1266}
1267
Mark Brown0be98982008-05-19 12:31:28 +02001268static int wm8753_set_bias_level(struct snd_soc_codec *codec,
1269 enum snd_soc_bias_level level)
Liam Girdwood1f53aee2007-04-16 19:17:44 +02001270{
1271 u16 pwr_reg = wm8753_read_reg_cache(codec, WM8753_PWR1) & 0xfe3e;
1272
Mark Brown0be98982008-05-19 12:31:28 +02001273 switch (level) {
1274 case SND_SOC_BIAS_ON:
Liam Girdwood1f53aee2007-04-16 19:17:44 +02001275 /* set vmid to 50k and unmute dac */
1276 wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x00c0);
1277 break;
Mark Brown0be98982008-05-19 12:31:28 +02001278 case SND_SOC_BIAS_PREPARE:
Liam Girdwood1f53aee2007-04-16 19:17:44 +02001279 /* set vmid to 5k for quick power up */
1280 wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x01c1);
1281 break;
Mark Brown0be98982008-05-19 12:31:28 +02001282 case SND_SOC_BIAS_STANDBY:
Liam Girdwood1f53aee2007-04-16 19:17:44 +02001283 /* mute dac and set vmid to 500k, enable VREF */
1284 wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x0141);
1285 break;
Mark Brown0be98982008-05-19 12:31:28 +02001286 case SND_SOC_BIAS_OFF:
Liam Girdwood1f53aee2007-04-16 19:17:44 +02001287 wm8753_write(codec, WM8753_PWR1, 0x0001);
1288 break;
1289 }
Mark Brown0be98982008-05-19 12:31:28 +02001290 codec->bias_level = level;
Liam Girdwood1f53aee2007-04-16 19:17:44 +02001291 return 0;
1292}
1293
1294#define WM8753_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
Mark Brown60fc6842008-04-30 17:18:43 +02001295 SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
1296 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
1297 SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
Liam Girdwood1f53aee2007-04-16 19:17:44 +02001298
1299#define WM8753_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
1300 SNDRV_PCM_FMTBIT_S24_LE)
1301
1302/*
1303 * The WM8753 supports upto 4 different and mutually exclusive DAI
1304 * configurations. This gives 2 PCM's available for use, hifi and voice.
1305 * NOTE: The Voice PCM cannot play or capture audio to the CPU as it's DAI
1306 * is connected between the wm8753 and a BT codec or GSM modem.
1307 *
1308 * 1. Voice over PCM DAI - HIFI DAC over HIFI DAI
1309 * 2. Voice over HIFI DAI - HIFI disabled
1310 * 3. Voice disabled - HIFI over HIFI
1311 * 4. Voice disabled - HIFI over HIFI, uses voice DAI LRC for capture
1312 */
1313static const struct snd_soc_codec_dai wm8753_all_dai[] = {
1314/* DAI HiFi mode 1 */
1315{ .name = "WM8753 HiFi",
1316 .id = 1,
1317 .playback = {
1318 .stream_name = "HiFi Playback",
1319 .channels_min = 1,
1320 .channels_max = 2,
1321 .rates = WM8753_RATES,
1322 .formats = WM8753_FORMATS,},
1323 .capture = { /* dummy for fast DAI switching */
1324 .stream_name = "Capture",
1325 .channels_min = 1,
1326 .channels_max = 2,
1327 .rates = WM8753_RATES,
1328 .formats = WM8753_FORMATS,},
1329 .ops = {
1330 .hw_params = wm8753_i2s_hw_params,},
1331 .dai_ops = {
1332 .digital_mute = wm8753_mute,
1333 .set_fmt = wm8753_mode1h_set_dai_fmt,
1334 .set_clkdiv = wm8753_set_dai_clkdiv,
1335 .set_pll = wm8753_set_dai_pll,
1336 .set_sysclk = wm8753_set_dai_sysclk,
1337 },
1338},
1339/* DAI Voice mode 1 */
1340{ .name = "WM8753 Voice",
1341 .id = 1,
1342 .playback = {
1343 .stream_name = "Voice Playback",
1344 .channels_min = 1,
1345 .channels_max = 1,
1346 .rates = WM8753_RATES,
1347 .formats = WM8753_FORMATS,},
1348 .capture = {
1349 .stream_name = "Capture",
1350 .channels_min = 1,
1351 .channels_max = 2,
1352 .rates = WM8753_RATES,
1353 .formats = WM8753_FORMATS,},
1354 .ops = {
1355 .hw_params = wm8753_pcm_hw_params,},
1356 .dai_ops = {
1357 .digital_mute = wm8753_mute,
1358 .set_fmt = wm8753_mode1v_set_dai_fmt,
1359 .set_clkdiv = wm8753_set_dai_clkdiv,
1360 .set_pll = wm8753_set_dai_pll,
1361 .set_sysclk = wm8753_set_dai_sysclk,
1362 },
1363},
1364/* DAI HiFi mode 2 - dummy */
1365{ .name = "WM8753 HiFi",
1366 .id = 2,
1367},
1368/* DAI Voice mode 2 */
1369{ .name = "WM8753 Voice",
1370 .id = 2,
1371 .playback = {
1372 .stream_name = "Voice Playback",
1373 .channels_min = 1,
1374 .channels_max = 1,
1375 .rates = WM8753_RATES,
1376 .formats = WM8753_FORMATS,},
1377 .capture = {
1378 .stream_name = "Capture",
1379 .channels_min = 1,
1380 .channels_max = 2,
1381 .rates = WM8753_RATES,
1382 .formats = WM8753_FORMATS,},
1383 .ops = {
1384 .hw_params = wm8753_pcm_hw_params,},
1385 .dai_ops = {
1386 .digital_mute = wm8753_mute,
1387 .set_fmt = wm8753_mode2_set_dai_fmt,
1388 .set_clkdiv = wm8753_set_dai_clkdiv,
1389 .set_pll = wm8753_set_dai_pll,
1390 .set_sysclk = wm8753_set_dai_sysclk,
1391 },
1392},
1393/* DAI HiFi mode 3 */
1394{ .name = "WM8753 HiFi",
1395 .id = 3,
1396 .playback = {
1397 .stream_name = "HiFi Playback",
1398 .channels_min = 1,
1399 .channels_max = 2,
1400 .rates = WM8753_RATES,
1401 .formats = WM8753_FORMATS,},
1402 .capture = {
1403 .stream_name = "Capture",
1404 .channels_min = 1,
1405 .channels_max = 2,
1406 .rates = WM8753_RATES,
1407 .formats = WM8753_FORMATS,},
1408 .ops = {
1409 .hw_params = wm8753_i2s_hw_params,},
1410 .dai_ops = {
1411 .digital_mute = wm8753_mute,
1412 .set_fmt = wm8753_mode3_4_set_dai_fmt,
1413 .set_clkdiv = wm8753_set_dai_clkdiv,
1414 .set_pll = wm8753_set_dai_pll,
1415 .set_sysclk = wm8753_set_dai_sysclk,
1416 },
1417},
1418/* DAI Voice mode 3 - dummy */
1419{ .name = "WM8753 Voice",
1420 .id = 3,
1421},
1422/* DAI HiFi mode 4 */
1423{ .name = "WM8753 HiFi",
1424 .id = 4,
1425 .playback = {
1426 .stream_name = "HiFi Playback",
1427 .channels_min = 1,
1428 .channels_max = 2,
1429 .rates = WM8753_RATES,
1430 .formats = WM8753_FORMATS,},
1431 .capture = {
1432 .stream_name = "Capture",
1433 .channels_min = 1,
1434 .channels_max = 2,
1435 .rates = WM8753_RATES,
1436 .formats = WM8753_FORMATS,},
1437 .ops = {
1438 .hw_params = wm8753_i2s_hw_params,},
1439 .dai_ops = {
1440 .digital_mute = wm8753_mute,
1441 .set_fmt = wm8753_mode3_4_set_dai_fmt,
1442 .set_clkdiv = wm8753_set_dai_clkdiv,
1443 .set_pll = wm8753_set_dai_pll,
1444 .set_sysclk = wm8753_set_dai_sysclk,
1445 },
1446},
1447/* DAI Voice mode 4 - dummy */
1448{ .name = "WM8753 Voice",
1449 .id = 4,
1450},
1451};
1452
1453struct snd_soc_codec_dai wm8753_dai[2];
1454EXPORT_SYMBOL_GPL(wm8753_dai);
1455
1456static void wm8753_set_dai_mode(struct snd_soc_codec *codec, unsigned int mode)
1457{
1458 if (mode < 4) {
1459 int playback_active, capture_active, codec_active, pop_wait;
1460 void *private_data;
1461
1462 playback_active = wm8753_dai[0].playback.active;
1463 capture_active = wm8753_dai[0].capture.active;
1464 codec_active = wm8753_dai[0].active;
1465 private_data = wm8753_dai[0].private_data;
1466 pop_wait = wm8753_dai[0].pop_wait;
1467 wm8753_dai[0] = wm8753_all_dai[mode << 1];
1468 wm8753_dai[0].playback.active = playback_active;
1469 wm8753_dai[0].capture.active = capture_active;
1470 wm8753_dai[0].active = codec_active;
1471 wm8753_dai[0].private_data = private_data;
1472 wm8753_dai[0].pop_wait = pop_wait;
1473
1474 playback_active = wm8753_dai[1].playback.active;
1475 capture_active = wm8753_dai[1].capture.active;
1476 codec_active = wm8753_dai[1].active;
1477 private_data = wm8753_dai[1].private_data;
1478 pop_wait = wm8753_dai[1].pop_wait;
1479 wm8753_dai[1] = wm8753_all_dai[(mode << 1) + 1];
1480 wm8753_dai[1].playback.active = playback_active;
1481 wm8753_dai[1].capture.active = capture_active;
1482 wm8753_dai[1].active = codec_active;
1483 wm8753_dai[1].private_data = private_data;
1484 wm8753_dai[1].pop_wait = pop_wait;
1485 }
1486 wm8753_dai[0].codec = codec;
1487 wm8753_dai[1].codec = codec;
1488}
1489
1490static void wm8753_work(struct work_struct *work)
1491{
1492 struct snd_soc_codec *codec =
1493 container_of(work, struct snd_soc_codec, delayed_work.work);
Mark Brown0be98982008-05-19 12:31:28 +02001494 wm8753_set_bias_level(codec, codec->bias_level);
Liam Girdwood1f53aee2007-04-16 19:17:44 +02001495}
1496
1497static int wm8753_suspend(struct platform_device *pdev, pm_message_t state)
1498{
1499 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
1500 struct snd_soc_codec *codec = socdev->codec;
1501
1502 /* we only need to suspend if we are a valid card */
Mark Brown60fc6842008-04-30 17:18:43 +02001503 if (!codec->card)
Liam Girdwood1f53aee2007-04-16 19:17:44 +02001504 return 0;
Mark Brown60fc6842008-04-30 17:18:43 +02001505
Mark Brown0be98982008-05-19 12:31:28 +02001506 wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF);
Liam Girdwood1f53aee2007-04-16 19:17:44 +02001507 return 0;
1508}
1509
1510static int wm8753_resume(struct platform_device *pdev)
1511{
1512 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
1513 struct snd_soc_codec *codec = socdev->codec;
1514 int i;
1515 u8 data[2];
1516 u16 *cache = codec->reg_cache;
1517
1518 /* we only need to resume if we are a valid card */
Mark Brown60fc6842008-04-30 17:18:43 +02001519 if (!codec->card)
Liam Girdwood1f53aee2007-04-16 19:17:44 +02001520 return 0;
1521
1522 /* Sync reg_cache with the hardware */
1523 for (i = 0; i < ARRAY_SIZE(wm8753_reg); i++) {
1524 if (i + 1 == WM8753_RESET)
1525 continue;
1526 data[0] = ((i + 1) << 1) | ((cache[i] >> 8) & 0x0001);
1527 data[1] = cache[i] & 0x00ff;
1528 codec->hw_write(codec->control_data, data, 2);
1529 }
1530
Mark Brown0be98982008-05-19 12:31:28 +02001531 wm8753_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
Liam Girdwood1f53aee2007-04-16 19:17:44 +02001532
1533 /* charge wm8753 caps */
Mark Brown0be98982008-05-19 12:31:28 +02001534 if (codec->suspend_bias_level == SND_SOC_BIAS_ON) {
1535 wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
1536 codec->bias_level = SND_SOC_BIAS_ON;
Liam Girdwood1f53aee2007-04-16 19:17:44 +02001537 schedule_delayed_work(&codec->delayed_work,
1538 msecs_to_jiffies(caps_charge));
1539 }
1540
1541 return 0;
1542}
1543
1544/*
1545 * initialise the WM8753 driver
1546 * register the mixer and dsp interfaces with the kernel
1547 */
1548static int wm8753_init(struct snd_soc_device *socdev)
1549{
1550 struct snd_soc_codec *codec = socdev->codec;
1551 int reg, ret = 0;
1552
1553 codec->name = "WM8753";
1554 codec->owner = THIS_MODULE;
1555 codec->read = wm8753_read_reg_cache;
1556 codec->write = wm8753_write;
Mark Brown0be98982008-05-19 12:31:28 +02001557 codec->set_bias_level = wm8753_set_bias_level;
Liam Girdwood1f53aee2007-04-16 19:17:44 +02001558 codec->dai = wm8753_dai;
1559 codec->num_dai = 2;
1560 codec->reg_cache_size = sizeof(wm8753_reg);
1561 codec->reg_cache = kmemdup(wm8753_reg, sizeof(wm8753_reg), GFP_KERNEL);
1562
1563 if (codec->reg_cache == NULL)
1564 return -ENOMEM;
1565
1566 wm8753_set_dai_mode(codec, 0);
1567
1568 wm8753_reset(codec);
1569
1570 /* register pcms */
1571 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
1572 if (ret < 0) {
1573 printk(KERN_ERR "wm8753: failed to create pcms\n");
1574 goto pcm_err;
1575 }
1576
1577 /* charge output caps */
Mark Brown0be98982008-05-19 12:31:28 +02001578 wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
1579 codec->bias_level = SND_SOC_BIAS_STANDBY;
Liam Girdwood1f53aee2007-04-16 19:17:44 +02001580 schedule_delayed_work(&codec->delayed_work,
1581 msecs_to_jiffies(caps_charge));
1582
1583 /* set the update bits */
1584 reg = wm8753_read_reg_cache(codec, WM8753_LDAC);
1585 wm8753_write(codec, WM8753_LDAC, reg | 0x0100);
1586 reg = wm8753_read_reg_cache(codec, WM8753_RDAC);
1587 wm8753_write(codec, WM8753_RDAC, reg | 0x0100);
1588 reg = wm8753_read_reg_cache(codec, WM8753_LADC);
1589 wm8753_write(codec, WM8753_LADC, reg | 0x0100);
1590 reg = wm8753_read_reg_cache(codec, WM8753_RADC);
1591 wm8753_write(codec, WM8753_RADC, reg | 0x0100);
1592 reg = wm8753_read_reg_cache(codec, WM8753_LOUT1V);
1593 wm8753_write(codec, WM8753_LOUT1V, reg | 0x0100);
1594 reg = wm8753_read_reg_cache(codec, WM8753_ROUT1V);
1595 wm8753_write(codec, WM8753_ROUT1V, reg | 0x0100);
1596 reg = wm8753_read_reg_cache(codec, WM8753_LOUT2V);
1597 wm8753_write(codec, WM8753_LOUT2V, reg | 0x0100);
1598 reg = wm8753_read_reg_cache(codec, WM8753_ROUT2V);
1599 wm8753_write(codec, WM8753_ROUT2V, reg | 0x0100);
1600 reg = wm8753_read_reg_cache(codec, WM8753_LINVOL);
1601 wm8753_write(codec, WM8753_LINVOL, reg | 0x0100);
1602 reg = wm8753_read_reg_cache(codec, WM8753_RINVOL);
1603 wm8753_write(codec, WM8753_RINVOL, reg | 0x0100);
1604
1605 wm8753_add_controls(codec);
1606 wm8753_add_widgets(codec);
1607 ret = snd_soc_register_card(socdev);
1608 if (ret < 0) {
Mark Brown60fc6842008-04-30 17:18:43 +02001609 printk(KERN_ERR "wm8753: failed to register card\n");
Liam Girdwood1f53aee2007-04-16 19:17:44 +02001610 goto card_err;
Mark Brown60fc6842008-04-30 17:18:43 +02001611 }
1612
Liam Girdwood1f53aee2007-04-16 19:17:44 +02001613 return ret;
1614
1615card_err:
1616 snd_soc_free_pcms(socdev);
1617 snd_soc_dapm_free(socdev);
1618pcm_err:
1619 kfree(codec->reg_cache);
1620 return ret;
1621}
1622
1623/* If the i2c layer weren't so broken, we could pass this kind of data
1624 around */
1625static struct snd_soc_device *wm8753_socdev;
1626
Mark Brown60fc6842008-04-30 17:18:43 +02001627#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
Liam Girdwood1f53aee2007-04-16 19:17:44 +02001628
1629/*
1630 * WM8753 2 wire address is determined by GPIO5
1631 * state during powerup.
1632 * low = 0x1a
1633 * high = 0x1b
1634 */
1635static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END };
1636
1637/* Magic definition of all other variables and things */
1638I2C_CLIENT_INSMOD;
1639
1640static struct i2c_driver wm8753_i2c_driver;
1641static struct i2c_client client_template;
1642
1643static int wm8753_codec_probe(struct i2c_adapter *adap, int addr, int kind)
1644{
1645 struct snd_soc_device *socdev = wm8753_socdev;
1646 struct wm8753_setup_data *setup = socdev->codec_data;
1647 struct snd_soc_codec *codec = socdev->codec;
1648 struct i2c_client *i2c;
1649 int ret;
1650
1651 if (addr != setup->i2c_address)
1652 return -ENODEV;
1653
1654 client_template.adapter = adap;
1655 client_template.addr = addr;
1656
1657 i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
Mark Brown60fc6842008-04-30 17:18:43 +02001658 if (!i2c) {
Liam Girdwood1f53aee2007-04-16 19:17:44 +02001659 kfree(codec);
1660 return -ENOMEM;
1661 }
1662 i2c_set_clientdata(i2c, codec);
1663 codec->control_data = i2c;
1664
1665 ret = i2c_attach_client(i2c);
1666 if (ret < 0) {
1667 err("failed to attach codec at addr %x\n", addr);
1668 goto err;
1669 }
1670
1671 ret = wm8753_init(socdev);
1672 if (ret < 0) {
1673 err("failed to initialise WM8753\n");
1674 goto err;
1675 }
1676
1677 return ret;
1678
1679err:
1680 kfree(codec);
1681 kfree(i2c);
1682 return ret;
1683}
1684
1685static int wm8753_i2c_detach(struct i2c_client *client)
1686{
1687 struct snd_soc_codec *codec = i2c_get_clientdata(client);
1688 i2c_detach_client(client);
1689 kfree(codec->reg_cache);
1690 kfree(client);
1691 return 0;
1692}
1693
1694static int wm8753_i2c_attach(struct i2c_adapter *adap)
1695{
1696 return i2c_probe(adap, &addr_data, wm8753_codec_probe);
1697}
1698
1699/* corgi i2c codec control layer */
1700static struct i2c_driver wm8753_i2c_driver = {
1701 .driver = {
1702 .name = "WM8753 I2C Codec",
1703 .owner = THIS_MODULE,
1704 },
1705 .id = I2C_DRIVERID_WM8753,
1706 .attach_adapter = wm8753_i2c_attach,
1707 .detach_client = wm8753_i2c_detach,
1708 .command = NULL,
1709};
1710
1711static struct i2c_client client_template = {
1712 .name = "WM8753",
1713 .driver = &wm8753_i2c_driver,
1714};
1715#endif
1716
1717static int wm8753_probe(struct platform_device *pdev)
1718{
1719 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
1720 struct wm8753_setup_data *setup;
1721 struct snd_soc_codec *codec;
1722 struct wm8753_priv *wm8753;
1723 int ret = 0;
1724
1725 info("WM8753 Audio Codec %s", WM8753_VERSION);
1726
1727 setup = socdev->codec_data;
1728 codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
1729 if (codec == NULL)
1730 return -ENOMEM;
1731
1732 wm8753 = kzalloc(sizeof(struct wm8753_priv), GFP_KERNEL);
1733 if (wm8753 == NULL) {
1734 kfree(codec);
1735 return -ENOMEM;
1736 }
1737
1738 codec->private_data = wm8753;
1739 socdev->codec = codec;
1740 mutex_init(&codec->mutex);
1741 INIT_LIST_HEAD(&codec->dapm_widgets);
1742 INIT_LIST_HEAD(&codec->dapm_paths);
1743 wm8753_socdev = socdev;
1744 INIT_DELAYED_WORK(&codec->delayed_work, wm8753_work);
1745
Mark Brown60fc6842008-04-30 17:18:43 +02001746#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
Liam Girdwood1f53aee2007-04-16 19:17:44 +02001747 if (setup->i2c_address) {
1748 normal_i2c[0] = setup->i2c_address;
1749 codec->hw_write = (hw_write_t)i2c_master_send;
1750 ret = i2c_add_driver(&wm8753_i2c_driver);
1751 if (ret != 0)
1752 printk(KERN_ERR "can't add i2c driver");
1753 }
1754#else
1755 /* Add other interfaces here */
1756#endif
1757 return ret;
1758}
1759
1760/*
1761 * This function forces any delayed work to be queued and run.
1762 */
1763static int run_delayed_work(struct delayed_work *dwork)
1764{
1765 int ret;
1766
1767 /* cancel any work waiting to be queued. */
1768 ret = cancel_delayed_work(dwork);
1769
1770 /* if there was any work waiting then we run it now and
1771 * wait for it's completion */
1772 if (ret) {
1773 schedule_delayed_work(dwork, 0);
1774 flush_scheduled_work();
1775 }
1776 return ret;
1777}
1778
1779/* power down chip */
1780static int wm8753_remove(struct platform_device *pdev)
1781{
1782 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
1783 struct snd_soc_codec *codec = socdev->codec;
1784
1785 if (codec->control_data)
Mark Brown0be98982008-05-19 12:31:28 +02001786 wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF);
Liam Girdwood1f53aee2007-04-16 19:17:44 +02001787 run_delayed_work(&codec->delayed_work);
1788 snd_soc_free_pcms(socdev);
1789 snd_soc_dapm_free(socdev);
Mark Brown60fc6842008-04-30 17:18:43 +02001790#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
Liam Girdwood1f53aee2007-04-16 19:17:44 +02001791 i2c_del_driver(&wm8753_i2c_driver);
1792#endif
1793 kfree(codec->private_data);
1794 kfree(codec);
1795
1796 return 0;
1797}
1798
1799struct snd_soc_codec_device soc_codec_dev_wm8753 = {
1800 .probe = wm8753_probe,
1801 .remove = wm8753_remove,
1802 .suspend = wm8753_suspend,
1803 .resume = wm8753_resume,
1804};
Liam Girdwood1f53aee2007-04-16 19:17:44 +02001805EXPORT_SYMBOL_GPL(soc_codec_dev_wm8753);
1806
1807MODULE_DESCRIPTION("ASoC WM8753 driver");
1808MODULE_AUTHOR("Liam Girdwood");
1809MODULE_LICENSE("GPL");