File Index
Files and directories
Sign in
FILE

acp3x-es83xx.c

File preview with syntax highlighting.

linux-6.19.14/sound/soc/amd/acp/acp3x-es83xx/acp3x-es83xx.c C
  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 <posteuca@mutex.one>
  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
 33struct 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
 45static const unsigned int channels[] = {
 46	DUAL_CHANNEL,
 47};
 48
 49static 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
 58static int acp3x_es83xx_headphone_power_event(struct snd_soc_dapm_widget *w,
 59					    struct snd_kcontrol *kcontrol, int event);
 60static int acp3x_es83xx_speaker_power_event(struct snd_soc_dapm_widget *w,
 61					    struct snd_kcontrol *kcontrol, int event);
 62
 63static 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
 98static struct snd_soc_jack es83xx_jack;
 99
100static 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
111static 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
125static 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
140static 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
147static 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
159static 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
177static 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
195static 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
214static 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
226static 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
253static 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
275static 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
329static const struct snd_soc_ops acp3x_es83xx_ops = {
330	.startup = acp3x_es83xx_codec_startup,
331};
332
333
334SND_SOC_DAILINK_DEF(codec,
335		    DAILINK_COMP_ARRAY(COMP_CODEC("i2c-ESSX8336:00", "ES8316 HiFi")));
336
337static 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
389static 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
401static 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
449void 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}
~/ Read-only file preview.