xref: /openbmc/linux/sound/soc/codecs/wm8750.c (revision f081a227aeeb081bf0a886d59d5dd78f35882575)
1abadfc92SRichard Purdie /*
2abadfc92SRichard Purdie  * wm8750.c -- WM8750 ALSA SoC audio driver
3abadfc92SRichard Purdie  *
4abadfc92SRichard Purdie  * Copyright 2005 Openedhand Ltd.
5abadfc92SRichard Purdie  *
6abadfc92SRichard Purdie  * Author: Richard Purdie <richard@openedhand.com>
7abadfc92SRichard Purdie  *
8abadfc92SRichard Purdie  * Based on WM8753.c
9abadfc92SRichard Purdie  *
10abadfc92SRichard Purdie  * This program is free software; you can redistribute it and/or modify
11abadfc92SRichard Purdie  * it under the terms of the GNU General Public License version 2 as
12abadfc92SRichard Purdie  * published by the Free Software Foundation.
13abadfc92SRichard Purdie  */
14abadfc92SRichard Purdie 
15abadfc92SRichard Purdie #include <linux/module.h>
16abadfc92SRichard Purdie #include <linux/moduleparam.h>
17abadfc92SRichard Purdie #include <linux/init.h>
18abadfc92SRichard Purdie #include <linux/delay.h>
19abadfc92SRichard Purdie #include <linux/pm.h>
20abadfc92SRichard Purdie #include <linux/i2c.h>
21ed79edacSMark Brown #include <linux/regmap.h>
222f3dfaf5SMark Brown #include <linux/spi/spi.h>
235a0e3ad6STejun Heo #include <linux/slab.h>
24ce31a0f5SMark Brown #include <linux/of_device.h>
25abadfc92SRichard Purdie #include <sound/core.h>
26abadfc92SRichard Purdie #include <sound/pcm.h>
27abadfc92SRichard Purdie #include <sound/pcm_params.h>
28abadfc92SRichard Purdie #include <sound/soc.h>
29abadfc92SRichard Purdie #include <sound/initval.h>
30abadfc92SRichard Purdie 
31abadfc92SRichard Purdie #include "wm8750.h"
32abadfc92SRichard Purdie 
33abadfc92SRichard Purdie /*
34abadfc92SRichard Purdie  * wm8750 register cache
35abadfc92SRichard Purdie  * We can't read the WM8750 register space when we
36abadfc92SRichard Purdie  * are using 2 wire for device control, so we cache them instead.
37abadfc92SRichard Purdie  */
38ed79edacSMark Brown static const struct reg_default wm8750_reg_defaults[] = {
39ed79edacSMark Brown 	{  0, 0x0097 },
40ed79edacSMark Brown 	{  1, 0x0097 },
41ed79edacSMark Brown 	{  2, 0x0079 },
42ed79edacSMark Brown 	{  3, 0x0079 },
43ed79edacSMark Brown 	{  4, 0x0000 },
44ed79edacSMark Brown 	{  5, 0x0008 },
45ed79edacSMark Brown 	{  6, 0x0000 },
46ed79edacSMark Brown 	{  7, 0x000a },
47ed79edacSMark Brown 	{  8, 0x0000 },
48ed79edacSMark Brown 	{  9, 0x0000 },
49ed79edacSMark Brown 	{ 10, 0x00ff },
50ed79edacSMark Brown 	{ 11, 0x00ff },
51ed79edacSMark Brown 	{ 12, 0x000f },
52ed79edacSMark Brown 	{ 13, 0x000f },
53ed79edacSMark Brown 	{ 14, 0x0000 },
54ed79edacSMark Brown 	{ 15, 0x0000 },
55ed79edacSMark Brown 	{ 16, 0x0000 },
56ed79edacSMark Brown 	{ 17, 0x007b },
57ed79edacSMark Brown 	{ 18, 0x0000 },
58ed79edacSMark Brown 	{ 19, 0x0032 },
59ed79edacSMark Brown 	{ 20, 0x0000 },
60ed79edacSMark Brown 	{ 21, 0x00c3 },
61ed79edacSMark Brown 	{ 22, 0x00c3 },
62ed79edacSMark Brown 	{ 23, 0x00c0 },
63ed79edacSMark Brown 	{ 24, 0x0000 },
64ed79edacSMark Brown 	{ 25, 0x0000 },
65ed79edacSMark Brown 	{ 26, 0x0000 },
66ed79edacSMark Brown 	{ 27, 0x0000 },
67ed79edacSMark Brown 	{ 28, 0x0000 },
68ed79edacSMark Brown 	{ 29, 0x0000 },
69ed79edacSMark Brown 	{ 30, 0x0000 },
70ed79edacSMark Brown 	{ 31, 0x0000 },
71ed79edacSMark Brown 	{ 32, 0x0000 },
72ed79edacSMark Brown 	{ 33, 0x0000 },
73ed79edacSMark Brown 	{ 34, 0x0050 },
74ed79edacSMark Brown 	{ 35, 0x0050 },
75ed79edacSMark Brown 	{ 36, 0x0050 },
76ed79edacSMark Brown 	{ 37, 0x0050 },
77ed79edacSMark Brown 	{ 38, 0x0050 },
78ed79edacSMark Brown 	{ 39, 0x0050 },
79ed79edacSMark Brown 	{ 40, 0x0079 },
80ed79edacSMark Brown 	{ 41, 0x0079 },
81ed79edacSMark Brown 	{ 42, 0x0079 },
82abadfc92SRichard Purdie };
83abadfc92SRichard Purdie 
846ca0c22eSMarek Vasut /* codec private data */
856ca0c22eSMarek Vasut struct wm8750_priv {
866ca0c22eSMarek Vasut 	unsigned int sysclk;
876ca0c22eSMarek Vasut };
886ca0c22eSMarek Vasut 
89*f081a227SKuninori Morimoto #define wm8750_reset(c)	snd_soc_component_write(c, WM8750_RESET, 0)
90abadfc92SRichard Purdie 
91abadfc92SRichard Purdie /*
92abadfc92SRichard Purdie  * WM8750 Controls
93abadfc92SRichard Purdie  */
94abadfc92SRichard Purdie static const char *wm8750_bass[] = {"Linear Control", "Adaptive Boost"};
95abadfc92SRichard Purdie static const char *wm8750_bass_filter[] = { "130Hz @ 48kHz", "200Hz @ 48kHz" };
96abadfc92SRichard Purdie static const char *wm8750_treble[] = {"8kHz", "4kHz"};
97abadfc92SRichard Purdie static const char *wm8750_3d_lc[] = {"200Hz", "500Hz"};
98abadfc92SRichard Purdie static const char *wm8750_3d_uc[] = {"2.2kHz", "1.5kHz"};
99abadfc92SRichard Purdie static const char *wm8750_3d_func[] = {"Capture", "Playback"};
100abadfc92SRichard Purdie static const char *wm8750_alc_func[] = {"Off", "Right", "Left", "Stereo"};
101abadfc92SRichard Purdie static const char *wm8750_ng_type[] = {"Constant PGA Gain",
102abadfc92SRichard Purdie 	"Mute ADC Output"};
103abadfc92SRichard Purdie static const char *wm8750_line_mux[] = {"Line 1", "Line 2", "Line 3", "PGA",
104abadfc92SRichard Purdie 	"Differential"};
105abadfc92SRichard Purdie static const char *wm8750_pga_sel[] = {"Line 1", "Line 2", "Line 3",
106abadfc92SRichard Purdie 	"Differential"};
107abadfc92SRichard Purdie static const char *wm8750_out3[] = {"VREF", "ROUT1 + Vol", "MonoOut",
108abadfc92SRichard Purdie 	"ROUT1"};
109abadfc92SRichard Purdie static const char *wm8750_diff_sel[] = {"Line 1", "Line 2"};
110abadfc92SRichard Purdie static const char *wm8750_adcpol[] = {"Normal", "L Invert", "R Invert",
111abadfc92SRichard Purdie 	"L + R Invert"};
112abadfc92SRichard Purdie static const char *wm8750_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"};
113abadfc92SRichard Purdie static const char *wm8750_mono_mux[] = {"Stereo", "Mono (Left)",
114abadfc92SRichard Purdie 	"Mono (Right)", "Digital Mono"};
115abadfc92SRichard Purdie 
116abadfc92SRichard Purdie static const struct soc_enum wm8750_enum[] = {
117abadfc92SRichard Purdie SOC_ENUM_SINGLE(WM8750_BASS, 7, 2, wm8750_bass),
118abadfc92SRichard Purdie SOC_ENUM_SINGLE(WM8750_BASS, 6, 2, wm8750_bass_filter),
119abadfc92SRichard Purdie SOC_ENUM_SINGLE(WM8750_TREBLE, 6, 2, wm8750_treble),
120abadfc92SRichard Purdie SOC_ENUM_SINGLE(WM8750_3D, 5, 2, wm8750_3d_lc),
121abadfc92SRichard Purdie SOC_ENUM_SINGLE(WM8750_3D, 6, 2, wm8750_3d_uc),
122abadfc92SRichard Purdie SOC_ENUM_SINGLE(WM8750_3D, 7, 2, wm8750_3d_func),
123abadfc92SRichard Purdie SOC_ENUM_SINGLE(WM8750_ALC1, 7, 4, wm8750_alc_func),
124abadfc92SRichard Purdie SOC_ENUM_SINGLE(WM8750_NGATE, 1, 2, wm8750_ng_type),
125abadfc92SRichard Purdie SOC_ENUM_SINGLE(WM8750_LOUTM1, 0, 5, wm8750_line_mux),
126abadfc92SRichard Purdie SOC_ENUM_SINGLE(WM8750_ROUTM1, 0, 5, wm8750_line_mux),
127abadfc92SRichard Purdie SOC_ENUM_SINGLE(WM8750_LADCIN, 6, 4, wm8750_pga_sel), /* 10 */
128abadfc92SRichard Purdie SOC_ENUM_SINGLE(WM8750_RADCIN, 6, 4, wm8750_pga_sel),
129abadfc92SRichard Purdie SOC_ENUM_SINGLE(WM8750_ADCTL2, 7, 4, wm8750_out3),
130abadfc92SRichard Purdie SOC_ENUM_SINGLE(WM8750_ADCIN, 8, 2, wm8750_diff_sel),
131abadfc92SRichard Purdie SOC_ENUM_SINGLE(WM8750_ADCDAC, 5, 4, wm8750_adcpol),
132abadfc92SRichard Purdie SOC_ENUM_SINGLE(WM8750_ADCDAC, 1, 4, wm8750_deemph),
133abadfc92SRichard Purdie SOC_ENUM_SINGLE(WM8750_ADCIN, 6, 4, wm8750_mono_mux), /* 16 */
134abadfc92SRichard Purdie 
135abadfc92SRichard Purdie };
136abadfc92SRichard Purdie 
137abadfc92SRichard Purdie static const struct snd_kcontrol_new wm8750_snd_controls[] = {
138abadfc92SRichard Purdie 
139abadfc92SRichard Purdie SOC_DOUBLE_R("Capture Volume", WM8750_LINVOL, WM8750_RINVOL, 0, 63, 0),
140abadfc92SRichard Purdie SOC_DOUBLE_R("Capture ZC Switch", WM8750_LINVOL, WM8750_RINVOL, 6, 1, 0),
141abadfc92SRichard Purdie SOC_DOUBLE_R("Capture Switch", WM8750_LINVOL, WM8750_RINVOL, 7, 1, 1),
142abadfc92SRichard Purdie 
143bd903b6eSLiam Girdwood SOC_DOUBLE_R("Headphone Playback ZC Switch", WM8750_LOUT1V,
144abadfc92SRichard Purdie 	WM8750_ROUT1V, 7, 1, 0),
145bd903b6eSLiam Girdwood SOC_DOUBLE_R("Speaker Playback ZC Switch", WM8750_LOUT2V,
146abadfc92SRichard Purdie 	WM8750_ROUT2V, 7, 1, 0),
147abadfc92SRichard Purdie 
148abadfc92SRichard Purdie SOC_ENUM("Playback De-emphasis", wm8750_enum[15]),
149abadfc92SRichard Purdie 
150abadfc92SRichard Purdie SOC_ENUM("Capture Polarity", wm8750_enum[14]),
151abadfc92SRichard Purdie SOC_SINGLE("Playback 6dB Attenuate", WM8750_ADCDAC, 7, 1, 0),
152abadfc92SRichard Purdie SOC_SINGLE("Capture 6dB Attenuate", WM8750_ADCDAC, 8, 1, 0),
153abadfc92SRichard Purdie 
154abadfc92SRichard Purdie SOC_DOUBLE_R("PCM Volume", WM8750_LDAC, WM8750_RDAC, 0, 255, 0),
155abadfc92SRichard Purdie 
156abadfc92SRichard Purdie SOC_ENUM("Bass Boost", wm8750_enum[0]),
157abadfc92SRichard Purdie SOC_ENUM("Bass Filter", wm8750_enum[1]),
158abadfc92SRichard Purdie SOC_SINGLE("Bass Volume", WM8750_BASS, 0, 15, 1),
159abadfc92SRichard Purdie 
1606a7b8cf4SStanislav Brabec SOC_SINGLE("Treble Volume", WM8750_TREBLE, 0, 15, 1),
161abadfc92SRichard Purdie SOC_ENUM("Treble Cut-off", wm8750_enum[2]),
162abadfc92SRichard Purdie 
163abadfc92SRichard Purdie SOC_SINGLE("3D Switch", WM8750_3D, 0, 1, 0),
164abadfc92SRichard Purdie SOC_SINGLE("3D Volume", WM8750_3D, 1, 15, 0),
165abadfc92SRichard Purdie SOC_ENUM("3D Lower Cut-off", wm8750_enum[3]),
166abadfc92SRichard Purdie SOC_ENUM("3D Upper Cut-off", wm8750_enum[4]),
167abadfc92SRichard Purdie SOC_ENUM("3D Mode", wm8750_enum[5]),
168abadfc92SRichard Purdie 
169abadfc92SRichard Purdie SOC_SINGLE("ALC Capture Target Volume", WM8750_ALC1, 0, 7, 0),
170abadfc92SRichard Purdie SOC_SINGLE("ALC Capture Max Volume", WM8750_ALC1, 4, 7, 0),
171abadfc92SRichard Purdie SOC_ENUM("ALC Capture Function", wm8750_enum[6]),
172abadfc92SRichard Purdie SOC_SINGLE("ALC Capture ZC Switch", WM8750_ALC2, 7, 1, 0),
173abadfc92SRichard Purdie SOC_SINGLE("ALC Capture Hold Time", WM8750_ALC2, 0, 15, 0),
174abadfc92SRichard Purdie SOC_SINGLE("ALC Capture Decay Time", WM8750_ALC3, 4, 15, 0),
175abadfc92SRichard Purdie SOC_SINGLE("ALC Capture Attack Time", WM8750_ALC3, 0, 15, 0),
176abadfc92SRichard Purdie SOC_SINGLE("ALC Capture NG Threshold", WM8750_NGATE, 3, 31, 0),
177abadfc92SRichard Purdie SOC_ENUM("ALC Capture NG Type", wm8750_enum[4]),
178abadfc92SRichard Purdie SOC_SINGLE("ALC Capture NG Switch", WM8750_NGATE, 0, 1, 0),
179abadfc92SRichard Purdie 
180abadfc92SRichard Purdie SOC_SINGLE("Left ADC Capture Volume", WM8750_LADC, 0, 255, 0),
181abadfc92SRichard Purdie SOC_SINGLE("Right ADC Capture Volume", WM8750_RADC, 0, 255, 0),
182abadfc92SRichard Purdie 
183abadfc92SRichard Purdie SOC_SINGLE("ZC Timeout Switch", WM8750_ADCTL1, 0, 1, 0),
184abadfc92SRichard Purdie SOC_SINGLE("Playback Invert Switch", WM8750_ADCTL1, 1, 1, 0),
185abadfc92SRichard Purdie 
186bd903b6eSLiam Girdwood SOC_SINGLE("Right Speaker Playback Invert Switch", WM8750_ADCTL2, 4, 1, 0),
187abadfc92SRichard Purdie 
188abadfc92SRichard Purdie /* Unimplemented */
189abadfc92SRichard Purdie /* ADCDAC Bit 0 - ADCHPD */
190abadfc92SRichard Purdie /* ADCDAC Bit 4 - HPOR */
191abadfc92SRichard Purdie /* ADCTL1 Bit 2,3 - DATSEL */
192abadfc92SRichard Purdie /* ADCTL1 Bit 4,5 - DMONOMIX */
193abadfc92SRichard Purdie /* ADCTL1 Bit 6,7 - VSEL */
194abadfc92SRichard Purdie /* ADCTL2 Bit 2 - LRCM */
195abadfc92SRichard Purdie /* ADCTL2 Bit 3 - TRI */
196abadfc92SRichard Purdie /* ADCTL3 Bit 5 - HPFLREN */
197abadfc92SRichard Purdie /* ADCTL3 Bit 6 - VROI */
198abadfc92SRichard Purdie /* ADCTL3 Bit 7,8 - ADCLRM */
199abadfc92SRichard Purdie /* ADCIN Bit 4 - LDCM */
200abadfc92SRichard Purdie /* ADCIN Bit 5 - RDCM */
201abadfc92SRichard Purdie 
202abadfc92SRichard Purdie SOC_DOUBLE_R("Mic Boost", WM8750_LADCIN, WM8750_RADCIN, 4, 3, 0),
203abadfc92SRichard Purdie 
204abadfc92SRichard Purdie SOC_DOUBLE_R("Bypass Left Playback Volume", WM8750_LOUTM1,
205abadfc92SRichard Purdie 	WM8750_LOUTM2, 4, 7, 1),
206abadfc92SRichard Purdie SOC_DOUBLE_R("Bypass Right Playback Volume", WM8750_ROUTM1,
207abadfc92SRichard Purdie 	WM8750_ROUTM2, 4, 7, 1),
208abadfc92SRichard Purdie SOC_DOUBLE_R("Bypass Mono Playback Volume", WM8750_MOUTM1,
209abadfc92SRichard Purdie 	WM8750_MOUTM2, 4, 7, 1),
210abadfc92SRichard Purdie 
211abadfc92SRichard Purdie SOC_SINGLE("Mono Playback ZC Switch", WM8750_MOUTV, 7, 1, 0),
212abadfc92SRichard Purdie 
213bd903b6eSLiam Girdwood SOC_DOUBLE_R("Headphone Playback Volume", WM8750_LOUT1V, WM8750_ROUT1V,
214bd903b6eSLiam Girdwood 	0, 127, 0),
215bd903b6eSLiam Girdwood SOC_DOUBLE_R("Speaker Playback Volume", WM8750_LOUT2V, WM8750_ROUT2V,
216bd903b6eSLiam Girdwood 	0, 127, 0),
217abadfc92SRichard Purdie 
218abadfc92SRichard Purdie SOC_SINGLE("Mono Playback Volume", WM8750_MOUTV, 0, 127, 0),
219abadfc92SRichard Purdie 
220abadfc92SRichard Purdie };
221abadfc92SRichard Purdie 
222abadfc92SRichard Purdie /*
223abadfc92SRichard Purdie  * DAPM Controls
224abadfc92SRichard Purdie  */
225abadfc92SRichard Purdie 
226abadfc92SRichard Purdie /* Left Mixer */
227abadfc92SRichard Purdie static const struct snd_kcontrol_new wm8750_left_mixer_controls[] = {
228abadfc92SRichard Purdie SOC_DAPM_SINGLE("Playback Switch", WM8750_LOUTM1, 8, 1, 0),
229abadfc92SRichard Purdie SOC_DAPM_SINGLE("Left Bypass Switch", WM8750_LOUTM1, 7, 1, 0),
230abadfc92SRichard Purdie SOC_DAPM_SINGLE("Right Playback Switch", WM8750_LOUTM2, 8, 1, 0),
231abadfc92SRichard Purdie SOC_DAPM_SINGLE("Right Bypass Switch", WM8750_LOUTM2, 7, 1, 0),
232abadfc92SRichard Purdie };
233abadfc92SRichard Purdie 
234abadfc92SRichard Purdie /* Right Mixer */
235abadfc92SRichard Purdie static const struct snd_kcontrol_new wm8750_right_mixer_controls[] = {
236abadfc92SRichard Purdie SOC_DAPM_SINGLE("Left Playback Switch", WM8750_ROUTM1, 8, 1, 0),
237abadfc92SRichard Purdie SOC_DAPM_SINGLE("Left Bypass Switch", WM8750_ROUTM1, 7, 1, 0),
238abadfc92SRichard Purdie SOC_DAPM_SINGLE("Playback Switch", WM8750_ROUTM2, 8, 1, 0),
239abadfc92SRichard Purdie SOC_DAPM_SINGLE("Right Bypass Switch", WM8750_ROUTM2, 7, 1, 0),
240abadfc92SRichard Purdie };
241abadfc92SRichard Purdie 
242abadfc92SRichard Purdie /* Mono Mixer */
243abadfc92SRichard Purdie static const struct snd_kcontrol_new wm8750_mono_mixer_controls[] = {
244abadfc92SRichard Purdie SOC_DAPM_SINGLE("Left Playback Switch", WM8750_MOUTM1, 8, 1, 0),
245abadfc92SRichard Purdie SOC_DAPM_SINGLE("Left Bypass Switch", WM8750_MOUTM1, 7, 1, 0),
246abadfc92SRichard Purdie SOC_DAPM_SINGLE("Right Playback Switch", WM8750_MOUTM2, 8, 1, 0),
247abadfc92SRichard Purdie SOC_DAPM_SINGLE("Right Bypass Switch", WM8750_MOUTM2, 7, 1, 0),
248abadfc92SRichard Purdie };
249abadfc92SRichard Purdie 
250abadfc92SRichard Purdie /* Left Line Mux */
251abadfc92SRichard Purdie static const struct snd_kcontrol_new wm8750_left_line_controls =
252abadfc92SRichard Purdie SOC_DAPM_ENUM("Route", wm8750_enum[8]);
253abadfc92SRichard Purdie 
254abadfc92SRichard Purdie /* Right Line Mux */
255abadfc92SRichard Purdie static const struct snd_kcontrol_new wm8750_right_line_controls =
256abadfc92SRichard Purdie SOC_DAPM_ENUM("Route", wm8750_enum[9]);
257abadfc92SRichard Purdie 
258abadfc92SRichard Purdie /* Left PGA Mux */
259abadfc92SRichard Purdie static const struct snd_kcontrol_new wm8750_left_pga_controls =
260abadfc92SRichard Purdie SOC_DAPM_ENUM("Route", wm8750_enum[10]);
261abadfc92SRichard Purdie 
262abadfc92SRichard Purdie /* Right PGA Mux */
263abadfc92SRichard Purdie static const struct snd_kcontrol_new wm8750_right_pga_controls =
264abadfc92SRichard Purdie SOC_DAPM_ENUM("Route", wm8750_enum[11]);
265abadfc92SRichard Purdie 
266abadfc92SRichard Purdie /* Out 3 Mux */
267abadfc92SRichard Purdie static const struct snd_kcontrol_new wm8750_out3_controls =
268abadfc92SRichard Purdie SOC_DAPM_ENUM("Route", wm8750_enum[12]);
269abadfc92SRichard Purdie 
270abadfc92SRichard Purdie /* Differential Mux */
271abadfc92SRichard Purdie static const struct snd_kcontrol_new wm8750_diffmux_controls =
272abadfc92SRichard Purdie SOC_DAPM_ENUM("Route", wm8750_enum[13]);
273abadfc92SRichard Purdie 
274abadfc92SRichard Purdie /* Mono ADC Mux */
275abadfc92SRichard Purdie static const struct snd_kcontrol_new wm8750_monomux_controls =
276abadfc92SRichard Purdie SOC_DAPM_ENUM("Route", wm8750_enum[16]);
277abadfc92SRichard Purdie 
278abadfc92SRichard Purdie static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = {
279abadfc92SRichard Purdie 	SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0,
280abadfc92SRichard Purdie 		&wm8750_left_mixer_controls[0],
281abadfc92SRichard Purdie 		ARRAY_SIZE(wm8750_left_mixer_controls)),
282abadfc92SRichard Purdie 	SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0,
283abadfc92SRichard Purdie 		&wm8750_right_mixer_controls[0],
284abadfc92SRichard Purdie 		ARRAY_SIZE(wm8750_right_mixer_controls)),
285abadfc92SRichard Purdie 	SND_SOC_DAPM_MIXER("Mono Mixer", WM8750_PWR2, 2, 0,
286abadfc92SRichard Purdie 		&wm8750_mono_mixer_controls[0],
287abadfc92SRichard Purdie 		ARRAY_SIZE(wm8750_mono_mixer_controls)),
288abadfc92SRichard Purdie 
289abadfc92SRichard Purdie 	SND_SOC_DAPM_PGA("Right Out 2", WM8750_PWR2, 3, 0, NULL, 0),
290abadfc92SRichard Purdie 	SND_SOC_DAPM_PGA("Left Out 2", WM8750_PWR2, 4, 0, NULL, 0),
291abadfc92SRichard Purdie 	SND_SOC_DAPM_PGA("Right Out 1", WM8750_PWR2, 5, 0, NULL, 0),
292abadfc92SRichard Purdie 	SND_SOC_DAPM_PGA("Left Out 1", WM8750_PWR2, 6, 0, NULL, 0),
293abadfc92SRichard Purdie 	SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8750_PWR2, 7, 0),
294abadfc92SRichard Purdie 	SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8750_PWR2, 8, 0),
295abadfc92SRichard Purdie 
296abadfc92SRichard Purdie 	SND_SOC_DAPM_MICBIAS("Mic Bias", WM8750_PWR1, 1, 0),
297abadfc92SRichard Purdie 	SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8750_PWR1, 2, 0),
298abadfc92SRichard Purdie 	SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8750_PWR1, 3, 0),
299abadfc92SRichard Purdie 
300abadfc92SRichard Purdie 	SND_SOC_DAPM_MUX("Left PGA Mux", WM8750_PWR1, 5, 0,
301abadfc92SRichard Purdie 		&wm8750_left_pga_controls),
302abadfc92SRichard Purdie 	SND_SOC_DAPM_MUX("Right PGA Mux", WM8750_PWR1, 4, 0,
303abadfc92SRichard Purdie 		&wm8750_right_pga_controls),
304abadfc92SRichard Purdie 	SND_SOC_DAPM_MUX("Left Line Mux", SND_SOC_NOPM, 0, 0,
305abadfc92SRichard Purdie 		&wm8750_left_line_controls),
306abadfc92SRichard Purdie 	SND_SOC_DAPM_MUX("Right Line Mux", SND_SOC_NOPM, 0, 0,
307abadfc92SRichard Purdie 		&wm8750_right_line_controls),
308abadfc92SRichard Purdie 
309abadfc92SRichard Purdie 	SND_SOC_DAPM_MUX("Out3 Mux", SND_SOC_NOPM, 0, 0, &wm8750_out3_controls),
310abadfc92SRichard Purdie 	SND_SOC_DAPM_PGA("Out 3", WM8750_PWR2, 1, 0, NULL, 0),
311abadfc92SRichard Purdie 	SND_SOC_DAPM_PGA("Mono Out 1", WM8750_PWR2, 2, 0, NULL, 0),
312abadfc92SRichard Purdie 
313abadfc92SRichard Purdie 	SND_SOC_DAPM_MUX("Differential Mux", SND_SOC_NOPM, 0, 0,
314abadfc92SRichard Purdie 		&wm8750_diffmux_controls),
315abadfc92SRichard Purdie 	SND_SOC_DAPM_MUX("Left ADC Mux", SND_SOC_NOPM, 0, 0,
316abadfc92SRichard Purdie 		&wm8750_monomux_controls),
317abadfc92SRichard Purdie 	SND_SOC_DAPM_MUX("Right ADC Mux", SND_SOC_NOPM, 0, 0,
318abadfc92SRichard Purdie 		&wm8750_monomux_controls),
319abadfc92SRichard Purdie 
320abadfc92SRichard Purdie 	SND_SOC_DAPM_OUTPUT("LOUT1"),
321abadfc92SRichard Purdie 	SND_SOC_DAPM_OUTPUT("ROUT1"),
322abadfc92SRichard Purdie 	SND_SOC_DAPM_OUTPUT("LOUT2"),
323abadfc92SRichard Purdie 	SND_SOC_DAPM_OUTPUT("ROUT2"),
32423ba79bdSDmitry Baryshkov 	SND_SOC_DAPM_OUTPUT("MONO1"),
325abadfc92SRichard Purdie 	SND_SOC_DAPM_OUTPUT("OUT3"),
3265ede19c5SLars-Peter Clausen 	SND_SOC_DAPM_VMID("VREF"),
327abadfc92SRichard Purdie 
328abadfc92SRichard Purdie 	SND_SOC_DAPM_INPUT("LINPUT1"),
329abadfc92SRichard Purdie 	SND_SOC_DAPM_INPUT("LINPUT2"),
330abadfc92SRichard Purdie 	SND_SOC_DAPM_INPUT("LINPUT3"),
331abadfc92SRichard Purdie 	SND_SOC_DAPM_INPUT("RINPUT1"),
332abadfc92SRichard Purdie 	SND_SOC_DAPM_INPUT("RINPUT2"),
333abadfc92SRichard Purdie 	SND_SOC_DAPM_INPUT("RINPUT3"),
334abadfc92SRichard Purdie };
335abadfc92SRichard Purdie 
3360f185e3fSMark Brown static const struct snd_soc_dapm_route wm8750_dapm_routes[] = {
337abadfc92SRichard Purdie 	/* left mixer */
338abadfc92SRichard Purdie 	{"Left Mixer", "Playback Switch", "Left DAC"},
339abadfc92SRichard Purdie 	{"Left Mixer", "Left Bypass Switch", "Left Line Mux"},
340abadfc92SRichard Purdie 	{"Left Mixer", "Right Playback Switch", "Right DAC"},
341abadfc92SRichard Purdie 	{"Left Mixer", "Right Bypass Switch", "Right Line Mux"},
342abadfc92SRichard Purdie 
343abadfc92SRichard Purdie 	/* right mixer */
344abadfc92SRichard Purdie 	{"Right Mixer", "Left Playback Switch", "Left DAC"},
345abadfc92SRichard Purdie 	{"Right Mixer", "Left Bypass Switch", "Left Line Mux"},
346abadfc92SRichard Purdie 	{"Right Mixer", "Playback Switch", "Right DAC"},
347abadfc92SRichard Purdie 	{"Right Mixer", "Right Bypass Switch", "Right Line Mux"},
348abadfc92SRichard Purdie 
349abadfc92SRichard Purdie 	/* left out 1 */
350abadfc92SRichard Purdie 	{"Left Out 1", NULL, "Left Mixer"},
351abadfc92SRichard Purdie 	{"LOUT1", NULL, "Left Out 1"},
352abadfc92SRichard Purdie 
353abadfc92SRichard Purdie 	/* left out 2 */
354abadfc92SRichard Purdie 	{"Left Out 2", NULL, "Left Mixer"},
355abadfc92SRichard Purdie 	{"LOUT2", NULL, "Left Out 2"},
356abadfc92SRichard Purdie 
357abadfc92SRichard Purdie 	/* right out 1 */
358abadfc92SRichard Purdie 	{"Right Out 1", NULL, "Right Mixer"},
359abadfc92SRichard Purdie 	{"ROUT1", NULL, "Right Out 1"},
360abadfc92SRichard Purdie 
361abadfc92SRichard Purdie 	/* right out 2 */
362abadfc92SRichard Purdie 	{"Right Out 2", NULL, "Right Mixer"},
363abadfc92SRichard Purdie 	{"ROUT2", NULL, "Right Out 2"},
364abadfc92SRichard Purdie 
365abadfc92SRichard Purdie 	/* mono mixer */
366abadfc92SRichard Purdie 	{"Mono Mixer", "Left Playback Switch", "Left DAC"},
367abadfc92SRichard Purdie 	{"Mono Mixer", "Left Bypass Switch", "Left Line Mux"},
368abadfc92SRichard Purdie 	{"Mono Mixer", "Right Playback Switch", "Right DAC"},
369abadfc92SRichard Purdie 	{"Mono Mixer", "Right Bypass Switch", "Right Line Mux"},
370abadfc92SRichard Purdie 
371abadfc92SRichard Purdie 	/* mono out */
372abadfc92SRichard Purdie 	{"Mono Out 1", NULL, "Mono Mixer"},
373abadfc92SRichard Purdie 	{"MONO1", NULL, "Mono Out 1"},
374abadfc92SRichard Purdie 
375abadfc92SRichard Purdie 	/* out 3 */
376abadfc92SRichard Purdie 	{"Out3 Mux", "VREF", "VREF"},
377abadfc92SRichard Purdie 	{"Out3 Mux", "ROUT1 + Vol", "ROUT1"},
378abadfc92SRichard Purdie 	{"Out3 Mux", "ROUT1", "Right Mixer"},
379abadfc92SRichard Purdie 	{"Out3 Mux", "MonoOut", "MONO1"},
380abadfc92SRichard Purdie 	{"Out 3", NULL, "Out3 Mux"},
381abadfc92SRichard Purdie 	{"OUT3", NULL, "Out 3"},
382abadfc92SRichard Purdie 
383abadfc92SRichard Purdie 	/* Left Line Mux */
384abadfc92SRichard Purdie 	{"Left Line Mux", "Line 1", "LINPUT1"},
385abadfc92SRichard Purdie 	{"Left Line Mux", "Line 2", "LINPUT2"},
386abadfc92SRichard Purdie 	{"Left Line Mux", "Line 3", "LINPUT3"},
387abadfc92SRichard Purdie 	{"Left Line Mux", "PGA", "Left PGA Mux"},
388abadfc92SRichard Purdie 	{"Left Line Mux", "Differential", "Differential Mux"},
389abadfc92SRichard Purdie 
390abadfc92SRichard Purdie 	/* Right Line Mux */
391abadfc92SRichard Purdie 	{"Right Line Mux", "Line 1", "RINPUT1"},
392abadfc92SRichard Purdie 	{"Right Line Mux", "Line 2", "RINPUT2"},
393abadfc92SRichard Purdie 	{"Right Line Mux", "Line 3", "RINPUT3"},
394abadfc92SRichard Purdie 	{"Right Line Mux", "PGA", "Right PGA Mux"},
395abadfc92SRichard Purdie 	{"Right Line Mux", "Differential", "Differential Mux"},
396abadfc92SRichard Purdie 
397abadfc92SRichard Purdie 	/* Left PGA Mux */
398abadfc92SRichard Purdie 	{"Left PGA Mux", "Line 1", "LINPUT1"},
399abadfc92SRichard Purdie 	{"Left PGA Mux", "Line 2", "LINPUT2"},
400abadfc92SRichard Purdie 	{"Left PGA Mux", "Line 3", "LINPUT3"},
401abadfc92SRichard Purdie 	{"Left PGA Mux", "Differential", "Differential Mux"},
402abadfc92SRichard Purdie 
403abadfc92SRichard Purdie 	/* Right PGA Mux */
404abadfc92SRichard Purdie 	{"Right PGA Mux", "Line 1", "RINPUT1"},
405abadfc92SRichard Purdie 	{"Right PGA Mux", "Line 2", "RINPUT2"},
406abadfc92SRichard Purdie 	{"Right PGA Mux", "Line 3", "RINPUT3"},
407abadfc92SRichard Purdie 	{"Right PGA Mux", "Differential", "Differential Mux"},
408abadfc92SRichard Purdie 
409abadfc92SRichard Purdie 	/* Differential Mux */
410abadfc92SRichard Purdie 	{"Differential Mux", "Line 1", "LINPUT1"},
411abadfc92SRichard Purdie 	{"Differential Mux", "Line 1", "RINPUT1"},
412abadfc92SRichard Purdie 	{"Differential Mux", "Line 2", "LINPUT2"},
413abadfc92SRichard Purdie 	{"Differential Mux", "Line 2", "RINPUT2"},
414abadfc92SRichard Purdie 
415abadfc92SRichard Purdie 	/* Left ADC Mux */
416abadfc92SRichard Purdie 	{"Left ADC Mux", "Stereo", "Left PGA Mux"},
417abadfc92SRichard Purdie 	{"Left ADC Mux", "Mono (Left)", "Left PGA Mux"},
418abadfc92SRichard Purdie 	{"Left ADC Mux", "Digital Mono", "Left PGA Mux"},
419abadfc92SRichard Purdie 
420abadfc92SRichard Purdie 	/* Right ADC Mux */
421abadfc92SRichard Purdie 	{"Right ADC Mux", "Stereo", "Right PGA Mux"},
422abadfc92SRichard Purdie 	{"Right ADC Mux", "Mono (Right)", "Right PGA Mux"},
423abadfc92SRichard Purdie 	{"Right ADC Mux", "Digital Mono", "Right PGA Mux"},
424abadfc92SRichard Purdie 
425abadfc92SRichard Purdie 	/* ADC */
426abadfc92SRichard Purdie 	{"Left ADC", NULL, "Left ADC Mux"},
427abadfc92SRichard Purdie 	{"Right ADC", NULL, "Right ADC Mux"},
428abadfc92SRichard Purdie };
429abadfc92SRichard Purdie 
430abadfc92SRichard Purdie struct _coeff_div {
431abadfc92SRichard Purdie 	u32 mclk;
432abadfc92SRichard Purdie 	u32 rate;
433abadfc92SRichard Purdie 	u16 fs;
434abadfc92SRichard Purdie 	u8 sr:5;
435abadfc92SRichard Purdie 	u8 usb:1;
436abadfc92SRichard Purdie };
437abadfc92SRichard Purdie 
438abadfc92SRichard Purdie /* codec hifi mclk clock divider coefficients */
439abadfc92SRichard Purdie static const struct _coeff_div coeff_div[] = {
440abadfc92SRichard Purdie 	/* 8k */
441abadfc92SRichard Purdie 	{12288000, 8000, 1536, 0x6, 0x0},
442abadfc92SRichard Purdie 	{11289600, 8000, 1408, 0x16, 0x0},
443abadfc92SRichard Purdie 	{18432000, 8000, 2304, 0x7, 0x0},
444abadfc92SRichard Purdie 	{16934400, 8000, 2112, 0x17, 0x0},
445abadfc92SRichard Purdie 	{12000000, 8000, 1500, 0x6, 0x1},
446abadfc92SRichard Purdie 
447abadfc92SRichard Purdie 	/* 11.025k */
448abadfc92SRichard Purdie 	{11289600, 11025, 1024, 0x18, 0x0},
449abadfc92SRichard Purdie 	{16934400, 11025, 1536, 0x19, 0x0},
450abadfc92SRichard Purdie 	{12000000, 11025, 1088, 0x19, 0x1},
451abadfc92SRichard Purdie 
452abadfc92SRichard Purdie 	/* 16k */
453abadfc92SRichard Purdie 	{12288000, 16000, 768, 0xa, 0x0},
454abadfc92SRichard Purdie 	{18432000, 16000, 1152, 0xb, 0x0},
455abadfc92SRichard Purdie 	{12000000, 16000, 750, 0xa, 0x1},
456abadfc92SRichard Purdie 
457abadfc92SRichard Purdie 	/* 22.05k */
458abadfc92SRichard Purdie 	{11289600, 22050, 512, 0x1a, 0x0},
459abadfc92SRichard Purdie 	{16934400, 22050, 768, 0x1b, 0x0},
460abadfc92SRichard Purdie 	{12000000, 22050, 544, 0x1b, 0x1},
461abadfc92SRichard Purdie 
462abadfc92SRichard Purdie 	/* 32k */
463abadfc92SRichard Purdie 	{12288000, 32000, 384, 0xc, 0x0},
464abadfc92SRichard Purdie 	{18432000, 32000, 576, 0xd, 0x0},
465abadfc92SRichard Purdie 	{12000000, 32000, 375, 0xa, 0x1},
466abadfc92SRichard Purdie 
467abadfc92SRichard Purdie 	/* 44.1k */
468abadfc92SRichard Purdie 	{11289600, 44100, 256, 0x10, 0x0},
469abadfc92SRichard Purdie 	{16934400, 44100, 384, 0x11, 0x0},
470abadfc92SRichard Purdie 	{12000000, 44100, 272, 0x11, 0x1},
471abadfc92SRichard Purdie 
472abadfc92SRichard Purdie 	/* 48k */
473abadfc92SRichard Purdie 	{12288000, 48000, 256, 0x0, 0x0},
474abadfc92SRichard Purdie 	{18432000, 48000, 384, 0x1, 0x0},
475abadfc92SRichard Purdie 	{12000000, 48000, 250, 0x0, 0x1},
476abadfc92SRichard Purdie 
477abadfc92SRichard Purdie 	/* 88.2k */
478abadfc92SRichard Purdie 	{11289600, 88200, 128, 0x1e, 0x0},
479abadfc92SRichard Purdie 	{16934400, 88200, 192, 0x1f, 0x0},
480abadfc92SRichard Purdie 	{12000000, 88200, 136, 0x1f, 0x1},
481abadfc92SRichard Purdie 
482abadfc92SRichard Purdie 	/* 96k */
483abadfc92SRichard Purdie 	{12288000, 96000, 128, 0xe, 0x0},
484abadfc92SRichard Purdie 	{18432000, 96000, 192, 0xf, 0x0},
485abadfc92SRichard Purdie 	{12000000, 96000, 125, 0xe, 0x1},
486abadfc92SRichard Purdie };
487abadfc92SRichard Purdie 
488abadfc92SRichard Purdie static inline int get_coeff(int mclk, int rate)
489abadfc92SRichard Purdie {
490abadfc92SRichard Purdie 	int i;
491abadfc92SRichard Purdie 
492abadfc92SRichard Purdie 	for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
493abadfc92SRichard Purdie 		if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
494abadfc92SRichard Purdie 			return i;
495abadfc92SRichard Purdie 	}
496a71a468aSLiam Girdwood 
497a71a468aSLiam Girdwood 	printk(KERN_ERR "wm8750: could not get coeff for mclk %d @ rate %d\n",
498a71a468aSLiam Girdwood 		mclk, rate);
499abadfc92SRichard Purdie 	return -EINVAL;
500abadfc92SRichard Purdie }
501abadfc92SRichard Purdie 
502e550e17fSLiam Girdwood static int wm8750_set_dai_sysclk(struct snd_soc_dai *codec_dai,
5034422b606SLiam Girdwood 		int clk_id, unsigned int freq, int dir)
504abadfc92SRichard Purdie {
505*f081a227SKuninori Morimoto 	struct snd_soc_component *component = codec_dai->component;
506*f081a227SKuninori Morimoto 	struct wm8750_priv *wm8750 = snd_soc_component_get_drvdata(component);
5074422b606SLiam Girdwood 
5084422b606SLiam Girdwood 	switch (freq) {
5094422b606SLiam Girdwood 	case 11289600:
5104422b606SLiam Girdwood 	case 12000000:
5114422b606SLiam Girdwood 	case 12288000:
5124422b606SLiam Girdwood 	case 16934400:
5134422b606SLiam Girdwood 	case 18432000:
5144422b606SLiam Girdwood 		wm8750->sysclk = freq;
5154422b606SLiam Girdwood 		return 0;
5164422b606SLiam Girdwood 	}
5174422b606SLiam Girdwood 	return -EINVAL;
518abadfc92SRichard Purdie }
519abadfc92SRichard Purdie 
520e550e17fSLiam Girdwood static int wm8750_set_dai_fmt(struct snd_soc_dai *codec_dai,
5214422b606SLiam Girdwood 		unsigned int fmt)
522abadfc92SRichard Purdie {
523*f081a227SKuninori Morimoto 	struct snd_soc_component *component = codec_dai->component;
5244422b606SLiam Girdwood 	u16 iface = 0;
525abadfc92SRichard Purdie 
526abadfc92SRichard Purdie 	/* set master/slave audio interface */
5274422b606SLiam Girdwood 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
528abadfc92SRichard Purdie 	case SND_SOC_DAIFMT_CBM_CFM:
529abadfc92SRichard Purdie 		iface = 0x0040;
530abadfc92SRichard Purdie 		break;
531abadfc92SRichard Purdie 	case SND_SOC_DAIFMT_CBS_CFS:
532abadfc92SRichard Purdie 		break;
5334422b606SLiam Girdwood 	default:
5344422b606SLiam Girdwood 		return -EINVAL;
535abadfc92SRichard Purdie 	}
536abadfc92SRichard Purdie 
537abadfc92SRichard Purdie 	/* interface format */
5384422b606SLiam Girdwood 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
539abadfc92SRichard Purdie 	case SND_SOC_DAIFMT_I2S:
540abadfc92SRichard Purdie 		iface |= 0x0002;
541abadfc92SRichard Purdie 		break;
542abadfc92SRichard Purdie 	case SND_SOC_DAIFMT_RIGHT_J:
543abadfc92SRichard Purdie 		break;
544abadfc92SRichard Purdie 	case SND_SOC_DAIFMT_LEFT_J:
545abadfc92SRichard Purdie 		iface |= 0x0001;
546abadfc92SRichard Purdie 		break;
547abadfc92SRichard Purdie 	case SND_SOC_DAIFMT_DSP_A:
548abadfc92SRichard Purdie 		iface |= 0x0003;
549abadfc92SRichard Purdie 		break;
550abadfc92SRichard Purdie 	case SND_SOC_DAIFMT_DSP_B:
551abadfc92SRichard Purdie 		iface |= 0x0013;
552abadfc92SRichard Purdie 		break;
5534422b606SLiam Girdwood 	default:
5544422b606SLiam Girdwood 		return -EINVAL;
555abadfc92SRichard Purdie 	}
556abadfc92SRichard Purdie 
557abadfc92SRichard Purdie 	/* clock inversion */
5584422b606SLiam Girdwood 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
559abadfc92SRichard Purdie 	case SND_SOC_DAIFMT_NB_NF:
560abadfc92SRichard Purdie 		break;
561abadfc92SRichard Purdie 	case SND_SOC_DAIFMT_IB_IF:
562abadfc92SRichard Purdie 		iface |= 0x0090;
563abadfc92SRichard Purdie 		break;
564abadfc92SRichard Purdie 	case SND_SOC_DAIFMT_IB_NF:
565abadfc92SRichard Purdie 		iface |= 0x0080;
566abadfc92SRichard Purdie 		break;
567abadfc92SRichard Purdie 	case SND_SOC_DAIFMT_NB_IF:
568abadfc92SRichard Purdie 		iface |= 0x0010;
569abadfc92SRichard Purdie 		break;
5704422b606SLiam Girdwood 	default:
5714422b606SLiam Girdwood 		return -EINVAL;
572abadfc92SRichard Purdie 	}
573abadfc92SRichard Purdie 
574*f081a227SKuninori Morimoto 	snd_soc_component_write(component, WM8750_IFACE, iface);
5754422b606SLiam Girdwood 	return 0;
5764422b606SLiam Girdwood }
5774422b606SLiam Girdwood 
5784422b606SLiam Girdwood static int wm8750_pcm_hw_params(struct snd_pcm_substream *substream,
579dee89c4dSMark Brown 				struct snd_pcm_hw_params *params,
580dee89c4dSMark Brown 				struct snd_soc_dai *dai)
5814422b606SLiam Girdwood {
582*f081a227SKuninori Morimoto 	struct snd_soc_component *component = dai->component;
583*f081a227SKuninori Morimoto 	struct wm8750_priv *wm8750 = snd_soc_component_get_drvdata(component);
584*f081a227SKuninori Morimoto 	u16 iface = snd_soc_component_read32(component, WM8750_IFACE) & 0x1f3;
585*f081a227SKuninori Morimoto 	u16 srate = snd_soc_component_read32(component, WM8750_SRATE) & 0x1c0;
5864422b606SLiam Girdwood 	int coeff = get_coeff(wm8750->sysclk, params_rate(params));
5874422b606SLiam Girdwood 
5884422b606SLiam Girdwood 	/* bit size */
5897e322dffSMark Brown 	switch (params_width(params)) {
5907e322dffSMark Brown 	case 16:
591abadfc92SRichard Purdie 		break;
5927e322dffSMark Brown 	case 20:
5934422b606SLiam Girdwood 		iface |= 0x0004;
594abadfc92SRichard Purdie 		break;
5957e322dffSMark Brown 	case 24:
5964422b606SLiam Girdwood 		iface |= 0x0008;
597abadfc92SRichard Purdie 		break;
5987e322dffSMark Brown 	case 32:
5994422b606SLiam Girdwood 		iface |= 0x000c;
600abadfc92SRichard Purdie 		break;
601abadfc92SRichard Purdie 	}
602abadfc92SRichard Purdie 
603abadfc92SRichard Purdie 	/* set iface & srate */
604*f081a227SKuninori Morimoto 	snd_soc_component_write(component, WM8750_IFACE, iface);
6054422b606SLiam Girdwood 	if (coeff >= 0)
606*f081a227SKuninori Morimoto 		snd_soc_component_write(component, WM8750_SRATE, srate |
6074422b606SLiam Girdwood 			(coeff_div[coeff].sr << 1) | coeff_div[coeff].usb);
608abadfc92SRichard Purdie 
609abadfc92SRichard Purdie 	return 0;
610abadfc92SRichard Purdie }
611abadfc92SRichard Purdie 
612e550e17fSLiam Girdwood static int wm8750_mute(struct snd_soc_dai *dai, int mute)
613abadfc92SRichard Purdie {
614*f081a227SKuninori Morimoto 	struct snd_soc_component *component = dai->component;
615*f081a227SKuninori Morimoto 	u16 mute_reg = snd_soc_component_read32(component, WM8750_ADCDAC) & 0xfff7;
6164422b606SLiam Girdwood 
617abadfc92SRichard Purdie 	if (mute)
618*f081a227SKuninori Morimoto 		snd_soc_component_write(component, WM8750_ADCDAC, mute_reg | 0x8);
619abadfc92SRichard Purdie 	else
620*f081a227SKuninori Morimoto 		snd_soc_component_write(component, WM8750_ADCDAC, mute_reg);
621abadfc92SRichard Purdie 	return 0;
622abadfc92SRichard Purdie }
623abadfc92SRichard Purdie 
624*f081a227SKuninori Morimoto static int wm8750_set_bias_level(struct snd_soc_component *component,
6250be9898aSMark Brown 				 enum snd_soc_bias_level level)
626abadfc92SRichard Purdie {
627*f081a227SKuninori Morimoto 	u16 pwr_reg = snd_soc_component_read32(component, WM8750_PWR1) & 0xfe3e;
628abadfc92SRichard Purdie 
6290be9898aSMark Brown 	switch (level) {
6300be9898aSMark Brown 	case SND_SOC_BIAS_ON:
631abadfc92SRichard Purdie 		/* set vmid to 50k and unmute dac */
632*f081a227SKuninori Morimoto 		snd_soc_component_write(component, WM8750_PWR1, pwr_reg | 0x00c0);
633abadfc92SRichard Purdie 		break;
6340be9898aSMark Brown 	case SND_SOC_BIAS_PREPARE:
635abadfc92SRichard Purdie 		break;
6360be9898aSMark Brown 	case SND_SOC_BIAS_STANDBY:
637*f081a227SKuninori Morimoto 		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
638*f081a227SKuninori Morimoto 			snd_soc_component_cache_sync(component);
6394d4adfc9SAxel Lin 
640dd76769dSMark Brown 			/* Set VMID to 5k */
641*f081a227SKuninori Morimoto 			snd_soc_component_write(component, WM8750_PWR1, pwr_reg | 0x01c1);
642dd76769dSMark Brown 
643dd76769dSMark Brown 			/* ...and ramp */
644dd76769dSMark Brown 			msleep(1000);
645dd76769dSMark Brown 		}
646dd76769dSMark Brown 
647abadfc92SRichard Purdie 		/* mute dac and set vmid to 500k, enable VREF */
648*f081a227SKuninori Morimoto 		snd_soc_component_write(component, WM8750_PWR1, pwr_reg | 0x0141);
649abadfc92SRichard Purdie 		break;
6500be9898aSMark Brown 	case SND_SOC_BIAS_OFF:
651*f081a227SKuninori Morimoto 		snd_soc_component_write(component, WM8750_PWR1, 0x0001);
652abadfc92SRichard Purdie 		break;
653abadfc92SRichard Purdie 	}
654abadfc92SRichard Purdie 	return 0;
655abadfc92SRichard Purdie }
656abadfc92SRichard Purdie 
6574422b606SLiam Girdwood #define WM8750_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
6584422b606SLiam Girdwood 	SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \
6594422b606SLiam Girdwood 	SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
6604422b606SLiam Girdwood 
6614422b606SLiam Girdwood #define WM8750_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
6624422b606SLiam Girdwood 	SNDRV_PCM_FMTBIT_S24_LE)
6634422b606SLiam Girdwood 
66485e7652dSLars-Peter Clausen static const struct snd_soc_dai_ops wm8750_dai_ops = {
6656335d055SEric Miao 	.hw_params	= wm8750_pcm_hw_params,
6666335d055SEric Miao 	.digital_mute	= wm8750_mute,
6676335d055SEric Miao 	.set_fmt	= wm8750_set_dai_fmt,
6686335d055SEric Miao 	.set_sysclk	= wm8750_set_dai_sysclk,
6696335d055SEric Miao };
6706335d055SEric Miao 
671f0fba2adSLiam Girdwood static struct snd_soc_dai_driver wm8750_dai = {
672f0fba2adSLiam Girdwood 	.name = "wm8750-hifi",
673abadfc92SRichard Purdie 	.playback = {
674abadfc92SRichard Purdie 		.stream_name = "Playback",
675abadfc92SRichard Purdie 		.channels_min = 1,
676abadfc92SRichard Purdie 		.channels_max = 2,
6774422b606SLiam Girdwood 		.rates = WM8750_RATES,
6784422b606SLiam Girdwood 		.formats = WM8750_FORMATS,},
679abadfc92SRichard Purdie 	.capture = {
680abadfc92SRichard Purdie 		.stream_name = "Capture",
681abadfc92SRichard Purdie 		.channels_min = 1,
682abadfc92SRichard Purdie 		.channels_max = 2,
6834422b606SLiam Girdwood 		.rates = WM8750_RATES,
6844422b606SLiam Girdwood 		.formats = WM8750_FORMATS,},
6856335d055SEric Miao 	.ops = &wm8750_dai_ops,
686abadfc92SRichard Purdie };
687abadfc92SRichard Purdie 
688*f081a227SKuninori Morimoto static int wm8750_probe(struct snd_soc_component *component)
6896ca0c22eSMarek Vasut {
690f5b00d02SAxel Lin 	int ret;
6916ca0c22eSMarek Vasut 
692*f081a227SKuninori Morimoto 	ret = wm8750_reset(component);
69317a52fd6SMark Brown 	if (ret < 0) {
69417a52fd6SMark Brown 		printk(KERN_ERR "wm8750: failed to reset: %d\n", ret);
695f0fba2adSLiam Girdwood 		return ret;
69617a52fd6SMark Brown 	}
697abadfc92SRichard Purdie 
698abadfc92SRichard Purdie 	/* set the update bits */
699*f081a227SKuninori Morimoto 	snd_soc_component_update_bits(component, WM8750_LDAC, 0x0100, 0x0100);
700*f081a227SKuninori Morimoto 	snd_soc_component_update_bits(component, WM8750_RDAC, 0x0100, 0x0100);
701*f081a227SKuninori Morimoto 	snd_soc_component_update_bits(component, WM8750_LOUT1V, 0x0100, 0x0100);
702*f081a227SKuninori Morimoto 	snd_soc_component_update_bits(component, WM8750_ROUT1V, 0x0100, 0x0100);
703*f081a227SKuninori Morimoto 	snd_soc_component_update_bits(component, WM8750_LOUT2V, 0x0100, 0x0100);
704*f081a227SKuninori Morimoto 	snd_soc_component_update_bits(component, WM8750_ROUT2V, 0x0100, 0x0100);
705*f081a227SKuninori Morimoto 	snd_soc_component_update_bits(component, WM8750_LINVOL, 0x0100, 0x0100);
706*f081a227SKuninori Morimoto 	snd_soc_component_update_bits(component, WM8750_RINVOL, 0x0100, 0x0100);
707abadfc92SRichard Purdie 
708abadfc92SRichard Purdie 	return ret;
709abadfc92SRichard Purdie }
710abadfc92SRichard Purdie 
711*f081a227SKuninori Morimoto static const struct snd_soc_component_driver soc_component_dev_wm8750 = {
712f0fba2adSLiam Girdwood 	.probe			= wm8750_probe,
713f0fba2adSLiam Girdwood 	.set_bias_level		= wm8750_set_bias_level,
7140f185e3fSMark Brown 	.controls		= wm8750_snd_controls,
7150f185e3fSMark Brown 	.num_controls		= ARRAY_SIZE(wm8750_snd_controls),
7160f185e3fSMark Brown 	.dapm_widgets		= wm8750_dapm_widgets,
7170f185e3fSMark Brown 	.num_dapm_widgets	= ARRAY_SIZE(wm8750_dapm_widgets),
7180f185e3fSMark Brown 	.dapm_routes		= wm8750_dapm_routes,
7190f185e3fSMark Brown 	.num_dapm_routes	= ARRAY_SIZE(wm8750_dapm_routes),
720*f081a227SKuninori Morimoto 	.suspend_bias_off	= 1,
721*f081a227SKuninori Morimoto 	.idle_bias_on		= 1,
722*f081a227SKuninori Morimoto 	.use_pmdown_time	= 1,
723*f081a227SKuninori Morimoto 	.endianness		= 1,
724*f081a227SKuninori Morimoto 	.non_legacy_dai_naming	= 1,
725f0fba2adSLiam Girdwood };
726abadfc92SRichard Purdie 
727ce31a0f5SMark Brown static const struct of_device_id wm8750_of_match[] = {
728ce31a0f5SMark Brown 	{ .compatible = "wlf,wm8750", },
729ce31a0f5SMark Brown 	{ .compatible = "wlf,wm8987", },
730ce31a0f5SMark Brown 	{ }
731ce31a0f5SMark Brown };
732ce31a0f5SMark Brown MODULE_DEVICE_TABLE(of, wm8750_of_match);
733ce31a0f5SMark Brown 
734ed79edacSMark Brown static const struct regmap_config wm8750_regmap = {
735ed79edacSMark Brown 	.reg_bits = 7,
736ed79edacSMark Brown 	.val_bits = 9,
737ed79edacSMark Brown 	.max_register = WM8750_MOUTV,
738ed79edacSMark Brown 
739ed79edacSMark Brown 	.reg_defaults = wm8750_reg_defaults,
740ed79edacSMark Brown 	.num_reg_defaults = ARRAY_SIZE(wm8750_reg_defaults),
741ed79edacSMark Brown 	.cache_type = REGCACHE_RBTREE,
742ed79edacSMark Brown };
743ed79edacSMark Brown 
744f0fba2adSLiam Girdwood #if defined(CONFIG_SPI_MASTER)
7457a79e94eSBill Pemberton static int wm8750_spi_probe(struct spi_device *spi)
746abadfc92SRichard Purdie {
7476ca0c22eSMarek Vasut 	struct wm8750_priv *wm8750;
748ed79edacSMark Brown 	struct regmap *regmap;
749f0fba2adSLiam Girdwood 	int ret;
750abadfc92SRichard Purdie 
7512edaed82SMark Brown 	wm8750 = devm_kzalloc(&spi->dev, sizeof(struct wm8750_priv),
7522edaed82SMark Brown 			      GFP_KERNEL);
7536ca0c22eSMarek Vasut 	if (wm8750 == NULL)
7546ca0c22eSMarek Vasut 		return -ENOMEM;
7556ca0c22eSMarek Vasut 
756ed79edacSMark Brown 	regmap = devm_regmap_init_spi(spi, &wm8750_regmap);
757ed79edacSMark Brown 	if (IS_ERR(regmap))
758ed79edacSMark Brown 		return PTR_ERR(regmap);
759ed79edacSMark Brown 
760f0fba2adSLiam Girdwood 	spi_set_drvdata(spi, wm8750);
761abadfc92SRichard Purdie 
762*f081a227SKuninori Morimoto 	ret = devm_snd_soc_register_component(&spi->dev,
763*f081a227SKuninori Morimoto 			&soc_component_dev_wm8750, &wm8750_dai, 1);
764f0fba2adSLiam Girdwood 	return ret;
765abadfc92SRichard Purdie }
766abadfc92SRichard Purdie 
76740045a85SMark Brown static const struct spi_device_id wm8750_spi_ids[] = {
76840045a85SMark Brown 	{ "wm8750", 0 },
76940045a85SMark Brown 	{ "wm8987", 0 },
770f6b864a9STakashi Iwai 	{ },
77140045a85SMark Brown };
772511d8cf0SMark Brown MODULE_DEVICE_TABLE(spi, wm8750_spi_ids);
77340045a85SMark Brown 
774f0fba2adSLiam Girdwood static struct spi_driver wm8750_spi_driver = {
775f0fba2adSLiam Girdwood 	.driver = {
776dc5de62bSMark Brown 		.name	= "wm8750",
777ce31a0f5SMark Brown 		.of_match_table = wm8750_of_match,
778f0fba2adSLiam Girdwood 	},
77940045a85SMark Brown 	.id_table	= wm8750_spi_ids,
780f0fba2adSLiam Girdwood 	.probe		= wm8750_spi_probe,
781f0fba2adSLiam Girdwood };
782f0fba2adSLiam Girdwood #endif /* CONFIG_SPI_MASTER */
783f0fba2adSLiam Girdwood 
7849ea6fbc6SFabio Estevam #if IS_ENABLED(CONFIG_I2C)
7857a79e94eSBill Pemberton static int wm8750_i2c_probe(struct i2c_client *i2c,
786f0fba2adSLiam Girdwood 			    const struct i2c_device_id *id)
787f0fba2adSLiam Girdwood {
788f0fba2adSLiam Girdwood 	struct wm8750_priv *wm8750;
789ed79edacSMark Brown 	struct regmap *regmap;
790f0fba2adSLiam Girdwood 	int ret;
791f0fba2adSLiam Girdwood 
7922edaed82SMark Brown 	wm8750 = devm_kzalloc(&i2c->dev, sizeof(struct wm8750_priv),
7932edaed82SMark Brown 			      GFP_KERNEL);
794f0fba2adSLiam Girdwood 	if (wm8750 == NULL)
795f0fba2adSLiam Girdwood 		return -ENOMEM;
796f0fba2adSLiam Girdwood 
797f0fba2adSLiam Girdwood 	i2c_set_clientdata(i2c, wm8750);
798ed79edacSMark Brown 
799ed79edacSMark Brown 	regmap = devm_regmap_init_i2c(i2c, &wm8750_regmap);
800ed79edacSMark Brown 	if (IS_ERR(regmap))
801ed79edacSMark Brown 		return PTR_ERR(regmap);
802f0fba2adSLiam Girdwood 
803*f081a227SKuninori Morimoto 	ret = devm_snd_soc_register_component(&i2c->dev,
804*f081a227SKuninori Morimoto 			&soc_component_dev_wm8750, &wm8750_dai, 1);
805f0fba2adSLiam Girdwood 	return ret;
806f0fba2adSLiam Girdwood }
807f0fba2adSLiam Girdwood 
808ee1d0099SJean Delvare static const struct i2c_device_id wm8750_i2c_id[] = {
809ee1d0099SJean Delvare 	{ "wm8750", 0 },
810f0fba2adSLiam Girdwood 	{ "wm8987", 0 },
811ee1d0099SJean Delvare 	{ }
812ee1d0099SJean Delvare };
813ee1d0099SJean Delvare MODULE_DEVICE_TABLE(i2c, wm8750_i2c_id);
814abadfc92SRichard Purdie 
815abadfc92SRichard Purdie static struct i2c_driver wm8750_i2c_driver = {
816abadfc92SRichard Purdie 	.driver = {
817dc5de62bSMark Brown 		.name = "wm8750",
818ce31a0f5SMark Brown 		.of_match_table = wm8750_of_match,
819abadfc92SRichard Purdie 	},
820ee1d0099SJean Delvare 	.probe =    wm8750_i2c_probe,
821ee1d0099SJean Delvare 	.id_table = wm8750_i2c_id,
822abadfc92SRichard Purdie };
823abadfc92SRichard Purdie #endif
824abadfc92SRichard Purdie 
825c9b3a40fSTakashi Iwai static int __init wm8750_modinit(void)
82664089b84SMark Brown {
827f0fba2adSLiam Girdwood 	int ret = 0;
8289ea6fbc6SFabio Estevam #if IS_ENABLED(CONFIG_I2C)
8296ca0c22eSMarek Vasut 	ret = i2c_add_driver(&wm8750_i2c_driver);
830f0fba2adSLiam Girdwood 	if (ret != 0) {
831f0fba2adSLiam Girdwood 		printk(KERN_ERR "Failed to register wm8750 I2C driver: %d\n",
832f0fba2adSLiam Girdwood 		       ret);
833f0fba2adSLiam Girdwood 	}
8346ca0c22eSMarek Vasut #endif
8356ca0c22eSMarek Vasut #if defined(CONFIG_SPI_MASTER)
8366ca0c22eSMarek Vasut 	ret = spi_register_driver(&wm8750_spi_driver);
837f0fba2adSLiam Girdwood 	if (ret != 0) {
838f0fba2adSLiam Girdwood 		printk(KERN_ERR "Failed to register wm8750 SPI driver: %d\n",
839f0fba2adSLiam Girdwood 		       ret);
840f0fba2adSLiam Girdwood 	}
8416ca0c22eSMarek Vasut #endif
842f0fba2adSLiam Girdwood 	return ret;
84364089b84SMark Brown }
84464089b84SMark Brown module_init(wm8750_modinit);
84564089b84SMark Brown 
84664089b84SMark Brown static void __exit wm8750_exit(void)
84764089b84SMark Brown {
8489ea6fbc6SFabio Estevam #if IS_ENABLED(CONFIG_I2C)
8496ca0c22eSMarek Vasut 	i2c_del_driver(&wm8750_i2c_driver);
8506ca0c22eSMarek Vasut #endif
8516ca0c22eSMarek Vasut #if defined(CONFIG_SPI_MASTER)
8526ca0c22eSMarek Vasut 	spi_unregister_driver(&wm8750_spi_driver);
8536ca0c22eSMarek Vasut #endif
85464089b84SMark Brown }
85564089b84SMark Brown module_exit(wm8750_exit);
85664089b84SMark Brown 
857abadfc92SRichard Purdie MODULE_DESCRIPTION("ASoC WM8750 driver");
858abadfc92SRichard Purdie MODULE_AUTHOR("Liam Girdwood");
859abadfc92SRichard Purdie MODULE_LICENSE("GPL");
860