Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/soc/amd/acp3x-rt5682-max9836.c
26451 views
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(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(codec_dai, RT5682_PLL2, 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(codec_dai, 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(codec_dai, 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(component->dev, "rt5682-dai-wclk");
98
rt5682_dai_bclk = clk_get(component->dev, "rt5682-dai-bclk");
99
100
ret = snd_soc_card_jack_new_pins(card, "Headset Jack",
101
SND_JACK_HEADSET |
102
SND_JACK_BTN_0 | SND_JACK_BTN_1 |
103
SND_JACK_BTN_2 | SND_JACK_BTN_3,
104
&pco_jack,
105
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(pco_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
113
snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
114
snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
115
snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
116
117
ret = snd_soc_component_set_jack(component, &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(rt5682_dai_wclk, 48000);
133
clk_set_rate(rt5682_dai_bclk, 48000 * 64);
134
ret = clk_prepare_enable(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 = snd_soc_substream_to_rtd(substream);
147
struct snd_soc_dai *codec_dai;
148
int srate, i, ret;
149
150
ret = 0;
151
srate = params_rate(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(codec_dai, 0, RT1015_PLL_S_BCLK,
158
64 * srate, 256 * srate);
159
if (ret < 0)
160
return ret;
161
ret = snd_soc_dai_set_sysclk(codec_dai, RT1015_SCLK_S_PLL,
162
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(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, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
206
&constraints_channels);
207
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
208
&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, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
223
&constraints_channels);
224
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
225
&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(codec_dai, 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(dmic_sel, 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
.ops = &acp3x_5682_ops,
321
SND_SOC_DAILINK_REG(acp3x_i2s, rt5682, platform),
322
},
323
[MAX] = {
324
.name = "acp3x-max98357-play",
325
.stream_name = "HiFi Playback",
326
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
327
| SND_SOC_DAIFMT_CBC_CFC,
328
.playback_only = 1,
329
.ops = &acp3x_max_play_ops,
330
.cpus = acp3x_bt,
331
.num_cpus = ARRAY_SIZE(acp3x_bt),
332
.platforms = platform,
333
.num_platforms = ARRAY_SIZE(platform),
334
},
335
[EC] = {
336
.name = "acp3x-ec-dmic0-capture",
337
.stream_name = "Capture DMIC0",
338
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
339
| SND_SOC_DAIFMT_CBC_CFC,
340
.capture_only = 1,
341
.ops = &acp3x_ec_cap0_ops,
342
SND_SOC_DAILINK_REG(acp3x_bt, cros_ec, platform),
343
},
344
};
345
346
static const char * const dmic_mux_text[] = {
347
"Front Mic",
348
"Rear Mic",
349
};
350
351
static SOC_ENUM_SINGLE_DECL(
352
acp3x_dmic_enum, SND_SOC_NOPM, 0, dmic_mux_text);
353
354
static const struct snd_kcontrol_new acp3x_dmic_mux_control =
355
SOC_DAPM_ENUM_EXT("DMIC Select Mux", acp3x_dmic_enum,
356
dmic_get, dmic_set);
357
358
static const struct snd_soc_dapm_widget acp3x_5682_widgets[] = {
359
SND_SOC_DAPM_HP("Headphone Jack", NULL),
360
SND_SOC_DAPM_SPK("Spk", NULL),
361
SND_SOC_DAPM_MIC("Headset Mic", NULL),
362
SND_SOC_DAPM_MUX("Dmic Mux", SND_SOC_NOPM, 0, 0,
363
&acp3x_dmic_mux_control),
364
};
365
366
static const struct snd_soc_dapm_route acp3x_5682_audio_route[] = {
367
{"Headphone Jack", NULL, "HPOL"},
368
{"Headphone Jack", NULL, "HPOR"},
369
{"IN1P", NULL, "Headset Mic"},
370
{"Spk", NULL, "Speaker"},
371
{"Dmic Mux", "Front Mic", "DMIC"},
372
{"Dmic Mux", "Rear Mic", "DMIC"},
373
};
374
375
static const struct snd_kcontrol_new acp3x_5682_mc_controls[] = {
376
SOC_DAPM_PIN_SWITCH("Headphone Jack"),
377
SOC_DAPM_PIN_SWITCH("Spk"),
378
SOC_DAPM_PIN_SWITCH("Headset Mic"),
379
};
380
381
static struct snd_soc_card acp3x_5682 = {
382
.name = "acp3xalc5682m98357",
383
.owner = THIS_MODULE,
384
.dai_link = acp3x_dai,
385
.num_links = ARRAY_SIZE(acp3x_dai),
386
.dapm_widgets = acp3x_5682_widgets,
387
.num_dapm_widgets = ARRAY_SIZE(acp3x_5682_widgets),
388
.dapm_routes = acp3x_5682_audio_route,
389
.num_dapm_routes = ARRAY_SIZE(acp3x_5682_audio_route),
390
.controls = acp3x_5682_mc_controls,
391
.num_controls = ARRAY_SIZE(acp3x_5682_mc_controls),
392
};
393
394
static const struct snd_soc_dapm_widget acp3x_1015_widgets[] = {
395
SND_SOC_DAPM_HP("Headphone Jack", NULL),
396
SND_SOC_DAPM_MIC("Headset Mic", NULL),
397
SND_SOC_DAPM_MUX("Dmic Mux", SND_SOC_NOPM, 0, 0,
398
&acp3x_dmic_mux_control),
399
SND_SOC_DAPM_SPK("Left Spk", NULL),
400
SND_SOC_DAPM_SPK("Right Spk", NULL),
401
};
402
403
static const struct snd_soc_dapm_route acp3x_1015_route[] = {
404
{"Headphone Jack", NULL, "HPOL"},
405
{"Headphone Jack", NULL, "HPOR"},
406
{"IN1P", NULL, "Headset Mic"},
407
{"Dmic Mux", "Front Mic", "DMIC"},
408
{"Dmic Mux", "Rear Mic", "DMIC"},
409
{"Left Spk", NULL, "Left SPO"},
410
{"Right Spk", NULL, "Right SPO"},
411
};
412
413
static const struct snd_kcontrol_new acp3x_mc_1015_controls[] = {
414
SOC_DAPM_PIN_SWITCH("Headphone Jack"),
415
SOC_DAPM_PIN_SWITCH("Headset Mic"),
416
SOC_DAPM_PIN_SWITCH("Left Spk"),
417
SOC_DAPM_PIN_SWITCH("Right Spk"),
418
};
419
420
static struct snd_soc_card acp3x_1015 = {
421
.name = "acp3xalc56821015",
422
.owner = THIS_MODULE,
423
.dai_link = acp3x_dai,
424
.num_links = ARRAY_SIZE(acp3x_dai),
425
.dapm_widgets = acp3x_1015_widgets,
426
.num_dapm_widgets = ARRAY_SIZE(acp3x_1015_widgets),
427
.dapm_routes = acp3x_1015_route,
428
.num_dapm_routes = ARRAY_SIZE(acp3x_1015_route),
429
.codec_conf = rt1015_conf,
430
.num_configs = ARRAY_SIZE(rt1015_conf),
431
.controls = acp3x_mc_1015_controls,
432
.num_controls = ARRAY_SIZE(acp3x_mc_1015_controls),
433
};
434
435
static const struct snd_soc_dapm_widget acp3x_1015p_widgets[] = {
436
SND_SOC_DAPM_HP("Headphone Jack", NULL),
437
SND_SOC_DAPM_MIC("Headset Mic", NULL),
438
SND_SOC_DAPM_MUX("Dmic Mux", SND_SOC_NOPM, 0, 0,
439
&acp3x_dmic_mux_control),
440
SND_SOC_DAPM_SPK("Speakers", NULL),
441
};
442
443
static const struct snd_soc_dapm_route acp3x_1015p_route[] = {
444
{"Headphone Jack", NULL, "HPOL"},
445
{"Headphone Jack", NULL, "HPOR"},
446
{"IN1P", NULL, "Headset Mic"},
447
{"Dmic Mux", "Front Mic", "DMIC"},
448
{"Dmic Mux", "Rear Mic", "DMIC"},
449
/* speaker */
450
{ "Speakers", NULL, "Speaker" },
451
};
452
453
static const struct snd_kcontrol_new acp3x_mc_1015p_controls[] = {
454
SOC_DAPM_PIN_SWITCH("Speakers"),
455
SOC_DAPM_PIN_SWITCH("Headphone Jack"),
456
SOC_DAPM_PIN_SWITCH("Headset Mic"),
457
};
458
459
static struct snd_soc_card acp3x_1015p = {
460
.name = "acp3xalc56821015p",
461
.owner = THIS_MODULE,
462
.dai_link = acp3x_dai,
463
.num_links = ARRAY_SIZE(acp3x_dai),
464
.dapm_widgets = acp3x_1015p_widgets,
465
.num_dapm_widgets = ARRAY_SIZE(acp3x_1015p_widgets),
466
.dapm_routes = acp3x_1015p_route,
467
.num_dapm_routes = ARRAY_SIZE(acp3x_1015p_route),
468
.controls = acp3x_mc_1015p_controls,
469
.num_controls = ARRAY_SIZE(acp3x_mc_1015p_controls),
470
};
471
472
void *soc_is_rltk_max(struct device *dev)
473
{
474
const struct acpi_device_id *match;
475
476
match = acpi_match_device(dev->driver->acpi_match_table, dev);
477
if (!match)
478
return NULL;
479
return (void *)match->driver_data;
480
}
481
482
static void card_spk_dai_link_present(struct snd_soc_dai_link *links,
483
const char *card_name)
484
{
485
if (!strcmp(card_name, "acp3xalc56821015")) {
486
links[1].codecs = rt1015;
487
links[1].num_codecs = ARRAY_SIZE(rt1015);
488
} else if (!strcmp(card_name, "acp3xalc56821015p")) {
489
links[1].codecs = rt1015p;
490
links[1].num_codecs = ARRAY_SIZE(rt1015p);
491
} else {
492
links[1].codecs = max;
493
links[1].num_codecs = ARRAY_SIZE(max);
494
}
495
}
496
497
static int acp3x_probe(struct platform_device *pdev)
498
{
499
int ret;
500
struct snd_soc_card *card;
501
struct acp3x_platform_info *machine;
502
struct device *dev = &pdev->dev;
503
504
card = (struct snd_soc_card *)soc_is_rltk_max(dev);
505
if (!card)
506
return -ENODEV;
507
508
machine = devm_kzalloc(&pdev->dev, sizeof(*machine), GFP_KERNEL);
509
if (!machine)
510
return -ENOMEM;
511
512
card_spk_dai_link_present(card->dai_link, card->name);
513
card->dev = &pdev->dev;
514
platform_set_drvdata(pdev, card);
515
snd_soc_card_set_drvdata(card, machine);
516
517
dmic_sel = devm_gpiod_get(&pdev->dev, "dmic", GPIOD_OUT_LOW);
518
if (IS_ERR(dmic_sel)) {
519
dev_err(&pdev->dev, "DMIC gpio failed err=%ld\n",
520
PTR_ERR(dmic_sel));
521
return PTR_ERR(dmic_sel);
522
}
523
524
ret = devm_snd_soc_register_card(&pdev->dev, card);
525
if (ret) {
526
return dev_err_probe(&pdev->dev, ret,
527
"devm_snd_soc_register_card(%s) failed\n",
528
card->name);
529
}
530
return 0;
531
}
532
533
static const struct acpi_device_id acp3x_audio_acpi_match[] = {
534
{ "AMDI5682", (unsigned long)&acp3x_5682},
535
{ "AMDI1015", (unsigned long)&acp3x_1015},
536
{ "10021015", (unsigned long)&acp3x_1015p},
537
{},
538
};
539
MODULE_DEVICE_TABLE(acpi, acp3x_audio_acpi_match);
540
541
static struct platform_driver acp3x_audio = {
542
.driver = {
543
.name = "acp3x-alc5682-max98357",
544
.acpi_match_table = ACPI_PTR(acp3x_audio_acpi_match),
545
.pm = &snd_soc_pm_ops,
546
},
547
.probe = acp3x_probe,
548
};
549
550
module_platform_driver(acp3x_audio);
551
552
MODULE_AUTHOR("[email protected]");
553
MODULE_AUTHOR("[email protected]");
554
MODULE_AUTHOR("[email protected]");
555
MODULE_DESCRIPTION("ALC5682 ALC1015, ALC1015P & MAX98357 audio support");
556
MODULE_LICENSE("GPL v2");
557
558