xref: /openbmc/linux/sound/soc/codecs/wm8750.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
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