Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/soc/amd/acp/acp3x-es83xx/acp3x-es83xx.c
56148 views
1
// SPDX-License-Identifier: GPL-2.0+
2
//
3
// Machine driver for AMD ACP Audio engine using ES8336 codec.
4
//
5
// Copyright 2023 Marian Postevca <[email protected]>
6
#include <sound/core.h>
7
#include <sound/soc.h>
8
#include <sound/pcm.h>
9
#include <sound/pcm_params.h>
10
#include <sound/soc-dapm.h>
11
#include <sound/jack.h>
12
#include <sound/soc-acpi.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
#include <linux/dmi.h>
22
#include <linux/string_choices.h>
23
#include "../acp-mach.h"
24
#include "acp3x-es83xx.h"
25
26
#define get_mach_priv(card) ((struct acp3x_es83xx_private *)((acp_get_drvdata(card))->mach_priv))
27
28
#define DUAL_CHANNEL 2
29
30
#define ES83XX_ENABLE_DMIC BIT(4)
31
#define ES83XX_48_MHZ_MCLK BIT(5)
32
33
struct acp3x_es83xx_private {
34
bool speaker_on;
35
bool headphone_on;
36
unsigned long quirk;
37
struct snd_soc_component *codec;
38
struct device *codec_dev;
39
struct gpio_desc *gpio_speakers, *gpio_headphone;
40
struct acpi_gpio_params enable_spk_gpio, enable_hp_gpio;
41
struct acpi_gpio_mapping gpio_mapping[3];
42
struct snd_soc_dapm_route mic_map[2];
43
};
44
45
static const unsigned int channels[] = {
46
DUAL_CHANNEL,
47
};
48
49
static const struct snd_pcm_hw_constraint_list constraints_channels = {
50
.count = ARRAY_SIZE(channels),
51
.list = channels,
52
.mask = 0,
53
};
54
55
#define ES83xx_12288_KHZ_MCLK_FREQ (48000 * 256)
56
#define ES83xx_48_MHZ_MCLK_FREQ (48000 * 1000)
57
58
static int acp3x_es83xx_headphone_power_event(struct snd_soc_dapm_widget *w,
59
struct snd_kcontrol *kcontrol, int event);
60
static int acp3x_es83xx_speaker_power_event(struct snd_soc_dapm_widget *w,
61
struct snd_kcontrol *kcontrol, int event);
62
63
static int acp3x_es83xx_codec_startup(struct snd_pcm_substream *substream)
64
{
65
struct snd_pcm_runtime *runtime;
66
struct snd_soc_pcm_runtime *rtd;
67
struct snd_soc_dai *codec_dai;
68
struct acp3x_es83xx_private *priv;
69
unsigned int freq;
70
int ret;
71
72
runtime = substream->runtime;
73
rtd = snd_soc_substream_to_rtd(substream);
74
codec_dai = snd_soc_rtd_to_codec(rtd, 0);
75
priv = get_mach_priv(rtd->card);
76
77
if (priv->quirk & ES83XX_48_MHZ_MCLK) {
78
dev_dbg(priv->codec_dev, "using a 48Mhz MCLK\n");
79
freq = ES83xx_48_MHZ_MCLK_FREQ;
80
} else {
81
dev_dbg(priv->codec_dev, "using a 12.288Mhz MCLK\n");
82
freq = ES83xx_12288_KHZ_MCLK_FREQ;
83
}
84
85
ret = snd_soc_dai_set_sysclk(codec_dai, 0, freq, SND_SOC_CLOCK_OUT);
86
if (ret < 0) {
87
dev_err(rtd->dev, "can't set codec sysclk: %d\n", ret);
88
return ret;
89
}
90
91
runtime->hw.channels_max = DUAL_CHANNEL;
92
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
93
&constraints_channels);
94
95
return 0;
96
}
97
98
static struct snd_soc_jack es83xx_jack;
99
100
static struct snd_soc_jack_pin es83xx_jack_pins[] = {
101
{
102
.pin = "Headphone",
103
.mask = SND_JACK_HEADPHONE,
104
},
105
{
106
.pin = "Headset Mic",
107
.mask = SND_JACK_MICROPHONE,
108
},
109
};
110
111
static const struct snd_soc_dapm_widget acp3x_es83xx_widgets[] = {
112
SND_SOC_DAPM_SPK("Speaker", NULL),
113
SND_SOC_DAPM_HP("Headphone", NULL),
114
SND_SOC_DAPM_MIC("Headset Mic", NULL),
115
SND_SOC_DAPM_MIC("Internal Mic", NULL),
116
117
SND_SOC_DAPM_SUPPLY("Headphone Power", SND_SOC_NOPM, 0, 0,
118
acp3x_es83xx_headphone_power_event,
119
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
120
SND_SOC_DAPM_SUPPLY("Speaker Power", SND_SOC_NOPM, 0, 0,
121
acp3x_es83xx_speaker_power_event,
122
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
123
};
124
125
static const struct snd_soc_dapm_route acp3x_es83xx_audio_map[] = {
126
{"Headphone", NULL, "HPOL"},
127
{"Headphone", NULL, "HPOR"},
128
{"Headphone", NULL, "Headphone Power"},
129
130
/*
131
* There is no separate speaker output instead the speakers are muxed to
132
* the HP outputs. The mux is controlled Speaker and/or headphone switch.
133
*/
134
{"Speaker", NULL, "HPOL"},
135
{"Speaker", NULL, "HPOR"},
136
{"Speaker", NULL, "Speaker Power"},
137
};
138
139
140
static const struct snd_kcontrol_new acp3x_es83xx_controls[] = {
141
SOC_DAPM_PIN_SWITCH("Speaker"),
142
SOC_DAPM_PIN_SWITCH("Headphone"),
143
SOC_DAPM_PIN_SWITCH("Headset Mic"),
144
SOC_DAPM_PIN_SWITCH("Internal Mic"),
145
};
146
147
static int acp3x_es83xx_configure_widgets(struct snd_soc_card *card)
148
{
149
card->dapm_widgets = acp3x_es83xx_widgets;
150
card->num_dapm_widgets = ARRAY_SIZE(acp3x_es83xx_widgets);
151
card->controls = acp3x_es83xx_controls;
152
card->num_controls = ARRAY_SIZE(acp3x_es83xx_controls);
153
card->dapm_routes = acp3x_es83xx_audio_map;
154
card->num_dapm_routes = ARRAY_SIZE(acp3x_es83xx_audio_map);
155
156
return 0;
157
}
158
159
static int acp3x_es83xx_headphone_power_event(struct snd_soc_dapm_widget *w,
160
struct snd_kcontrol *kcontrol, int event)
161
{
162
struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm);
163
struct acp3x_es83xx_private *priv = get_mach_priv(card);
164
165
dev_dbg(priv->codec_dev, "headphone power event = %d\n", event);
166
if (SND_SOC_DAPM_EVENT_ON(event))
167
priv->headphone_on = true;
168
else
169
priv->headphone_on = false;
170
171
gpiod_set_value_cansleep(priv->gpio_speakers, priv->speaker_on);
172
gpiod_set_value_cansleep(priv->gpio_headphone, priv->headphone_on);
173
174
return 0;
175
}
176
177
static int acp3x_es83xx_speaker_power_event(struct snd_soc_dapm_widget *w,
178
struct snd_kcontrol *kcontrol, int event)
179
{
180
struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm);
181
struct acp3x_es83xx_private *priv = get_mach_priv(card);
182
183
dev_dbg(priv->codec_dev, "speaker power event: %d\n", event);
184
if (SND_SOC_DAPM_EVENT_ON(event))
185
priv->speaker_on = true;
186
else
187
priv->speaker_on = false;
188
189
gpiod_set_value_cansleep(priv->gpio_speakers, priv->speaker_on);
190
gpiod_set_value_cansleep(priv->gpio_headphone, priv->headphone_on);
191
192
return 0;
193
}
194
195
static int acp3x_es83xx_suspend_pre(struct snd_soc_card *card)
196
{
197
struct acp3x_es83xx_private *priv = get_mach_priv(card);
198
199
/* We need to disable the jack in the machine driver suspend
200
* callback so that the CODEC suspend callback actually gets
201
* called. Without doing it, the CODEC suspend/resume
202
* callbacks do not get called if headphones are plugged in.
203
* This is because plugging in headphones keeps some supplies
204
* active, this in turn means that the lowest bias level
205
* that the CODEC can go to is SND_SOC_BIAS_STANDBY.
206
* If components do not set idle_bias_on to true then
207
* their suspend/resume callbacks do not get called.
208
*/
209
dev_dbg(priv->codec_dev, "card suspend\n");
210
snd_soc_component_set_jack(priv->codec, NULL, NULL);
211
return 0;
212
}
213
214
static int acp3x_es83xx_resume_post(struct snd_soc_card *card)
215
{
216
struct acp3x_es83xx_private *priv = get_mach_priv(card);
217
218
/* We disabled jack detection in suspend callback,
219
* enable it back.
220
*/
221
dev_dbg(priv->codec_dev, "card resume\n");
222
snd_soc_component_set_jack(priv->codec, &es83xx_jack, NULL);
223
return 0;
224
}
225
226
static int acp3x_es83xx_configure_gpios(struct acp3x_es83xx_private *priv)
227
{
228
229
priv->enable_spk_gpio.crs_entry_index = 0;
230
priv->enable_hp_gpio.crs_entry_index = 1;
231
232
priv->enable_spk_gpio.active_low = false;
233
priv->enable_hp_gpio.active_low = false;
234
235
priv->gpio_mapping[0].name = "speakers-enable-gpios";
236
priv->gpio_mapping[0].data = &priv->enable_spk_gpio;
237
priv->gpio_mapping[0].size = 1;
238
priv->gpio_mapping[0].quirks = ACPI_GPIO_QUIRK_ONLY_GPIOIO;
239
240
priv->gpio_mapping[1].name = "headphone-enable-gpios";
241
priv->gpio_mapping[1].data = &priv->enable_hp_gpio;
242
priv->gpio_mapping[1].size = 1;
243
priv->gpio_mapping[1].quirks = ACPI_GPIO_QUIRK_ONLY_GPIOIO;
244
245
dev_info(priv->codec_dev, "speaker gpio %d active %s, headphone gpio %d active %s\n",
246
priv->enable_spk_gpio.crs_entry_index,
247
str_low_high(priv->enable_spk_gpio.active_low),
248
priv->enable_hp_gpio.crs_entry_index,
249
str_low_high(priv->enable_hp_gpio.active_low));
250
return 0;
251
}
252
253
static int acp3x_es83xx_configure_mics(struct acp3x_es83xx_private *priv)
254
{
255
int num_routes = 0;
256
int i;
257
258
if (!(priv->quirk & ES83XX_ENABLE_DMIC)) {
259
priv->mic_map[num_routes].sink = "MIC1";
260
priv->mic_map[num_routes].source = "Internal Mic";
261
num_routes++;
262
}
263
264
priv->mic_map[num_routes].sink = "MIC2";
265
priv->mic_map[num_routes].source = "Headset Mic";
266
num_routes++;
267
268
for (i = 0; i < num_routes; i++)
269
dev_info(priv->codec_dev, "%s is %s\n",
270
priv->mic_map[i].source, priv->mic_map[i].sink);
271
272
return num_routes;
273
}
274
275
static int acp3x_es83xx_init(struct snd_soc_pcm_runtime *runtime)
276
{
277
struct snd_soc_component *codec = snd_soc_rtd_to_codec(runtime, 0)->component;
278
struct snd_soc_card *card = runtime->card;
279
struct acp3x_es83xx_private *priv = get_mach_priv(card);
280
int ret = 0;
281
int num_routes;
282
283
ret = snd_soc_card_jack_new_pins(card, "Headset",
284
SND_JACK_HEADSET | SND_JACK_BTN_0,
285
&es83xx_jack, es83xx_jack_pins,
286
ARRAY_SIZE(es83xx_jack_pins));
287
if (ret) {
288
dev_err(card->dev, "jack creation failed %d\n", ret);
289
return ret;
290
}
291
292
snd_jack_set_key(es83xx_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
293
294
snd_soc_component_set_jack(codec, &es83xx_jack, NULL);
295
296
priv->codec = codec;
297
acp3x_es83xx_configure_gpios(priv);
298
299
ret = devm_acpi_dev_add_driver_gpios(priv->codec_dev, priv->gpio_mapping);
300
if (ret)
301
dev_warn(priv->codec_dev, "failed to add speaker gpio\n");
302
303
priv->gpio_speakers = gpiod_get_optional(priv->codec_dev, "speakers-enable",
304
priv->enable_spk_gpio.active_low ? GPIOD_OUT_LOW : GPIOD_OUT_HIGH);
305
if (IS_ERR(priv->gpio_speakers)) {
306
dev_err(priv->codec_dev, "could not get speakers-enable GPIO\n");
307
return PTR_ERR(priv->gpio_speakers);
308
}
309
310
priv->gpio_headphone = gpiod_get_optional(priv->codec_dev, "headphone-enable",
311
priv->enable_hp_gpio.active_low ? GPIOD_OUT_LOW : GPIOD_OUT_HIGH);
312
if (IS_ERR(priv->gpio_headphone)) {
313
dev_err(priv->codec_dev, "could not get headphone-enable GPIO\n");
314
return PTR_ERR(priv->gpio_headphone);
315
}
316
317
num_routes = acp3x_es83xx_configure_mics(priv);
318
if (num_routes > 0) {
319
struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
320
321
ret = snd_soc_dapm_add_routes(dapm, priv->mic_map, num_routes);
322
if (ret != 0)
323
device_remove_software_node(priv->codec_dev);
324
}
325
326
return ret;
327
}
328
329
static const struct snd_soc_ops acp3x_es83xx_ops = {
330
.startup = acp3x_es83xx_codec_startup,
331
};
332
333
334
SND_SOC_DAILINK_DEF(codec,
335
DAILINK_COMP_ARRAY(COMP_CODEC("i2c-ESSX8336:00", "ES8316 HiFi")));
336
337
static const struct dmi_system_id acp3x_es83xx_dmi_table[] = {
338
{
339
.matches = {
340
DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "HUAWEI"),
341
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "KLVL-WXXW"),
342
DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "M1010"),
343
},
344
.driver_data = (void *)(ES83XX_ENABLE_DMIC),
345
},
346
{
347
.matches = {
348
DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "HUAWEI"),
349
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "KLVL-WXX9"),
350
DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "M1010"),
351
},
352
.driver_data = (void *)(ES83XX_ENABLE_DMIC),
353
},
354
{
355
.matches = {
356
DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "HUAWEI"),
357
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "BOM-WXX9"),
358
DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "M1010"),
359
},
360
.driver_data = (void *)(ES83XX_ENABLE_DMIC|ES83XX_48_MHZ_MCLK),
361
},
362
{
363
.matches = {
364
DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "HUAWEI"),
365
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "HVY-WXX9"),
366
DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "M1010"),
367
},
368
.driver_data = (void *)(ES83XX_ENABLE_DMIC),
369
},
370
{
371
.matches = {
372
DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "HUAWEI"),
373
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "HVY-WXX9"),
374
DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "M1020"),
375
},
376
.driver_data = (void *)(ES83XX_ENABLE_DMIC),
377
},
378
{
379
.matches = {
380
DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "HUAWEI"),
381
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "HVY-WXX9"),
382
DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "M1040"),
383
},
384
.driver_data = (void *)(ES83XX_ENABLE_DMIC),
385
},
386
{}
387
};
388
389
static int acp3x_es83xx_configure_link(struct snd_soc_card *card, struct snd_soc_dai_link *link)
390
{
391
link->codecs = codec;
392
link->num_codecs = ARRAY_SIZE(codec);
393
link->init = acp3x_es83xx_init;
394
link->ops = &acp3x_es83xx_ops;
395
link->dai_fmt = SND_SOC_DAIFMT_I2S
396
| SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP;
397
398
return 0;
399
}
400
401
static int acp3x_es83xx_probe(struct snd_soc_card *card)
402
{
403
int ret = 0;
404
struct device *dev = card->dev;
405
const struct dmi_system_id *dmi_id;
406
407
dmi_id = dmi_first_match(acp3x_es83xx_dmi_table);
408
if (dmi_id && dmi_id->driver_data) {
409
struct acp3x_es83xx_private *priv;
410
struct acp_card_drvdata *acp_drvdata;
411
struct acpi_device *adev;
412
struct device *codec_dev;
413
414
acp_drvdata = (struct acp_card_drvdata *)card->drvdata;
415
416
dev_info(dev, "matched DMI table with this system, trying to register sound card\n");
417
418
adev = acpi_dev_get_first_match_dev(acp_drvdata->acpi_mach->id, NULL, -1);
419
if (!adev) {
420
dev_err(dev, "Error cannot find '%s' dev\n", acp_drvdata->acpi_mach->id);
421
return -ENXIO;
422
}
423
424
codec_dev = acpi_get_first_physical_node(adev);
425
acpi_dev_put(adev);
426
if (!codec_dev) {
427
dev_warn(dev, "Error cannot find codec device, will defer probe\n");
428
return -EPROBE_DEFER;
429
}
430
431
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
432
if (!priv) {
433
put_device(codec_dev);
434
return -ENOMEM;
435
}
436
437
priv->codec_dev = codec_dev;
438
priv->quirk = (unsigned long)dmi_id->driver_data;
439
acp_drvdata->mach_priv = priv;
440
dev_info(dev, "successfully probed the sound card\n");
441
} else {
442
ret = -ENODEV;
443
dev_warn(dev, "this system has a ES83xx codec defined in ACPI, but the driver doesn't have this system registered in DMI table\n");
444
}
445
return ret;
446
}
447
448
449
void acp3x_es83xx_init_ops(struct acp_mach_ops *ops)
450
{
451
ops->probe = acp3x_es83xx_probe;
452
ops->configure_widgets = acp3x_es83xx_configure_widgets;
453
ops->configure_link = acp3x_es83xx_configure_link;
454
ops->suspend_pre = acp3x_es83xx_suspend_pre;
455
ops->resume_post = acp3x_es83xx_resume_post;
456
}
457
458