1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2abadfc92SRichard Purdie /*
3abadfc92SRichard Purdie * wm8750.c -- WM8750 ALSA SoC audio driver
4abadfc92SRichard Purdie *
5abadfc92SRichard Purdie * Copyright 2005 Openedhand Ltd.
6abadfc92SRichard Purdie *
7abadfc92SRichard Purdie * Author: Richard Purdie <richard@openedhand.com>
8abadfc92SRichard Purdie *
9abadfc92SRichard Purdie * Based on WM8753.c
10abadfc92SRichard Purdie */
11abadfc92SRichard Purdie
12abadfc92SRichard Purdie #include <linux/module.h>
13abadfc92SRichard Purdie #include <linux/moduleparam.h>
14abadfc92SRichard Purdie #include <linux/init.h>
15abadfc92SRichard Purdie #include <linux/delay.h>
16abadfc92SRichard Purdie #include <linux/pm.h>
17abadfc92SRichard Purdie #include <linux/i2c.h>
18ed79edacSMark Brown #include <linux/regmap.h>
192f3dfaf5SMark Brown #include <linux/spi/spi.h>
205a0e3ad6STejun Heo #include <linux/slab.h>
21ce31a0f5SMark Brown #include <linux/of_device.h>
22abadfc92SRichard Purdie #include <sound/core.h>
23abadfc92SRichard Purdie #include <sound/pcm.h>
24abadfc92SRichard Purdie #include <sound/pcm_params.h>
25abadfc92SRichard Purdie #include <sound/soc.h>
26abadfc92SRichard Purdie #include <sound/initval.h>
27abadfc92SRichard Purdie
28abadfc92SRichard Purdie #include "wm8750.h"
29abadfc92SRichard Purdie
30abadfc92SRichard Purdie /*
31abadfc92SRichard Purdie * wm8750 register cache
32abadfc92SRichard Purdie * We can't read the WM8750 register space when we
33abadfc92SRichard Purdie * are using 2 wire for device control, so we cache them instead.
34abadfc92SRichard Purdie */
35ed79edacSMark Brown static const struct reg_default wm8750_reg_defaults[] = {
36ed79edacSMark Brown { 0, 0x0097 },
37ed79edacSMark Brown { 1, 0x0097 },
38ed79edacSMark Brown { 2, 0x0079 },
39ed79edacSMark Brown { 3, 0x0079 },
40ed79edacSMark Brown { 4, 0x0000 },
41ed79edacSMark Brown { 5, 0x0008 },
42ed79edacSMark Brown { 6, 0x0000 },
43ed79edacSMark Brown { 7, 0x000a },
44ed79edacSMark Brown { 8, 0x0000 },
45ed79edacSMark Brown { 9, 0x0000 },
46ed79edacSMark Brown { 10, 0x00ff },
47ed79edacSMark Brown { 11, 0x00ff },
48ed79edacSMark Brown { 12, 0x000f },
49ed79edacSMark Brown { 13, 0x000f },
50ed79edacSMark Brown { 14, 0x0000 },
51ed79edacSMark Brown { 15, 0x0000 },
52ed79edacSMark Brown { 16, 0x0000 },
53ed79edacSMark Brown { 17, 0x007b },
54ed79edacSMark Brown { 18, 0x0000 },
55ed79edacSMark Brown { 19, 0x0032 },
56ed79edacSMark Brown { 20, 0x0000 },
57ed79edacSMark Brown { 21, 0x00c3 },
58ed79edacSMark Brown { 22, 0x00c3 },
59ed79edacSMark Brown { 23, 0x00c0 },
60ed79edacSMark Brown { 24, 0x0000 },
61ed79edacSMark Brown { 25, 0x0000 },
62ed79edacSMark Brown { 26, 0x0000 },
63ed79edacSMark Brown { 27, 0x0000 },
64ed79edacSMark Brown { 28, 0x0000 },
65ed79edacSMark Brown { 29, 0x0000 },
66ed79edacSMark Brown { 30, 0x0000 },
67ed79edacSMark Brown { 31, 0x0000 },
68ed79edacSMark Brown { 32, 0x0000 },
69ed79edacSMark Brown { 33, 0x0000 },
70ed79edacSMark Brown { 34, 0x0050 },
71ed79edacSMark Brown { 35, 0x0050 },
72ed79edacSMark Brown { 36, 0x0050 },
73ed79edacSMark Brown { 37, 0x0050 },
74ed79edacSMark Brown { 38, 0x0050 },
75ed79edacSMark Brown { 39, 0x0050 },
76ed79edacSMark Brown { 40, 0x0079 },
77ed79edacSMark Brown { 41, 0x0079 },
78ed79edacSMark Brown { 42, 0x0079 },
79abadfc92SRichard Purdie };
80abadfc92SRichard Purdie
816ca0c22eSMarek Vasut /* codec private data */
826ca0c22eSMarek Vasut struct wm8750_priv {
836ca0c22eSMarek Vasut unsigned int sysclk;
846ca0c22eSMarek Vasut };
856ca0c22eSMarek Vasut
86f081a227SKuninori Morimoto #define wm8750_reset(c) snd_soc_component_write(c, WM8750_RESET, 0)
87abadfc92SRichard Purdie
88abadfc92SRichard Purdie /*
89abadfc92SRichard Purdie * WM8750 Controls
90abadfc92SRichard Purdie */
91abadfc92SRichard Purdie static const char *wm8750_bass[] = {"Linear Control", "Adaptive Boost"};
92abadfc92SRichard Purdie static const char *wm8750_bass_filter[] = { "130Hz @ 48kHz", "200Hz @ 48kHz" };
93abadfc92SRichard Purdie static const char *wm8750_treble[] = {"8kHz", "4kHz"};
94abadfc92SRichard Purdie static const char *wm8750_3d_lc[] = {"200Hz", "500Hz"};
95abadfc92SRichard Purdie static const char *wm8750_3d_uc[] = {"2.2kHz", "1.5kHz"};
96abadfc92SRichard Purdie static const char *wm8750_3d_func[] = {"Capture", "Playback"};
97abadfc92SRichard Purdie static const char *wm8750_alc_func[] = {"Off", "Right", "Left", "Stereo"};
98abadfc92SRichard Purdie static const char *wm8750_ng_type[] = {"Constant PGA Gain",
99abadfc92SRichard Purdie "Mute ADC Output"};
100abadfc92SRichard Purdie static const char *wm8750_line_mux[] = {"Line 1", "Line 2", "Line 3", "PGA",
101abadfc92SRichard Purdie "Differential"};
102abadfc92SRichard Purdie static const char *wm8750_pga_sel[] = {"Line 1", "Line 2", "Line 3",
103abadfc92SRichard Purdie "Differential"};
104abadfc92SRichard Purdie static const char *wm8750_out3[] = {"VREF", "ROUT1 + Vol", "MonoOut",
105abadfc92SRichard Purdie "ROUT1"};
106abadfc92SRichard Purdie static const char *wm8750_diff_sel[] = {"Line 1", "Line 2"};
107abadfc92SRichard Purdie static const char *wm8750_adcpol[] = {"Normal", "L Invert", "R Invert",
108abadfc92SRichard Purdie "L + R Invert"};
109abadfc92SRichard Purdie static const char *wm8750_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"};
110abadfc92SRichard Purdie static const char *wm8750_mono_mux[] = {"Stereo", "Mono (Left)",
111abadfc92SRichard Purdie "Mono (Right)", "Digital Mono"};
112abadfc92SRichard Purdie
113abadfc92SRichard Purdie static const struct soc_enum wm8750_enum[] = {
114abadfc92SRichard Purdie SOC_ENUM_SINGLE(WM8750_BASS, 7, 2, wm8750_bass),
115abadfc92SRichard Purdie SOC_ENUM_SINGLE(WM8750_BASS, 6, 2, wm8750_bass_filter),
116abadfc92SRichard Purdie SOC_ENUM_SINGLE(WM8750_TREBLE, 6, 2, wm8750_treble),
117abadfc92SRichard Purdie SOC_ENUM_SINGLE(WM8750_3D, 5, 2, wm8750_3d_lc),
118abadfc92SRichard Purdie SOC_ENUM_SINGLE(WM8750_3D, 6, 2, wm8750_3d_uc),
119abadfc92SRichard Purdie SOC_ENUM_SINGLE(WM8750_3D, 7, 2, wm8750_3d_func),
120abadfc92SRichard Purdie SOC_ENUM_SINGLE(WM8750_ALC1, 7, 4, wm8750_alc_func),
121abadfc92SRichard Purdie SOC_ENUM_SINGLE(WM8750_NGATE, 1, 2, wm8750_ng_type),
122abadfc92SRichard Purdie SOC_ENUM_SINGLE(WM8750_LOUTM1, 0, 5, wm8750_line_mux),
123abadfc92SRichard Purdie SOC_ENUM_SINGLE(WM8750_ROUTM1, 0, 5, wm8750_line_mux),
124abadfc92SRichard Purdie SOC_ENUM_SINGLE(WM8750_LADCIN, 6, 4, wm8750_pga_sel), /* 10 */
125abadfc92SRichard Purdie SOC_ENUM_SINGLE(WM8750_RADCIN, 6, 4, wm8750_pga_sel),
126abadfc92SRichard Purdie SOC_ENUM_SINGLE(WM8750_ADCTL2, 7, 4, wm8750_out3),
127abadfc92SRichard Purdie SOC_ENUM_SINGLE(WM8750_ADCIN, 8, 2, wm8750_diff_sel),
128abadfc92SRichard Purdie SOC_ENUM_SINGLE(WM8750_ADCDAC, 5, 4, wm8750_adcpol),
129abadfc92SRichard Purdie SOC_ENUM_SINGLE(WM8750_ADCDAC, 1, 4, wm8750_deemph),
130abadfc92SRichard Purdie SOC_ENUM_SINGLE(WM8750_ADCIN, 6, 4, wm8750_mono_mux), /* 16 */
131abadfc92SRichard Purdie
132abadfc92SRichard Purdie };
133abadfc92SRichard Purdie
134abadfc92SRichard Purdie static const struct snd_kcontrol_new wm8750_snd_controls[] = {
135abadfc92SRichard Purdie
136abadfc92SRichard Purdie SOC_DOUBLE_R("Capture Volume", WM8750_LINVOL, WM8750_RINVOL, 0, 63, 0),
137abadfc92SRichard Purdie SOC_DOUBLE_R("Capture ZC Switch", WM8750_LINVOL, WM8750_RINVOL, 6, 1, 0),
138abadfc92SRichard Purdie SOC_DOUBLE_R("Capture Switch", WM8750_LINVOL, WM8750_RINVOL, 7, 1, 1),
139abadfc92SRichard Purdie
140bd903b6eSLiam Girdwood SOC_DOUBLE_R("Headphone Playback ZC Switch", WM8750_LOUT1V,
141abadfc92SRichard Purdie WM8750_ROUT1V, 7, 1, 0),
142bd903b6eSLiam Girdwood SOC_DOUBLE_R("Speaker Playback ZC Switch", WM8750_LOUT2V,
143abadfc92SRichard Purdie WM8750_ROUT2V, 7, 1, 0),
144abadfc92SRichard Purdie
145abadfc92SRichard Purdie SOC_ENUM("Playback De-emphasis", wm8750_enum[15]),
146abadfc92SRichard Purdie
147abadfc92SRichard Purdie SOC_ENUM("Capture Polarity", wm8750_enum[14]),
148abadfc92SRichard Purdie SOC_SINGLE("Playback 6dB Attenuate", WM8750_ADCDAC, 7, 1, 0),
149abadfc92SRichard Purdie SOC_SINGLE("Capture 6dB Attenuate", WM8750_ADCDAC, 8, 1, 0),
150abadfc92SRichard Purdie
151abadfc92SRichard Purdie SOC_DOUBLE_R("PCM Volume", WM8750_LDAC, WM8750_RDAC, 0, 255, 0),
152abadfc92SRichard Purdie
153abadfc92SRichard Purdie SOC_ENUM("Bass Boost", wm8750_enum[0]),
154abadfc92SRichard Purdie SOC_ENUM("Bass Filter", wm8750_enum[1]),
155abadfc92SRichard Purdie SOC_SINGLE("Bass Volume", WM8750_BASS, 0, 15, 1),
156abadfc92SRichard Purdie
1576a7b8cf4SStanislav Brabec SOC_SINGLE("Treble Volume", WM8750_TREBLE, 0, 15, 1),
158abadfc92SRichard Purdie SOC_ENUM("Treble Cut-off", wm8750_enum[2]),
159abadfc92SRichard Purdie
160abadfc92SRichard Purdie SOC_SINGLE("3D Switch", WM8750_3D, 0, 1, 0),
161abadfc92SRichard Purdie SOC_SINGLE("3D Volume", WM8750_3D, 1, 15, 0),
162abadfc92SRichard Purdie SOC_ENUM("3D Lower Cut-off", wm8750_enum[3]),
163abadfc92SRichard Purdie SOC_ENUM("3D Upper Cut-off", wm8750_enum[4]),
164abadfc92SRichard Purdie SOC_ENUM("3D Mode", wm8750_enum[5]),
165abadfc92SRichard Purdie
166abadfc92SRichard Purdie SOC_SINGLE("ALC Capture Target Volume", WM8750_ALC1, 0, 7, 0),
167abadfc92SRichard Purdie SOC_SINGLE("ALC Capture Max Volume", WM8750_ALC1, 4, 7, 0),
168abadfc92SRichard Purdie SOC_ENUM("ALC Capture Function", wm8750_enum[6]),
169abadfc92SRichard Purdie SOC_SINGLE("ALC Capture ZC Switch", WM8750_ALC2, 7, 1, 0),
170abadfc92SRichard Purdie SOC_SINGLE("ALC Capture Hold Time", WM8750_ALC2, 0, 15, 0),
171abadfc92SRichard Purdie SOC_SINGLE("ALC Capture Decay Time", WM8750_ALC3, 4, 15, 0),
172abadfc92SRichard Purdie SOC_SINGLE("ALC Capture Attack Time", WM8750_ALC3, 0, 15, 0),
173abadfc92SRichard Purdie SOC_SINGLE("ALC Capture NG Threshold", WM8750_NGATE, 3, 31, 0),
174abadfc92SRichard Purdie SOC_ENUM("ALC Capture NG Type", wm8750_enum[4]),
175abadfc92SRichard Purdie SOC_SINGLE("ALC Capture NG Switch", WM8750_NGATE, 0, 1, 0),
176abadfc92SRichard Purdie
177abadfc92SRichard Purdie SOC_SINGLE("Left ADC Capture Volume", WM8750_LADC, 0, 255, 0),
178abadfc92SRichard Purdie SOC_SINGLE("Right ADC Capture Volume", WM8750_RADC, 0, 255, 0),
179abadfc92SRichard Purdie
180abadfc92SRichard Purdie SOC_SINGLE("ZC Timeout Switch", WM8750_ADCTL1, 0, 1, 0),
181abadfc92SRichard Purdie SOC_SINGLE("Playback Invert Switch", WM8750_ADCTL1, 1, 1, 0),
182abadfc92SRichard Purdie
183bd903b6eSLiam Girdwood SOC_SINGLE("Right Speaker Playback Invert Switch", WM8750_ADCTL2, 4, 1, 0),
184abadfc92SRichard Purdie
185abadfc92SRichard Purdie /* Unimplemented */
186abadfc92SRichard Purdie /* ADCDAC Bit 0 - ADCHPD */
187abadfc92SRichard Purdie /* ADCDAC Bit 4 - HPOR */
188abadfc92SRichard Purdie /* ADCTL1 Bit 2,3 - DATSEL */
189abadfc92SRichard Purdie /* ADCTL1 Bit 4,5 - DMONOMIX */
190abadfc92SRichard Purdie /* ADCTL1 Bit 6,7 - VSEL */
191abadfc92SRichard Purdie /* ADCTL2 Bit 2 - LRCM */
192abadfc92SRichard Purdie /* ADCTL2 Bit 3 - TRI */
193abadfc92SRichard Purdie /* ADCTL3 Bit 5 - HPFLREN */
194abadfc92SRichard Purdie /* ADCTL3 Bit 6 - VROI */
195abadfc92SRichard Purdie /* ADCTL3 Bit 7,8 - ADCLRM */
196abadfc92SRichard Purdie /* ADCIN Bit 4 - LDCM */
197abadfc92SRichard Purdie /* ADCIN Bit 5 - RDCM */
198abadfc92SRichard Purdie
199abadfc92SRichard Purdie SOC_DOUBLE_R("Mic Boost", WM8750_LADCIN, WM8750_RADCIN, 4, 3, 0),
200abadfc92SRichard Purdie
201abadfc92SRichard Purdie SOC_DOUBLE_R("Bypass Left Playback Volume", WM8750_LOUTM1,
202abadfc92SRichard Purdie WM8750_LOUTM2, 4, 7, 1),
203abadfc92SRichard Purdie SOC_DOUBLE_R("Bypass Right Playback Volume", WM8750_ROUTM1,
204abadfc92SRichard Purdie WM8750_ROUTM2, 4, 7, 1),
205abadfc92SRichard Purdie SOC_DOUBLE_R("Bypass Mono Playback Volume", WM8750_MOUTM1,
206abadfc92SRichard Purdie WM8750_MOUTM2, 4, 7, 1),
207abadfc92SRichard Purdie
208abadfc92SRichard Purdie SOC_SINGLE("Mono Playback ZC Switch", WM8750_MOUTV, 7, 1, 0),
209abadfc92SRichard Purdie
210bd903b6eSLiam Girdwood SOC_DOUBLE_R("Headphone Playback Volume", WM8750_LOUT1V, WM8750_ROUT1V,
211bd903b6eSLiam Girdwood 0, 127, 0),
212bd903b6eSLiam Girdwood SOC_DOUBLE_R("Speaker Playback Volume", WM8750_LOUT2V, WM8750_ROUT2V,
213bd903b6eSLiam Girdwood 0, 127, 0),
214abadfc92SRichard Purdie
215abadfc92SRichard Purdie SOC_SINGLE("Mono Playback Volume", WM8750_MOUTV, 0, 127, 0),
216abadfc92SRichard Purdie
217abadfc92SRichard Purdie };
218abadfc92SRichard Purdie
219abadfc92SRichard Purdie /*
220abadfc92SRichard Purdie * DAPM Controls
221abadfc92SRichard Purdie */
222abadfc92SRichard Purdie
223abadfc92SRichard Purdie /* Left Mixer */
224abadfc92SRichard Purdie static const struct snd_kcontrol_new wm8750_left_mixer_controls[] = {
225abadfc92SRichard Purdie SOC_DAPM_SINGLE("Playback Switch", WM8750_LOUTM1, 8, 1, 0),
226abadfc92SRichard Purdie SOC_DAPM_SINGLE("Left Bypass Switch", WM8750_LOUTM1, 7, 1, 0),
227abadfc92SRichard Purdie SOC_DAPM_SINGLE("Right Playback Switch", WM8750_LOUTM2, 8, 1, 0),
228abadfc92SRichard Purdie SOC_DAPM_SINGLE("Right Bypass Switch", WM8750_LOUTM2, 7, 1, 0),
229abadfc92SRichard Purdie };
230abadfc92SRichard Purdie
231abadfc92SRichard Purdie /* Right Mixer */
232abadfc92SRichard Purdie static const struct snd_kcontrol_new wm8750_right_mixer_controls[] = {
233abadfc92SRichard Purdie SOC_DAPM_SINGLE("Left Playback Switch", WM8750_ROUTM1, 8, 1, 0),
234abadfc92SRichard Purdie SOC_DAPM_SINGLE("Left Bypass Switch", WM8750_ROUTM1, 7, 1, 0),
235abadfc92SRichard Purdie SOC_DAPM_SINGLE("Playback Switch", WM8750_ROUTM2, 8, 1, 0),
236abadfc92SRichard Purdie SOC_DAPM_SINGLE("Right Bypass Switch", WM8750_ROUTM2, 7, 1, 0),
237abadfc92SRichard Purdie };
238abadfc92SRichard Purdie
239abadfc92SRichard Purdie /* Mono Mixer */
240abadfc92SRichard Purdie static const struct snd_kcontrol_new wm8750_mono_mixer_controls[] = {
241abadfc92SRichard Purdie SOC_DAPM_SINGLE("Left Playback Switch", WM8750_MOUTM1, 8, 1, 0),
242abadfc92SRichard Purdie SOC_DAPM_SINGLE("Left Bypass Switch", WM8750_MOUTM1, 7, 1, 0),
243abadfc92SRichard Purdie SOC_DAPM_SINGLE("Right Playback Switch", WM8750_MOUTM2, 8, 1, 0),
244abadfc92SRichard Purdie SOC_DAPM_SINGLE("Right Bypass Switch", WM8750_MOUTM2, 7, 1, 0),
245abadfc92SRichard Purdie };
246abadfc92SRichard Purdie
247abadfc92SRichard Purdie /* Left Line Mux */
248abadfc92SRichard Purdie static const struct snd_kcontrol_new wm8750_left_line_controls =
249abadfc92SRichard Purdie SOC_DAPM_ENUM("Route", wm8750_enum[8]);
250abadfc92SRichard Purdie
251abadfc92SRichard Purdie /* Right Line Mux */
252abadfc92SRichard Purdie static const struct snd_kcontrol_new wm8750_right_line_controls =
253abadfc92SRichard Purdie SOC_DAPM_ENUM("Route", wm8750_enum[9]);
254abadfc92SRichard Purdie
255abadfc92SRichard Purdie /* Left PGA Mux */
256abadfc92SRichard Purdie static const struct snd_kcontrol_new wm8750_left_pga_controls =
257abadfc92SRichard Purdie SOC_DAPM_ENUM("Route", wm8750_enum[10]);
258abadfc92SRichard Purdie
259abadfc92SRichard Purdie /* Right PGA Mux */
260abadfc92SRichard Purdie static const struct snd_kcontrol_new wm8750_right_pga_controls =
261abadfc92SRichard Purdie SOC_DAPM_ENUM("Route", wm8750_enum[11]);
262abadfc92SRichard Purdie
263abadfc92SRichard Purdie /* Out 3 Mux */
264abadfc92SRichard Purdie static const struct snd_kcontrol_new wm8750_out3_controls =
265abadfc92SRichard Purdie SOC_DAPM_ENUM("Route", wm8750_enum[12]);
266abadfc92SRichard Purdie
267abadfc92SRichard Purdie /* Differential Mux */
268abadfc92SRichard Purdie static const struct snd_kcontrol_new wm8750_diffmux_controls =
269abadfc92SRichard Purdie SOC_DAPM_ENUM("Route", wm8750_enum[13]);
270abadfc92SRichard Purdie
271abadfc92SRichard Purdie /* Mono ADC Mux */
272abadfc92SRichard Purdie static const struct snd_kcontrol_new wm8750_monomux_controls =
273abadfc92SRichard Purdie SOC_DAPM_ENUM("Route", wm8750_enum[16]);
274abadfc92SRichard Purdie
275abadfc92SRichard Purdie static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = {
276abadfc92SRichard Purdie SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0,
277abadfc92SRichard Purdie &wm8750_left_mixer_controls[0],
278abadfc92SRichard Purdie ARRAY_SIZE(wm8750_left_mixer_controls)),
279abadfc92SRichard Purdie SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0,
280abadfc92SRichard Purdie &wm8750_right_mixer_controls[0],
281abadfc92SRichard Purdie ARRAY_SIZE(wm8750_right_mixer_controls)),
282abadfc92SRichard Purdie SND_SOC_DAPM_MIXER("Mono Mixer", WM8750_PWR2, 2, 0,
283abadfc92SRichard Purdie &wm8750_mono_mixer_controls[0],
284abadfc92SRichard Purdie ARRAY_SIZE(wm8750_mono_mixer_controls)),
285abadfc92SRichard Purdie
286abadfc92SRichard Purdie SND_SOC_DAPM_PGA("Right Out 2", WM8750_PWR2, 3, 0, NULL, 0),
287abadfc92SRichard Purdie SND_SOC_DAPM_PGA("Left Out 2", WM8750_PWR2, 4, 0, NULL, 0),
288abadfc92SRichard Purdie SND_SOC_DAPM_PGA("Right Out 1", WM8750_PWR2, 5, 0, NULL, 0),
289abadfc92SRichard Purdie SND_SOC_DAPM_PGA("Left Out 1", WM8750_PWR2, 6, 0, NULL, 0),
290abadfc92SRichard Purdie SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8750_PWR2, 7, 0),
291abadfc92SRichard Purdie SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8750_PWR2, 8, 0),
292abadfc92SRichard Purdie
293abadfc92SRichard Purdie SND_SOC_DAPM_MICBIAS("Mic Bias", WM8750_PWR1, 1, 0),
294abadfc92SRichard Purdie SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8750_PWR1, 2, 0),
295abadfc92SRichard Purdie SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8750_PWR1, 3, 0),
296abadfc92SRichard Purdie
297abadfc92SRichard Purdie SND_SOC_DAPM_MUX("Left PGA Mux", WM8750_PWR1, 5, 0,
298abadfc92SRichard Purdie &wm8750_left_pga_controls),
299abadfc92SRichard Purdie SND_SOC_DAPM_MUX("Right PGA Mux", WM8750_PWR1, 4, 0,
300abadfc92SRichard Purdie &wm8750_right_pga_controls),
301abadfc92SRichard Purdie SND_SOC_DAPM_MUX("Left Line Mux", SND_SOC_NOPM, 0, 0,
302abadfc92SRichard Purdie &wm8750_left_line_controls),
303abadfc92SRichard Purdie SND_SOC_DAPM_MUX("Right Line Mux", SND_SOC_NOPM, 0, 0,
304abadfc92SRichard Purdie &wm8750_right_line_controls),
305abadfc92SRichard Purdie
306abadfc92SRichard Purdie SND_SOC_DAPM_MUX("Out3 Mux", SND_SOC_NOPM, 0, 0, &wm8750_out3_controls),
307abadfc92SRichard Purdie SND_SOC_DAPM_PGA("Out 3", WM8750_PWR2, 1, 0, NULL, 0),
308abadfc92SRichard Purdie SND_SOC_DAPM_PGA("Mono Out 1", WM8750_PWR2, 2, 0, NULL, 0),
309abadfc92SRichard Purdie
310abadfc92SRichard Purdie SND_SOC_DAPM_MUX("Differential Mux", SND_SOC_NOPM, 0, 0,
311abadfc92SRichard Purdie &wm8750_diffmux_controls),
312abadfc92SRichard Purdie SND_SOC_DAPM_MUX("Left ADC Mux", SND_SOC_NOPM, 0, 0,
313abadfc92SRichard Purdie &wm8750_monomux_controls),
314abadfc92SRichard Purdie SND_SOC_DAPM_MUX("Right ADC Mux", SND_SOC_NOPM, 0, 0,
315abadfc92SRichard Purdie &wm8750_monomux_controls),
316abadfc92SRichard Purdie
317abadfc92SRichard Purdie SND_SOC_DAPM_OUTPUT("LOUT1"),
318abadfc92SRichard Purdie SND_SOC_DAPM_OUTPUT("ROUT1"),
319abadfc92SRichard Purdie SND_SOC_DAPM_OUTPUT("LOUT2"),
320abadfc92SRichard Purdie SND_SOC_DAPM_OUTPUT("ROUT2"),
32123ba79bdSDmitry Baryshkov SND_SOC_DAPM_OUTPUT("MONO1"),
322abadfc92SRichard Purdie SND_SOC_DAPM_OUTPUT("OUT3"),
3235ede19c5SLars-Peter Clausen SND_SOC_DAPM_VMID("VREF"),
324abadfc92SRichard Purdie
325abadfc92SRichard Purdie SND_SOC_DAPM_INPUT("LINPUT1"),
326abadfc92SRichard Purdie SND_SOC_DAPM_INPUT("LINPUT2"),
327abadfc92SRichard Purdie SND_SOC_DAPM_INPUT("LINPUT3"),
328abadfc92SRichard Purdie SND_SOC_DAPM_INPUT("RINPUT1"),
329abadfc92SRichard Purdie SND_SOC_DAPM_INPUT("RINPUT2"),
330abadfc92SRichard Purdie SND_SOC_DAPM_INPUT("RINPUT3"),
331abadfc92SRichard Purdie };
332abadfc92SRichard Purdie
3330f185e3fSMark Brown static const struct snd_soc_dapm_route wm8750_dapm_routes[] = {
334abadfc92SRichard Purdie /* left mixer */
335abadfc92SRichard Purdie {"Left Mixer", "Playback Switch", "Left DAC"},
336abadfc92SRichard Purdie {"Left Mixer", "Left Bypass Switch", "Left Line Mux"},
337abadfc92SRichard Purdie {"Left Mixer", "Right Playback Switch", "Right DAC"},
338abadfc92SRichard Purdie {"Left Mixer", "Right Bypass Switch", "Right Line Mux"},
339abadfc92SRichard Purdie
340abadfc92SRichard Purdie /* right mixer */
341abadfc92SRichard Purdie {"Right Mixer", "Left Playback Switch", "Left DAC"},
342abadfc92SRichard Purdie {"Right Mixer", "Left Bypass Switch", "Left Line Mux"},
343abadfc92SRichard Purdie {"Right Mixer", "Playback Switch", "Right DAC"},
344abadfc92SRichard Purdie {"Right Mixer", "Right Bypass Switch", "Right Line Mux"},
345abadfc92SRichard Purdie
346abadfc92SRichard Purdie /* left out 1 */
347abadfc92SRichard Purdie {"Left Out 1", NULL, "Left Mixer"},
348abadfc92SRichard Purdie {"LOUT1", NULL, "Left Out 1"},
349abadfc92SRichard Purdie
350abadfc92SRichard Purdie /* left out 2 */
351abadfc92SRichard Purdie {"Left Out 2", NULL, "Left Mixer"},
352abadfc92SRichard Purdie {"LOUT2", NULL, "Left Out 2"},
353abadfc92SRichard Purdie
354abadfc92SRichard Purdie /* right out 1 */
355abadfc92SRichard Purdie {"Right Out 1", NULL, "Right Mixer"},
356abadfc92SRichard Purdie {"ROUT1", NULL, "Right Out 1"},
357abadfc92SRichard Purdie
358abadfc92SRichard Purdie /* right out 2 */
359abadfc92SRichard Purdie {"Right Out 2", NULL, "Right Mixer"},
360abadfc92SRichard Purdie {"ROUT2", NULL, "Right Out 2"},
361abadfc92SRichard Purdie
362abadfc92SRichard Purdie /* mono mixer */
363abadfc92SRichard Purdie {"Mono Mixer", "Left Playback Switch", "Left DAC"},
364abadfc92SRichard Purdie {"Mono Mixer", "Left Bypass Switch", "Left Line Mux"},
365abadfc92SRichard Purdie {"Mono Mixer", "Right Playback Switch", "Right DAC"},
366abadfc92SRichard Purdie {"Mono Mixer", "Right Bypass Switch", "Right Line Mux"},
367abadfc92SRichard Purdie
368abadfc92SRichard Purdie /* mono out */
369abadfc92SRichard Purdie {"Mono Out 1", NULL, "Mono Mixer"},
370abadfc92SRichard Purdie {"MONO1", NULL, "Mono Out 1"},
371abadfc92SRichard Purdie
372abadfc92SRichard Purdie /* out 3 */
373abadfc92SRichard Purdie {"Out3 Mux", "VREF", "VREF"},
374abadfc92SRichard Purdie {"Out3 Mux", "ROUT1 + Vol", "ROUT1"},
375abadfc92SRichard Purdie {"Out3 Mux", "ROUT1", "Right Mixer"},
376abadfc92SRichard Purdie {"Out3 Mux", "MonoOut", "MONO1"},
377abadfc92SRichard Purdie {"Out 3", NULL, "Out3 Mux"},
378abadfc92SRichard Purdie {"OUT3", NULL, "Out 3"},
379abadfc92SRichard Purdie
380abadfc92SRichard Purdie /* Left Line Mux */
381abadfc92SRichard Purdie {"Left Line Mux", "Line 1", "LINPUT1"},
382abadfc92SRichard Purdie {"Left Line Mux", "Line 2", "LINPUT2"},
383abadfc92SRichard Purdie {"Left Line Mux", "Line 3", "LINPUT3"},
384abadfc92SRichard Purdie {"Left Line Mux", "PGA", "Left PGA Mux"},
385abadfc92SRichard Purdie {"Left Line Mux", "Differential", "Differential Mux"},
386abadfc92SRichard Purdie
387abadfc92SRichard Purdie /* Right Line Mux */
388abadfc92SRichard Purdie {"Right Line Mux", "Line 1", "RINPUT1"},
389abadfc92SRichard Purdie {"Right Line Mux", "Line 2", "RINPUT2"},
390abadfc92SRichard Purdie {"Right Line Mux", "Line 3", "RINPUT3"},
391abadfc92SRichard Purdie {"Right Line Mux", "PGA", "Right PGA Mux"},
392abadfc92SRichard Purdie {"Right Line Mux", "Differential", "Differential Mux"},
393abadfc92SRichard Purdie
394abadfc92SRichard Purdie /* Left PGA Mux */
395abadfc92SRichard Purdie {"Left PGA Mux", "Line 1", "LINPUT1"},
396abadfc92SRichard Purdie {"Left PGA Mux", "Line 2", "LINPUT2"},
397abadfc92SRichard Purdie {"Left PGA Mux", "Line 3", "LINPUT3"},
398abadfc92SRichard Purdie {"Left PGA Mux", "Differential", "Differential Mux"},
399abadfc92SRichard Purdie
400abadfc92SRichard Purdie /* Right PGA Mux */
401abadfc92SRichard Purdie {"Right PGA Mux", "Line 1", "RINPUT1"},
402abadfc92SRichard Purdie {"Right PGA Mux", "Line 2", "RINPUT2"},
403abadfc92SRichard Purdie {"Right PGA Mux", "Line 3", "RINPUT3"},
404abadfc92SRichard Purdie {"Right PGA Mux", "Differential", "Differential Mux"},
405abadfc92SRichard Purdie
406abadfc92SRichard Purdie /* Differential Mux */
407abadfc92SRichard Purdie {"Differential Mux", "Line 1", "LINPUT1"},
408abadfc92SRichard Purdie {"Differential Mux", "Line 1", "RINPUT1"},
409abadfc92SRichard Purdie {"Differential Mux", "Line 2", "LINPUT2"},
410abadfc92SRichard Purdie {"Differential Mux", "Line 2", "RINPUT2"},
411abadfc92SRichard Purdie
412abadfc92SRichard Purdie /* Left ADC Mux */
413abadfc92SRichard Purdie {"Left ADC Mux", "Stereo", "Left PGA Mux"},
414abadfc92SRichard Purdie {"Left ADC Mux", "Mono (Left)", "Left PGA Mux"},
415abadfc92SRichard Purdie {"Left ADC Mux", "Digital Mono", "Left PGA Mux"},
416abadfc92SRichard Purdie
417abadfc92SRichard Purdie /* Right ADC Mux */
418abadfc92SRichard Purdie {"Right ADC Mux", "Stereo", "Right PGA Mux"},
419abadfc92SRichard Purdie {"Right ADC Mux", "Mono (Right)", "Right PGA Mux"},
420abadfc92SRichard Purdie {"Right ADC Mux", "Digital Mono", "Right PGA Mux"},
421abadfc92SRichard Purdie
422abadfc92SRichard Purdie /* ADC */
423abadfc92SRichard Purdie {"Left ADC", NULL, "Left ADC Mux"},
424abadfc92SRichard Purdie {"Right ADC", NULL, "Right ADC Mux"},
425abadfc92SRichard Purdie };
426abadfc92SRichard Purdie
427abadfc92SRichard Purdie struct _coeff_div {
428abadfc92SRichard Purdie u32 mclk;
429abadfc92SRichard Purdie u32 rate;
430abadfc92SRichard Purdie u16 fs;
431abadfc92SRichard Purdie u8 sr:5;
432abadfc92SRichard Purdie u8 usb:1;
433abadfc92SRichard Purdie };
434abadfc92SRichard Purdie
435abadfc92SRichard Purdie /* codec hifi mclk clock divider coefficients */
436abadfc92SRichard Purdie static const struct _coeff_div coeff_div[] = {
437abadfc92SRichard Purdie /* 8k */
438abadfc92SRichard Purdie {12288000, 8000, 1536, 0x6, 0x0},
439abadfc92SRichard Purdie {11289600, 8000, 1408, 0x16, 0x0},
440abadfc92SRichard Purdie {18432000, 8000, 2304, 0x7, 0x0},
441abadfc92SRichard Purdie {16934400, 8000, 2112, 0x17, 0x0},
442abadfc92SRichard Purdie {12000000, 8000, 1500, 0x6, 0x1},
443abadfc92SRichard Purdie
444abadfc92SRichard Purdie /* 11.025k */
445abadfc92SRichard Purdie {11289600, 11025, 1024, 0x18, 0x0},
446abadfc92SRichard Purdie {16934400, 11025, 1536, 0x19, 0x0},
447abadfc92SRichard Purdie {12000000, 11025, 1088, 0x19, 0x1},
448abadfc92SRichard Purdie
449abadfc92SRichard Purdie /* 16k */
450abadfc92SRichard Purdie {12288000, 16000, 768, 0xa, 0x0},
451abadfc92SRichard Purdie {18432000, 16000, 1152, 0xb, 0x0},
452abadfc92SRichard Purdie {12000000, 16000, 750, 0xa, 0x1},
453abadfc92SRichard Purdie
454abadfc92SRichard Purdie /* 22.05k */
455abadfc92SRichard Purdie {11289600, 22050, 512, 0x1a, 0x0},
456abadfc92SRichard Purdie {16934400, 22050, 768, 0x1b, 0x0},
457abadfc92SRichard Purdie {12000000, 22050, 544, 0x1b, 0x1},
458abadfc92SRichard Purdie
459abadfc92SRichard Purdie /* 32k */
460abadfc92SRichard Purdie {12288000, 32000, 384, 0xc, 0x0},
461abadfc92SRichard Purdie {18432000, 32000, 576, 0xd, 0x0},
462abadfc92SRichard Purdie {12000000, 32000, 375, 0xa, 0x1},
463abadfc92SRichard Purdie
464abadfc92SRichard Purdie /* 44.1k */
465abadfc92SRichard Purdie {11289600, 44100, 256, 0x10, 0x0},
466abadfc92SRichard Purdie {16934400, 44100, 384, 0x11, 0x0},
467abadfc92SRichard Purdie {12000000, 44100, 272, 0x11, 0x1},
468abadfc92SRichard Purdie
469abadfc92SRichard Purdie /* 48k */
470abadfc92SRichard Purdie {12288000, 48000, 256, 0x0, 0x0},
471abadfc92SRichard Purdie {18432000, 48000, 384, 0x1, 0x0},
472abadfc92SRichard Purdie {12000000, 48000, 250, 0x0, 0x1},
473abadfc92SRichard Purdie
474abadfc92SRichard Purdie /* 88.2k */
475abadfc92SRichard Purdie {11289600, 88200, 128, 0x1e, 0x0},
476abadfc92SRichard Purdie {16934400, 88200, 192, 0x1f, 0x0},
477abadfc92SRichard Purdie {12000000, 88200, 136, 0x1f, 0x1},
478abadfc92SRichard Purdie
479abadfc92SRichard Purdie /* 96k */
480abadfc92SRichard Purdie {12288000, 96000, 128, 0xe, 0x0},
481abadfc92SRichard Purdie {18432000, 96000, 192, 0xf, 0x0},
482abadfc92SRichard Purdie {12000000, 96000, 125, 0xe, 0x1},
483abadfc92SRichard Purdie };
484abadfc92SRichard Purdie
get_coeff(int mclk,int rate)485abadfc92SRichard Purdie static inline int get_coeff(int mclk, int rate)
486abadfc92SRichard Purdie {
487abadfc92SRichard Purdie int i;
488abadfc92SRichard Purdie
489abadfc92SRichard Purdie for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
490abadfc92SRichard Purdie if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
491abadfc92SRichard Purdie return i;
492abadfc92SRichard Purdie }
493a71a468aSLiam Girdwood
494a71a468aSLiam Girdwood printk(KERN_ERR "wm8750: could not get coeff for mclk %d @ rate %d\n",
495a71a468aSLiam Girdwood mclk, rate);
496abadfc92SRichard Purdie return -EINVAL;
497abadfc92SRichard Purdie }
498abadfc92SRichard Purdie
wm8750_set_dai_sysclk(struct snd_soc_dai * codec_dai,int clk_id,unsigned int freq,int dir)499e550e17fSLiam Girdwood static int wm8750_set_dai_sysclk(struct snd_soc_dai *codec_dai,
5004422b606SLiam Girdwood int clk_id, unsigned int freq, int dir)
501abadfc92SRichard Purdie {
502f081a227SKuninori Morimoto struct snd_soc_component *component = codec_dai->component;
503f081a227SKuninori Morimoto struct wm8750_priv *wm8750 = snd_soc_component_get_drvdata(component);
5044422b606SLiam Girdwood
5054422b606SLiam Girdwood switch (freq) {
5064422b606SLiam Girdwood case 11289600:
5074422b606SLiam Girdwood case 12000000:
5084422b606SLiam Girdwood case 12288000:
5094422b606SLiam Girdwood case 16934400:
5104422b606SLiam Girdwood case 18432000:
5114422b606SLiam Girdwood wm8750->sysclk = freq;
5124422b606SLiam Girdwood return 0;
5134422b606SLiam Girdwood }
5144422b606SLiam Girdwood return -EINVAL;
515abadfc92SRichard Purdie }
516abadfc92SRichard Purdie
wm8750_set_dai_fmt(struct snd_soc_dai * codec_dai,unsigned int fmt)517e550e17fSLiam Girdwood static int wm8750_set_dai_fmt(struct snd_soc_dai *codec_dai,
5184422b606SLiam Girdwood unsigned int fmt)
519abadfc92SRichard Purdie {
520f081a227SKuninori Morimoto struct snd_soc_component *component = codec_dai->component;
5214422b606SLiam Girdwood u16 iface = 0;
522abadfc92SRichard Purdie
523abadfc92SRichard Purdie /* set master/slave audio interface */
5244422b606SLiam Girdwood switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
525abadfc92SRichard Purdie case SND_SOC_DAIFMT_CBM_CFM:
526abadfc92SRichard Purdie iface = 0x0040;
527abadfc92SRichard Purdie break;
528abadfc92SRichard Purdie case SND_SOC_DAIFMT_CBS_CFS:
529abadfc92SRichard Purdie break;
5304422b606SLiam Girdwood default:
5314422b606SLiam Girdwood return -EINVAL;
532abadfc92SRichard Purdie }
533abadfc92SRichard Purdie
534abadfc92SRichard Purdie /* interface format */
5354422b606SLiam Girdwood switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
536abadfc92SRichard Purdie case SND_SOC_DAIFMT_I2S:
537abadfc92SRichard Purdie iface |= 0x0002;
538abadfc92SRichard Purdie break;
539abadfc92SRichard Purdie case SND_SOC_DAIFMT_RIGHT_J:
540abadfc92SRichard Purdie break;
541abadfc92SRichard Purdie case SND_SOC_DAIFMT_LEFT_J:
542abadfc92SRichard Purdie iface |= 0x0001;
543abadfc92SRichard Purdie break;
544abadfc92SRichard Purdie case SND_SOC_DAIFMT_DSP_A:
545abadfc92SRichard Purdie iface |= 0x0003;
546abadfc92SRichard Purdie break;
547abadfc92SRichard Purdie case SND_SOC_DAIFMT_DSP_B:
548abadfc92SRichard Purdie iface |= 0x0013;
549abadfc92SRichard Purdie break;
5504422b606SLiam Girdwood default:
5514422b606SLiam Girdwood return -EINVAL;
552abadfc92SRichard Purdie }
553abadfc92SRichard Purdie
554abadfc92SRichard Purdie /* clock inversion */
5554422b606SLiam Girdwood switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
556abadfc92SRichard Purdie case SND_SOC_DAIFMT_NB_NF:
557abadfc92SRichard Purdie break;
558abadfc92SRichard Purdie case SND_SOC_DAIFMT_IB_IF:
559abadfc92SRichard Purdie iface |= 0x0090;
560abadfc92SRichard Purdie break;
561abadfc92SRichard Purdie case SND_SOC_DAIFMT_IB_NF:
562abadfc92SRichard Purdie iface |= 0x0080;
563abadfc92SRichard Purdie break;
564abadfc92SRichard Purdie case SND_SOC_DAIFMT_NB_IF:
565abadfc92SRichard Purdie iface |= 0x0010;
566abadfc92SRichard Purdie break;
5674422b606SLiam Girdwood default:
5684422b606SLiam Girdwood return -EINVAL;
569abadfc92SRichard Purdie }
570abadfc92SRichard Purdie
571f081a227SKuninori Morimoto snd_soc_component_write(component, WM8750_IFACE, iface);
5724422b606SLiam Girdwood return 0;
5734422b606SLiam Girdwood }
5744422b606SLiam Girdwood
wm8750_pcm_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)5754422b606SLiam Girdwood static int wm8750_pcm_hw_params(struct snd_pcm_substream *substream,
576dee89c4dSMark Brown struct snd_pcm_hw_params *params,
577dee89c4dSMark Brown struct snd_soc_dai *dai)
5784422b606SLiam Girdwood {
579f081a227SKuninori Morimoto struct snd_soc_component *component = dai->component;
580f081a227SKuninori Morimoto struct wm8750_priv *wm8750 = snd_soc_component_get_drvdata(component);
5816d75dfc3SKuninori Morimoto u16 iface = snd_soc_component_read(component, WM8750_IFACE) & 0x1f3;
5826d75dfc3SKuninori Morimoto u16 srate = snd_soc_component_read(component, WM8750_SRATE) & 0x1c0;
5834422b606SLiam Girdwood int coeff = get_coeff(wm8750->sysclk, params_rate(params));
5844422b606SLiam Girdwood
5854422b606SLiam Girdwood /* bit size */
5867e322dffSMark Brown switch (params_width(params)) {
5877e322dffSMark Brown case 16:
588abadfc92SRichard Purdie break;
5897e322dffSMark Brown case 20:
5904422b606SLiam Girdwood iface |= 0x0004;
591abadfc92SRichard Purdie break;
5927e322dffSMark Brown case 24:
5934422b606SLiam Girdwood iface |= 0x0008;
594abadfc92SRichard Purdie break;
5957e322dffSMark Brown case 32:
5964422b606SLiam Girdwood iface |= 0x000c;
597abadfc92SRichard Purdie break;
598abadfc92SRichard Purdie }
599abadfc92SRichard Purdie
600abadfc92SRichard Purdie /* set iface & srate */
601f081a227SKuninori Morimoto snd_soc_component_write(component, WM8750_IFACE, iface);
6024422b606SLiam Girdwood if (coeff >= 0)
603f081a227SKuninori Morimoto snd_soc_component_write(component, WM8750_SRATE, srate |
6044422b606SLiam Girdwood (coeff_div[coeff].sr << 1) | coeff_div[coeff].usb);
605abadfc92SRichard Purdie
606abadfc92SRichard Purdie return 0;
607abadfc92SRichard Purdie }
608abadfc92SRichard Purdie
wm8750_mute(struct snd_soc_dai * dai,int mute,int direction)60926d3c16eSKuninori Morimoto static int wm8750_mute(struct snd_soc_dai *dai, int mute, int direction)
610abadfc92SRichard Purdie {
611f081a227SKuninori Morimoto struct snd_soc_component *component = dai->component;
6126d75dfc3SKuninori Morimoto u16 mute_reg = snd_soc_component_read(component, WM8750_ADCDAC) & 0xfff7;
6134422b606SLiam Girdwood
614abadfc92SRichard Purdie if (mute)
615f081a227SKuninori Morimoto snd_soc_component_write(component, WM8750_ADCDAC, mute_reg | 0x8);
616abadfc92SRichard Purdie else
617f081a227SKuninori Morimoto snd_soc_component_write(component, WM8750_ADCDAC, mute_reg);
618abadfc92SRichard Purdie return 0;
619abadfc92SRichard Purdie }
620abadfc92SRichard Purdie
wm8750_set_bias_level(struct snd_soc_component * component,enum snd_soc_bias_level level)621f081a227SKuninori Morimoto static int wm8750_set_bias_level(struct snd_soc_component *component,
6220be9898aSMark Brown enum snd_soc_bias_level level)
623abadfc92SRichard Purdie {
6246d75dfc3SKuninori Morimoto u16 pwr_reg = snd_soc_component_read(component, WM8750_PWR1) & 0xfe3e;
625abadfc92SRichard Purdie
6260be9898aSMark Brown switch (level) {
6270be9898aSMark Brown case SND_SOC_BIAS_ON:
628abadfc92SRichard Purdie /* set vmid to 50k and unmute dac */
629f081a227SKuninori Morimoto snd_soc_component_write(component, WM8750_PWR1, pwr_reg | 0x00c0);
630abadfc92SRichard Purdie break;
6310be9898aSMark Brown case SND_SOC_BIAS_PREPARE:
632abadfc92SRichard Purdie break;
6330be9898aSMark Brown case SND_SOC_BIAS_STANDBY:
634f081a227SKuninori Morimoto if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
635f081a227SKuninori Morimoto snd_soc_component_cache_sync(component);
6364d4adfc9SAxel Lin
637dd76769dSMark Brown /* Set VMID to 5k */
638f081a227SKuninori Morimoto snd_soc_component_write(component, WM8750_PWR1, pwr_reg | 0x01c1);
639dd76769dSMark Brown
640dd76769dSMark Brown /* ...and ramp */
641dd76769dSMark Brown msleep(1000);
642dd76769dSMark Brown }
643dd76769dSMark Brown
644abadfc92SRichard Purdie /* mute dac and set vmid to 500k, enable VREF */
645f081a227SKuninori Morimoto snd_soc_component_write(component, WM8750_PWR1, pwr_reg | 0x0141);
646abadfc92SRichard Purdie break;
6470be9898aSMark Brown case SND_SOC_BIAS_OFF:
648f081a227SKuninori Morimoto snd_soc_component_write(component, WM8750_PWR1, 0x0001);
649abadfc92SRichard Purdie break;
650abadfc92SRichard Purdie }
651abadfc92SRichard Purdie return 0;
652abadfc92SRichard Purdie }
653abadfc92SRichard Purdie
6544422b606SLiam Girdwood #define WM8750_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
6554422b606SLiam Girdwood SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \
6564422b606SLiam Girdwood SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
6574422b606SLiam Girdwood
6584422b606SLiam Girdwood #define WM8750_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
6594422b606SLiam Girdwood SNDRV_PCM_FMTBIT_S24_LE)
6604422b606SLiam Girdwood
66185e7652dSLars-Peter Clausen static const struct snd_soc_dai_ops wm8750_dai_ops = {
6626335d055SEric Miao .hw_params = wm8750_pcm_hw_params,
66326d3c16eSKuninori Morimoto .mute_stream = wm8750_mute,
6646335d055SEric Miao .set_fmt = wm8750_set_dai_fmt,
6656335d055SEric Miao .set_sysclk = wm8750_set_dai_sysclk,
66626d3c16eSKuninori Morimoto .no_capture_mute = 1,
6676335d055SEric Miao };
6686335d055SEric Miao
669f0fba2adSLiam Girdwood static struct snd_soc_dai_driver wm8750_dai = {
670f0fba2adSLiam Girdwood .name = "wm8750-hifi",
671abadfc92SRichard Purdie .playback = {
672abadfc92SRichard Purdie .stream_name = "Playback",
673abadfc92SRichard Purdie .channels_min = 1,
674abadfc92SRichard Purdie .channels_max = 2,
6754422b606SLiam Girdwood .rates = WM8750_RATES,
6764422b606SLiam Girdwood .formats = WM8750_FORMATS,},
677abadfc92SRichard Purdie .capture = {
678abadfc92SRichard Purdie .stream_name = "Capture",
679abadfc92SRichard Purdie .channels_min = 1,
680abadfc92SRichard Purdie .channels_max = 2,
6814422b606SLiam Girdwood .rates = WM8750_RATES,
6824422b606SLiam Girdwood .formats = WM8750_FORMATS,},
6836335d055SEric Miao .ops = &wm8750_dai_ops,
684abadfc92SRichard Purdie };
685abadfc92SRichard Purdie
wm8750_probe(struct snd_soc_component * component)686f081a227SKuninori Morimoto static int wm8750_probe(struct snd_soc_component *component)
6876ca0c22eSMarek Vasut {
688f5b00d02SAxel Lin int ret;
6896ca0c22eSMarek Vasut
690f081a227SKuninori Morimoto ret = wm8750_reset(component);
69117a52fd6SMark Brown if (ret < 0) {
69217a52fd6SMark Brown printk(KERN_ERR "wm8750: failed to reset: %d\n", ret);
693f0fba2adSLiam Girdwood return ret;
69417a52fd6SMark Brown }
695abadfc92SRichard Purdie
696abadfc92SRichard Purdie /* set the update bits */
697f081a227SKuninori Morimoto snd_soc_component_update_bits(component, WM8750_LDAC, 0x0100, 0x0100);
698f081a227SKuninori Morimoto snd_soc_component_update_bits(component, WM8750_RDAC, 0x0100, 0x0100);
699f081a227SKuninori Morimoto snd_soc_component_update_bits(component, WM8750_LOUT1V, 0x0100, 0x0100);
700f081a227SKuninori Morimoto snd_soc_component_update_bits(component, WM8750_ROUT1V, 0x0100, 0x0100);
701f081a227SKuninori Morimoto snd_soc_component_update_bits(component, WM8750_LOUT2V, 0x0100, 0x0100);
702f081a227SKuninori Morimoto snd_soc_component_update_bits(component, WM8750_ROUT2V, 0x0100, 0x0100);
703f081a227SKuninori Morimoto snd_soc_component_update_bits(component, WM8750_LINVOL, 0x0100, 0x0100);
704f081a227SKuninori Morimoto snd_soc_component_update_bits(component, WM8750_RINVOL, 0x0100, 0x0100);
705abadfc92SRichard Purdie
706abadfc92SRichard Purdie return ret;
707abadfc92SRichard Purdie }
708abadfc92SRichard Purdie
709f081a227SKuninori Morimoto static const struct snd_soc_component_driver soc_component_dev_wm8750 = {
710f0fba2adSLiam Girdwood .probe = wm8750_probe,
711f0fba2adSLiam Girdwood .set_bias_level = wm8750_set_bias_level,
7120f185e3fSMark Brown .controls = wm8750_snd_controls,
7130f185e3fSMark Brown .num_controls = ARRAY_SIZE(wm8750_snd_controls),
7140f185e3fSMark Brown .dapm_widgets = wm8750_dapm_widgets,
7150f185e3fSMark Brown .num_dapm_widgets = ARRAY_SIZE(wm8750_dapm_widgets),
7160f185e3fSMark Brown .dapm_routes = wm8750_dapm_routes,
7170f185e3fSMark Brown .num_dapm_routes = ARRAY_SIZE(wm8750_dapm_routes),
718f081a227SKuninori Morimoto .suspend_bias_off = 1,
719f081a227SKuninori Morimoto .idle_bias_on = 1,
720f081a227SKuninori Morimoto .use_pmdown_time = 1,
721f081a227SKuninori Morimoto .endianness = 1,
722f0fba2adSLiam Girdwood };
723abadfc92SRichard Purdie
724ce31a0f5SMark Brown static const struct of_device_id wm8750_of_match[] = {
725ce31a0f5SMark Brown { .compatible = "wlf,wm8750", },
726ce31a0f5SMark Brown { .compatible = "wlf,wm8987", },
727ce31a0f5SMark Brown { }
728ce31a0f5SMark Brown };
729ce31a0f5SMark Brown MODULE_DEVICE_TABLE(of, wm8750_of_match);
730ce31a0f5SMark Brown
731ed79edacSMark Brown static const struct regmap_config wm8750_regmap = {
732ed79edacSMark Brown .reg_bits = 7,
733ed79edacSMark Brown .val_bits = 9,
734ed79edacSMark Brown .max_register = WM8750_MOUTV,
735ed79edacSMark Brown
736ed79edacSMark Brown .reg_defaults = wm8750_reg_defaults,
737ed79edacSMark Brown .num_reg_defaults = ARRAY_SIZE(wm8750_reg_defaults),
738*ef158912SMark Brown .cache_type = REGCACHE_MAPLE,
739ed79edacSMark Brown };
740ed79edacSMark Brown
741f0fba2adSLiam Girdwood #if defined(CONFIG_SPI_MASTER)
wm8750_spi_probe(struct spi_device * spi)7427a79e94eSBill Pemberton static int wm8750_spi_probe(struct spi_device *spi)
743abadfc92SRichard Purdie {
7446ca0c22eSMarek Vasut struct wm8750_priv *wm8750;
745ed79edacSMark Brown struct regmap *regmap;
746f0fba2adSLiam Girdwood int ret;
747abadfc92SRichard Purdie
7482edaed82SMark Brown wm8750 = devm_kzalloc(&spi->dev, sizeof(struct wm8750_priv),
7492edaed82SMark Brown GFP_KERNEL);
7506ca0c22eSMarek Vasut if (wm8750 == NULL)
7516ca0c22eSMarek Vasut return -ENOMEM;
7526ca0c22eSMarek Vasut
753ed79edacSMark Brown regmap = devm_regmap_init_spi(spi, &wm8750_regmap);
754ed79edacSMark Brown if (IS_ERR(regmap))
755ed79edacSMark Brown return PTR_ERR(regmap);
756ed79edacSMark Brown
757f0fba2adSLiam Girdwood spi_set_drvdata(spi, wm8750);
758abadfc92SRichard Purdie
759f081a227SKuninori Morimoto ret = devm_snd_soc_register_component(&spi->dev,
760f081a227SKuninori Morimoto &soc_component_dev_wm8750, &wm8750_dai, 1);
761f0fba2adSLiam Girdwood return ret;
762abadfc92SRichard Purdie }
763abadfc92SRichard Purdie
76440045a85SMark Brown static const struct spi_device_id wm8750_spi_ids[] = {
76540045a85SMark Brown { "wm8750", 0 },
76640045a85SMark Brown { "wm8987", 0 },
767f6b864a9STakashi Iwai { },
76840045a85SMark Brown };
769511d8cf0SMark Brown MODULE_DEVICE_TABLE(spi, wm8750_spi_ids);
77040045a85SMark Brown
771f0fba2adSLiam Girdwood static struct spi_driver wm8750_spi_driver = {
772f0fba2adSLiam Girdwood .driver = {
773dc5de62bSMark Brown .name = "wm8750",
774ce31a0f5SMark Brown .of_match_table = wm8750_of_match,
775f0fba2adSLiam Girdwood },
77640045a85SMark Brown .id_table = wm8750_spi_ids,
777f0fba2adSLiam Girdwood .probe = wm8750_spi_probe,
778f0fba2adSLiam Girdwood };
779f0fba2adSLiam Girdwood #endif /* CONFIG_SPI_MASTER */
780f0fba2adSLiam Girdwood
7819ea6fbc6SFabio Estevam #if IS_ENABLED(CONFIG_I2C)
wm8750_i2c_probe(struct i2c_client * i2c)78297b0b6e3SStephen Kitt static int wm8750_i2c_probe(struct i2c_client *i2c)
783f0fba2adSLiam Girdwood {
784f0fba2adSLiam Girdwood struct wm8750_priv *wm8750;
785ed79edacSMark Brown struct regmap *regmap;
786f0fba2adSLiam Girdwood int ret;
787f0fba2adSLiam Girdwood
7882edaed82SMark Brown wm8750 = devm_kzalloc(&i2c->dev, sizeof(struct wm8750_priv),
7892edaed82SMark Brown GFP_KERNEL);
790f0fba2adSLiam Girdwood if (wm8750 == NULL)
791f0fba2adSLiam Girdwood return -ENOMEM;
792f0fba2adSLiam Girdwood
793f0fba2adSLiam Girdwood i2c_set_clientdata(i2c, wm8750);
794ed79edacSMark Brown
795ed79edacSMark Brown regmap = devm_regmap_init_i2c(i2c, &wm8750_regmap);
796ed79edacSMark Brown if (IS_ERR(regmap))
797ed79edacSMark Brown return PTR_ERR(regmap);
798f0fba2adSLiam Girdwood
799f081a227SKuninori Morimoto ret = devm_snd_soc_register_component(&i2c->dev,
800f081a227SKuninori Morimoto &soc_component_dev_wm8750, &wm8750_dai, 1);
801f0fba2adSLiam Girdwood return ret;
802f0fba2adSLiam Girdwood }
803f0fba2adSLiam Girdwood
804ee1d0099SJean Delvare static const struct i2c_device_id wm8750_i2c_id[] = {
805ee1d0099SJean Delvare { "wm8750", 0 },
806f0fba2adSLiam Girdwood { "wm8987", 0 },
807ee1d0099SJean Delvare { }
808ee1d0099SJean Delvare };
809ee1d0099SJean Delvare MODULE_DEVICE_TABLE(i2c, wm8750_i2c_id);
810abadfc92SRichard Purdie
811abadfc92SRichard Purdie static struct i2c_driver wm8750_i2c_driver = {
812abadfc92SRichard Purdie .driver = {
813dc5de62bSMark Brown .name = "wm8750",
814ce31a0f5SMark Brown .of_match_table = wm8750_of_match,
815abadfc92SRichard Purdie },
8169abcd240SUwe Kleine-König .probe = wm8750_i2c_probe,
817ee1d0099SJean Delvare .id_table = wm8750_i2c_id,
818abadfc92SRichard Purdie };
819abadfc92SRichard Purdie #endif
820abadfc92SRichard Purdie
wm8750_modinit(void)821c9b3a40fSTakashi Iwai static int __init wm8750_modinit(void)
82264089b84SMark Brown {
823f0fba2adSLiam Girdwood int ret = 0;
8249ea6fbc6SFabio Estevam #if IS_ENABLED(CONFIG_I2C)
8256ca0c22eSMarek Vasut ret = i2c_add_driver(&wm8750_i2c_driver);
826f0fba2adSLiam Girdwood if (ret != 0) {
827f0fba2adSLiam Girdwood printk(KERN_ERR "Failed to register wm8750 I2C driver: %d\n",
828f0fba2adSLiam Girdwood ret);
829f0fba2adSLiam Girdwood }
8306ca0c22eSMarek Vasut #endif
8316ca0c22eSMarek Vasut #if defined(CONFIG_SPI_MASTER)
8326ca0c22eSMarek Vasut ret = spi_register_driver(&wm8750_spi_driver);
833f0fba2adSLiam Girdwood if (ret != 0) {
834f0fba2adSLiam Girdwood printk(KERN_ERR "Failed to register wm8750 SPI driver: %d\n",
835f0fba2adSLiam Girdwood ret);
836f0fba2adSLiam Girdwood }
8376ca0c22eSMarek Vasut #endif
838f0fba2adSLiam Girdwood return ret;
83964089b84SMark Brown }
84064089b84SMark Brown module_init(wm8750_modinit);
84164089b84SMark Brown
wm8750_exit(void)84264089b84SMark Brown static void __exit wm8750_exit(void)
84364089b84SMark Brown {
8449ea6fbc6SFabio Estevam #if IS_ENABLED(CONFIG_I2C)
8456ca0c22eSMarek Vasut i2c_del_driver(&wm8750_i2c_driver);
8466ca0c22eSMarek Vasut #endif
8476ca0c22eSMarek Vasut #if defined(CONFIG_SPI_MASTER)
8486ca0c22eSMarek Vasut spi_unregister_driver(&wm8750_spi_driver);
8496ca0c22eSMarek Vasut #endif
85064089b84SMark Brown }
85164089b84SMark Brown module_exit(wm8750_exit);
85264089b84SMark Brown
853abadfc92SRichard Purdie MODULE_DESCRIPTION("ASoC WM8750 driver");
854abadfc92SRichard Purdie MODULE_AUTHOR("Liam Girdwood");
855abadfc92SRichard Purdie MODULE_LICENSE("GPL");
856