1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * wm8960.c -- WM8960 ALSA SoC Audio driver |
4 | * |
5 | * Copyright 2007-11 Wolfson Microelectronics, plc |
6 | * |
7 | * Author: Liam Girdwood |
8 | */ |
9 | |
10 | #include <linux/module.h> |
11 | #include <linux/moduleparam.h> |
12 | #include <linux/init.h> |
13 | #include <linux/delay.h> |
14 | #include <linux/pm.h> |
15 | #include <linux/clk.h> |
16 | #include <linux/i2c.h> |
17 | #include <linux/acpi.h> |
18 | #include <linux/slab.h> |
19 | #include <sound/core.h> |
20 | #include <sound/pcm.h> |
21 | #include <sound/pcm_params.h> |
22 | #include <sound/soc.h> |
23 | #include <sound/initval.h> |
24 | #include <sound/tlv.h> |
25 | #include <sound/wm8960.h> |
26 | |
27 | #include "wm8960.h" |
28 | |
29 | /* R25 - Power 1 */ |
30 | #define WM8960_VMID_MASK 0x180 |
31 | #define WM8960_VREF 0x40 |
32 | |
33 | /* R26 - Power 2 */ |
34 | #define WM8960_PWR2_LOUT1 0x40 |
35 | #define WM8960_PWR2_ROUT1 0x20 |
36 | #define WM8960_PWR2_OUT3 0x02 |
37 | |
38 | /* R28 - Anti-pop 1 */ |
39 | #define WM8960_POBCTRL 0x80 |
40 | #define WM8960_BUFDCOPEN 0x10 |
41 | #define WM8960_BUFIOEN 0x08 |
42 | #define WM8960_SOFT_ST 0x04 |
43 | #define WM8960_HPSTBY 0x01 |
44 | |
45 | /* R29 - Anti-pop 2 */ |
46 | #define WM8960_DISOP 0x40 |
47 | #define WM8960_DRES_MASK 0x30 |
48 | |
49 | #define WM8960_DSCH_TOUT 600 /* discharge timeout, ms */ |
50 | |
51 | static bool is_pll_freq_available(unsigned int source, unsigned int target); |
52 | static int wm8960_set_pll(struct snd_soc_component *component, |
53 | unsigned int freq_in, unsigned int freq_out); |
54 | /* |
55 | * wm8960 register cache |
56 | * We can't read the WM8960 register space when we are |
57 | * using 2 wire for device control, so we cache them instead. |
58 | */ |
59 | static const struct reg_default wm8960_reg_defaults[] = { |
60 | { 0x0, 0x00a7 }, |
61 | { 0x1, 0x00a7 }, |
62 | { 0x2, 0x0000 }, |
63 | { 0x3, 0x0000 }, |
64 | { 0x4, 0x0000 }, |
65 | { 0x5, 0x0008 }, |
66 | { 0x6, 0x0000 }, |
67 | { 0x7, 0x000a }, |
68 | { 0x8, 0x01c0 }, |
69 | { 0x9, 0x0000 }, |
70 | { 0xa, 0x00ff }, |
71 | { 0xb, 0x00ff }, |
72 | |
73 | { 0x10, 0x0000 }, |
74 | { 0x11, 0x007b }, |
75 | { 0x12, 0x0100 }, |
76 | { 0x13, 0x0032 }, |
77 | { 0x14, 0x0000 }, |
78 | { 0x15, 0x00c3 }, |
79 | { 0x16, 0x00c3 }, |
80 | { 0x17, 0x01c0 }, |
81 | { 0x18, 0x0000 }, |
82 | { 0x19, 0x0000 }, |
83 | { 0x1a, 0x0000 }, |
84 | { 0x1b, 0x0000 }, |
85 | { 0x1c, 0x0000 }, |
86 | { 0x1d, 0x0000 }, |
87 | |
88 | { 0x20, 0x0100 }, |
89 | { 0x21, 0x0100 }, |
90 | { 0x22, 0x0050 }, |
91 | |
92 | { 0x25, 0x0050 }, |
93 | { 0x26, 0x0000 }, |
94 | { 0x27, 0x0000 }, |
95 | { 0x28, 0x0000 }, |
96 | { 0x29, 0x0000 }, |
97 | { 0x2a, 0x0040 }, |
98 | { 0x2b, 0x0000 }, |
99 | { 0x2c, 0x0000 }, |
100 | { 0x2d, 0x0050 }, |
101 | { 0x2e, 0x0050 }, |
102 | { 0x2f, 0x0000 }, |
103 | { 0x30, 0x0002 }, |
104 | { 0x31, 0x0037 }, |
105 | |
106 | { 0x33, 0x0080 }, |
107 | { 0x34, 0x0008 }, |
108 | { 0x35, 0x0031 }, |
109 | { 0x36, 0x0026 }, |
110 | { 0x37, 0x00e9 }, |
111 | }; |
112 | |
113 | static bool wm8960_volatile(struct device *dev, unsigned int reg) |
114 | { |
115 | switch (reg) { |
116 | case WM8960_RESET: |
117 | return true; |
118 | default: |
119 | return false; |
120 | } |
121 | } |
122 | |
123 | #define WM8960_NUM_SUPPLIES 5 |
124 | static const char *wm8960_supply_names[WM8960_NUM_SUPPLIES] = { |
125 | "DCVDD" , |
126 | "DBVDD" , |
127 | "AVDD" , |
128 | "SPKVDD1" , |
129 | "SPKVDD2" , |
130 | }; |
131 | |
132 | struct wm8960_priv { |
133 | struct clk *mclk; |
134 | struct regmap *regmap; |
135 | int (*set_bias_level)(struct snd_soc_component *, |
136 | enum snd_soc_bias_level level); |
137 | struct snd_soc_dapm_widget *lout1; |
138 | struct snd_soc_dapm_widget *rout1; |
139 | struct snd_soc_dapm_widget *out3; |
140 | bool deemph; |
141 | int lrclk; |
142 | int bclk; |
143 | int sysclk; |
144 | int clk_id; |
145 | int freq_in; |
146 | bool is_stream_in_use[2]; |
147 | struct wm8960_data pdata; |
148 | ktime_t dsch_start; |
149 | struct regulator_bulk_data supplies[WM8960_NUM_SUPPLIES]; |
150 | }; |
151 | |
152 | #define wm8960_reset(c) regmap_write(c, WM8960_RESET, 0) |
153 | |
154 | /* enumerated controls */ |
155 | static const char *wm8960_polarity[] = {"No Inversion" , "Left Inverted" , |
156 | "Right Inverted" , "Stereo Inversion" }; |
157 | static const char *wm8960_3d_upper_cutoff[] = {"High" , "Low" }; |
158 | static const char *wm8960_3d_lower_cutoff[] = {"Low" , "High" }; |
159 | static const char *wm8960_alcfunc[] = {"Off" , "Right" , "Left" , "Stereo" }; |
160 | static const char *wm8960_alcmode[] = {"ALC" , "Limiter" }; |
161 | static const char *wm8960_adc_data_output_sel[] = { |
162 | "Left Data = Left ADC; Right Data = Right ADC" , |
163 | "Left Data = Left ADC; Right Data = Left ADC" , |
164 | "Left Data = Right ADC; Right Data = Right ADC" , |
165 | "Left Data = Right ADC; Right Data = Left ADC" , |
166 | }; |
167 | static const char *wm8960_dmonomix[] = {"Stereo" , "Mono" }; |
168 | static const char *wm8960_dacslope[] = {"Normal" , "Sloping" }; |
169 | |
170 | static const struct soc_enum wm8960_enum[] = { |
171 | SOC_ENUM_SINGLE(WM8960_DACCTL1, 5, 4, wm8960_polarity), |
172 | SOC_ENUM_SINGLE(WM8960_DACCTL2, 5, 4, wm8960_polarity), |
173 | SOC_ENUM_SINGLE(WM8960_3D, 6, 2, wm8960_3d_upper_cutoff), |
174 | SOC_ENUM_SINGLE(WM8960_3D, 5, 2, wm8960_3d_lower_cutoff), |
175 | SOC_ENUM_SINGLE(WM8960_ALC1, 7, 4, wm8960_alcfunc), |
176 | SOC_ENUM_SINGLE(WM8960_ALC3, 8, 2, wm8960_alcmode), |
177 | SOC_ENUM_SINGLE(WM8960_ADDCTL1, 2, 4, wm8960_adc_data_output_sel), |
178 | SOC_ENUM_SINGLE(WM8960_ADDCTL1, 4, 2, wm8960_dmonomix), |
179 | SOC_ENUM_SINGLE(WM8960_DACCTL2, 1, 2, wm8960_dacslope), |
180 | }; |
181 | |
182 | static const int deemph_settings[] = { 0, 32000, 44100, 48000 }; |
183 | |
184 | static int wm8960_set_deemph(struct snd_soc_component *component) |
185 | { |
186 | struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(c: component); |
187 | int val, i, best; |
188 | |
189 | /* If we're using deemphasis select the nearest available sample |
190 | * rate. |
191 | */ |
192 | if (wm8960->deemph) { |
193 | best = 1; |
194 | for (i = 2; i < ARRAY_SIZE(deemph_settings); i++) { |
195 | if (abs(deemph_settings[i] - wm8960->lrclk) < |
196 | abs(deemph_settings[best] - wm8960->lrclk)) |
197 | best = i; |
198 | } |
199 | |
200 | val = best << 1; |
201 | } else { |
202 | val = 0; |
203 | } |
204 | |
205 | dev_dbg(component->dev, "Set deemphasis %d\n" , val); |
206 | |
207 | return snd_soc_component_update_bits(component, WM8960_DACCTL1, |
208 | mask: 0x6, val); |
209 | } |
210 | |
211 | static int wm8960_get_deemph(struct snd_kcontrol *kcontrol, |
212 | struct snd_ctl_elem_value *ucontrol) |
213 | { |
214 | struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
215 | struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(c: component); |
216 | |
217 | ucontrol->value.integer.value[0] = wm8960->deemph; |
218 | return 0; |
219 | } |
220 | |
221 | static int wm8960_put_deemph(struct snd_kcontrol *kcontrol, |
222 | struct snd_ctl_elem_value *ucontrol) |
223 | { |
224 | struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
225 | struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(c: component); |
226 | unsigned int deemph = ucontrol->value.integer.value[0]; |
227 | |
228 | if (deemph > 1) |
229 | return -EINVAL; |
230 | |
231 | wm8960->deemph = deemph; |
232 | |
233 | return wm8960_set_deemph(component); |
234 | } |
235 | |
236 | static const DECLARE_TLV_DB_SCALE(adc_tlv, -9750, 50, 1); |
237 | static const DECLARE_TLV_DB_SCALE(inpga_tlv, -1725, 75, 0); |
238 | static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1); |
239 | static const DECLARE_TLV_DB_SCALE(bypass_tlv, -2100, 300, 0); |
240 | static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1); |
241 | static const DECLARE_TLV_DB_SCALE(lineinboost_tlv, -1500, 300, 1); |
242 | static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(micboost_tlv, |
243 | 0, 1, TLV_DB_SCALE_ITEM(0, 1300, 0), |
244 | 2, 3, TLV_DB_SCALE_ITEM(2000, 900, 0), |
245 | ); |
246 | |
247 | static const struct snd_kcontrol_new wm8960_snd_controls[] = { |
248 | SOC_DOUBLE_R_TLV("Capture Volume" , WM8960_LINVOL, WM8960_RINVOL, |
249 | 0, 63, 0, inpga_tlv), |
250 | SOC_DOUBLE_R("Capture Volume ZC Switch" , WM8960_LINVOL, WM8960_RINVOL, |
251 | 6, 1, 0), |
252 | SOC_DOUBLE_R("Capture Switch" , WM8960_LINVOL, WM8960_RINVOL, |
253 | 7, 1, 1), |
254 | |
255 | SOC_SINGLE_TLV("Left Input Boost Mixer LINPUT3 Volume" , |
256 | WM8960_INBMIX1, 4, 7, 0, lineinboost_tlv), |
257 | SOC_SINGLE_TLV("Left Input Boost Mixer LINPUT2 Volume" , |
258 | WM8960_INBMIX1, 1, 7, 0, lineinboost_tlv), |
259 | SOC_SINGLE_TLV("Right Input Boost Mixer RINPUT3 Volume" , |
260 | WM8960_INBMIX2, 4, 7, 0, lineinboost_tlv), |
261 | SOC_SINGLE_TLV("Right Input Boost Mixer RINPUT2 Volume" , |
262 | WM8960_INBMIX2, 1, 7, 0, lineinboost_tlv), |
263 | SOC_SINGLE_TLV("Right Input Boost Mixer RINPUT1 Volume" , |
264 | WM8960_RINPATH, 4, 3, 0, micboost_tlv), |
265 | SOC_SINGLE_TLV("Left Input Boost Mixer LINPUT1 Volume" , |
266 | WM8960_LINPATH, 4, 3, 0, micboost_tlv), |
267 | |
268 | SOC_DOUBLE_R_TLV("Playback Volume" , WM8960_LDAC, WM8960_RDAC, |
269 | 0, 255, 0, dac_tlv), |
270 | |
271 | SOC_DOUBLE_R_TLV("Headphone Playback Volume" , WM8960_LOUT1, WM8960_ROUT1, |
272 | 0, 127, 0, out_tlv), |
273 | SOC_DOUBLE_R("Headphone Playback ZC Switch" , WM8960_LOUT1, WM8960_ROUT1, |
274 | 7, 1, 0), |
275 | |
276 | SOC_DOUBLE_R_TLV("Speaker Playback Volume" , WM8960_LOUT2, WM8960_ROUT2, |
277 | 0, 127, 0, out_tlv), |
278 | SOC_DOUBLE_R("Speaker Playback ZC Switch" , WM8960_LOUT2, WM8960_ROUT2, |
279 | 7, 1, 0), |
280 | SOC_SINGLE("Speaker DC Volume" , WM8960_CLASSD3, 3, 5, 0), |
281 | SOC_SINGLE("Speaker AC Volume" , WM8960_CLASSD3, 0, 5, 0), |
282 | |
283 | SOC_SINGLE("PCM Playback -6dB Switch" , WM8960_DACCTL1, 7, 1, 0), |
284 | SOC_ENUM("ADC Polarity" , wm8960_enum[0]), |
285 | SOC_SINGLE("ADC High Pass Filter Switch" , WM8960_DACCTL1, 0, 1, 0), |
286 | |
287 | SOC_ENUM("DAC Polarity" , wm8960_enum[1]), |
288 | SOC_SINGLE_BOOL_EXT("DAC Deemphasis Switch" , 0, |
289 | wm8960_get_deemph, wm8960_put_deemph), |
290 | |
291 | SOC_ENUM("3D Filter Upper Cut-Off" , wm8960_enum[2]), |
292 | SOC_ENUM("3D Filter Lower Cut-Off" , wm8960_enum[3]), |
293 | SOC_SINGLE("3D Volume" , WM8960_3D, 1, 15, 0), |
294 | SOC_SINGLE("3D Switch" , WM8960_3D, 0, 1, 0), |
295 | |
296 | SOC_ENUM("ALC Function" , wm8960_enum[4]), |
297 | SOC_SINGLE("ALC Max Gain" , WM8960_ALC1, 4, 7, 0), |
298 | SOC_SINGLE("ALC Target" , WM8960_ALC1, 0, 15, 1), |
299 | SOC_SINGLE("ALC Min Gain" , WM8960_ALC2, 4, 7, 0), |
300 | SOC_SINGLE("ALC Hold Time" , WM8960_ALC2, 0, 15, 0), |
301 | SOC_ENUM("ALC Mode" , wm8960_enum[5]), |
302 | SOC_SINGLE("ALC Decay" , WM8960_ALC3, 4, 15, 0), |
303 | SOC_SINGLE("ALC Attack" , WM8960_ALC3, 0, 15, 0), |
304 | |
305 | SOC_SINGLE("Noise Gate Threshold" , WM8960_NOISEG, 3, 31, 0), |
306 | SOC_SINGLE("Noise Gate Switch" , WM8960_NOISEG, 0, 1, 0), |
307 | |
308 | SOC_DOUBLE_R_TLV("ADC PCM Capture Volume" , WM8960_LADC, WM8960_RADC, |
309 | 0, 255, 0, adc_tlv), |
310 | |
311 | SOC_SINGLE_TLV("Left Output Mixer Boost Bypass Volume" , |
312 | WM8960_BYPASS1, 4, 7, 1, bypass_tlv), |
313 | SOC_SINGLE_TLV("Left Output Mixer LINPUT3 Volume" , |
314 | WM8960_LOUTMIX, 4, 7, 1, bypass_tlv), |
315 | SOC_SINGLE_TLV("Right Output Mixer Boost Bypass Volume" , |
316 | WM8960_BYPASS2, 4, 7, 1, bypass_tlv), |
317 | SOC_SINGLE_TLV("Right Output Mixer RINPUT3 Volume" , |
318 | WM8960_ROUTMIX, 4, 7, 1, bypass_tlv), |
319 | |
320 | SOC_ENUM("ADC Data Output Select" , wm8960_enum[6]), |
321 | SOC_ENUM("DAC Mono Mix" , wm8960_enum[7]), |
322 | SOC_ENUM("DAC Filter Characteristics" , wm8960_enum[8]), |
323 | }; |
324 | |
325 | static const struct snd_kcontrol_new wm8960_lin_boost[] = { |
326 | SOC_DAPM_SINGLE("LINPUT2 Switch" , WM8960_LINPATH, 6, 1, 0), |
327 | SOC_DAPM_SINGLE("LINPUT3 Switch" , WM8960_LINPATH, 7, 1, 0), |
328 | SOC_DAPM_SINGLE("LINPUT1 Switch" , WM8960_LINPATH, 8, 1, 0), |
329 | }; |
330 | |
331 | static const struct snd_kcontrol_new wm8960_lin[] = { |
332 | SOC_DAPM_SINGLE("Boost Switch" , WM8960_LINPATH, 3, 1, 0), |
333 | }; |
334 | |
335 | static const struct snd_kcontrol_new wm8960_rin_boost[] = { |
336 | SOC_DAPM_SINGLE("RINPUT2 Switch" , WM8960_RINPATH, 6, 1, 0), |
337 | SOC_DAPM_SINGLE("RINPUT3 Switch" , WM8960_RINPATH, 7, 1, 0), |
338 | SOC_DAPM_SINGLE("RINPUT1 Switch" , WM8960_RINPATH, 8, 1, 0), |
339 | }; |
340 | |
341 | static const struct snd_kcontrol_new wm8960_rin[] = { |
342 | SOC_DAPM_SINGLE("Boost Switch" , WM8960_RINPATH, 3, 1, 0), |
343 | }; |
344 | |
345 | static const struct snd_kcontrol_new wm8960_loutput_mixer[] = { |
346 | SOC_DAPM_SINGLE("PCM Playback Switch" , WM8960_LOUTMIX, 8, 1, 0), |
347 | SOC_DAPM_SINGLE("LINPUT3 Switch" , WM8960_LOUTMIX, 7, 1, 0), |
348 | SOC_DAPM_SINGLE("Boost Bypass Switch" , WM8960_BYPASS1, 7, 1, 0), |
349 | }; |
350 | |
351 | static const struct snd_kcontrol_new wm8960_routput_mixer[] = { |
352 | SOC_DAPM_SINGLE("PCM Playback Switch" , WM8960_ROUTMIX, 8, 1, 0), |
353 | SOC_DAPM_SINGLE("RINPUT3 Switch" , WM8960_ROUTMIX, 7, 1, 0), |
354 | SOC_DAPM_SINGLE("Boost Bypass Switch" , WM8960_BYPASS2, 7, 1, 0), |
355 | }; |
356 | |
357 | static const struct snd_kcontrol_new wm8960_mono_out[] = { |
358 | SOC_DAPM_SINGLE("Left Switch" , WM8960_MONOMIX1, 7, 1, 0), |
359 | SOC_DAPM_SINGLE("Right Switch" , WM8960_MONOMIX2, 7, 1, 0), |
360 | }; |
361 | |
362 | static const struct snd_soc_dapm_widget wm8960_dapm_widgets[] = { |
363 | SND_SOC_DAPM_INPUT("LINPUT1" ), |
364 | SND_SOC_DAPM_INPUT("RINPUT1" ), |
365 | SND_SOC_DAPM_INPUT("LINPUT2" ), |
366 | SND_SOC_DAPM_INPUT("RINPUT2" ), |
367 | SND_SOC_DAPM_INPUT("LINPUT3" ), |
368 | SND_SOC_DAPM_INPUT("RINPUT3" ), |
369 | |
370 | SND_SOC_DAPM_SUPPLY("MICB" , WM8960_POWER1, 1, 0, NULL, 0), |
371 | |
372 | SND_SOC_DAPM_MIXER("Left Boost Mixer" , WM8960_POWER1, 5, 0, |
373 | wm8960_lin_boost, ARRAY_SIZE(wm8960_lin_boost)), |
374 | SND_SOC_DAPM_MIXER("Right Boost Mixer" , WM8960_POWER1, 4, 0, |
375 | wm8960_rin_boost, ARRAY_SIZE(wm8960_rin_boost)), |
376 | |
377 | SND_SOC_DAPM_MIXER("Left Input Mixer" , WM8960_POWER3, 5, 0, |
378 | wm8960_lin, ARRAY_SIZE(wm8960_lin)), |
379 | SND_SOC_DAPM_MIXER("Right Input Mixer" , WM8960_POWER3, 4, 0, |
380 | wm8960_rin, ARRAY_SIZE(wm8960_rin)), |
381 | |
382 | SND_SOC_DAPM_ADC("Left ADC" , "Capture" , WM8960_POWER1, 3, 0), |
383 | SND_SOC_DAPM_ADC("Right ADC" , "Capture" , WM8960_POWER1, 2, 0), |
384 | |
385 | SND_SOC_DAPM_DAC("Left DAC" , "Playback" , WM8960_POWER2, 8, 0), |
386 | SND_SOC_DAPM_DAC("Right DAC" , "Playback" , WM8960_POWER2, 7, 0), |
387 | |
388 | SND_SOC_DAPM_MIXER("Left Output Mixer" , WM8960_POWER3, 3, 0, |
389 | &wm8960_loutput_mixer[0], |
390 | ARRAY_SIZE(wm8960_loutput_mixer)), |
391 | SND_SOC_DAPM_MIXER("Right Output Mixer" , WM8960_POWER3, 2, 0, |
392 | &wm8960_routput_mixer[0], |
393 | ARRAY_SIZE(wm8960_routput_mixer)), |
394 | |
395 | SND_SOC_DAPM_PGA("LOUT1 PGA" , WM8960_POWER2, 6, 0, NULL, 0), |
396 | SND_SOC_DAPM_PGA("ROUT1 PGA" , WM8960_POWER2, 5, 0, NULL, 0), |
397 | |
398 | SND_SOC_DAPM_PGA("Left Speaker PGA" , WM8960_POWER2, 4, 0, NULL, 0), |
399 | SND_SOC_DAPM_PGA("Right Speaker PGA" , WM8960_POWER2, 3, 0, NULL, 0), |
400 | |
401 | SND_SOC_DAPM_PGA("Right Speaker Output" , WM8960_CLASSD1, 7, 0, NULL, 0), |
402 | SND_SOC_DAPM_PGA("Left Speaker Output" , WM8960_CLASSD1, 6, 0, NULL, 0), |
403 | |
404 | SND_SOC_DAPM_OUTPUT("SPK_LP" ), |
405 | SND_SOC_DAPM_OUTPUT("SPK_LN" ), |
406 | SND_SOC_DAPM_OUTPUT("HP_L" ), |
407 | SND_SOC_DAPM_OUTPUT("HP_R" ), |
408 | SND_SOC_DAPM_OUTPUT("SPK_RP" ), |
409 | SND_SOC_DAPM_OUTPUT("SPK_RN" ), |
410 | SND_SOC_DAPM_OUTPUT("OUT3" ), |
411 | }; |
412 | |
413 | static const struct snd_soc_dapm_widget wm8960_dapm_widgets_out3[] = { |
414 | SND_SOC_DAPM_MIXER("Mono Output Mixer" , WM8960_POWER2, 1, 0, |
415 | &wm8960_mono_out[0], |
416 | ARRAY_SIZE(wm8960_mono_out)), |
417 | }; |
418 | |
419 | /* Represent OUT3 as a PGA so that it gets turned on with LOUT1/ROUT1 */ |
420 | static const struct snd_soc_dapm_widget wm8960_dapm_widgets_capless[] = { |
421 | SND_SOC_DAPM_PGA("OUT3 VMID" , WM8960_POWER2, 1, 0, NULL, 0), |
422 | }; |
423 | |
424 | static const struct snd_soc_dapm_route audio_paths[] = { |
425 | { "Left Boost Mixer" , "LINPUT1 Switch" , "LINPUT1" }, |
426 | { "Left Boost Mixer" , "LINPUT2 Switch" , "LINPUT2" }, |
427 | { "Left Boost Mixer" , "LINPUT3 Switch" , "LINPUT3" }, |
428 | |
429 | { "Left Input Mixer" , "Boost Switch" , "Left Boost Mixer" }, |
430 | { "Left Input Mixer" , "Boost Switch" , "LINPUT1" }, /* Really Boost Switch */ |
431 | { "Left Input Mixer" , NULL, "LINPUT2" }, |
432 | { "Left Input Mixer" , NULL, "LINPUT3" }, |
433 | |
434 | { "Right Boost Mixer" , "RINPUT1 Switch" , "RINPUT1" }, |
435 | { "Right Boost Mixer" , "RINPUT2 Switch" , "RINPUT2" }, |
436 | { "Right Boost Mixer" , "RINPUT3 Switch" , "RINPUT3" }, |
437 | |
438 | { "Right Input Mixer" , "Boost Switch" , "Right Boost Mixer" }, |
439 | { "Right Input Mixer" , "Boost Switch" , "RINPUT1" }, /* Really Boost Switch */ |
440 | { "Right Input Mixer" , NULL, "RINPUT2" }, |
441 | { "Right Input Mixer" , NULL, "RINPUT3" }, |
442 | |
443 | { "Left ADC" , NULL, "Left Input Mixer" }, |
444 | { "Right ADC" , NULL, "Right Input Mixer" }, |
445 | |
446 | { "Left Output Mixer" , "LINPUT3 Switch" , "LINPUT3" }, |
447 | { "Left Output Mixer" , "Boost Bypass Switch" , "Left Boost Mixer" }, |
448 | { "Left Output Mixer" , "PCM Playback Switch" , "Left DAC" }, |
449 | |
450 | { "Right Output Mixer" , "RINPUT3 Switch" , "RINPUT3" }, |
451 | { "Right Output Mixer" , "Boost Bypass Switch" , "Right Boost Mixer" }, |
452 | { "Right Output Mixer" , "PCM Playback Switch" , "Right DAC" }, |
453 | |
454 | { "LOUT1 PGA" , NULL, "Left Output Mixer" }, |
455 | { "ROUT1 PGA" , NULL, "Right Output Mixer" }, |
456 | |
457 | { "HP_L" , NULL, "LOUT1 PGA" }, |
458 | { "HP_R" , NULL, "ROUT1 PGA" }, |
459 | |
460 | { "Left Speaker PGA" , NULL, "Left Output Mixer" }, |
461 | { "Right Speaker PGA" , NULL, "Right Output Mixer" }, |
462 | |
463 | { "Left Speaker Output" , NULL, "Left Speaker PGA" }, |
464 | { "Right Speaker Output" , NULL, "Right Speaker PGA" }, |
465 | |
466 | { "SPK_LN" , NULL, "Left Speaker Output" }, |
467 | { "SPK_LP" , NULL, "Left Speaker Output" }, |
468 | { "SPK_RN" , NULL, "Right Speaker Output" }, |
469 | { "SPK_RP" , NULL, "Right Speaker Output" }, |
470 | }; |
471 | |
472 | static const struct snd_soc_dapm_route audio_paths_out3[] = { |
473 | { "Mono Output Mixer" , "Left Switch" , "Left Output Mixer" }, |
474 | { "Mono Output Mixer" , "Right Switch" , "Right Output Mixer" }, |
475 | |
476 | { "OUT3" , NULL, "Mono Output Mixer" , } |
477 | }; |
478 | |
479 | static const struct snd_soc_dapm_route audio_paths_capless[] = { |
480 | { "HP_L" , NULL, "OUT3 VMID" }, |
481 | { "HP_R" , NULL, "OUT3 VMID" }, |
482 | |
483 | { "OUT3 VMID" , NULL, "Left Output Mixer" }, |
484 | { "OUT3 VMID" , NULL, "Right Output Mixer" }, |
485 | }; |
486 | |
487 | static int wm8960_add_widgets(struct snd_soc_component *component) |
488 | { |
489 | struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(c: component); |
490 | struct wm8960_data *pdata = &wm8960->pdata; |
491 | struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); |
492 | struct snd_soc_dapm_widget *w; |
493 | |
494 | snd_soc_dapm_new_controls(dapm, widget: wm8960_dapm_widgets, |
495 | ARRAY_SIZE(wm8960_dapm_widgets)); |
496 | |
497 | snd_soc_dapm_add_routes(dapm, route: audio_paths, ARRAY_SIZE(audio_paths)); |
498 | |
499 | /* In capless mode OUT3 is used to provide VMID for the |
500 | * headphone outputs, otherwise it is used as a mono mixer. |
501 | */ |
502 | if (pdata && pdata->capless) { |
503 | snd_soc_dapm_new_controls(dapm, widget: wm8960_dapm_widgets_capless, |
504 | ARRAY_SIZE(wm8960_dapm_widgets_capless)); |
505 | |
506 | snd_soc_dapm_add_routes(dapm, route: audio_paths_capless, |
507 | ARRAY_SIZE(audio_paths_capless)); |
508 | } else { |
509 | snd_soc_dapm_new_controls(dapm, widget: wm8960_dapm_widgets_out3, |
510 | ARRAY_SIZE(wm8960_dapm_widgets_out3)); |
511 | |
512 | snd_soc_dapm_add_routes(dapm, route: audio_paths_out3, |
513 | ARRAY_SIZE(audio_paths_out3)); |
514 | } |
515 | |
516 | /* We need to power up the headphone output stage out of |
517 | * sequence for capless mode. To save scanning the widget |
518 | * list each time to find the desired power state do so now |
519 | * and save the result. |
520 | */ |
521 | list_for_each_entry(w, &component->card->widgets, list) { |
522 | if (w->dapm != dapm) |
523 | continue; |
524 | if (strcmp(w->name, "LOUT1 PGA" ) == 0) |
525 | wm8960->lout1 = w; |
526 | if (strcmp(w->name, "ROUT1 PGA" ) == 0) |
527 | wm8960->rout1 = w; |
528 | if (strcmp(w->name, "OUT3 VMID" ) == 0) |
529 | wm8960->out3 = w; |
530 | } |
531 | |
532 | return 0; |
533 | } |
534 | |
535 | static int wm8960_set_dai_fmt(struct snd_soc_dai *codec_dai, |
536 | unsigned int fmt) |
537 | { |
538 | struct snd_soc_component *component = codec_dai->component; |
539 | u16 iface = 0; |
540 | |
541 | /* set master/slave audio interface */ |
542 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
543 | case SND_SOC_DAIFMT_CBM_CFM: |
544 | iface |= 0x0040; |
545 | break; |
546 | case SND_SOC_DAIFMT_CBS_CFS: |
547 | break; |
548 | default: |
549 | return -EINVAL; |
550 | } |
551 | |
552 | /* interface format */ |
553 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
554 | case SND_SOC_DAIFMT_I2S: |
555 | iface |= 0x0002; |
556 | break; |
557 | case SND_SOC_DAIFMT_RIGHT_J: |
558 | break; |
559 | case SND_SOC_DAIFMT_LEFT_J: |
560 | iface |= 0x0001; |
561 | break; |
562 | case SND_SOC_DAIFMT_DSP_A: |
563 | iface |= 0x0003; |
564 | break; |
565 | case SND_SOC_DAIFMT_DSP_B: |
566 | iface |= 0x0013; |
567 | break; |
568 | default: |
569 | return -EINVAL; |
570 | } |
571 | |
572 | /* clock inversion */ |
573 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { |
574 | case SND_SOC_DAIFMT_NB_NF: |
575 | break; |
576 | case SND_SOC_DAIFMT_IB_IF: |
577 | iface |= 0x0090; |
578 | break; |
579 | case SND_SOC_DAIFMT_IB_NF: |
580 | iface |= 0x0080; |
581 | break; |
582 | case SND_SOC_DAIFMT_NB_IF: |
583 | iface |= 0x0010; |
584 | break; |
585 | default: |
586 | return -EINVAL; |
587 | } |
588 | |
589 | /* set iface */ |
590 | snd_soc_component_write(component, WM8960_IFACE1, val: iface); |
591 | return 0; |
592 | } |
593 | |
594 | static struct { |
595 | int rate; |
596 | unsigned int val; |
597 | } alc_rates[] = { |
598 | { 48000, 0 }, |
599 | { 44100, 0 }, |
600 | { 32000, 1 }, |
601 | { 22050, 2 }, |
602 | { 24000, 2 }, |
603 | { 16000, 3 }, |
604 | { 11025, 4 }, |
605 | { 12000, 4 }, |
606 | { 8000, 5 }, |
607 | }; |
608 | |
609 | /* -1 for reserved value */ |
610 | static const int sysclk_divs[] = { 1, -1, 2, -1 }; |
611 | |
612 | /* Multiply 256 for internal 256 div */ |
613 | static const int dac_divs[] = { 256, 384, 512, 768, 1024, 1408, 1536 }; |
614 | |
615 | /* Multiply 10 to eliminate decimials */ |
616 | static const int bclk_divs[] = { |
617 | 10, 15, 20, 30, 40, 55, 60, 80, 110, |
618 | 120, 160, 220, 240, 320, 320, 320 |
619 | }; |
620 | |
621 | /** |
622 | * wm8960_configure_sysclk - checks if there is a sysclk frequency available |
623 | * The sysclk must be chosen such that: |
624 | * - sysclk = MCLK / sysclk_divs |
625 | * - lrclk = sysclk / dac_divs |
626 | * - 10 * bclk = sysclk / bclk_divs |
627 | * |
628 | * @wm8960: codec private data |
629 | * @mclk: MCLK used to derive sysclk |
630 | * @sysclk_idx: sysclk_divs index for found sysclk |
631 | * @dac_idx: dac_divs index for found lrclk |
632 | * @bclk_idx: bclk_divs index for found bclk |
633 | * |
634 | * Returns: |
635 | * -1, in case no sysclk frequency available found |
636 | * >=0, in case we could derive bclk and lrclk from sysclk using |
637 | * (@sysclk_idx, @dac_idx, @bclk_idx) dividers |
638 | */ |
639 | static |
640 | int wm8960_configure_sysclk(struct wm8960_priv *wm8960, int mclk, |
641 | int *sysclk_idx, int *dac_idx, int *bclk_idx) |
642 | { |
643 | int sysclk, bclk, lrclk; |
644 | int i, j, k; |
645 | int diff; |
646 | |
647 | /* marker for no match */ |
648 | *bclk_idx = -1; |
649 | |
650 | bclk = wm8960->bclk; |
651 | lrclk = wm8960->lrclk; |
652 | |
653 | /* check if the sysclk frequency is available. */ |
654 | for (i = 0; i < ARRAY_SIZE(sysclk_divs); ++i) { |
655 | if (sysclk_divs[i] == -1) |
656 | continue; |
657 | sysclk = mclk / sysclk_divs[i]; |
658 | for (j = 0; j < ARRAY_SIZE(dac_divs); ++j) { |
659 | if (sysclk != dac_divs[j] * lrclk) |
660 | continue; |
661 | for (k = 0; k < ARRAY_SIZE(bclk_divs); ++k) { |
662 | diff = sysclk - bclk * bclk_divs[k] / 10; |
663 | if (diff == 0) { |
664 | *sysclk_idx = i; |
665 | *dac_idx = j; |
666 | *bclk_idx = k; |
667 | break; |
668 | } |
669 | } |
670 | if (k != ARRAY_SIZE(bclk_divs)) |
671 | break; |
672 | } |
673 | if (j != ARRAY_SIZE(dac_divs)) |
674 | break; |
675 | } |
676 | return *bclk_idx; |
677 | } |
678 | |
679 | /** |
680 | * wm8960_configure_pll - checks if there is a PLL out frequency available |
681 | * The PLL out frequency must be chosen such that: |
682 | * - sysclk = lrclk * dac_divs |
683 | * - freq_out = sysclk * sysclk_divs |
684 | * - 10 * sysclk = bclk * bclk_divs |
685 | * |
686 | * If we cannot find an exact match for (sysclk, lrclk, bclk) |
687 | * triplet, we relax the bclk such that bclk is chosen as the |
688 | * closest available frequency greater than expected bclk. |
689 | * |
690 | * @component: component structure |
691 | * @freq_in: input frequency used to derive freq out via PLL |
692 | * @sysclk_idx: sysclk_divs index for found sysclk |
693 | * @dac_idx: dac_divs index for found lrclk |
694 | * @bclk_idx: bclk_divs index for found bclk |
695 | * |
696 | * Returns: |
697 | * < 0, in case no PLL frequency out available was found |
698 | * >=0, in case we could derive bclk, lrclk, sysclk from PLL out using |
699 | * (@sysclk_idx, @dac_idx, @bclk_idx) dividers |
700 | */ |
701 | static |
702 | int wm8960_configure_pll(struct snd_soc_component *component, int freq_in, |
703 | int *sysclk_idx, int *dac_idx, int *bclk_idx) |
704 | { |
705 | struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(c: component); |
706 | int sysclk, bclk, lrclk, freq_out; |
707 | int diff, closest, best_freq_out; |
708 | int i, j, k; |
709 | |
710 | bclk = wm8960->bclk; |
711 | lrclk = wm8960->lrclk; |
712 | closest = freq_in; |
713 | |
714 | best_freq_out = -EINVAL; |
715 | *sysclk_idx = *dac_idx = *bclk_idx = -1; |
716 | |
717 | /* |
718 | * From Datasheet, the PLL performs best when f2 is between |
719 | * 90MHz and 100MHz, the desired sysclk output is 11.2896MHz |
720 | * or 12.288MHz, then sysclkdiv = 2 is the best choice. |
721 | * So search sysclk_divs from 2 to 1 other than from 1 to 2. |
722 | */ |
723 | for (i = ARRAY_SIZE(sysclk_divs) - 1; i >= 0; --i) { |
724 | if (sysclk_divs[i] == -1) |
725 | continue; |
726 | for (j = 0; j < ARRAY_SIZE(dac_divs); ++j) { |
727 | sysclk = lrclk * dac_divs[j]; |
728 | freq_out = sysclk * sysclk_divs[i]; |
729 | |
730 | for (k = 0; k < ARRAY_SIZE(bclk_divs); ++k) { |
731 | if (!is_pll_freq_available(source: freq_in, target: freq_out)) |
732 | continue; |
733 | |
734 | diff = sysclk - bclk * bclk_divs[k] / 10; |
735 | if (diff == 0) { |
736 | *sysclk_idx = i; |
737 | *dac_idx = j; |
738 | *bclk_idx = k; |
739 | return freq_out; |
740 | } |
741 | if (diff > 0 && closest > diff) { |
742 | *sysclk_idx = i; |
743 | *dac_idx = j; |
744 | *bclk_idx = k; |
745 | closest = diff; |
746 | best_freq_out = freq_out; |
747 | } |
748 | } |
749 | } |
750 | } |
751 | |
752 | return best_freq_out; |
753 | } |
754 | static int wm8960_configure_clocking(struct snd_soc_component *component) |
755 | { |
756 | struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(c: component); |
757 | int freq_out, freq_in; |
758 | u16 iface1 = snd_soc_component_read(component, WM8960_IFACE1); |
759 | int i, j, k; |
760 | int ret; |
761 | |
762 | /* |
763 | * For Slave mode clocking should still be configured, |
764 | * so this if statement should be removed, but some platform |
765 | * may not work if the sysclk is not configured, to avoid such |
766 | * compatible issue, just add '!wm8960->sysclk' condition in |
767 | * this if statement. |
768 | */ |
769 | if (!(iface1 & (1 << 6)) && !wm8960->sysclk) { |
770 | dev_warn(component->dev, |
771 | "slave mode, but proceeding with no clock configuration\n" ); |
772 | return 0; |
773 | } |
774 | |
775 | if (wm8960->clk_id != WM8960_SYSCLK_MCLK && !wm8960->freq_in) { |
776 | dev_err(component->dev, "No MCLK configured\n" ); |
777 | return -EINVAL; |
778 | } |
779 | |
780 | freq_in = wm8960->freq_in; |
781 | /* |
782 | * If it's sysclk auto mode, check if the MCLK can provide sysclk or |
783 | * not. If MCLK can provide sysclk, using MCLK to provide sysclk |
784 | * directly. Otherwise, auto select a available pll out frequency |
785 | * and set PLL. |
786 | */ |
787 | if (wm8960->clk_id == WM8960_SYSCLK_AUTO) { |
788 | /* disable the PLL and using MCLK to provide sysclk */ |
789 | wm8960_set_pll(component, freq_in: 0, freq_out: 0); |
790 | freq_out = freq_in; |
791 | } else if (wm8960->sysclk) { |
792 | freq_out = wm8960->sysclk; |
793 | } else { |
794 | dev_err(component->dev, "No SYSCLK configured\n" ); |
795 | return -EINVAL; |
796 | } |
797 | |
798 | if (wm8960->clk_id != WM8960_SYSCLK_PLL) { |
799 | ret = wm8960_configure_sysclk(wm8960, mclk: freq_out, sysclk_idx: &i, dac_idx: &j, bclk_idx: &k); |
800 | if (ret >= 0) { |
801 | goto configure_clock; |
802 | } else if (wm8960->clk_id != WM8960_SYSCLK_AUTO) { |
803 | dev_err(component->dev, "failed to configure clock\n" ); |
804 | return -EINVAL; |
805 | } |
806 | } |
807 | |
808 | freq_out = wm8960_configure_pll(component, freq_in, sysclk_idx: &i, dac_idx: &j, bclk_idx: &k); |
809 | if (freq_out < 0) { |
810 | dev_err(component->dev, "failed to configure clock via PLL\n" ); |
811 | return freq_out; |
812 | } |
813 | wm8960_set_pll(component, freq_in, freq_out); |
814 | |
815 | configure_clock: |
816 | /* configure sysclk clock */ |
817 | snd_soc_component_update_bits(component, WM8960_CLOCK1, mask: 3 << 1, val: i << 1); |
818 | |
819 | /* configure frame clock */ |
820 | snd_soc_component_update_bits(component, WM8960_CLOCK1, mask: 0x7 << 3, val: j << 3); |
821 | snd_soc_component_update_bits(component, WM8960_CLOCK1, mask: 0x7 << 6, val: j << 6); |
822 | |
823 | /* configure bit clock */ |
824 | snd_soc_component_update_bits(component, WM8960_CLOCK2, mask: 0xf, val: k); |
825 | |
826 | return 0; |
827 | } |
828 | |
829 | static int wm8960_hw_params(struct snd_pcm_substream *substream, |
830 | struct snd_pcm_hw_params *params, |
831 | struct snd_soc_dai *dai) |
832 | { |
833 | struct snd_soc_component *component = dai->component; |
834 | struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(c: component); |
835 | u16 iface = snd_soc_component_read(component, WM8960_IFACE1) & 0xfff3; |
836 | bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; |
837 | int i; |
838 | |
839 | wm8960->bclk = snd_soc_params_to_bclk(parms: params); |
840 | if (params_channels(p: params) == 1) |
841 | wm8960->bclk *= 2; |
842 | |
843 | /* bit size */ |
844 | switch (params_width(p: params)) { |
845 | case 16: |
846 | break; |
847 | case 20: |
848 | iface |= 0x0004; |
849 | break; |
850 | case 24: |
851 | iface |= 0x0008; |
852 | break; |
853 | case 32: |
854 | /* right justify mode does not support 32 word length */ |
855 | if ((iface & 0x3) != 0) { |
856 | iface |= 0x000c; |
857 | break; |
858 | } |
859 | fallthrough; |
860 | default: |
861 | dev_err(component->dev, "unsupported width %d\n" , |
862 | params_width(params)); |
863 | return -EINVAL; |
864 | } |
865 | |
866 | wm8960->lrclk = params_rate(p: params); |
867 | /* Update filters for the new rate */ |
868 | if (tx) { |
869 | wm8960_set_deemph(component); |
870 | } else { |
871 | for (i = 0; i < ARRAY_SIZE(alc_rates); i++) |
872 | if (alc_rates[i].rate == params_rate(p: params)) |
873 | snd_soc_component_update_bits(component, |
874 | WM8960_ADDCTL3, mask: 0x7, |
875 | val: alc_rates[i].val); |
876 | } |
877 | |
878 | /* set iface */ |
879 | snd_soc_component_write(component, WM8960_IFACE1, val: iface); |
880 | |
881 | wm8960->is_stream_in_use[tx] = true; |
882 | |
883 | if (!wm8960->is_stream_in_use[!tx]) |
884 | return wm8960_configure_clocking(component); |
885 | |
886 | return 0; |
887 | } |
888 | |
889 | static int wm8960_hw_free(struct snd_pcm_substream *substream, |
890 | struct snd_soc_dai *dai) |
891 | { |
892 | struct snd_soc_component *component = dai->component; |
893 | struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(c: component); |
894 | bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; |
895 | |
896 | wm8960->is_stream_in_use[tx] = false; |
897 | |
898 | return 0; |
899 | } |
900 | |
901 | static int wm8960_mute(struct snd_soc_dai *dai, int mute, int direction) |
902 | { |
903 | struct snd_soc_component *component = dai->component; |
904 | |
905 | if (mute) |
906 | snd_soc_component_update_bits(component, WM8960_DACCTL1, mask: 0x8, val: 0x8); |
907 | else |
908 | snd_soc_component_update_bits(component, WM8960_DACCTL1, mask: 0x8, val: 0); |
909 | return 0; |
910 | } |
911 | |
912 | static int wm8960_set_bias_level_out3(struct snd_soc_component *component, |
913 | enum snd_soc_bias_level level) |
914 | { |
915 | struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(c: component); |
916 | u16 pm2 = snd_soc_component_read(component, WM8960_POWER2); |
917 | int ret; |
918 | ktime_t tout; |
919 | |
920 | switch (level) { |
921 | case SND_SOC_BIAS_ON: |
922 | break; |
923 | |
924 | case SND_SOC_BIAS_PREPARE: |
925 | switch (snd_soc_component_get_bias_level(component)) { |
926 | case SND_SOC_BIAS_STANDBY: |
927 | if (!IS_ERR(ptr: wm8960->mclk)) { |
928 | ret = clk_prepare_enable(clk: wm8960->mclk); |
929 | if (ret) { |
930 | dev_err(component->dev, |
931 | "Failed to enable MCLK: %d\n" , |
932 | ret); |
933 | return ret; |
934 | } |
935 | } |
936 | |
937 | ret = wm8960_configure_clocking(component); |
938 | if (ret) |
939 | return ret; |
940 | |
941 | /* Set VMID to 2x50k */ |
942 | snd_soc_component_update_bits(component, WM8960_POWER1, mask: 0x180, val: 0x80); |
943 | break; |
944 | |
945 | case SND_SOC_BIAS_ON: |
946 | /* |
947 | * If it's sysclk auto mode, and the pll is enabled, |
948 | * disable the pll |
949 | */ |
950 | if (wm8960->clk_id == WM8960_SYSCLK_AUTO && (pm2 & 0x1)) |
951 | wm8960_set_pll(component, freq_in: 0, freq_out: 0); |
952 | |
953 | if (!IS_ERR(ptr: wm8960->mclk)) |
954 | clk_disable_unprepare(clk: wm8960->mclk); |
955 | break; |
956 | |
957 | default: |
958 | break; |
959 | } |
960 | |
961 | break; |
962 | |
963 | case SND_SOC_BIAS_STANDBY: |
964 | if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) { |
965 | /* ensure discharge is complete */ |
966 | tout = WM8960_DSCH_TOUT - ktime_ms_delta(later: ktime_get(), earlier: wm8960->dsch_start); |
967 | if (tout > 0) |
968 | msleep(msecs: tout); |
969 | |
970 | regcache_sync(map: wm8960->regmap); |
971 | |
972 | /* Enable anti-pop features */ |
973 | snd_soc_component_write(component, WM8960_APOP1, |
974 | WM8960_POBCTRL | WM8960_SOFT_ST | |
975 | WM8960_BUFDCOPEN | WM8960_BUFIOEN); |
976 | |
977 | /* Enable & ramp VMID at 2x50k */ |
978 | snd_soc_component_update_bits(component, WM8960_POWER1, mask: 0x80, val: 0x80); |
979 | msleep(msecs: 100); |
980 | |
981 | /* Enable VREF */ |
982 | snd_soc_component_update_bits(component, WM8960_POWER1, WM8960_VREF, |
983 | WM8960_VREF); |
984 | |
985 | /* Disable anti-pop features */ |
986 | snd_soc_component_write(component, WM8960_APOP1, WM8960_BUFIOEN); |
987 | } |
988 | |
989 | /* Set VMID to 2x250k */ |
990 | snd_soc_component_update_bits(component, WM8960_POWER1, mask: 0x180, val: 0x100); |
991 | break; |
992 | |
993 | case SND_SOC_BIAS_OFF: |
994 | /* Enable anti-pop features */ |
995 | snd_soc_component_write(component, WM8960_APOP1, |
996 | WM8960_POBCTRL | WM8960_SOFT_ST | |
997 | WM8960_BUFDCOPEN | WM8960_BUFIOEN); |
998 | |
999 | /* Disable VMID and VREF, mark discharge */ |
1000 | snd_soc_component_write(component, WM8960_POWER1, val: 0); |
1001 | wm8960->dsch_start = ktime_get(); |
1002 | break; |
1003 | } |
1004 | |
1005 | return 0; |
1006 | } |
1007 | |
1008 | static int wm8960_set_bias_level_capless(struct snd_soc_component *component, |
1009 | enum snd_soc_bias_level level) |
1010 | { |
1011 | struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(c: component); |
1012 | u16 pm2 = snd_soc_component_read(component, WM8960_POWER2); |
1013 | int reg, ret; |
1014 | |
1015 | switch (level) { |
1016 | case SND_SOC_BIAS_ON: |
1017 | break; |
1018 | |
1019 | case SND_SOC_BIAS_PREPARE: |
1020 | switch (snd_soc_component_get_bias_level(component)) { |
1021 | case SND_SOC_BIAS_STANDBY: |
1022 | /* Enable anti pop mode */ |
1023 | snd_soc_component_update_bits(component, WM8960_APOP1, |
1024 | WM8960_POBCTRL | WM8960_SOFT_ST | |
1025 | WM8960_BUFDCOPEN, |
1026 | WM8960_POBCTRL | WM8960_SOFT_ST | |
1027 | WM8960_BUFDCOPEN); |
1028 | |
1029 | /* Enable LOUT1, ROUT1 and OUT3 if they're enabled */ |
1030 | reg = 0; |
1031 | if (wm8960->lout1 && wm8960->lout1->power) |
1032 | reg |= WM8960_PWR2_LOUT1; |
1033 | if (wm8960->rout1 && wm8960->rout1->power) |
1034 | reg |= WM8960_PWR2_ROUT1; |
1035 | if (wm8960->out3 && wm8960->out3->power) |
1036 | reg |= WM8960_PWR2_OUT3; |
1037 | snd_soc_component_update_bits(component, WM8960_POWER2, |
1038 | WM8960_PWR2_LOUT1 | |
1039 | WM8960_PWR2_ROUT1 | |
1040 | WM8960_PWR2_OUT3, val: reg); |
1041 | |
1042 | /* Enable VMID at 2*50k */ |
1043 | snd_soc_component_update_bits(component, WM8960_POWER1, |
1044 | WM8960_VMID_MASK, val: 0x80); |
1045 | |
1046 | /* Ramp */ |
1047 | msleep(msecs: 100); |
1048 | |
1049 | /* Enable VREF */ |
1050 | snd_soc_component_update_bits(component, WM8960_POWER1, |
1051 | WM8960_VREF, WM8960_VREF); |
1052 | |
1053 | msleep(msecs: 100); |
1054 | |
1055 | if (!IS_ERR(ptr: wm8960->mclk)) { |
1056 | ret = clk_prepare_enable(clk: wm8960->mclk); |
1057 | if (ret) { |
1058 | dev_err(component->dev, |
1059 | "Failed to enable MCLK: %d\n" , |
1060 | ret); |
1061 | return ret; |
1062 | } |
1063 | } |
1064 | |
1065 | ret = wm8960_configure_clocking(component); |
1066 | if (ret) |
1067 | return ret; |
1068 | |
1069 | break; |
1070 | |
1071 | case SND_SOC_BIAS_ON: |
1072 | /* |
1073 | * If it's sysclk auto mode, and the pll is enabled, |
1074 | * disable the pll |
1075 | */ |
1076 | if (wm8960->clk_id == WM8960_SYSCLK_AUTO && (pm2 & 0x1)) |
1077 | wm8960_set_pll(component, freq_in: 0, freq_out: 0); |
1078 | |
1079 | if (!IS_ERR(ptr: wm8960->mclk)) |
1080 | clk_disable_unprepare(clk: wm8960->mclk); |
1081 | |
1082 | /* Enable anti-pop mode */ |
1083 | snd_soc_component_update_bits(component, WM8960_APOP1, |
1084 | WM8960_POBCTRL | WM8960_SOFT_ST | |
1085 | WM8960_BUFDCOPEN, |
1086 | WM8960_POBCTRL | WM8960_SOFT_ST | |
1087 | WM8960_BUFDCOPEN); |
1088 | |
1089 | /* Disable VMID and VREF */ |
1090 | snd_soc_component_update_bits(component, WM8960_POWER1, |
1091 | WM8960_VREF | WM8960_VMID_MASK, val: 0); |
1092 | break; |
1093 | |
1094 | case SND_SOC_BIAS_OFF: |
1095 | regcache_sync(map: wm8960->regmap); |
1096 | break; |
1097 | default: |
1098 | break; |
1099 | } |
1100 | break; |
1101 | |
1102 | case SND_SOC_BIAS_STANDBY: |
1103 | switch (snd_soc_component_get_bias_level(component)) { |
1104 | case SND_SOC_BIAS_PREPARE: |
1105 | /* Disable HP discharge */ |
1106 | snd_soc_component_update_bits(component, WM8960_APOP2, |
1107 | WM8960_DISOP | WM8960_DRES_MASK, |
1108 | val: 0); |
1109 | |
1110 | /* Disable anti-pop features */ |
1111 | snd_soc_component_update_bits(component, WM8960_APOP1, |
1112 | WM8960_POBCTRL | WM8960_SOFT_ST | |
1113 | WM8960_BUFDCOPEN, |
1114 | WM8960_POBCTRL | WM8960_SOFT_ST | |
1115 | WM8960_BUFDCOPEN); |
1116 | break; |
1117 | |
1118 | default: |
1119 | break; |
1120 | } |
1121 | break; |
1122 | |
1123 | case SND_SOC_BIAS_OFF: |
1124 | break; |
1125 | } |
1126 | |
1127 | return 0; |
1128 | } |
1129 | |
1130 | /* PLL divisors */ |
1131 | struct _pll_div { |
1132 | u32 pre_div:1; |
1133 | u32 n:4; |
1134 | u32 k:24; |
1135 | }; |
1136 | |
1137 | static bool is_pll_freq_available(unsigned int source, unsigned int target) |
1138 | { |
1139 | unsigned int Ndiv; |
1140 | |
1141 | if (source == 0 || target == 0) |
1142 | return false; |
1143 | |
1144 | /* Scale up target to PLL operating frequency */ |
1145 | target *= 4; |
1146 | Ndiv = target / source; |
1147 | |
1148 | if (Ndiv < 6) { |
1149 | source >>= 1; |
1150 | Ndiv = target / source; |
1151 | } |
1152 | |
1153 | if ((Ndiv < 6) || (Ndiv > 12)) |
1154 | return false; |
1155 | |
1156 | return true; |
1157 | } |
1158 | |
1159 | /* The size in bits of the pll divide multiplied by 10 |
1160 | * to allow rounding later */ |
1161 | #define FIXED_PLL_SIZE ((1 << 24) * 10) |
1162 | |
1163 | static int pll_factors(unsigned int source, unsigned int target, |
1164 | struct _pll_div *pll_div) |
1165 | { |
1166 | unsigned long long Kpart; |
1167 | unsigned int K, Ndiv, Nmod; |
1168 | |
1169 | pr_debug("WM8960 PLL: setting %dHz->%dHz\n" , source, target); |
1170 | |
1171 | /* Scale up target to PLL operating frequency */ |
1172 | target *= 4; |
1173 | |
1174 | Ndiv = target / source; |
1175 | if (Ndiv < 6) { |
1176 | source >>= 1; |
1177 | pll_div->pre_div = 1; |
1178 | Ndiv = target / source; |
1179 | } else |
1180 | pll_div->pre_div = 0; |
1181 | |
1182 | if ((Ndiv < 6) || (Ndiv > 12)) { |
1183 | pr_err("WM8960 PLL: Unsupported N=%d\n" , Ndiv); |
1184 | return -EINVAL; |
1185 | } |
1186 | |
1187 | pll_div->n = Ndiv; |
1188 | Nmod = target % source; |
1189 | Kpart = FIXED_PLL_SIZE * (long long)Nmod; |
1190 | |
1191 | do_div(Kpart, source); |
1192 | |
1193 | K = Kpart & 0xFFFFFFFF; |
1194 | |
1195 | /* Check if we need to round */ |
1196 | if ((K % 10) >= 5) |
1197 | K += 5; |
1198 | |
1199 | /* Move down to proper range now rounding is done */ |
1200 | K /= 10; |
1201 | |
1202 | pll_div->k = K; |
1203 | |
1204 | pr_debug("WM8960 PLL: N=%x K=%x pre_div=%d\n" , |
1205 | pll_div->n, pll_div->k, pll_div->pre_div); |
1206 | |
1207 | return 0; |
1208 | } |
1209 | |
1210 | static int wm8960_set_pll(struct snd_soc_component *component, |
1211 | unsigned int freq_in, unsigned int freq_out) |
1212 | { |
1213 | u16 reg; |
1214 | static struct _pll_div pll_div; |
1215 | int ret; |
1216 | |
1217 | if (freq_in && freq_out) { |
1218 | ret = pll_factors(source: freq_in, target: freq_out, pll_div: &pll_div); |
1219 | if (ret != 0) |
1220 | return ret; |
1221 | } |
1222 | |
1223 | /* Disable the PLL: even if we are changing the frequency the |
1224 | * PLL needs to be disabled while we do so. */ |
1225 | snd_soc_component_update_bits(component, WM8960_CLOCK1, mask: 0x1, val: 0); |
1226 | snd_soc_component_update_bits(component, WM8960_POWER2, mask: 0x1, val: 0); |
1227 | |
1228 | if (!freq_in || !freq_out) |
1229 | return 0; |
1230 | |
1231 | reg = snd_soc_component_read(component, WM8960_PLL1) & ~0x3f; |
1232 | reg |= pll_div.pre_div << 4; |
1233 | reg |= pll_div.n; |
1234 | |
1235 | if (pll_div.k) { |
1236 | reg |= 0x20; |
1237 | |
1238 | snd_soc_component_write(component, WM8960_PLL2, val: (pll_div.k >> 16) & 0xff); |
1239 | snd_soc_component_write(component, WM8960_PLL3, val: (pll_div.k >> 8) & 0xff); |
1240 | snd_soc_component_write(component, WM8960_PLL4, val: pll_div.k & 0xff); |
1241 | } |
1242 | snd_soc_component_write(component, WM8960_PLL1, val: reg); |
1243 | |
1244 | /* Turn it on */ |
1245 | snd_soc_component_update_bits(component, WM8960_POWER2, mask: 0x1, val: 0x1); |
1246 | msleep(msecs: 250); |
1247 | snd_soc_component_update_bits(component, WM8960_CLOCK1, mask: 0x1, val: 0x1); |
1248 | |
1249 | return 0; |
1250 | } |
1251 | |
1252 | static int wm8960_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, |
1253 | int source, unsigned int freq_in, unsigned int freq_out) |
1254 | { |
1255 | struct snd_soc_component *component = codec_dai->component; |
1256 | struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(c: component); |
1257 | |
1258 | wm8960->freq_in = freq_in; |
1259 | |
1260 | if (pll_id == WM8960_SYSCLK_AUTO) |
1261 | return 0; |
1262 | |
1263 | return wm8960_set_pll(component, freq_in, freq_out); |
1264 | } |
1265 | |
1266 | static int wm8960_set_dai_clkdiv(struct snd_soc_dai *codec_dai, |
1267 | int div_id, int div) |
1268 | { |
1269 | struct snd_soc_component *component = codec_dai->component; |
1270 | u16 reg; |
1271 | |
1272 | switch (div_id) { |
1273 | case WM8960_SYSCLKDIV: |
1274 | reg = snd_soc_component_read(component, WM8960_CLOCK1) & 0x1f9; |
1275 | snd_soc_component_write(component, WM8960_CLOCK1, val: reg | div); |
1276 | break; |
1277 | case WM8960_DACDIV: |
1278 | reg = snd_soc_component_read(component, WM8960_CLOCK1) & 0x1c7; |
1279 | snd_soc_component_write(component, WM8960_CLOCK1, val: reg | div); |
1280 | break; |
1281 | case WM8960_OPCLKDIV: |
1282 | reg = snd_soc_component_read(component, WM8960_PLL1) & 0x03f; |
1283 | snd_soc_component_write(component, WM8960_PLL1, val: reg | div); |
1284 | break; |
1285 | case WM8960_DCLKDIV: |
1286 | reg = snd_soc_component_read(component, WM8960_CLOCK2) & 0x03f; |
1287 | snd_soc_component_write(component, WM8960_CLOCK2, val: reg | div); |
1288 | break; |
1289 | case WM8960_TOCLKSEL: |
1290 | reg = snd_soc_component_read(component, WM8960_ADDCTL1) & 0x1fd; |
1291 | snd_soc_component_write(component, WM8960_ADDCTL1, val: reg | div); |
1292 | break; |
1293 | default: |
1294 | return -EINVAL; |
1295 | } |
1296 | |
1297 | return 0; |
1298 | } |
1299 | |
1300 | static int wm8960_set_bias_level(struct snd_soc_component *component, |
1301 | enum snd_soc_bias_level level) |
1302 | { |
1303 | struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(c: component); |
1304 | |
1305 | return wm8960->set_bias_level(component, level); |
1306 | } |
1307 | |
1308 | static int wm8960_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, |
1309 | unsigned int freq, int dir) |
1310 | { |
1311 | struct snd_soc_component *component = dai->component; |
1312 | struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(c: component); |
1313 | |
1314 | switch (clk_id) { |
1315 | case WM8960_SYSCLK_MCLK: |
1316 | snd_soc_component_update_bits(component, WM8960_CLOCK1, |
1317 | mask: 0x1, WM8960_SYSCLK_MCLK); |
1318 | break; |
1319 | case WM8960_SYSCLK_PLL: |
1320 | snd_soc_component_update_bits(component, WM8960_CLOCK1, |
1321 | mask: 0x1, WM8960_SYSCLK_PLL); |
1322 | break; |
1323 | case WM8960_SYSCLK_AUTO: |
1324 | break; |
1325 | default: |
1326 | return -EINVAL; |
1327 | } |
1328 | |
1329 | wm8960->sysclk = freq; |
1330 | wm8960->clk_id = clk_id; |
1331 | |
1332 | return 0; |
1333 | } |
1334 | |
1335 | #define WM8960_RATES SNDRV_PCM_RATE_8000_48000 |
1336 | |
1337 | #define WM8960_FORMATS \ |
1338 | (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ |
1339 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) |
1340 | |
1341 | static const struct snd_soc_dai_ops wm8960_dai_ops = { |
1342 | .hw_params = wm8960_hw_params, |
1343 | .hw_free = wm8960_hw_free, |
1344 | .mute_stream = wm8960_mute, |
1345 | .set_fmt = wm8960_set_dai_fmt, |
1346 | .set_clkdiv = wm8960_set_dai_clkdiv, |
1347 | .set_pll = wm8960_set_dai_pll, |
1348 | .set_sysclk = wm8960_set_dai_sysclk, |
1349 | .no_capture_mute = 1, |
1350 | }; |
1351 | |
1352 | static struct snd_soc_dai_driver wm8960_dai = { |
1353 | .name = "wm8960-hifi" , |
1354 | .playback = { |
1355 | .stream_name = "Playback" , |
1356 | .channels_min = 1, |
1357 | .channels_max = 2, |
1358 | .rates = WM8960_RATES, |
1359 | .formats = WM8960_FORMATS,}, |
1360 | .capture = { |
1361 | .stream_name = "Capture" , |
1362 | .channels_min = 1, |
1363 | .channels_max = 2, |
1364 | .rates = WM8960_RATES, |
1365 | .formats = WM8960_FORMATS,}, |
1366 | .ops = &wm8960_dai_ops, |
1367 | .symmetric_rate = 1, |
1368 | }; |
1369 | |
1370 | static int wm8960_probe(struct snd_soc_component *component) |
1371 | { |
1372 | struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(c: component); |
1373 | struct wm8960_data *pdata = &wm8960->pdata; |
1374 | |
1375 | if (pdata->capless) |
1376 | wm8960->set_bias_level = wm8960_set_bias_level_capless; |
1377 | else |
1378 | wm8960->set_bias_level = wm8960_set_bias_level_out3; |
1379 | |
1380 | snd_soc_add_component_controls(component, controls: wm8960_snd_controls, |
1381 | ARRAY_SIZE(wm8960_snd_controls)); |
1382 | wm8960_add_widgets(component); |
1383 | |
1384 | return 0; |
1385 | } |
1386 | |
1387 | static const struct snd_soc_component_driver soc_component_dev_wm8960 = { |
1388 | .probe = wm8960_probe, |
1389 | .set_bias_level = wm8960_set_bias_level, |
1390 | .suspend_bias_off = 1, |
1391 | .idle_bias_on = 1, |
1392 | .use_pmdown_time = 1, |
1393 | .endianness = 1, |
1394 | }; |
1395 | |
1396 | static const struct regmap_config wm8960_regmap = { |
1397 | .reg_bits = 7, |
1398 | .val_bits = 9, |
1399 | .max_register = WM8960_PLL4, |
1400 | |
1401 | .reg_defaults = wm8960_reg_defaults, |
1402 | .num_reg_defaults = ARRAY_SIZE(wm8960_reg_defaults), |
1403 | .cache_type = REGCACHE_MAPLE, |
1404 | |
1405 | .volatile_reg = wm8960_volatile, |
1406 | }; |
1407 | |
1408 | static void wm8960_set_pdata_from_of(struct i2c_client *i2c, |
1409 | struct wm8960_data *pdata) |
1410 | { |
1411 | const struct device_node *np = i2c->dev.of_node; |
1412 | |
1413 | if (of_property_read_bool(np, propname: "wlf,capless" )) |
1414 | pdata->capless = true; |
1415 | |
1416 | if (of_property_read_bool(np, propname: "wlf,shared-lrclk" )) |
1417 | pdata->shared_lrclk = true; |
1418 | |
1419 | of_property_read_u32_array(np, propname: "wlf,gpio-cfg" , out_values: pdata->gpio_cfg, |
1420 | ARRAY_SIZE(pdata->gpio_cfg)); |
1421 | |
1422 | of_property_read_u32_array(np, propname: "wlf,hp-cfg" , out_values: pdata->hp_cfg, |
1423 | ARRAY_SIZE(pdata->hp_cfg)); |
1424 | } |
1425 | |
1426 | static int wm8960_i2c_probe(struct i2c_client *i2c) |
1427 | { |
1428 | struct wm8960_data *pdata = dev_get_platdata(dev: &i2c->dev); |
1429 | struct wm8960_priv *wm8960; |
1430 | unsigned int i; |
1431 | int ret; |
1432 | u8 val; |
1433 | |
1434 | wm8960 = devm_kzalloc(dev: &i2c->dev, size: sizeof(struct wm8960_priv), |
1435 | GFP_KERNEL); |
1436 | if (wm8960 == NULL) |
1437 | return -ENOMEM; |
1438 | |
1439 | wm8960->mclk = devm_clk_get(dev: &i2c->dev, id: "mclk" ); |
1440 | if (IS_ERR(ptr: wm8960->mclk)) { |
1441 | if (PTR_ERR(ptr: wm8960->mclk) == -EPROBE_DEFER) |
1442 | return -EPROBE_DEFER; |
1443 | } else { |
1444 | ret = clk_get_rate(clk: wm8960->mclk); |
1445 | if (ret >= 0) { |
1446 | wm8960->freq_in = ret; |
1447 | } else { |
1448 | dev_err(&i2c->dev, "Failed to read MCLK rate: %d\n" , |
1449 | ret); |
1450 | } |
1451 | } |
1452 | |
1453 | for (i = 0; i < ARRAY_SIZE(wm8960->supplies); i++) |
1454 | wm8960->supplies[i].supply = wm8960_supply_names[i]; |
1455 | |
1456 | ret = devm_regulator_bulk_get(dev: &i2c->dev, ARRAY_SIZE(wm8960->supplies), |
1457 | consumers: wm8960->supplies); |
1458 | if (ret < 0) { |
1459 | dev_err(&i2c->dev, "Failed to request supplies: %d\n" , ret); |
1460 | return ret; |
1461 | } |
1462 | |
1463 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8960->supplies), |
1464 | consumers: wm8960->supplies); |
1465 | if (ret < 0) { |
1466 | dev_err(&i2c->dev, "Failed to enable supplies: %d\n" , ret); |
1467 | return ret; |
1468 | } |
1469 | |
1470 | wm8960->regmap = devm_regmap_init_i2c(i2c, &wm8960_regmap); |
1471 | if (IS_ERR(ptr: wm8960->regmap)) { |
1472 | ret = PTR_ERR(ptr: wm8960->regmap); |
1473 | goto bulk_disable; |
1474 | } |
1475 | |
1476 | if (pdata) |
1477 | memcpy(&wm8960->pdata, pdata, sizeof(struct wm8960_data)); |
1478 | else if (i2c->dev.of_node) |
1479 | wm8960_set_pdata_from_of(i2c, pdata: &wm8960->pdata); |
1480 | |
1481 | ret = i2c_master_recv(client: i2c, buf: &val, count: sizeof(val)); |
1482 | if (ret >= 0) { |
1483 | dev_err(&i2c->dev, "Not wm8960, wm8960 reg can not read by i2c\n" ); |
1484 | ret = -EINVAL; |
1485 | goto bulk_disable; |
1486 | } |
1487 | |
1488 | ret = wm8960_reset(wm8960->regmap); |
1489 | if (ret != 0) { |
1490 | dev_err(&i2c->dev, "Failed to issue reset\n" ); |
1491 | goto bulk_disable; |
1492 | } |
1493 | |
1494 | if (wm8960->pdata.shared_lrclk) { |
1495 | ret = regmap_update_bits(map: wm8960->regmap, WM8960_ADDCTL2, |
1496 | mask: 0x4, val: 0x4); |
1497 | if (ret != 0) { |
1498 | dev_err(&i2c->dev, "Failed to enable LRCM: %d\n" , |
1499 | ret); |
1500 | goto bulk_disable; |
1501 | } |
1502 | } |
1503 | |
1504 | /* Latch the update bits */ |
1505 | regmap_update_bits(map: wm8960->regmap, WM8960_LINVOL, mask: 0x100, val: 0x100); |
1506 | regmap_update_bits(map: wm8960->regmap, WM8960_RINVOL, mask: 0x100, val: 0x100); |
1507 | regmap_update_bits(map: wm8960->regmap, WM8960_LADC, mask: 0x100, val: 0x100); |
1508 | regmap_update_bits(map: wm8960->regmap, WM8960_RADC, mask: 0x100, val: 0x100); |
1509 | regmap_update_bits(map: wm8960->regmap, WM8960_LDAC, mask: 0x100, val: 0x100); |
1510 | regmap_update_bits(map: wm8960->regmap, WM8960_RDAC, mask: 0x100, val: 0x100); |
1511 | regmap_update_bits(map: wm8960->regmap, WM8960_LOUT1, mask: 0x100, val: 0x100); |
1512 | regmap_update_bits(map: wm8960->regmap, WM8960_ROUT1, mask: 0x100, val: 0x100); |
1513 | regmap_update_bits(map: wm8960->regmap, WM8960_LOUT2, mask: 0x100, val: 0x100); |
1514 | regmap_update_bits(map: wm8960->regmap, WM8960_ROUT2, mask: 0x100, val: 0x100); |
1515 | |
1516 | /* ADCLRC pin configured as GPIO. */ |
1517 | regmap_update_bits(map: wm8960->regmap, WM8960_IFACE2, mask: 1 << 6, |
1518 | val: wm8960->pdata.gpio_cfg[0] << 6); |
1519 | regmap_update_bits(map: wm8960->regmap, WM8960_ADDCTL4, mask: 0xF << 4, |
1520 | val: wm8960->pdata.gpio_cfg[1] << 4); |
1521 | |
1522 | /* Enable headphone jack detect */ |
1523 | regmap_update_bits(map: wm8960->regmap, WM8960_ADDCTL4, mask: 3 << 2, |
1524 | val: wm8960->pdata.hp_cfg[0] << 2); |
1525 | regmap_update_bits(map: wm8960->regmap, WM8960_ADDCTL2, mask: 3 << 5, |
1526 | val: wm8960->pdata.hp_cfg[1] << 5); |
1527 | regmap_update_bits(map: wm8960->regmap, WM8960_ADDCTL1, mask: 3, |
1528 | val: wm8960->pdata.hp_cfg[2]); |
1529 | |
1530 | i2c_set_clientdata(client: i2c, data: wm8960); |
1531 | |
1532 | ret = devm_snd_soc_register_component(dev: &i2c->dev, |
1533 | component_driver: &soc_component_dev_wm8960, dai_drv: &wm8960_dai, num_dai: 1); |
1534 | if (ret) |
1535 | goto bulk_disable; |
1536 | |
1537 | return 0; |
1538 | |
1539 | bulk_disable: |
1540 | regulator_bulk_disable(ARRAY_SIZE(wm8960->supplies), consumers: wm8960->supplies); |
1541 | return ret; |
1542 | } |
1543 | |
1544 | static void wm8960_i2c_remove(struct i2c_client *client) |
1545 | { |
1546 | struct wm8960_priv *wm8960 = i2c_get_clientdata(client); |
1547 | |
1548 | regulator_bulk_disable(ARRAY_SIZE(wm8960->supplies), consumers: wm8960->supplies); |
1549 | } |
1550 | |
1551 | static const struct i2c_device_id wm8960_i2c_id[] = { |
1552 | { "wm8960" , 0 }, |
1553 | { } |
1554 | }; |
1555 | MODULE_DEVICE_TABLE(i2c, wm8960_i2c_id); |
1556 | |
1557 | #if defined(CONFIG_OF) |
1558 | static const struct of_device_id wm8960_of_match[] = { |
1559 | { .compatible = "wlf,wm8960" , }, |
1560 | { } |
1561 | }; |
1562 | MODULE_DEVICE_TABLE(of, wm8960_of_match); |
1563 | #endif |
1564 | |
1565 | #if defined(CONFIG_ACPI) |
1566 | static const struct acpi_device_id wm8960_acpi_match[] = { |
1567 | { "1AEC8960" , 0 }, /* Wolfson PCI ID + part ID */ |
1568 | { "10138960" , 0 }, /* Cirrus Logic PCI ID + part ID */ |
1569 | { }, |
1570 | }; |
1571 | MODULE_DEVICE_TABLE(acpi, wm8960_acpi_match); |
1572 | #endif |
1573 | |
1574 | static struct i2c_driver wm8960_i2c_driver = { |
1575 | .driver = { |
1576 | .name = "wm8960" , |
1577 | .of_match_table = of_match_ptr(wm8960_of_match), |
1578 | .acpi_match_table = ACPI_PTR(wm8960_acpi_match), |
1579 | }, |
1580 | .probe = wm8960_i2c_probe, |
1581 | .remove = wm8960_i2c_remove, |
1582 | .id_table = wm8960_i2c_id, |
1583 | }; |
1584 | |
1585 | module_i2c_driver(wm8960_i2c_driver); |
1586 | |
1587 | MODULE_DESCRIPTION("ASoC WM8960 driver" ); |
1588 | MODULE_AUTHOR("Liam Girdwood" ); |
1589 | MODULE_LICENSE("GPL" ); |
1590 | |