1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | // |
3 | // Machine driver for AMD ACP Audio engine using DA7219 & MAX98357 codec. |
4 | // |
5 | //Copyright 2016 Advanced Micro Devices, Inc. |
6 | |
7 | #include <sound/core.h> |
8 | #include <sound/soc.h> |
9 | #include <sound/pcm.h> |
10 | #include <sound/pcm_params.h> |
11 | #include <sound/soc-dapm.h> |
12 | #include <sound/jack.h> |
13 | #include <linux/clk.h> |
14 | #include <linux/gpio.h> |
15 | #include <linux/gpio/consumer.h> |
16 | #include <linux/module.h> |
17 | #include <linux/i2c.h> |
18 | #include <linux/input.h> |
19 | #include <linux/io.h> |
20 | #include <linux/acpi.h> |
21 | |
22 | #include "raven/acp3x.h" |
23 | #include "../codecs/rt5682.h" |
24 | #include "../codecs/rt1015.h" |
25 | |
26 | #define PCO_PLAT_CLK 48000000 |
27 | #define RT5682_PLL_FREQ (48000 * 512) |
28 | #define DUAL_CHANNEL 2 |
29 | |
30 | static struct snd_soc_jack pco_jack; |
31 | static struct snd_soc_jack_pin pco_jack_pins[] = { |
32 | { |
33 | .pin = "Headphone Jack" , |
34 | .mask = SND_JACK_HEADPHONE, |
35 | }, |
36 | { |
37 | .pin = "Headset Mic" , |
38 | .mask = SND_JACK_MICROPHONE, |
39 | }, |
40 | }; |
41 | |
42 | static struct clk *rt5682_dai_wclk; |
43 | static struct clk *rt5682_dai_bclk; |
44 | static struct gpio_desc *dmic_sel; |
45 | void *soc_is_rltk_max(struct device *dev); |
46 | |
47 | enum { |
48 | RT5682 = 0, |
49 | MAX, |
50 | EC, |
51 | }; |
52 | |
53 | static int acp3x_5682_init(struct snd_soc_pcm_runtime *rtd) |
54 | { |
55 | int ret; |
56 | struct snd_soc_card *card = rtd->card; |
57 | struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); |
58 | struct snd_soc_component *component = codec_dai->component; |
59 | |
60 | dev_info(rtd->dev, "codec dai name = %s\n" , codec_dai->name); |
61 | |
62 | /* set rt5682 dai fmt */ |
63 | ret = snd_soc_dai_set_fmt(dai: codec_dai, SND_SOC_DAIFMT_I2S |
64 | | SND_SOC_DAIFMT_NB_NF |
65 | | SND_SOC_DAIFMT_CBP_CFP); |
66 | if (ret < 0) { |
67 | dev_err(rtd->card->dev, |
68 | "Failed to set rt5682 dai fmt: %d\n" , ret); |
69 | return ret; |
70 | } |
71 | |
72 | /* set codec PLL */ |
73 | ret = snd_soc_dai_set_pll(dai: codec_dai, pll_id: RT5682_PLL2, source: RT5682_PLL2_S_MCLK, |
74 | PCO_PLAT_CLK, RT5682_PLL_FREQ); |
75 | if (ret < 0) { |
76 | dev_err(rtd->dev, "can't set rt5682 PLL: %d\n" , ret); |
77 | return ret; |
78 | } |
79 | |
80 | /* Set codec sysclk */ |
81 | ret = snd_soc_dai_set_sysclk(dai: codec_dai, clk_id: RT5682_SCLK_S_PLL2, |
82 | RT5682_PLL_FREQ, SND_SOC_CLOCK_IN); |
83 | if (ret < 0) { |
84 | dev_err(rtd->dev, |
85 | "Failed to set rt5682 SYSCLK: %d\n" , ret); |
86 | return ret; |
87 | } |
88 | |
89 | /* Set tdm/i2s1 master bclk ratio */ |
90 | ret = snd_soc_dai_set_bclk_ratio(dai: codec_dai, ratio: 64); |
91 | if (ret < 0) { |
92 | dev_err(rtd->dev, |
93 | "Failed to set rt5682 tdm bclk ratio: %d\n" , ret); |
94 | return ret; |
95 | } |
96 | |
97 | rt5682_dai_wclk = clk_get(dev: component->dev, id: "rt5682-dai-wclk" ); |
98 | rt5682_dai_bclk = clk_get(dev: component->dev, id: "rt5682-dai-bclk" ); |
99 | |
100 | ret = snd_soc_card_jack_new_pins(card, id: "Headset Jack" , |
101 | type: SND_JACK_HEADSET | |
102 | SND_JACK_BTN_0 | SND_JACK_BTN_1 | |
103 | SND_JACK_BTN_2 | SND_JACK_BTN_3, |
104 | jack: &pco_jack, |
105 | pins: pco_jack_pins, |
106 | ARRAY_SIZE(pco_jack_pins)); |
107 | if (ret) { |
108 | dev_err(card->dev, "HP jack creation failed %d\n" , ret); |
109 | return ret; |
110 | } |
111 | |
112 | snd_jack_set_key(jack: pco_jack.jack, type: SND_JACK_BTN_0, KEY_PLAYPAUSE); |
113 | snd_jack_set_key(jack: pco_jack.jack, type: SND_JACK_BTN_1, KEY_VOICECOMMAND); |
114 | snd_jack_set_key(jack: pco_jack.jack, type: SND_JACK_BTN_2, KEY_VOLUMEUP); |
115 | snd_jack_set_key(jack: pco_jack.jack, type: SND_JACK_BTN_3, KEY_VOLUMEDOWN); |
116 | |
117 | ret = snd_soc_component_set_jack(component, jack: &pco_jack, NULL); |
118 | if (ret) { |
119 | dev_err(rtd->dev, "Headset Jack call-back failed: %d\n" , ret); |
120 | return ret; |
121 | } |
122 | |
123 | return ret; |
124 | } |
125 | |
126 | static int rt5682_clk_enable(struct snd_pcm_substream *substream) |
127 | { |
128 | int ret = 0; |
129 | struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); |
130 | |
131 | /* RT5682 will support only 48K output with 48M mclk */ |
132 | clk_set_rate(clk: rt5682_dai_wclk, rate: 48000); |
133 | clk_set_rate(clk: rt5682_dai_bclk, rate: 48000 * 64); |
134 | ret = clk_prepare_enable(clk: rt5682_dai_wclk); |
135 | if (ret < 0) { |
136 | dev_err(rtd->dev, "can't enable wclk %d\n" , ret); |
137 | return ret; |
138 | } |
139 | |
140 | return ret; |
141 | } |
142 | |
143 | static int acp3x_1015_hw_params(struct snd_pcm_substream *substream, |
144 | struct snd_pcm_hw_params *params) |
145 | { |
146 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
147 | struct snd_soc_dai *codec_dai; |
148 | int srate, i, ret; |
149 | |
150 | ret = 0; |
151 | srate = params_rate(p: params); |
152 | |
153 | for_each_rtd_codec_dais(rtd, i, codec_dai) { |
154 | if (strcmp(codec_dai->name, "rt1015-aif" )) |
155 | continue; |
156 | |
157 | ret = snd_soc_dai_set_pll(dai: codec_dai, pll_id: 0, source: RT1015_PLL_S_BCLK, |
158 | freq_in: 64 * srate, freq_out: 256 * srate); |
159 | if (ret < 0) |
160 | return ret; |
161 | ret = snd_soc_dai_set_sysclk(dai: codec_dai, clk_id: RT1015_SCLK_S_PLL, |
162 | freq: 256 * srate, SND_SOC_CLOCK_IN); |
163 | if (ret < 0) |
164 | return ret; |
165 | } |
166 | return ret; |
167 | } |
168 | |
169 | static void rt5682_clk_disable(void) |
170 | { |
171 | clk_disable_unprepare(clk: rt5682_dai_wclk); |
172 | } |
173 | |
174 | static const unsigned int channels[] = { |
175 | DUAL_CHANNEL, |
176 | }; |
177 | |
178 | static const unsigned int rates[] = { |
179 | 48000, |
180 | }; |
181 | |
182 | static const struct snd_pcm_hw_constraint_list constraints_rates = { |
183 | .count = ARRAY_SIZE(rates), |
184 | .list = rates, |
185 | .mask = 0, |
186 | }; |
187 | |
188 | static const struct snd_pcm_hw_constraint_list constraints_channels = { |
189 | .count = ARRAY_SIZE(channels), |
190 | .list = channels, |
191 | .mask = 0, |
192 | }; |
193 | |
194 | static int acp3x_5682_startup(struct snd_pcm_substream *substream) |
195 | { |
196 | struct snd_pcm_runtime *runtime = substream->runtime; |
197 | struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); |
198 | struct snd_soc_card *card = rtd->card; |
199 | struct acp3x_platform_info *machine = snd_soc_card_get_drvdata(card); |
200 | |
201 | machine->play_i2s_instance = I2S_SP_INSTANCE; |
202 | machine->cap_i2s_instance = I2S_SP_INSTANCE; |
203 | |
204 | runtime->hw.channels_max = DUAL_CHANNEL; |
205 | snd_pcm_hw_constraint_list(runtime, cond: 0, SNDRV_PCM_HW_PARAM_CHANNELS, |
206 | l: &constraints_channels); |
207 | snd_pcm_hw_constraint_list(runtime, cond: 0, SNDRV_PCM_HW_PARAM_RATE, |
208 | l: &constraints_rates); |
209 | return rt5682_clk_enable(substream); |
210 | } |
211 | |
212 | static int acp3x_max_startup(struct snd_pcm_substream *substream) |
213 | { |
214 | struct snd_pcm_runtime *runtime = substream->runtime; |
215 | struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); |
216 | struct snd_soc_card *card = rtd->card; |
217 | struct acp3x_platform_info *machine = snd_soc_card_get_drvdata(card); |
218 | |
219 | machine->play_i2s_instance = I2S_BT_INSTANCE; |
220 | |
221 | runtime->hw.channels_max = DUAL_CHANNEL; |
222 | snd_pcm_hw_constraint_list(runtime, cond: 0, SNDRV_PCM_HW_PARAM_CHANNELS, |
223 | l: &constraints_channels); |
224 | snd_pcm_hw_constraint_list(runtime, cond: 0, SNDRV_PCM_HW_PARAM_RATE, |
225 | l: &constraints_rates); |
226 | return rt5682_clk_enable(substream); |
227 | } |
228 | |
229 | static int acp3x_ec_dmic0_startup(struct snd_pcm_substream *substream) |
230 | { |
231 | struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); |
232 | struct snd_soc_card *card = rtd->card; |
233 | struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); |
234 | struct acp3x_platform_info *machine = snd_soc_card_get_drvdata(card); |
235 | |
236 | machine->cap_i2s_instance = I2S_BT_INSTANCE; |
237 | snd_soc_dai_set_bclk_ratio(dai: codec_dai, ratio: 64); |
238 | |
239 | return rt5682_clk_enable(substream); |
240 | } |
241 | |
242 | static int dmic_switch; |
243 | |
244 | static int dmic_get(struct snd_kcontrol *kcontrol, |
245 | struct snd_ctl_elem_value *ucontrol) |
246 | { |
247 | ucontrol->value.integer.value[0] = dmic_switch; |
248 | return 0; |
249 | } |
250 | |
251 | static int dmic_set(struct snd_kcontrol *kcontrol, |
252 | struct snd_ctl_elem_value *ucontrol) |
253 | { |
254 | if (dmic_sel) { |
255 | dmic_switch = ucontrol->value.integer.value[0]; |
256 | gpiod_set_value(desc: dmic_sel, value: dmic_switch); |
257 | } |
258 | return 0; |
259 | } |
260 | |
261 | static void rt5682_shutdown(struct snd_pcm_substream *substream) |
262 | { |
263 | rt5682_clk_disable(); |
264 | } |
265 | |
266 | static const struct snd_soc_ops acp3x_5682_ops = { |
267 | .startup = acp3x_5682_startup, |
268 | .shutdown = rt5682_shutdown, |
269 | }; |
270 | |
271 | static const struct snd_soc_ops acp3x_max_play_ops = { |
272 | .startup = acp3x_max_startup, |
273 | .shutdown = rt5682_shutdown, |
274 | .hw_params = acp3x_1015_hw_params, |
275 | }; |
276 | |
277 | static const struct snd_soc_ops acp3x_ec_cap0_ops = { |
278 | .startup = acp3x_ec_dmic0_startup, |
279 | .shutdown = rt5682_shutdown, |
280 | }; |
281 | |
282 | SND_SOC_DAILINK_DEF(acp3x_i2s, |
283 | DAILINK_COMP_ARRAY(COMP_CPU("acp3x_i2s_playcap.0" ))); |
284 | SND_SOC_DAILINK_DEF(acp3x_bt, |
285 | DAILINK_COMP_ARRAY(COMP_CPU("acp3x_i2s_playcap.2" ))); |
286 | |
287 | SND_SOC_DAILINK_DEF(rt5682, |
288 | DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC5682:00" , "rt5682-aif1" ))); |
289 | SND_SOC_DAILINK_DEF(max, |
290 | DAILINK_COMP_ARRAY(COMP_CODEC("MX98357A:00" , "HiFi" ))); |
291 | SND_SOC_DAILINK_DEF(rt1015p, |
292 | DAILINK_COMP_ARRAY(COMP_CODEC("RTL1015:00" , "HiFi" ))); |
293 | SND_SOC_DAILINK_DEF(rt1015, |
294 | DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC1015:00" , "rt1015-aif" ), |
295 | COMP_CODEC("i2c-10EC1015:01" , "rt1015-aif" ))); |
296 | SND_SOC_DAILINK_DEF(cros_ec, |
297 | DAILINK_COMP_ARRAY(COMP_CODEC("GOOG0013:00" , "EC Codec I2S RX" ))); |
298 | |
299 | SND_SOC_DAILINK_DEF(platform, |
300 | DAILINK_COMP_ARRAY(COMP_PLATFORM("acp3x_rv_i2s_dma.0" ))); |
301 | |
302 | static struct snd_soc_codec_conf rt1015_conf[] = { |
303 | { |
304 | .dlc = COMP_CODEC_CONF("i2c-10EC1015:00" ), |
305 | .name_prefix = "Left" , |
306 | }, |
307 | { |
308 | .dlc = COMP_CODEC_CONF("i2c-10EC1015:01" ), |
309 | .name_prefix = "Right" , |
310 | }, |
311 | }; |
312 | |
313 | static struct snd_soc_dai_link acp3x_dai[] = { |
314 | [RT5682] = { |
315 | .name = "acp3x-5682-play" , |
316 | .stream_name = "Playback" , |
317 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
318 | | SND_SOC_DAIFMT_CBP_CFP, |
319 | .init = acp3x_5682_init, |
320 | .dpcm_playback = 1, |
321 | .dpcm_capture = 1, |
322 | .ops = &acp3x_5682_ops, |
323 | SND_SOC_DAILINK_REG(acp3x_i2s, rt5682, platform), |
324 | }, |
325 | [MAX] = { |
326 | .name = "acp3x-max98357-play" , |
327 | .stream_name = "HiFi Playback" , |
328 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
329 | | SND_SOC_DAIFMT_CBC_CFC, |
330 | .dpcm_playback = 1, |
331 | .ops = &acp3x_max_play_ops, |
332 | .cpus = acp3x_bt, |
333 | .num_cpus = ARRAY_SIZE(acp3x_bt), |
334 | .platforms = platform, |
335 | .num_platforms = ARRAY_SIZE(platform), |
336 | }, |
337 | [EC] = { |
338 | .name = "acp3x-ec-dmic0-capture" , |
339 | .stream_name = "Capture DMIC0" , |
340 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
341 | | SND_SOC_DAIFMT_CBC_CFC, |
342 | .dpcm_capture = 1, |
343 | .ops = &acp3x_ec_cap0_ops, |
344 | SND_SOC_DAILINK_REG(acp3x_bt, cros_ec, platform), |
345 | }, |
346 | }; |
347 | |
348 | static const char * const dmic_mux_text[] = { |
349 | "Front Mic" , |
350 | "Rear Mic" , |
351 | }; |
352 | |
353 | static SOC_ENUM_SINGLE_DECL( |
354 | acp3x_dmic_enum, SND_SOC_NOPM, 0, dmic_mux_text); |
355 | |
356 | static const struct snd_kcontrol_new acp3x_dmic_mux_control = |
357 | SOC_DAPM_ENUM_EXT("DMIC Select Mux" , acp3x_dmic_enum, |
358 | dmic_get, dmic_set); |
359 | |
360 | static const struct snd_soc_dapm_widget acp3x_5682_widgets[] = { |
361 | SND_SOC_DAPM_HP("Headphone Jack" , NULL), |
362 | SND_SOC_DAPM_SPK("Spk" , NULL), |
363 | SND_SOC_DAPM_MIC("Headset Mic" , NULL), |
364 | SND_SOC_DAPM_MUX("Dmic Mux" , SND_SOC_NOPM, 0, 0, |
365 | &acp3x_dmic_mux_control), |
366 | }; |
367 | |
368 | static const struct snd_soc_dapm_route acp3x_5682_audio_route[] = { |
369 | {"Headphone Jack" , NULL, "HPOL" }, |
370 | {"Headphone Jack" , NULL, "HPOR" }, |
371 | {"IN1P" , NULL, "Headset Mic" }, |
372 | {"Spk" , NULL, "Speaker" }, |
373 | {"Dmic Mux" , "Front Mic" , "DMIC" }, |
374 | {"Dmic Mux" , "Rear Mic" , "DMIC" }, |
375 | }; |
376 | |
377 | static const struct snd_kcontrol_new acp3x_5682_mc_controls[] = { |
378 | SOC_DAPM_PIN_SWITCH("Headphone Jack" ), |
379 | SOC_DAPM_PIN_SWITCH("Spk" ), |
380 | SOC_DAPM_PIN_SWITCH("Headset Mic" ), |
381 | }; |
382 | |
383 | static struct snd_soc_card acp3x_5682 = { |
384 | .name = "acp3xalc5682m98357" , |
385 | .owner = THIS_MODULE, |
386 | .dai_link = acp3x_dai, |
387 | .num_links = ARRAY_SIZE(acp3x_dai), |
388 | .dapm_widgets = acp3x_5682_widgets, |
389 | .num_dapm_widgets = ARRAY_SIZE(acp3x_5682_widgets), |
390 | .dapm_routes = acp3x_5682_audio_route, |
391 | .num_dapm_routes = ARRAY_SIZE(acp3x_5682_audio_route), |
392 | .controls = acp3x_5682_mc_controls, |
393 | .num_controls = ARRAY_SIZE(acp3x_5682_mc_controls), |
394 | }; |
395 | |
396 | static const struct snd_soc_dapm_widget acp3x_1015_widgets[] = { |
397 | SND_SOC_DAPM_HP("Headphone Jack" , NULL), |
398 | SND_SOC_DAPM_MIC("Headset Mic" , NULL), |
399 | SND_SOC_DAPM_MUX("Dmic Mux" , SND_SOC_NOPM, 0, 0, |
400 | &acp3x_dmic_mux_control), |
401 | SND_SOC_DAPM_SPK("Left Spk" , NULL), |
402 | SND_SOC_DAPM_SPK("Right Spk" , NULL), |
403 | }; |
404 | |
405 | static const struct snd_soc_dapm_route acp3x_1015_route[] = { |
406 | {"Headphone Jack" , NULL, "HPOL" }, |
407 | {"Headphone Jack" , NULL, "HPOR" }, |
408 | {"IN1P" , NULL, "Headset Mic" }, |
409 | {"Dmic Mux" , "Front Mic" , "DMIC" }, |
410 | {"Dmic Mux" , "Rear Mic" , "DMIC" }, |
411 | {"Left Spk" , NULL, "Left SPO" }, |
412 | {"Right Spk" , NULL, "Right SPO" }, |
413 | }; |
414 | |
415 | static const struct snd_kcontrol_new acp3x_mc_1015_controls[] = { |
416 | SOC_DAPM_PIN_SWITCH("Headphone Jack" ), |
417 | SOC_DAPM_PIN_SWITCH("Headset Mic" ), |
418 | SOC_DAPM_PIN_SWITCH("Left Spk" ), |
419 | SOC_DAPM_PIN_SWITCH("Right Spk" ), |
420 | }; |
421 | |
422 | static struct snd_soc_card acp3x_1015 = { |
423 | .name = "acp3xalc56821015" , |
424 | .owner = THIS_MODULE, |
425 | .dai_link = acp3x_dai, |
426 | .num_links = ARRAY_SIZE(acp3x_dai), |
427 | .dapm_widgets = acp3x_1015_widgets, |
428 | .num_dapm_widgets = ARRAY_SIZE(acp3x_1015_widgets), |
429 | .dapm_routes = acp3x_1015_route, |
430 | .num_dapm_routes = ARRAY_SIZE(acp3x_1015_route), |
431 | .codec_conf = rt1015_conf, |
432 | .num_configs = ARRAY_SIZE(rt1015_conf), |
433 | .controls = acp3x_mc_1015_controls, |
434 | .num_controls = ARRAY_SIZE(acp3x_mc_1015_controls), |
435 | }; |
436 | |
437 | static const struct snd_soc_dapm_widget acp3x_1015p_widgets[] = { |
438 | SND_SOC_DAPM_HP("Headphone Jack" , NULL), |
439 | SND_SOC_DAPM_MIC("Headset Mic" , NULL), |
440 | SND_SOC_DAPM_MUX("Dmic Mux" , SND_SOC_NOPM, 0, 0, |
441 | &acp3x_dmic_mux_control), |
442 | SND_SOC_DAPM_SPK("Speakers" , NULL), |
443 | }; |
444 | |
445 | static const struct snd_soc_dapm_route acp3x_1015p_route[] = { |
446 | {"Headphone Jack" , NULL, "HPOL" }, |
447 | {"Headphone Jack" , NULL, "HPOR" }, |
448 | {"IN1P" , NULL, "Headset Mic" }, |
449 | {"Dmic Mux" , "Front Mic" , "DMIC" }, |
450 | {"Dmic Mux" , "Rear Mic" , "DMIC" }, |
451 | /* speaker */ |
452 | { "Speakers" , NULL, "Speaker" }, |
453 | }; |
454 | |
455 | static const struct snd_kcontrol_new acp3x_mc_1015p_controls[] = { |
456 | SOC_DAPM_PIN_SWITCH("Speakers" ), |
457 | SOC_DAPM_PIN_SWITCH("Headphone Jack" ), |
458 | SOC_DAPM_PIN_SWITCH("Headset Mic" ), |
459 | }; |
460 | |
461 | static struct snd_soc_card acp3x_1015p = { |
462 | .name = "acp3xalc56821015p" , |
463 | .owner = THIS_MODULE, |
464 | .dai_link = acp3x_dai, |
465 | .num_links = ARRAY_SIZE(acp3x_dai), |
466 | .dapm_widgets = acp3x_1015p_widgets, |
467 | .num_dapm_widgets = ARRAY_SIZE(acp3x_1015p_widgets), |
468 | .dapm_routes = acp3x_1015p_route, |
469 | .num_dapm_routes = ARRAY_SIZE(acp3x_1015p_route), |
470 | .controls = acp3x_mc_1015p_controls, |
471 | .num_controls = ARRAY_SIZE(acp3x_mc_1015p_controls), |
472 | }; |
473 | |
474 | void *soc_is_rltk_max(struct device *dev) |
475 | { |
476 | const struct acpi_device_id *match; |
477 | |
478 | match = acpi_match_device(ids: dev->driver->acpi_match_table, dev); |
479 | if (!match) |
480 | return NULL; |
481 | return (void *)match->driver_data; |
482 | } |
483 | |
484 | static void card_spk_dai_link_present(struct snd_soc_dai_link *links, |
485 | const char *card_name) |
486 | { |
487 | if (!strcmp(card_name, "acp3xalc56821015" )) { |
488 | links[1].codecs = rt1015; |
489 | links[1].num_codecs = ARRAY_SIZE(rt1015); |
490 | } else if (!strcmp(card_name, "acp3xalc56821015p" )) { |
491 | links[1].codecs = rt1015p; |
492 | links[1].num_codecs = ARRAY_SIZE(rt1015p); |
493 | } else { |
494 | links[1].codecs = max; |
495 | links[1].num_codecs = ARRAY_SIZE(max); |
496 | } |
497 | } |
498 | |
499 | static int acp3x_probe(struct platform_device *pdev) |
500 | { |
501 | int ret; |
502 | struct snd_soc_card *card; |
503 | struct acp3x_platform_info *machine; |
504 | struct device *dev = &pdev->dev; |
505 | |
506 | card = (struct snd_soc_card *)soc_is_rltk_max(dev); |
507 | if (!card) |
508 | return -ENODEV; |
509 | |
510 | machine = devm_kzalloc(dev: &pdev->dev, size: sizeof(*machine), GFP_KERNEL); |
511 | if (!machine) |
512 | return -ENOMEM; |
513 | |
514 | card_spk_dai_link_present(links: card->dai_link, card_name: card->name); |
515 | card->dev = &pdev->dev; |
516 | platform_set_drvdata(pdev, data: card); |
517 | snd_soc_card_set_drvdata(card, data: machine); |
518 | |
519 | dmic_sel = devm_gpiod_get(dev: &pdev->dev, con_id: "dmic" , flags: GPIOD_OUT_LOW); |
520 | if (IS_ERR(ptr: dmic_sel)) { |
521 | dev_err(&pdev->dev, "DMIC gpio failed err=%ld\n" , |
522 | PTR_ERR(dmic_sel)); |
523 | return PTR_ERR(ptr: dmic_sel); |
524 | } |
525 | |
526 | ret = devm_snd_soc_register_card(dev: &pdev->dev, card); |
527 | if (ret) { |
528 | return dev_err_probe(dev: &pdev->dev, err: ret, |
529 | fmt: "devm_snd_soc_register_card(%s) failed\n" , |
530 | card->name); |
531 | } |
532 | return 0; |
533 | } |
534 | |
535 | static const struct acpi_device_id acp3x_audio_acpi_match[] = { |
536 | { "AMDI5682" , (unsigned long)&acp3x_5682}, |
537 | { "AMDI1015" , (unsigned long)&acp3x_1015}, |
538 | { "10021015" , (unsigned long)&acp3x_1015p}, |
539 | {}, |
540 | }; |
541 | MODULE_DEVICE_TABLE(acpi, acp3x_audio_acpi_match); |
542 | |
543 | static struct platform_driver acp3x_audio = { |
544 | .driver = { |
545 | .name = "acp3x-alc5682-max98357" , |
546 | .acpi_match_table = ACPI_PTR(acp3x_audio_acpi_match), |
547 | .pm = &snd_soc_pm_ops, |
548 | }, |
549 | .probe = acp3x_probe, |
550 | }; |
551 | |
552 | module_platform_driver(acp3x_audio); |
553 | |
554 | MODULE_AUTHOR("akshu.agrawal@amd.com" ); |
555 | MODULE_AUTHOR("Vishnuvardhanrao.Ravulapati@amd.com" ); |
556 | MODULE_AUTHOR("Vijendar.Mukunda@amd.com" ); |
557 | MODULE_DESCRIPTION("ALC5682 ALC1015, ALC1015P & MAX98357 audio support" ); |
558 | MODULE_LICENSE("GPL v2" ); |
559 | |