]>
Commit | Line | Data |
---|---|---|
8e8e69d6 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
996cc849 SP |
2 | /* |
3 | * byt_cr_dpcm_rt5640.c - ASoc Machine driver for Intel Byt CR platform | |
4 | * | |
5 | * Copyright (C) 2014 Intel Corp | |
6 | * Author: Subhransu S. Prusty <subhransu.s.prusty@intel.com> | |
7 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
8 | * | |
996cc849 SP |
9 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
10 | */ | |
11 | ||
6a7c05e5 | 12 | #include <linux/i2c.h> |
996cc849 SP |
13 | #include <linux/init.h> |
14 | #include <linux/module.h> | |
9f2cf73e | 15 | #include <linux/moduleparam.h> |
996cc849 | 16 | #include <linux/platform_device.h> |
a2d5563b | 17 | #include <linux/acpi.h> |
17b5273d | 18 | #include <linux/clk.h> |
996cc849 | 19 | #include <linux/device.h> |
a2d5563b | 20 | #include <linux/dmi.h> |
77323108 | 21 | #include <linux/input.h> |
996cc849 | 22 | #include <linux/slab.h> |
e214f5e7 | 23 | #include <asm/cpu_device_id.h> |
996cc849 SP |
24 | #include <sound/pcm.h> |
25 | #include <sound/pcm_params.h> | |
26 | #include <sound/soc.h> | |
a2d5563b | 27 | #include <sound/jack.h> |
7feb2f78 | 28 | #include <sound/soc-acpi.h> |
a3ad2911 | 29 | #include <dt-bindings/sound/rt5640.h> |
e56c72d5 | 30 | #include "../../codecs/rt5640.h" |
b97169da | 31 | #include "../atom/sst-atom-controls.h" |
e214f5e7 | 32 | #include "../common/sst-dsp.h" |
996cc849 | 33 | |
ab738e4e PLB |
34 | enum { |
35 | BYT_RT5640_DMIC1_MAP, | |
36 | BYT_RT5640_DMIC2_MAP, | |
37 | BYT_RT5640_IN1_MAP, | |
59e8b652 | 38 | BYT_RT5640_IN3_MAP, |
ab738e4e PLB |
39 | }; |
40 | ||
77323108 HG |
41 | enum { |
42 | BYT_RT5640_JD_SRC_GPIO1 = (RT5640_JD_SRC_GPIO1 << 4), | |
43 | BYT_RT5640_JD_SRC_JD1_IN4P = (RT5640_JD_SRC_JD1_IN4P << 4), | |
44 | BYT_RT5640_JD_SRC_JD2_IN4N = (RT5640_JD_SRC_JD2_IN4N << 4), | |
45 | BYT_RT5640_JD_SRC_GPIO2 = (RT5640_JD_SRC_GPIO2 << 4), | |
46 | BYT_RT5640_JD_SRC_GPIO3 = (RT5640_JD_SRC_GPIO3 << 4), | |
47 | BYT_RT5640_JD_SRC_GPIO4 = (RT5640_JD_SRC_GPIO4 << 4), | |
48 | }; | |
49 | ||
50 | enum { | |
51 | BYT_RT5640_OVCD_TH_600UA = (6 << 8), | |
52 | BYT_RT5640_OVCD_TH_1500UA = (15 << 8), | |
53 | BYT_RT5640_OVCD_TH_2000UA = (20 << 8), | |
54 | }; | |
55 | ||
56 | enum { | |
57 | BYT_RT5640_OVCD_SF_0P5 = (RT5640_OVCD_SF_0P5 << 13), | |
58 | BYT_RT5640_OVCD_SF_0P75 = (RT5640_OVCD_SF_0P75 << 13), | |
59 | BYT_RT5640_OVCD_SF_1P0 = (RT5640_OVCD_SF_1P0 << 13), | |
60 | BYT_RT5640_OVCD_SF_1P5 = (RT5640_OVCD_SF_1P5 << 13), | |
61 | }; | |
df1a2776 | 62 | |
77323108 HG |
63 | #define BYT_RT5640_MAP(quirk) ((quirk) & GENMASK(3, 0)) |
64 | #define BYT_RT5640_JDSRC(quirk) (((quirk) & GENMASK(7, 4)) >> 4) | |
65 | #define BYT_RT5640_OVCD_TH(quirk) (((quirk) & GENMASK(12, 8)) >> 8) | |
66 | #define BYT_RT5640_OVCD_SF(quirk) (((quirk) & GENMASK(14, 13)) >> 13) | |
67 | #define BYT_RT5640_JD_NOT_INV BIT(16) | |
68 | #define BYT_RT5640_MONO_SPEAKER BIT(17) | |
69 | #define BYT_RT5640_DIFF_MIC BIT(18) /* default is single-ended */ | |
70 | #define BYT_RT5640_SSP2_AIF2 BIT(19) /* default is using AIF1 */ | |
71 | #define BYT_RT5640_SSP0_AIF1 BIT(20) | |
72 | #define BYT_RT5640_SSP0_AIF2 BIT(21) | |
73 | #define BYT_RT5640_MCLK_EN BIT(22) | |
74 | #define BYT_RT5640_MCLK_25MHZ BIT(23) | |
75 | ||
96a388fe HG |
76 | #define BYTCR_INPUT_DEFAULTS \ |
77 | (BYT_RT5640_IN3_MAP | \ | |
56ff4409 HG |
78 | BYT_RT5640_JD_SRC_JD1_IN4P | \ |
79 | BYT_RT5640_OVCD_TH_2000UA | \ | |
80 | BYT_RT5640_OVCD_SF_0P75 | \ | |
96a388fe HG |
81 | BYT_RT5640_DIFF_MIC) |
82 | ||
77323108 HG |
83 | /* in-diff or dmic-pin + jdsrc + ovcd-th + -sf + jd-inv + terminating entry */ |
84 | #define MAX_NO_PROPS 6 | |
6a7c05e5 | 85 | |
df1a2776 | 86 | struct byt_rt5640_private { |
77323108 | 87 | struct snd_soc_jack jack; |
df1a2776 IT |
88 | struct clk *mclk; |
89 | }; | |
cb67d765 | 90 | static bool is_bytcr; |
ab738e4e | 91 | |
bf46241b | 92 | static unsigned long byt_rt5640_quirk = BYT_RT5640_MCLK_EN; |
2fb2a19a PLB |
93 | static int quirk_override = -1; |
94 | module_param_named(quirk, quirk_override, int, 0444); | |
9f2cf73e | 95 | MODULE_PARM_DESC(quirk, "Board-specific quirk override"); |
df1a2776 | 96 | |
d7e60d52 PLB |
97 | static void log_quirks(struct device *dev) |
98 | { | |
cb67d765 | 99 | int map; |
cb67d765 PLB |
100 | bool has_mclk = false; |
101 | bool has_ssp0 = false; | |
102 | bool has_ssp0_aif1 = false; | |
103 | bool has_ssp0_aif2 = false; | |
104 | bool has_ssp2_aif2 = false; | |
105 | ||
106 | map = BYT_RT5640_MAP(byt_rt5640_quirk); | |
107 | switch (map) { | |
108 | case BYT_RT5640_DMIC1_MAP: | |
109 | dev_info(dev, "quirk DMIC1_MAP enabled\n"); | |
cb67d765 PLB |
110 | break; |
111 | case BYT_RT5640_DMIC2_MAP: | |
112 | dev_info(dev, "quirk DMIC2_MAP enabled\n"); | |
cb67d765 PLB |
113 | break; |
114 | case BYT_RT5640_IN1_MAP: | |
115 | dev_info(dev, "quirk IN1_MAP enabled\n"); | |
116 | break; | |
117 | case BYT_RT5640_IN3_MAP: | |
118 | dev_info(dev, "quirk IN3_MAP enabled\n"); | |
119 | break; | |
120 | default: | |
121 | dev_err(dev, "quirk map 0x%x is not supported, microphone input will not work\n", map); | |
122 | break; | |
123 | } | |
77323108 HG |
124 | if (BYT_RT5640_JDSRC(byt_rt5640_quirk)) { |
125 | dev_info(dev, "quirk realtek,jack-detect-source %ld\n", | |
126 | BYT_RT5640_JDSRC(byt_rt5640_quirk)); | |
127 | dev_info(dev, "quirk realtek,over-current-threshold-microamp %ld\n", | |
128 | BYT_RT5640_OVCD_TH(byt_rt5640_quirk) * 100); | |
129 | dev_info(dev, "quirk realtek,over-current-scale-factor %ld\n", | |
130 | BYT_RT5640_OVCD_SF(byt_rt5640_quirk)); | |
131 | } | |
132 | if (byt_rt5640_quirk & BYT_RT5640_JD_NOT_INV) | |
133 | dev_info(dev, "quirk JD_NOT_INV enabled\n"); | |
d7e60d52 | 134 | if (byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER) |
cb67d765 | 135 | dev_info(dev, "quirk MONO_SPEAKER enabled\n"); |
a3ad2911 HG |
136 | if (byt_rt5640_quirk & BYT_RT5640_DIFF_MIC) |
137 | dev_info(dev, "quirk DIFF_MIC enabled\n"); | |
cb67d765 PLB |
138 | if (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF1) { |
139 | dev_info(dev, "quirk SSP0_AIF1 enabled\n"); | |
140 | has_ssp0 = true; | |
141 | has_ssp0_aif1 = true; | |
142 | } | |
143 | if (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2) { | |
144 | dev_info(dev, "quirk SSP0_AIF2 enabled\n"); | |
145 | has_ssp0 = true; | |
146 | has_ssp0_aif2 = true; | |
147 | } | |
148 | if (byt_rt5640_quirk & BYT_RT5640_SSP2_AIF2) { | |
149 | dev_info(dev, "quirk SSP2_AIF2 enabled\n"); | |
150 | has_ssp2_aif2 = true; | |
151 | } | |
152 | if (is_bytcr && !has_ssp0) | |
153 | dev_err(dev, "Invalid routing, bytcr detected but no SSP0-based quirk, audio cannot work with SSP2 on bytcr\n"); | |
154 | if (has_ssp0_aif1 && has_ssp0_aif2) | |
155 | dev_err(dev, "Invalid routing, SSP0 cannot be connected to both AIF1 and AIF2\n"); | |
156 | if (has_ssp0 && has_ssp2_aif2) | |
157 | dev_err(dev, "Invalid routing, cannot have both SSP0 and SSP2 connected to codec\n"); | |
158 | ||
159 | if (byt_rt5640_quirk & BYT_RT5640_MCLK_EN) { | |
160 | dev_info(dev, "quirk MCLK_EN enabled\n"); | |
161 | has_mclk = true; | |
162 | } | |
163 | if (byt_rt5640_quirk & BYT_RT5640_MCLK_25MHZ) { | |
164 | if (has_mclk) | |
165 | dev_info(dev, "quirk MCLK_25MHZ enabled\n"); | |
166 | else | |
167 | dev_err(dev, "quirk MCLK_25MHZ enabled but quirk MCLK not selected, will be ignored\n"); | |
168 | } | |
d7e60d52 PLB |
169 | } |
170 | ||
bcd9a325 HG |
171 | static int byt_rt5640_prepare_and_enable_pll1(struct snd_soc_dai *codec_dai, |
172 | int rate) | |
173 | { | |
174 | int ret; | |
175 | ||
176 | /* Configure the PLL before selecting it */ | |
177 | if (!(byt_rt5640_quirk & BYT_RT5640_MCLK_EN)) { | |
178 | /* use bitclock as PLL input */ | |
179 | if ((byt_rt5640_quirk & BYT_RT5640_SSP0_AIF1) || | |
180 | (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2)) { | |
181 | /* 2x16 bit slots on SSP0 */ | |
182 | ret = snd_soc_dai_set_pll(codec_dai, 0, | |
183 | RT5640_PLL1_S_BCLK1, | |
184 | rate * 32, rate * 512); | |
185 | } else { | |
186 | /* 2x15 bit slots on SSP2 */ | |
187 | ret = snd_soc_dai_set_pll(codec_dai, 0, | |
188 | RT5640_PLL1_S_BCLK1, | |
189 | rate * 50, rate * 512); | |
190 | } | |
191 | } else { | |
192 | if (byt_rt5640_quirk & BYT_RT5640_MCLK_25MHZ) { | |
193 | ret = snd_soc_dai_set_pll(codec_dai, 0, | |
194 | RT5640_PLL1_S_MCLK, | |
195 | 25000000, rate * 512); | |
196 | } else { | |
197 | ret = snd_soc_dai_set_pll(codec_dai, 0, | |
198 | RT5640_PLL1_S_MCLK, | |
199 | 19200000, rate * 512); | |
200 | } | |
201 | } | |
202 | ||
203 | if (ret < 0) { | |
a3a956a6 | 204 | dev_err(codec_dai->component->dev, "can't set pll: %d\n", ret); |
bcd9a325 HG |
205 | return ret; |
206 | } | |
207 | ||
208 | ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_PLL1, | |
209 | rate * 512, SND_SOC_CLOCK_IN); | |
210 | if (ret < 0) { | |
a3a956a6 | 211 | dev_err(codec_dai->component->dev, "can't set clock %d\n", ret); |
bcd9a325 HG |
212 | return ret; |
213 | } | |
214 | ||
215 | return 0; | |
216 | } | |
d7e60d52 | 217 | |
df1a2776 IT |
218 | #define BYT_CODEC_DAI1 "rt5640-aif1" |
219 | #define BYT_CODEC_DAI2 "rt5640-aif2" | |
220 | ||
df1a2776 IT |
221 | static int platform_clock_control(struct snd_soc_dapm_widget *w, |
222 | struct snd_kcontrol *k, int event) | |
223 | { | |
224 | struct snd_soc_dapm_context *dapm = w->dapm; | |
225 | struct snd_soc_card *card = dapm->card; | |
226 | struct snd_soc_dai *codec_dai; | |
227 | struct byt_rt5640_private *priv = snd_soc_card_get_drvdata(card); | |
228 | int ret; | |
229 | ||
dfb6ec7a PLB |
230 | codec_dai = snd_soc_card_get_codec_dai(card, BYT_CODEC_DAI1); |
231 | if (!codec_dai) | |
232 | codec_dai = snd_soc_card_get_codec_dai(card, BYT_CODEC_DAI2); | |
233 | ||
df1a2776 IT |
234 | if (!codec_dai) { |
235 | dev_err(card->dev, | |
236 | "Codec dai not found; Unable to set platform clock\n"); | |
237 | return -EIO; | |
238 | } | |
239 | ||
240 | if (SND_SOC_DAPM_EVENT_ON(event)) { | |
17b5273d | 241 | if (byt_rt5640_quirk & BYT_RT5640_MCLK_EN) { |
df1a2776 IT |
242 | ret = clk_prepare_enable(priv->mclk); |
243 | if (ret < 0) { | |
244 | dev_err(card->dev, | |
cb67d765 | 245 | "could not configure MCLK state\n"); |
df1a2776 IT |
246 | return ret; |
247 | } | |
248 | } | |
bcd9a325 | 249 | ret = byt_rt5640_prepare_and_enable_pll1(codec_dai, 48000); |
df1a2776 IT |
250 | } else { |
251 | /* | |
252 | * Set codec clock source to internal clock before | |
253 | * turning off the platform clock. Codec needs clock | |
254 | * for Jack detection and button press | |
255 | */ | |
256 | ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_RCCLK, | |
60448b07 | 257 | 48000 * 512, |
df1a2776 IT |
258 | SND_SOC_CLOCK_IN); |
259 | if (!ret) { | |
17b5273d | 260 | if (byt_rt5640_quirk & BYT_RT5640_MCLK_EN) |
df1a2776 IT |
261 | clk_disable_unprepare(priv->mclk); |
262 | } | |
263 | } | |
264 | ||
265 | if (ret < 0) { | |
266 | dev_err(card->dev, "can't set codec sysclk: %d\n", ret); | |
267 | return ret; | |
268 | } | |
269 | ||
270 | return 0; | |
271 | } | |
ab738e4e | 272 | |
a2d5563b | 273 | static const struct snd_soc_dapm_widget byt_rt5640_widgets[] = { |
996cc849 SP |
274 | SND_SOC_DAPM_HP("Headphone", NULL), |
275 | SND_SOC_DAPM_MIC("Headset Mic", NULL), | |
e2be1da0 PLB |
276 | SND_SOC_DAPM_MIC("Internal Mic", NULL), |
277 | SND_SOC_DAPM_SPK("Speaker", NULL), | |
df1a2776 IT |
278 | SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, |
279 | platform_clock_control, SND_SOC_DAPM_PRE_PMU | | |
280 | SND_SOC_DAPM_POST_PMD), | |
281 | ||
996cc849 SP |
282 | }; |
283 | ||
a2d5563b | 284 | static const struct snd_soc_dapm_route byt_rt5640_audio_map[] = { |
df1a2776 IT |
285 | {"Headphone", NULL, "Platform Clock"}, |
286 | {"Headset Mic", NULL, "Platform Clock"}, | |
287 | {"Internal Mic", NULL, "Platform Clock"}, | |
288 | {"Speaker", NULL, "Platform Clock"}, | |
289 | ||
996cc849 | 290 | {"Headset Mic", NULL, "MICBIAS1"}, |
e2be1da0 | 291 | {"IN2P", NULL, "Headset Mic"}, |
996cc849 SP |
292 | {"Headphone", NULL, "HPOL"}, |
293 | {"Headphone", NULL, "HPOR"}, | |
996cc849 SP |
294 | }; |
295 | ||
a2d5563b PLB |
296 | static const struct snd_soc_dapm_route byt_rt5640_intmic_dmic1_map[] = { |
297 | {"DMIC1", NULL, "Internal Mic"}, | |
298 | }; | |
299 | ||
300 | static const struct snd_soc_dapm_route byt_rt5640_intmic_dmic2_map[] = { | |
301 | {"DMIC2", NULL, "Internal Mic"}, | |
302 | }; | |
303 | ||
304 | static const struct snd_soc_dapm_route byt_rt5640_intmic_in1_map[] = { | |
305 | {"Internal Mic", NULL, "MICBIAS1"}, | |
306 | {"IN1P", NULL, "Internal Mic"}, | |
307 | }; | |
308 | ||
59e8b652 PLB |
309 | static const struct snd_soc_dapm_route byt_rt5640_intmic_in3_map[] = { |
310 | {"Internal Mic", NULL, "MICBIAS1"}, | |
311 | {"IN3P", NULL, "Internal Mic"}, | |
312 | }; | |
313 | ||
89b8907c PLB |
314 | static const struct snd_soc_dapm_route byt_rt5640_ssp2_aif1_map[] = { |
315 | {"ssp2 Tx", NULL, "codec_out0"}, | |
316 | {"ssp2 Tx", NULL, "codec_out1"}, | |
317 | {"codec_in0", NULL, "ssp2 Rx"}, | |
318 | {"codec_in1", NULL, "ssp2 Rx"}, | |
319 | ||
320 | {"AIF1 Playback", NULL, "ssp2 Tx"}, | |
321 | {"ssp2 Rx", NULL, "AIF1 Capture"}, | |
322 | }; | |
323 | ||
324 | static const struct snd_soc_dapm_route byt_rt5640_ssp2_aif2_map[] = { | |
325 | {"ssp2 Tx", NULL, "codec_out0"}, | |
326 | {"ssp2 Tx", NULL, "codec_out1"}, | |
327 | {"codec_in0", NULL, "ssp2 Rx"}, | |
328 | {"codec_in1", NULL, "ssp2 Rx"}, | |
329 | ||
330 | {"AIF2 Playback", NULL, "ssp2 Tx"}, | |
331 | {"ssp2 Rx", NULL, "AIF2 Capture"}, | |
332 | }; | |
333 | ||
f47088d5 PLB |
334 | static const struct snd_soc_dapm_route byt_rt5640_ssp0_aif1_map[] = { |
335 | {"ssp0 Tx", NULL, "modem_out"}, | |
336 | {"modem_in", NULL, "ssp0 Rx"}, | |
337 | ||
338 | {"AIF1 Playback", NULL, "ssp0 Tx"}, | |
339 | {"ssp0 Rx", NULL, "AIF1 Capture"}, | |
340 | }; | |
341 | ||
342 | static const struct snd_soc_dapm_route byt_rt5640_ssp0_aif2_map[] = { | |
343 | {"ssp0 Tx", NULL, "modem_out"}, | |
344 | {"modem_in", NULL, "ssp0 Rx"}, | |
345 | ||
346 | {"AIF2 Playback", NULL, "ssp0 Tx"}, | |
347 | {"ssp0 Rx", NULL, "AIF2 Capture"}, | |
348 | }; | |
349 | ||
68817cdb PLB |
350 | static const struct snd_soc_dapm_route byt_rt5640_stereo_spk_map[] = { |
351 | {"Speaker", NULL, "SPOLP"}, | |
352 | {"Speaker", NULL, "SPOLN"}, | |
353 | {"Speaker", NULL, "SPORP"}, | |
354 | {"Speaker", NULL, "SPORN"}, | |
355 | }; | |
356 | ||
357 | static const struct snd_soc_dapm_route byt_rt5640_mono_spk_map[] = { | |
358 | {"Speaker", NULL, "SPOLP"}, | |
359 | {"Speaker", NULL, "SPOLN"}, | |
360 | }; | |
361 | ||
a2d5563b | 362 | static const struct snd_kcontrol_new byt_rt5640_controls[] = { |
996cc849 SP |
363 | SOC_DAPM_PIN_SWITCH("Headphone"), |
364 | SOC_DAPM_PIN_SWITCH("Headset Mic"), | |
e2be1da0 PLB |
365 | SOC_DAPM_PIN_SWITCH("Internal Mic"), |
366 | SOC_DAPM_PIN_SWITCH("Speaker"), | |
996cc849 SP |
367 | }; |
368 | ||
77323108 HG |
369 | static struct snd_soc_jack_pin rt5640_pins[] = { |
370 | { | |
371 | .pin = "Headphone", | |
372 | .mask = SND_JACK_HEADPHONE, | |
373 | }, | |
374 | { | |
375 | .pin = "Headset Mic", | |
376 | .mask = SND_JACK_MICROPHONE, | |
377 | }, | |
378 | }; | |
379 | ||
a2d5563b | 380 | static int byt_rt5640_aif1_hw_params(struct snd_pcm_substream *substream, |
996cc849 SP |
381 | struct snd_pcm_hw_params *params) |
382 | { | |
383 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | |
bcd9a325 | 384 | struct snd_soc_dai *dai = rtd->codec_dai; |
996cc849 | 385 | |
bcd9a325 | 386 | return byt_rt5640_prepare_and_enable_pll1(dai, params_rate(params)); |
996cc849 SP |
387 | } |
388 | ||
3c0d0116 | 389 | /* Please keep this list alphabetically sorted */ |
a2d5563b | 390 | static const struct dmi_system_id byt_rt5640_quirk_table[] = { |
ec8e8418 HG |
391 | { /* Acer Iconia Tab 8 W1-810 */ |
392 | .matches = { | |
393 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Acer"), | |
394 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Iconia W1-810"), | |
395 | }, | |
396 | .driver_data = (void *)(BYT_RT5640_DMIC1_MAP | | |
397 | BYT_RT5640_JD_SRC_JD1_IN4P | | |
f12a0a3c | 398 | BYT_RT5640_OVCD_TH_1500UA | |
ec8e8418 HG |
399 | BYT_RT5640_OVCD_SF_0P75 | |
400 | BYT_RT5640_SSP0_AIF1 | | |
401 | BYT_RT5640_MCLK_EN), | |
402 | }, | |
3c0d0116 | 403 | { |
3c0d0116 HG |
404 | .matches = { |
405 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), | |
406 | DMI_MATCH(DMI_PRODUCT_NAME, "Aspire SW5-012"), | |
407 | }, | |
408 | .driver_data = (void *)(BYT_RT5640_IN1_MAP | | |
409 | BYT_RT5640_MCLK_EN | | |
410 | BYT_RT5640_SSP0_AIF1), | |
411 | ||
412 | }, | |
bcf441ac HG |
413 | { |
414 | .matches = { | |
415 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ARCHOS"), | |
416 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "ARCHOS 80 Cesium"), | |
417 | }, | |
418 | .driver_data = (void *)(BYTCR_INPUT_DEFAULTS | | |
419 | BYT_RT5640_MONO_SPEAKER | | |
420 | BYT_RT5640_SSP0_AIF1 | | |
421 | BYT_RT5640_MCLK_EN), | |
422 | }, | |
51a13e40 SG |
423 | { |
424 | .matches = { | |
425 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), | |
426 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "ME176C"), | |
427 | }, | |
428 | .driver_data = (void *)(BYT_RT5640_IN1_MAP | | |
429 | BYT_RT5640_JD_SRC_JD2_IN4N | | |
430 | BYT_RT5640_OVCD_TH_2000UA | | |
431 | BYT_RT5640_OVCD_SF_0P75 | | |
432 | BYT_RT5640_SSP0_AIF1 | | |
433 | BYT_RT5640_MCLK_EN), | |
434 | }, | |
a2d5563b | 435 | { |
a2d5563b | 436 | .matches = { |
73442e3c PLB |
437 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), |
438 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TA"), | |
a2d5563b | 439 | }, |
17b5273d | 440 | .driver_data = (void *)(BYT_RT5640_IN1_MAP | |
77323108 HG |
441 | BYT_RT5640_JD_SRC_JD2_IN4N | |
442 | BYT_RT5640_OVCD_TH_2000UA | | |
443 | BYT_RT5640_OVCD_SF_0P75 | | |
17b5273d | 444 | BYT_RT5640_MCLK_EN), |
a2d5563b PLB |
445 | }, |
446 | { | |
a2d5563b | 447 | .matches = { |
73442e3c PLB |
448 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), |
449 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TAF"), | |
450 | }, | |
17b5273d PLB |
451 | .driver_data = (void *)(BYT_RT5640_IN1_MAP | |
452 | BYT_RT5640_MONO_SPEAKER | | |
453 | BYT_RT5640_DIFF_MIC | | |
454 | BYT_RT5640_SSP0_AIF2 | | |
455 | BYT_RT5640_MCLK_EN), | |
73442e3c | 456 | }, |
ec8e8418 HG |
457 | { /* Chuwi Vi8 (CWI506) */ |
458 | .matches = { | |
459 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Insyde"), | |
460 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "i86"), | |
461 | /* The above are too generic, also match BIOS info */ | |
462 | DMI_MATCH(DMI_BIOS_VERSION, "CHUWI.D86JLBNR"), | |
463 | }, | |
464 | .driver_data = (void *)(BYTCR_INPUT_DEFAULTS | | |
465 | BYT_RT5640_MONO_SPEAKER | | |
466 | BYT_RT5640_SSP0_AIF1 | | |
467 | BYT_RT5640_MCLK_EN), | |
468 | }, | |
d5a1826c HG |
469 | { |
470 | /* Chuwi Vi10 (CWI505) */ | |
471 | .matches = { | |
472 | DMI_MATCH(DMI_BOARD_VENDOR, "Hampoo"), | |
473 | DMI_MATCH(DMI_BOARD_NAME, "BYT-PF02"), | |
474 | DMI_MATCH(DMI_SYS_VENDOR, "ilife"), | |
475 | DMI_MATCH(DMI_PRODUCT_NAME, "S165"), | |
476 | }, | |
477 | .driver_data = (void *)(BYT_RT5640_IN1_MAP | | |
478 | BYT_RT5640_JD_SRC_JD2_IN4N | | |
479 | BYT_RT5640_OVCD_TH_2000UA | | |
480 | BYT_RT5640_OVCD_SF_0P75 | | |
481 | BYT_RT5640_DIFF_MIC | | |
482 | BYT_RT5640_SSP0_AIF1 | | |
483 | BYT_RT5640_MCLK_EN), | |
484 | }, | |
3c0d0116 | 485 | { |
3c0d0116 HG |
486 | .matches = { |
487 | DMI_MATCH(DMI_SYS_VENDOR, "Circuitco"), | |
488 | DMI_MATCH(DMI_PRODUCT_NAME, "Minnowboard Max B3 PLATFORM"), | |
489 | }, | |
490 | .driver_data = (void *)(BYT_RT5640_DMIC1_MAP), | |
491 | }, | |
9ee6f8a8 HG |
492 | { /* Connect Tablet 9 */ |
493 | .matches = { | |
494 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Connect"), | |
495 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Tablet 9"), | |
496 | }, | |
497 | .driver_data = (void *)(BYTCR_INPUT_DEFAULTS | | |
498 | BYT_RT5640_MONO_SPEAKER | | |
499 | BYT_RT5640_SSP0_AIF1 | | |
500 | BYT_RT5640_MCLK_EN), | |
501 | }, | |
73442e3c | 502 | { |
73442e3c | 503 | .matches = { |
6748fb7e | 504 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
73442e3c | 505 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Venue 8 Pro 5830"), |
a2d5563b | 506 | }, |
6748fb7e | 507 | .driver_data = (void *)(BYT_RT5640_DMIC1_MAP | |
77323108 HG |
508 | BYT_RT5640_JD_SRC_JD2_IN4N | |
509 | BYT_RT5640_OVCD_TH_2000UA | | |
510 | BYT_RT5640_OVCD_SF_0P75 | | |
6748fb7e | 511 | BYT_RT5640_MONO_SPEAKER | |
17b5273d | 512 | BYT_RT5640_MCLK_EN), |
a2d5563b | 513 | }, |
55fc2056 | 514 | { |
55fc2056 | 515 | .matches = { |
73442e3c PLB |
516 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), |
517 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "HP ElitePad 1000 G2"), | |
55fc2056 | 518 | }, |
17b5273d PLB |
519 | .driver_data = (void *)(BYT_RT5640_IN1_MAP | |
520 | BYT_RT5640_MCLK_EN), | |
55fc2056 | 521 | }, |
ec8e8418 HG |
522 | { /* HP Pavilion x2 10-n000nd */ |
523 | .matches = { | |
524 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), | |
525 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "HP Pavilion x2 Detachable"), | |
526 | }, | |
527 | .driver_data = (void *)(BYT_RT5640_DMIC1_MAP | | |
528 | BYT_RT5640_JD_SRC_JD2_IN4N | | |
529 | BYT_RT5640_OVCD_TH_1500UA | | |
530 | BYT_RT5640_OVCD_SF_0P75 | | |
531 | BYT_RT5640_SSP0_AIF1 | | |
532 | BYT_RT5640_MCLK_EN), | |
533 | }, | |
534 | { /* HP Stream 7 */ | |
535 | .matches = { | |
536 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), | |
537 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "HP Stream 7 Tablet"), | |
538 | }, | |
539 | .driver_data = (void *)(BYTCR_INPUT_DEFAULTS | | |
540 | BYT_RT5640_MONO_SPEAKER | | |
541 | BYT_RT5640_JD_NOT_INV | | |
542 | BYT_RT5640_SSP0_AIF1 | | |
543 | BYT_RT5640_MCLK_EN), | |
544 | }, | |
545 | { /* I.T.Works TW891 */ | |
546 | .matches = { | |
547 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "To be filled by O.E.M."), | |
548 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "TW891"), | |
549 | DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "To be filled by O.E.M."), | |
550 | DMI_EXACT_MATCH(DMI_BOARD_NAME, "TW891"), | |
551 | }, | |
552 | .driver_data = (void *)(BYTCR_INPUT_DEFAULTS | | |
553 | BYT_RT5640_MONO_SPEAKER | | |
554 | BYT_RT5640_SSP0_AIF1 | | |
555 | BYT_RT5640_MCLK_EN), | |
556 | }, | |
557 | { /* Lamina I8270 / T701BR.SE */ | |
558 | .matches = { | |
559 | DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Lamina"), | |
560 | DMI_EXACT_MATCH(DMI_BOARD_NAME, "T701BR.SE"), | |
561 | }, | |
562 | .driver_data = (void *)(BYTCR_INPUT_DEFAULTS | | |
563 | BYT_RT5640_MONO_SPEAKER | | |
564 | BYT_RT5640_JD_NOT_INV | | |
565 | BYT_RT5640_SSP0_AIF1 | | |
566 | BYT_RT5640_MCLK_EN), | |
567 | }, | |
81583afe HG |
568 | { /* Lenovo Miix 2 8 */ |
569 | .matches = { | |
570 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"), | |
571 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "20326"), | |
572 | DMI_EXACT_MATCH(DMI_BOARD_NAME, "Hiking"), | |
573 | }, | |
574 | .driver_data = (void *)(BYT_RT5640_DMIC1_MAP | | |
575 | BYT_RT5640_JD_SRC_JD2_IN4N | | |
576 | BYT_RT5640_OVCD_TH_2000UA | | |
577 | BYT_RT5640_OVCD_SF_0P75 | | |
578 | BYT_RT5640_MONO_SPEAKER | | |
579 | BYT_RT5640_MCLK_EN), | |
580 | }, | |
260c48b7 HG |
581 | { /* Linx Linx7 tablet */ |
582 | .matches = { | |
583 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LINX"), | |
584 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "LINX7"), | |
585 | }, | |
586 | .driver_data = (void *)(BYTCR_INPUT_DEFAULTS | | |
587 | BYT_RT5640_MONO_SPEAKER | | |
588 | BYT_RT5640_JD_NOT_INV | | |
589 | BYT_RT5640_SSP0_AIF1 | | |
590 | BYT_RT5640_MCLK_EN), | |
591 | }, | |
ec8e8418 HG |
592 | { /* MSI S100 tablet */ |
593 | .matches = { | |
594 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Micro-Star International Co., Ltd."), | |
595 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "S100"), | |
596 | }, | |
597 | .driver_data = (void *)(BYT_RT5640_IN1_MAP | | |
598 | BYT_RT5640_JD_SRC_JD2_IN4N | | |
599 | BYT_RT5640_OVCD_TH_2000UA | | |
600 | BYT_RT5640_OVCD_SF_0P75 | | |
601 | BYT_RT5640_MONO_SPEAKER | | |
602 | BYT_RT5640_DIFF_MIC | | |
603 | BYT_RT5640_MCLK_EN), | |
604 | }, | |
6cea3590 HG |
605 | { /* Nuvison/TMax TM800W560 */ |
606 | .matches = { | |
607 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TMAX"), | |
608 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "TM800W560L"), | |
609 | }, | |
610 | .driver_data = (void *)(BYT_RT5640_IN1_MAP | | |
611 | BYT_RT5640_JD_SRC_JD2_IN4N | | |
612 | BYT_RT5640_OVCD_TH_2000UA | | |
613 | BYT_RT5640_OVCD_SF_0P75 | | |
614 | BYT_RT5640_JD_NOT_INV | | |
615 | BYT_RT5640_DIFF_MIC | | |
616 | BYT_RT5640_SSP0_AIF1 | | |
617 | BYT_RT5640_MCLK_EN), | |
618 | }, | |
260c48b7 HG |
619 | { /* Onda v975w */ |
620 | .matches = { | |
621 | DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), | |
622 | DMI_EXACT_MATCH(DMI_BOARD_NAME, "Aptio CRB"), | |
623 | /* The above are too generic, also match BIOS info */ | |
624 | DMI_EXACT_MATCH(DMI_BIOS_VERSION, "5.6.5"), | |
625 | DMI_EXACT_MATCH(DMI_BIOS_DATE, "07/25/2014"), | |
626 | }, | |
627 | .driver_data = (void *)(BYT_RT5640_IN1_MAP | | |
628 | BYT_RT5640_JD_SRC_JD2_IN4N | | |
629 | BYT_RT5640_OVCD_TH_2000UA | | |
630 | BYT_RT5640_OVCD_SF_0P75 | | |
631 | BYT_RT5640_DIFF_MIC | | |
632 | BYT_RT5640_MCLK_EN), | |
633 | }, | |
ec8e8418 HG |
634 | { /* Pipo W4 */ |
635 | .matches = { | |
636 | DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), | |
637 | DMI_EXACT_MATCH(DMI_BOARD_NAME, "Aptio CRB"), | |
638 | /* The above are too generic, also match BIOS info */ | |
639 | DMI_MATCH(DMI_BIOS_VERSION, "V8L_WIN32_CHIPHD"), | |
640 | }, | |
641 | .driver_data = (void *)(BYTCR_INPUT_DEFAULTS | | |
642 | BYT_RT5640_MONO_SPEAKER | | |
643 | BYT_RT5640_SSP0_AIF1 | | |
644 | BYT_RT5640_MCLK_EN), | |
645 | }, | |
646 | { /* Point of View Mobii TAB-P800W (V2.0) */ | |
647 | .matches = { | |
648 | DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), | |
649 | DMI_EXACT_MATCH(DMI_BOARD_NAME, "Aptio CRB"), | |
650 | /* The above are too generic, also match BIOS info */ | |
651 | DMI_EXACT_MATCH(DMI_BIOS_VERSION, "3BAIR1014"), | |
652 | DMI_EXACT_MATCH(DMI_BIOS_DATE, "10/24/2014"), | |
653 | }, | |
654 | .driver_data = (void *)(BYT_RT5640_IN1_MAP | | |
655 | BYT_RT5640_JD_SRC_JD2_IN4N | | |
656 | BYT_RT5640_OVCD_TH_2000UA | | |
657 | BYT_RT5640_OVCD_SF_0P75 | | |
658 | BYT_RT5640_MONO_SPEAKER | | |
659 | BYT_RT5640_DIFF_MIC | | |
660 | BYT_RT5640_SSP0_AIF2 | | |
661 | BYT_RT5640_MCLK_EN), | |
662 | }, | |
663 | { /* Point of View Mobii TAB-P800W (V2.1) */ | |
664 | .matches = { | |
665 | DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), | |
666 | DMI_EXACT_MATCH(DMI_BOARD_NAME, "Aptio CRB"), | |
667 | /* The above are too generic, also match BIOS info */ | |
668 | DMI_EXACT_MATCH(DMI_BIOS_VERSION, "3BAIR1013"), | |
669 | DMI_EXACT_MATCH(DMI_BIOS_DATE, "08/22/2014"), | |
670 | }, | |
671 | .driver_data = (void *)(BYT_RT5640_IN1_MAP | | |
672 | BYT_RT5640_JD_SRC_JD2_IN4N | | |
673 | BYT_RT5640_OVCD_TH_2000UA | | |
674 | BYT_RT5640_OVCD_SF_0P75 | | |
675 | BYT_RT5640_MONO_SPEAKER | | |
676 | BYT_RT5640_DIFF_MIC | | |
677 | BYT_RT5640_SSP0_AIF2 | | |
678 | BYT_RT5640_MCLK_EN), | |
679 | }, | |
02e5af65 HG |
680 | { /* Point of View Mobii TAB-P1005W-232 (V2.0) */ |
681 | .matches = { | |
682 | DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "POV"), | |
683 | DMI_EXACT_MATCH(DMI_BOARD_NAME, "I102A"), | |
684 | }, | |
685 | .driver_data = (void *)(BYT_RT5640_IN1_MAP | | |
686 | BYT_RT5640_JD_SRC_JD2_IN4N | | |
687 | BYT_RT5640_OVCD_TH_2000UA | | |
688 | BYT_RT5640_OVCD_SF_0P75 | | |
689 | BYT_RT5640_DIFF_MIC | | |
690 | BYT_RT5640_SSP0_AIF1 | | |
691 | BYT_RT5640_MCLK_EN), | |
692 | }, | |
271248f4 HG |
693 | { |
694 | /* Prowise PT301 */ | |
695 | .matches = { | |
696 | DMI_MATCH(DMI_SYS_VENDOR, "Prowise"), | |
697 | DMI_MATCH(DMI_PRODUCT_NAME, "PT301"), | |
698 | }, | |
699 | .driver_data = (void *)(BYT_RT5640_IN1_MAP | | |
700 | BYT_RT5640_JD_SRC_JD2_IN4N | | |
701 | BYT_RT5640_OVCD_TH_2000UA | | |
702 | BYT_RT5640_OVCD_SF_0P75 | | |
703 | BYT_RT5640_DIFF_MIC | | |
704 | BYT_RT5640_SSP0_AIF1 | | |
705 | BYT_RT5640_MCLK_EN), | |
706 | }, | |
ec1c90e7 | 707 | { |
ec1c90e7 PLB |
708 | .matches = { |
709 | DMI_MATCH(DMI_BOARD_VENDOR, "TECLAST"), | |
710 | DMI_MATCH(DMI_BOARD_NAME, "tPAD"), | |
711 | }, | |
17b5273d PLB |
712 | .driver_data = (void *)(BYT_RT5640_IN3_MAP | |
713 | BYT_RT5640_MCLK_EN | | |
714 | BYT_RT5640_SSP0_AIF1), | |
ec1c90e7 | 715 | }, |
ec8e8418 HG |
716 | { /* Toshiba Satellite Click Mini L9W-B */ |
717 | .matches = { | |
718 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), | |
719 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "SATELLITE Click Mini L9W-B"), | |
720 | }, | |
721 | .driver_data = (void *)(BYT_RT5640_DMIC1_MAP | | |
722 | BYT_RT5640_JD_SRC_JD2_IN4N | | |
723 | BYT_RT5640_OVCD_TH_1500UA | | |
724 | BYT_RT5640_OVCD_SF_0P75 | | |
725 | BYT_RT5640_SSP0_AIF1 | | |
726 | BYT_RT5640_MCLK_EN), | |
727 | }, | |
3c0d0116 | 728 | { /* Catch-all for generic Insyde tablets, must be last */ |
57180048 | 729 | .matches = { |
730 | DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), | |
731 | }, | |
96a388fe | 732 | .driver_data = (void *)(BYTCR_INPUT_DEFAULTS | |
17b5273d PLB |
733 | BYT_RT5640_MCLK_EN | |
734 | BYT_RT5640_SSP0_AIF1), | |
8f98307d PLB |
735 | |
736 | }, | |
a2d5563b PLB |
737 | {} |
738 | }; | |
739 | ||
6a7c05e5 HG |
740 | /* |
741 | * Note this MUST be called before snd_soc_register_card(), so that the props | |
742 | * are in place before the codec component driver's probe function parses them. | |
743 | */ | |
744 | static int byt_rt5640_add_codec_device_props(const char *i2c_dev_name) | |
745 | { | |
746 | struct property_entry props[MAX_NO_PROPS] = {}; | |
747 | struct device *i2c_dev; | |
748 | int ret, cnt = 0; | |
749 | ||
750 | i2c_dev = bus_find_device_by_name(&i2c_bus_type, NULL, i2c_dev_name); | |
751 | if (!i2c_dev) | |
752 | return -EPROBE_DEFER; | |
753 | ||
754 | switch (BYT_RT5640_MAP(byt_rt5640_quirk)) { | |
a3ad2911 HG |
755 | case BYT_RT5640_DMIC1_MAP: |
756 | props[cnt++] = PROPERTY_ENTRY_U32("realtek,dmic1-data-pin", | |
757 | RT5640_DMIC1_DATA_PIN_IN1P); | |
758 | break; | |
759 | case BYT_RT5640_DMIC2_MAP: | |
760 | props[cnt++] = PROPERTY_ENTRY_U32("realtek,dmic2-data-pin", | |
761 | RT5640_DMIC2_DATA_PIN_IN1N); | |
762 | break; | |
6a7c05e5 HG |
763 | case BYT_RT5640_IN1_MAP: |
764 | if (byt_rt5640_quirk & BYT_RT5640_DIFF_MIC) | |
765 | props[cnt++] = | |
766 | PROPERTY_ENTRY_BOOL("realtek,in1-differential"); | |
767 | break; | |
768 | case BYT_RT5640_IN3_MAP: | |
769 | if (byt_rt5640_quirk & BYT_RT5640_DIFF_MIC) | |
770 | props[cnt++] = | |
771 | PROPERTY_ENTRY_BOOL("realtek,in3-differential"); | |
772 | break; | |
773 | } | |
774 | ||
77323108 HG |
775 | if (BYT_RT5640_JDSRC(byt_rt5640_quirk)) { |
776 | props[cnt++] = PROPERTY_ENTRY_U32( | |
777 | "realtek,jack-detect-source", | |
778 | BYT_RT5640_JDSRC(byt_rt5640_quirk)); | |
779 | ||
780 | props[cnt++] = PROPERTY_ENTRY_U32( | |
781 | "realtek,over-current-threshold-microamp", | |
782 | BYT_RT5640_OVCD_TH(byt_rt5640_quirk) * 100); | |
783 | ||
784 | props[cnt++] = PROPERTY_ENTRY_U32( | |
785 | "realtek,over-current-scale-factor", | |
786 | BYT_RT5640_OVCD_SF(byt_rt5640_quirk)); | |
787 | } | |
788 | ||
789 | if (byt_rt5640_quirk & BYT_RT5640_JD_NOT_INV) | |
790 | props[cnt++] = PROPERTY_ENTRY_BOOL("realtek,jack-detect-not-inverted"); | |
791 | ||
6a7c05e5 HG |
792 | ret = device_add_properties(i2c_dev, props); |
793 | put_device(i2c_dev); | |
794 | ||
795 | return ret; | |
796 | } | |
797 | ||
9fd57471 PLB |
798 | static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) |
799 | { | |
9fd57471 | 800 | struct snd_soc_card *card = runtime->card; |
df1a2776 | 801 | struct byt_rt5640_private *priv = snd_soc_card_get_drvdata(card); |
d5a41b5d | 802 | struct snd_soc_component *component = runtime->codec_dai->component; |
17b5273d | 803 | const struct snd_soc_dapm_route *custom_map; |
9fd57471 | 804 | int num_routes; |
17b5273d | 805 | int ret; |
9fd57471 PLB |
806 | |
807 | card->dapm.idle_bias_off = true; | |
808 | ||
77323108 HG |
809 | /* Start with RC clk for jack-detect (we disable MCLK below) */ |
810 | if (byt_rt5640_quirk & BYT_RT5640_MCLK_EN) | |
811 | snd_soc_component_update_bits(component, RT5640_GLB_CLK, | |
812 | RT5640_SCLK_SRC_MASK, RT5640_SCLK_SRC_RCCLK); | |
813 | ||
d5a41b5d | 814 | rt5640_sel_asrc_clk_src(component, |
0ec66e2d | 815 | RT5640_DA_STEREO_FILTER | |
df1a2776 IT |
816 | RT5640_DA_MONO_L_FILTER | |
817 | RT5640_DA_MONO_R_FILTER | | |
818 | RT5640_AD_STEREO_FILTER | | |
819 | RT5640_AD_MONO_L_FILTER | | |
820 | RT5640_AD_MONO_R_FILTER, | |
0ec66e2d PLB |
821 | RT5640_CLK_SEL_ASRC); |
822 | ||
9fd57471 PLB |
823 | ret = snd_soc_add_card_controls(card, byt_rt5640_controls, |
824 | ARRAY_SIZE(byt_rt5640_controls)); | |
825 | if (ret) { | |
826 | dev_err(card->dev, "unable to add card controls\n"); | |
827 | return ret; | |
828 | } | |
829 | ||
9fd57471 PLB |
830 | switch (BYT_RT5640_MAP(byt_rt5640_quirk)) { |
831 | case BYT_RT5640_IN1_MAP: | |
832 | custom_map = byt_rt5640_intmic_in1_map; | |
833 | num_routes = ARRAY_SIZE(byt_rt5640_intmic_in1_map); | |
834 | break; | |
59e8b652 PLB |
835 | case BYT_RT5640_IN3_MAP: |
836 | custom_map = byt_rt5640_intmic_in3_map; | |
837 | num_routes = ARRAY_SIZE(byt_rt5640_intmic_in3_map); | |
838 | break; | |
9fd57471 PLB |
839 | case BYT_RT5640_DMIC2_MAP: |
840 | custom_map = byt_rt5640_intmic_dmic2_map; | |
841 | num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic2_map); | |
842 | break; | |
843 | default: | |
844 | custom_map = byt_rt5640_intmic_dmic1_map; | |
845 | num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic1_map); | |
846 | } | |
847 | ||
848 | ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes); | |
849 | if (ret) | |
850 | return ret; | |
851 | ||
89b8907c PLB |
852 | if (byt_rt5640_quirk & BYT_RT5640_SSP2_AIF2) { |
853 | ret = snd_soc_dapm_add_routes(&card->dapm, | |
854 | byt_rt5640_ssp2_aif2_map, | |
855 | ARRAY_SIZE(byt_rt5640_ssp2_aif2_map)); | |
f47088d5 PLB |
856 | } else if (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF1) { |
857 | ret = snd_soc_dapm_add_routes(&card->dapm, | |
858 | byt_rt5640_ssp0_aif1_map, | |
859 | ARRAY_SIZE(byt_rt5640_ssp0_aif1_map)); | |
860 | } else if (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2) { | |
861 | ret = snd_soc_dapm_add_routes(&card->dapm, | |
862 | byt_rt5640_ssp0_aif2_map, | |
863 | ARRAY_SIZE(byt_rt5640_ssp0_aif2_map)); | |
89b8907c PLB |
864 | } else { |
865 | ret = snd_soc_dapm_add_routes(&card->dapm, | |
866 | byt_rt5640_ssp2_aif1_map, | |
867 | ARRAY_SIZE(byt_rt5640_ssp2_aif1_map)); | |
868 | } | |
869 | if (ret) | |
870 | return ret; | |
871 | ||
68817cdb PLB |
872 | if (byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER) { |
873 | ret = snd_soc_dapm_add_routes(&card->dapm, | |
874 | byt_rt5640_mono_spk_map, | |
875 | ARRAY_SIZE(byt_rt5640_mono_spk_map)); | |
876 | } else { | |
877 | ret = snd_soc_dapm_add_routes(&card->dapm, | |
878 | byt_rt5640_stereo_spk_map, | |
879 | ARRAY_SIZE(byt_rt5640_stereo_spk_map)); | |
880 | } | |
881 | if (ret) | |
882 | return ret; | |
883 | ||
9fd57471 PLB |
884 | snd_soc_dapm_ignore_suspend(&card->dapm, "Headphone"); |
885 | snd_soc_dapm_ignore_suspend(&card->dapm, "Speaker"); | |
886 | ||
17b5273d | 887 | if (byt_rt5640_quirk & BYT_RT5640_MCLK_EN) { |
df1a2776 IT |
888 | /* |
889 | * The firmware might enable the clock at | |
890 | * boot (this information may or may not | |
891 | * be reflected in the enable clock register). | |
892 | * To change the rate we must disable the clock | |
893 | * first to cover these cases. Due to common | |
894 | * clock framework restrictions that do not allow | |
895 | * to disable a clock that has not been enabled, | |
896 | * we need to enable the clock first. | |
897 | */ | |
898 | ret = clk_prepare_enable(priv->mclk); | |
899 | if (!ret) | |
900 | clk_disable_unprepare(priv->mclk); | |
901 | ||
902 | if (byt_rt5640_quirk & BYT_RT5640_MCLK_25MHZ) | |
903 | ret = clk_set_rate(priv->mclk, 25000000); | |
904 | else | |
905 | ret = clk_set_rate(priv->mclk, 19200000); | |
906 | ||
77323108 | 907 | if (ret) { |
df1a2776 | 908 | dev_err(card->dev, "unable to set MCLK rate\n"); |
77323108 HG |
909 | return ret; |
910 | } | |
df1a2776 IT |
911 | } |
912 | ||
77323108 HG |
913 | if (BYT_RT5640_JDSRC(byt_rt5640_quirk)) { |
914 | ret = snd_soc_card_jack_new(card, "Headset", | |
915 | SND_JACK_HEADSET | SND_JACK_BTN_0, | |
916 | &priv->jack, rt5640_pins, | |
917 | ARRAY_SIZE(rt5640_pins)); | |
918 | if (ret) { | |
919 | dev_err(card->dev, "Jack creation failed %d\n", ret); | |
920 | return ret; | |
921 | } | |
922 | snd_jack_set_key(priv->jack.jack, SND_JACK_BTN_0, | |
923 | KEY_PLAYPAUSE); | |
924 | snd_soc_component_set_jack(component, &priv->jack, NULL); | |
925 | } | |
926 | ||
927 | return 0; | |
9fd57471 PLB |
928 | } |
929 | ||
a2d5563b | 930 | static const struct snd_soc_pcm_stream byt_rt5640_dai_params = { |
996cc849 SP |
931 | .formats = SNDRV_PCM_FMTBIT_S24_LE, |
932 | .rate_min = 48000, | |
933 | .rate_max = 48000, | |
934 | .channels_min = 2, | |
935 | .channels_max = 2, | |
936 | }; | |
937 | ||
a2d5563b | 938 | static int byt_rt5640_codec_fixup(struct snd_soc_pcm_runtime *rtd, |
996cc849 SP |
939 | struct snd_pcm_hw_params *params) |
940 | { | |
941 | struct snd_interval *rate = hw_param_interval(params, | |
942 | SNDRV_PCM_HW_PARAM_RATE); | |
943 | struct snd_interval *channels = hw_param_interval(params, | |
944 | SNDRV_PCM_HW_PARAM_CHANNELS); | |
3f27dedd | 945 | int ret; |
996cc849 | 946 | |
038a50e7 | 947 | /* The DSP will covert the FE rate to 48k, stereo */ |
996cc849 SP |
948 | rate->min = rate->max = 48000; |
949 | channels->min = channels->max = 2; | |
950 | ||
038a50e7 PLB |
951 | if ((byt_rt5640_quirk & BYT_RT5640_SSP0_AIF1) || |
952 | (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2)) { | |
953 | ||
8f98307d | 954 | /* set SSP0 to 16-bit */ |
038a50e7 PLB |
955 | params_set_format(params, SNDRV_PCM_FORMAT_S16_LE); |
956 | ||
957 | /* | |
958 | * Default mode for SSP configuration is TDM 4 slot, override config | |
959 | * with explicit setting to I2S 2ch 16-bit. The word length is set with | |
960 | * dai_set_tdm_slot() since there is no other API exposed | |
961 | */ | |
962 | ret = snd_soc_dai_set_fmt(rtd->cpu_dai, | |
963 | SND_SOC_DAIFMT_I2S | | |
f12f5c84 | 964 | SND_SOC_DAIFMT_NB_NF | |
038a50e7 PLB |
965 | SND_SOC_DAIFMT_CBS_CFS |
966 | ); | |
967 | if (ret < 0) { | |
968 | dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); | |
969 | return ret; | |
970 | } | |
3f27dedd | 971 | |
038a50e7 PLB |
972 | ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 16); |
973 | if (ret < 0) { | |
974 | dev_err(rtd->dev, "can't set I2S config, err %d\n", ret); | |
975 | return ret; | |
976 | } | |
977 | ||
978 | } else { | |
3f27dedd | 979 | |
038a50e7 PLB |
980 | /* set SSP2 to 24-bit */ |
981 | params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); | |
982 | ||
983 | /* | |
984 | * Default mode for SSP configuration is TDM 4 slot, override config | |
985 | * with explicit setting to I2S 2ch 24-bit. The word length is set with | |
986 | * dai_set_tdm_slot() since there is no other API exposed | |
987 | */ | |
988 | ret = snd_soc_dai_set_fmt(rtd->cpu_dai, | |
989 | SND_SOC_DAIFMT_I2S | | |
f12f5c84 | 990 | SND_SOC_DAIFMT_NB_NF | |
038a50e7 PLB |
991 | SND_SOC_DAIFMT_CBS_CFS |
992 | ); | |
993 | if (ret < 0) { | |
994 | dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); | |
995 | return ret; | |
996 | } | |
997 | ||
998 | ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 24); | |
999 | if (ret < 0) { | |
1000 | dev_err(rtd->dev, "can't set I2S config, err %d\n", ret); | |
1001 | return ret; | |
1002 | } | |
1003 | } | |
996cc849 SP |
1004 | return 0; |
1005 | } | |
1006 | ||
a2d5563b | 1007 | static int byt_rt5640_aif1_startup(struct snd_pcm_substream *substream) |
996cc849 | 1008 | { |
d0a1b660 LPC |
1009 | return snd_pcm_hw_constraint_single(substream->runtime, |
1010 | SNDRV_PCM_HW_PARAM_RATE, 48000); | |
996cc849 SP |
1011 | } |
1012 | ||
9b6fdef6 | 1013 | static const struct snd_soc_ops byt_rt5640_aif1_ops = { |
a2d5563b | 1014 | .startup = byt_rt5640_aif1_startup, |
996cc849 SP |
1015 | }; |
1016 | ||
9b6fdef6 | 1017 | static const struct snd_soc_ops byt_rt5640_be_ssp2_ops = { |
a2d5563b | 1018 | .hw_params = byt_rt5640_aif1_hw_params, |
996cc849 SP |
1019 | }; |
1020 | ||
a2d5563b | 1021 | static struct snd_soc_dai_link byt_rt5640_dais[] = { |
996cc849 SP |
1022 | [MERR_DPCM_AUDIO] = { |
1023 | .name = "Baytrail Audio Port", | |
1024 | .stream_name = "Baytrail Audio", | |
1025 | .cpu_dai_name = "media-cpu-dai", | |
1026 | .codec_dai_name = "snd-soc-dummy-dai", | |
1027 | .codec_name = "snd-soc-dummy", | |
1028 | .platform_name = "sst-mfld-platform", | |
6e4cac23 | 1029 | .nonatomic = true, |
996cc849 SP |
1030 | .dynamic = 1, |
1031 | .dpcm_playback = 1, | |
1032 | .dpcm_capture = 1, | |
a2d5563b | 1033 | .ops = &byt_rt5640_aif1_ops, |
996cc849 | 1034 | }, |
d35eb96a PLB |
1035 | [MERR_DPCM_DEEP_BUFFER] = { |
1036 | .name = "Deep-Buffer Audio Port", | |
1037 | .stream_name = "Deep-Buffer Audio", | |
1038 | .cpu_dai_name = "deepbuffer-cpu-dai", | |
1039 | .codec_dai_name = "snd-soc-dummy-dai", | |
1040 | .codec_name = "snd-soc-dummy", | |
1041 | .platform_name = "sst-mfld-platform", | |
d35eb96a PLB |
1042 | .nonatomic = true, |
1043 | .dynamic = 1, | |
1044 | .dpcm_playback = 1, | |
1045 | .ops = &byt_rt5640_aif1_ops, | |
996cc849 SP |
1046 | }, |
1047 | /* back ends */ | |
1048 | { | |
1049 | .name = "SSP2-Codec", | |
149f7757 | 1050 | .id = 0, |
f47088d5 | 1051 | .cpu_dai_name = "ssp2-port", /* overwritten for ssp0 routing */ |
996cc849 SP |
1052 | .platform_name = "sst-mfld-platform", |
1053 | .no_pcm = 1, | |
89b8907c | 1054 | .codec_dai_name = "rt5640-aif1", /* changed w/ quirk */ |
7762ef42 | 1055 | .codec_name = "i2c-10EC5640:00", /* overwritten with HID */ |
996cc849 SP |
1056 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
1057 | | SND_SOC_DAIFMT_CBS_CFS, | |
a2d5563b | 1058 | .be_hw_params_fixup = byt_rt5640_codec_fixup, |
996cc849 | 1059 | .ignore_suspend = 1, |
6e4cac23 | 1060 | .nonatomic = true, |
996cc849 SP |
1061 | .dpcm_playback = 1, |
1062 | .dpcm_capture = 1, | |
9fd57471 | 1063 | .init = byt_rt5640_init, |
a2d5563b | 1064 | .ops = &byt_rt5640_be_ssp2_ops, |
996cc849 SP |
1065 | }, |
1066 | }; | |
1067 | ||
1068 | /* SoC card */ | |
77323108 HG |
1069 | static char byt_rt5640_codec_name[SND_ACPI_I2C_ID_LEN]; |
1070 | static char byt_rt5640_codec_aif_name[12]; /* = "rt5640-aif[1|2]" */ | |
1071 | static char byt_rt5640_cpu_dai_name[10]; /* = "ssp[0|2]-port" */ | |
063422ca | 1072 | static char byt_rt5640_long_name[40]; /* = "bytcr-rt5640-*-spk-*-mic" */ |
77323108 HG |
1073 | |
1074 | static int byt_rt5640_suspend(struct snd_soc_card *card) | |
1075 | { | |
1076 | struct snd_soc_component *component; | |
1077 | ||
1078 | if (!BYT_RT5640_JDSRC(byt_rt5640_quirk)) | |
1079 | return 0; | |
1080 | ||
f70f18f7 | 1081 | for_each_card_components(card, component) { |
77323108 HG |
1082 | if (!strcmp(component->name, byt_rt5640_codec_name)) { |
1083 | dev_dbg(component->dev, "disabling jack detect before suspend\n"); | |
1084 | snd_soc_component_set_jack(component, NULL, NULL); | |
1085 | break; | |
1086 | } | |
1087 | } | |
1088 | ||
1089 | return 0; | |
1090 | } | |
1091 | ||
1092 | static int byt_rt5640_resume(struct snd_soc_card *card) | |
1093 | { | |
1094 | struct byt_rt5640_private *priv = snd_soc_card_get_drvdata(card); | |
1095 | struct snd_soc_component *component; | |
1096 | ||
1097 | if (!BYT_RT5640_JDSRC(byt_rt5640_quirk)) | |
1098 | return 0; | |
1099 | ||
f70f18f7 | 1100 | for_each_card_components(card, component) { |
77323108 HG |
1101 | if (!strcmp(component->name, byt_rt5640_codec_name)) { |
1102 | dev_dbg(component->dev, "re-enabling jack detect after resume\n"); | |
1103 | snd_soc_component_set_jack(component, &priv->jack, NULL); | |
1104 | break; | |
1105 | } | |
1106 | } | |
1107 | ||
1108 | return 0; | |
1109 | } | |
1110 | ||
9fd57471 | 1111 | static struct snd_soc_card byt_rt5640_card = { |
a2d5563b | 1112 | .name = "bytcr-rt5640", |
54d8697f | 1113 | .owner = THIS_MODULE, |
a2d5563b PLB |
1114 | .dai_link = byt_rt5640_dais, |
1115 | .num_links = ARRAY_SIZE(byt_rt5640_dais), | |
1116 | .dapm_widgets = byt_rt5640_widgets, | |
1117 | .num_dapm_widgets = ARRAY_SIZE(byt_rt5640_widgets), | |
1118 | .dapm_routes = byt_rt5640_audio_map, | |
1119 | .num_dapm_routes = ARRAY_SIZE(byt_rt5640_audio_map), | |
9fd57471 | 1120 | .fully_routed = true, |
77323108 HG |
1121 | .suspend_pre = byt_rt5640_suspend, |
1122 | .resume_post = byt_rt5640_resume, | |
996cc849 SP |
1123 | }; |
1124 | ||
e214f5e7 PLB |
1125 | static bool is_valleyview(void) |
1126 | { | |
cac17731 | 1127 | static const struct x86_cpu_id cpu_ids[] = { |
e214f5e7 PLB |
1128 | { X86_VENDOR_INTEL, 6, 55 }, /* Valleyview, Bay Trail */ |
1129 | {} | |
1130 | }; | |
1131 | ||
1132 | if (!x86_match_cpu(cpu_ids)) | |
1133 | return false; | |
1134 | return true; | |
1135 | } | |
1136 | ||
64e84305 PLB |
1137 | struct acpi_chan_package { /* ACPICA seems to require 64 bit integers */ |
1138 | u64 aif_value; /* 1: AIF1, 2: AIF2 */ | |
1139 | u64 mclock_value; /* usually 25MHz (0x17d7940), ignored */ | |
1140 | }; | |
df1a2776 | 1141 | |
a2d5563b | 1142 | static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) |
996cc849 | 1143 | { |
4ffdca62 | 1144 | static const char * const map_name[] = { "dmic1", "dmic2", "in1", "in3" }; |
6d1bfcc5 | 1145 | const struct dmi_system_id *dmi_id; |
17b5273d | 1146 | struct byt_rt5640_private *priv; |
7feb2f78 | 1147 | struct snd_soc_acpi_mach *mach; |
bd7661b7 | 1148 | const char *platform_name; |
a320d89e | 1149 | struct acpi_device *adev; |
17b5273d | 1150 | int ret_val = 0; |
2193eb96 | 1151 | int dai_index = 0; |
17b5273d | 1152 | int i; |
df1a2776 | 1153 | |
cb67d765 | 1154 | is_bytcr = false; |
7a3a6323 | 1155 | priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); |
df1a2776 IT |
1156 | if (!priv) |
1157 | return -ENOMEM; | |
996cc849 SP |
1158 | |
1159 | /* register the soc card */ | |
9fd57471 | 1160 | byt_rt5640_card.dev = &pdev->dev; |
caf94ed8 | 1161 | mach = byt_rt5640_card.dev->platform_data; |
df1a2776 | 1162 | snd_soc_card_set_drvdata(&byt_rt5640_card, priv); |
caf94ed8 | 1163 | |
a232b96d | 1164 | /* fix index of codec dai */ |
a232b96d PLB |
1165 | for (i = 0; i < ARRAY_SIZE(byt_rt5640_dais); i++) { |
1166 | if (!strcmp(byt_rt5640_dais[i].codec_name, "i2c-10EC5640:00")) { | |
1167 | dai_index = i; | |
1168 | break; | |
1169 | } | |
1170 | } | |
1171 | ||
caf94ed8 | 1172 | /* fixup codec name based on HID */ |
a320d89e AS |
1173 | adev = acpi_dev_get_first_match_dev(mach->id, NULL, -1); |
1174 | if (adev) { | |
a232b96d | 1175 | snprintf(byt_rt5640_codec_name, sizeof(byt_rt5640_codec_name), |
a320d89e AS |
1176 | "i2c-%s", acpi_dev_name(adev)); |
1177 | put_device(&adev->dev); | |
a232b96d PLB |
1178 | byt_rt5640_dais[dai_index].codec_name = byt_rt5640_codec_name; |
1179 | } | |
9fd57471 | 1180 | |
e214f5e7 PLB |
1181 | /* |
1182 | * swap SSP0 if bytcr is detected | |
1183 | * (will be overridden if DMI quirk is detected) | |
1184 | */ | |
1185 | if (is_valleyview()) { | |
3ee1cd4f | 1186 | if (mach->mach_params.acpi_ipc_irq_index == 0) |
64e84305 PLB |
1187 | is_bytcr = true; |
1188 | } | |
1189 | ||
1190 | if (is_bytcr) { | |
1191 | /* | |
1192 | * Baytrail CR platforms may have CHAN package in BIOS, try | |
1193 | * to find relevant routing quirk based as done on Windows | |
1194 | * platforms. We have to read the information directly from the | |
1195 | * BIOS, at this stage the card is not created and the links | |
1196 | * with the codec driver/pdata are non-existent | |
1197 | */ | |
1198 | ||
1199 | struct acpi_chan_package chan_package; | |
1200 | ||
1201 | /* format specified: 2 64-bit integers */ | |
1202 | struct acpi_buffer format = {sizeof("NN"), "NN"}; | |
1203 | struct acpi_buffer state = {0, NULL}; | |
7feb2f78 | 1204 | struct snd_soc_acpi_package_context pkg_ctx; |
64e84305 PLB |
1205 | bool pkg_found = false; |
1206 | ||
1207 | state.length = sizeof(chan_package); | |
1208 | state.pointer = &chan_package; | |
1209 | ||
1210 | pkg_ctx.name = "CHAN"; | |
1211 | pkg_ctx.length = 2; | |
1212 | pkg_ctx.format = &format; | |
1213 | pkg_ctx.state = &state; | |
1214 | pkg_ctx.data_valid = false; | |
1215 | ||
7feb2f78 PLB |
1216 | pkg_found = snd_soc_acpi_find_package_from_hid(mach->id, |
1217 | &pkg_ctx); | |
64e84305 PLB |
1218 | if (pkg_found) { |
1219 | if (chan_package.aif_value == 1) { | |
1220 | dev_info(&pdev->dev, "BIOS Routing: AIF1 connected\n"); | |
1221 | byt_rt5640_quirk |= BYT_RT5640_SSP0_AIF1; | |
1222 | } else if (chan_package.aif_value == 2) { | |
1223 | dev_info(&pdev->dev, "BIOS Routing: AIF2 connected\n"); | |
1224 | byt_rt5640_quirk |= BYT_RT5640_SSP0_AIF2; | |
1225 | } else { | |
1226 | dev_info(&pdev->dev, "BIOS Routing isn't valid, ignored\n"); | |
1227 | pkg_found = false; | |
1228 | } | |
1229 | } | |
1230 | ||
1231 | if (!pkg_found) { | |
1232 | /* no BIOS indications, assume SSP0-AIF2 connection */ | |
e214f5e7 PLB |
1233 | byt_rt5640_quirk |= BYT_RT5640_SSP0_AIF2; |
1234 | } | |
bf46241b PLB |
1235 | |
1236 | /* change defaults for Baytrail-CR capture */ | |
96a388fe | 1237 | byt_rt5640_quirk |= BYTCR_INPUT_DEFAULTS; |
bf46241b | 1238 | } else { |
56ff4409 HG |
1239 | byt_rt5640_quirk |= BYT_RT5640_DMIC1_MAP | |
1240 | BYT_RT5640_JD_SRC_JD2_IN4N | | |
1241 | BYT_RT5640_OVCD_TH_2000UA | | |
1242 | BYT_RT5640_OVCD_SF_0P75; | |
e214f5e7 PLB |
1243 | } |
1244 | ||
ab738e4e | 1245 | /* check quirks before creating card */ |
6d1bfcc5 HG |
1246 | dmi_id = dmi_first_match(byt_rt5640_quirk_table); |
1247 | if (dmi_id) | |
1248 | byt_rt5640_quirk = (unsigned long)dmi_id->driver_data; | |
2fb2a19a | 1249 | if (quirk_override != -1) { |
0b2c9f88 | 1250 | dev_info(&pdev->dev, "Overriding quirk 0x%x => 0x%x\n", |
9f2cf73e TI |
1251 | (unsigned int)byt_rt5640_quirk, quirk_override); |
1252 | byt_rt5640_quirk = quirk_override; | |
1253 | } | |
6a7c05e5 HG |
1254 | |
1255 | /* Must be called before register_card, also see declaration comment. */ | |
1256 | ret_val = byt_rt5640_add_codec_device_props(byt_rt5640_codec_name); | |
1257 | if (ret_val) | |
1258 | return ret_val; | |
1259 | ||
d7e60d52 | 1260 | log_quirks(&pdev->dev); |
ab738e4e | 1261 | |
f47088d5 PLB |
1262 | if ((byt_rt5640_quirk & BYT_RT5640_SSP2_AIF2) || |
1263 | (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2)) { | |
89b8907c PLB |
1264 | |
1265 | /* fixup codec aif name */ | |
1266 | snprintf(byt_rt5640_codec_aif_name, | |
1267 | sizeof(byt_rt5640_codec_aif_name), | |
1268 | "%s", "rt5640-aif2"); | |
1269 | ||
1270 | byt_rt5640_dais[dai_index].codec_dai_name = | |
1271 | byt_rt5640_codec_aif_name; | |
1272 | } | |
1273 | ||
f47088d5 PLB |
1274 | if ((byt_rt5640_quirk & BYT_RT5640_SSP0_AIF1) || |
1275 | (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2)) { | |
1276 | ||
1277 | /* fixup cpu dai name name */ | |
1278 | snprintf(byt_rt5640_cpu_dai_name, | |
1279 | sizeof(byt_rt5640_cpu_dai_name), | |
1280 | "%s", "ssp0-port"); | |
1281 | ||
1282 | byt_rt5640_dais[dai_index].cpu_dai_name = | |
1283 | byt_rt5640_cpu_dai_name; | |
1284 | } | |
1285 | ||
7735bce0 | 1286 | if (byt_rt5640_quirk & BYT_RT5640_MCLK_EN) { |
df1a2776 IT |
1287 | priv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3"); |
1288 | if (IS_ERR(priv->mclk)) { | |
4a8b3a68 PLB |
1289 | ret_val = PTR_ERR(priv->mclk); |
1290 | ||
df1a2776 | 1291 | dev_err(&pdev->dev, |
4a8b3a68 PLB |
1292 | "Failed to get MCLK from pmc_plt_clk_3: %d\n", |
1293 | ret_val); | |
1294 | ||
1295 | /* | |
1296 | * Fall back to bit clock usage for -ENOENT (clock not | |
1297 | * available likely due to missing dependencies), bail | |
1298 | * for all other errors, including -EPROBE_DEFER | |
1299 | */ | |
1300 | if (ret_val != -ENOENT) | |
1301 | return ret_val; | |
1302 | byt_rt5640_quirk &= ~BYT_RT5640_MCLK_EN; | |
df1a2776 IT |
1303 | } |
1304 | } | |
1305 | ||
063422ca HG |
1306 | snprintf(byt_rt5640_long_name, sizeof(byt_rt5640_long_name), |
1307 | "bytcr-rt5640-%s-spk-%s-mic", | |
1308 | (byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER) ? | |
1309 | "mono" : "stereo", | |
1310 | map_name[BYT_RT5640_MAP(byt_rt5640_quirk)]); | |
1311 | byt_rt5640_card.long_name = byt_rt5640_long_name; | |
1312 | ||
bd7661b7 PLB |
1313 | /* override plaform name, if required */ |
1314 | platform_name = mach->mach_params.platform; | |
1315 | ||
1316 | ret_val = snd_soc_fixup_dai_links_platform_name(&byt_rt5640_card, | |
1317 | platform_name); | |
1318 | if (ret_val) | |
1319 | return ret_val; | |
1320 | ||
9fd57471 | 1321 | ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5640_card); |
996cc849 | 1322 | |
996cc849 | 1323 | if (ret_val) { |
a2d5563b PLB |
1324 | dev_err(&pdev->dev, "devm_snd_soc_register_card failed %d\n", |
1325 | ret_val); | |
996cc849 SP |
1326 | return ret_val; |
1327 | } | |
9fd57471 | 1328 | platform_set_drvdata(pdev, &byt_rt5640_card); |
996cc849 SP |
1329 | return ret_val; |
1330 | } | |
1331 | ||
a2d5563b | 1332 | static struct platform_driver snd_byt_rt5640_mc_driver = { |
996cc849 | 1333 | .driver = { |
a2d5563b | 1334 | .name = "bytcr_rt5640", |
996cc849 | 1335 | }, |
a2d5563b | 1336 | .probe = snd_byt_rt5640_mc_probe, |
996cc849 SP |
1337 | }; |
1338 | ||
a2d5563b | 1339 | module_platform_driver(snd_byt_rt5640_mc_driver); |
996cc849 SP |
1340 | |
1341 | MODULE_DESCRIPTION("ASoC Intel(R) Baytrail CR Machine driver"); | |
1342 | MODULE_AUTHOR("Subhransu S. Prusty <subhransu.s.prusty@intel.com>"); | |
1343 | MODULE_LICENSE("GPL v2"); | |
a2d5563b | 1344 | MODULE_ALIAS("platform:bytcr_rt5640"); |