ALT Linux kernel packages development
 help / color / mirror / Atom feed
* [d-kernel] [PATCH 0/2] Add support for ES8336 codecs on Ryzen machines in 5.15
@ 2023-03-02 11:58 nickel
  2023-03-02 11:58 ` [d-kernel] [PATCH 1/2] ASoC: AMD: add ACP machine driver for ES8336 nickel
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: nickel @ 2023-03-02 11:58 UTC (permalink / raw)
  To: devel-kernel

These patches are intended for both p10 un-def and Sisyphus std-def 5.15 kernels.
For full featured support one needs to update alsa-ucm-conf up to at least 1.2.8-alt5.

[PATCH 1/2] ASoC: AMD: add ACP machine driver for ES8336
[PATCH 2/2] ASoC: AMD: acp3x-es8336-mach: add quirk override mclk



^ permalink raw reply	[flat|nested] 4+ messages in thread

* [d-kernel] [PATCH 1/2] ASoC: AMD: add ACP machine driver for ES8336
  2023-03-02 11:58 [d-kernel] [PATCH 0/2] Add support for ES8336 codecs on Ryzen machines in 5.15 nickel
@ 2023-03-02 11:58 ` nickel
  2023-03-02 11:58 ` [d-kernel] [PATCH 2/2] ASoC: AMD: acp3x-es8336-mach: add quirk override mclk freq nickel
  2023-03-02 16:03 ` [d-kernel] [PATCH 0/2] Add support for ES8336 codecs on Ryzen machines in 5.15 Vitaly Chikunov
  2 siblings, 0 replies; 4+ messages in thread
From: nickel @ 2023-03-02 11:58 UTC (permalink / raw)
  To: devel-kernel; +Cc: Vasiliy Kovalev

From: Vasiliy Kovalev <kovalev@altlinux.org>

Backport from 6.1.3
Based on commit 6976fc0fea0dcc5a367580cd7edf94574601837e from
fork of Marian Postevca aka @codepayne

Link: https://github.com/thesofproject/linux/issues/3249#issuecomment-1378025039
Link: https://github.com/codepayne/linux-sound-huawei/issues/5

Signed-off-by: Vasiliy Kovalev <kovalev@altlinux.org>
Signed-off-by: Nikolai Kostrigin <nickel@altlinux.org>
---
 config                          |   1 +
 sound/soc/amd/Kconfig           |  13 +
 sound/soc/amd/Makefile          |   2 +
 sound/soc/amd/acp3x-es8336.c    | 437 ++++++++++++++++++++++++++++++++
 sound/soc/amd/raven/pci-acp3x.c |   4 +-
 sound/soc/codecs/es8316.c       | 130 ++++++----
 6 files changed, 534 insertions(+), 53 deletions(-)
 create mode 100644 sound/soc/amd/acp3x-es8336.c

diff --git a/config b/config
index 76e54c37e497a..722dcbd3c74f9 100644
--- a/config
+++ b/config
@@ -6823,6 +6823,7 @@ CONFIG_SND_SOC_AMD_ACP=m
 CONFIG_SND_SOC_AMD_CZ_DA7219MX98357_MACH=m
 CONFIG_SND_SOC_AMD_CZ_RT5645_MACH=m
 CONFIG_SND_SOC_AMD_ACP3x=m
+CONFIG_SND_SOC_AMD_ACP3x_ES8336_MACH=m
 CONFIG_SND_SOC_AMD_RV_RT5682_MACH=m
 CONFIG_SND_SOC_AMD_RENOIR=m
 CONFIG_SND_SOC_AMD_RENOIR_MACH=m
diff --git a/sound/soc/amd/Kconfig b/sound/soc/amd/Kconfig
index 49ff5e73e9bad..5d03db45751d1 100644
--- a/sound/soc/amd/Kconfig
+++ b/sound/soc/amd/Kconfig
@@ -28,6 +28,19 @@ config SND_SOC_AMD_ACP3x
 	help
 	 This option enables ACP v3.x I2S support on AMD platform
 
+config SND_SOC_AMD_ACP3x_ES8336_MACH
+	tristate "AMD ACP3x support for ES8336"
+	select SND_SOC_ACPI if ACPI
+	select SND_SOC_ES8316
+	depends on ACPI
+	depends on I2C
+	depends on SND_SOC_AMD_ACP3x
+	help
+	 This option enables machine driver for ACP3x platform
+	 using es8336 codec.
+	 Say m if you have such a device.
+	 If unsure select "N".
+
 config SND_SOC_AMD_RV_RT5682_MACH
 	tristate "AMD RV support for RT5682"
 	select SND_SOC_RT5682_I2C
diff --git a/sound/soc/amd/Makefile b/sound/soc/amd/Makefile
index 07150d26f3155..0f0b6ca7bd9cb 100644
--- a/sound/soc/amd/Makefile
+++ b/sound/soc/amd/Makefile
@@ -3,6 +3,7 @@ acp_audio_dma-objs := acp-pcm-dma.o
 snd-soc-acp-da7219mx98357-mach-objs := acp-da7219-max98357a.o
 snd-soc-acp-rt5645-mach-objs := acp-rt5645.o
 snd-soc-acp-rt5682-mach-objs := acp3x-rt5682-max9836.o
+snd-soc-acp3x-es8336-mach-objs := acp3x-es8336.o
 
 obj-$(CONFIG_SND_SOC_AMD_ACP) += acp_audio_dma.o
 obj-$(CONFIG_SND_SOC_AMD_CZ_DA7219MX98357_MACH) += snd-soc-acp-da7219mx98357-mach.o
@@ -11,3 +12,4 @@ obj-$(CONFIG_SND_SOC_AMD_ACP3x) += raven/
 obj-$(CONFIG_SND_SOC_AMD_RV_RT5682_MACH) += snd-soc-acp-rt5682-mach.o
 obj-$(CONFIG_SND_SOC_AMD_RENOIR) += renoir/
 obj-$(CONFIG_SND_SOC_AMD_ACP5x) += vangogh/
+obj-$(CONFIG_SND_SOC_AMD_ACP3x_ES8336_MACH) += snd-soc-acp3x-es8336-mach.o
diff --git a/sound/soc/amd/acp3x-es8336.c b/sound/soc/amd/acp3x-es8336.c
new file mode 100644
index 0000000000000..f930cc258dfc9
--- /dev/null
+++ b/sound/soc/amd/acp3x-es8336.c
@@ -0,0 +1,437 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Machine driver for AMD ACP Audio engine using DA7219 & MAX98357 codec.
+//
+//Copyright 2016 Advanced Micro Devices, Inc.
+
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc-dapm.h>
+#include <sound/jack.h>
+#include <linux/clk.h>
+#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/io.h>
+#include <linux/acpi.h>
+#include <linux/dmi.h>
+
+#include "raven/acp3x.h"
+
+#define DRV_NAME        "amd-acp3x-essx8336"
+#define SND_CARD_NAME   DRV_NAME
+#define DUAL_CHANNEL	2
+
+struct acp3x_es8336_private {
+	/* struct acp3x_platform_info machine must always be
+	 * the first entry in the structure,
+	 * the acp3x-i2s driver casts the card private data to
+	 * struct acp3x_platform_info
+	 */
+	struct acp3x_platform_info machine;
+	struct device *codec_dev;
+	struct gpio_desc *gpio_speakers;
+	bool speaker_en;
+};
+
+static const unsigned int channels[] = {
+	DUAL_CHANNEL,
+};
+
+static const unsigned int rates[] = {
+	48000
+};
+
+static const struct snd_pcm_hw_constraint_list constraints_rates = {
+	.count = ARRAY_SIZE(rates),
+	.list  = rates,
+	.mask = 0,
+};
+
+static const struct snd_pcm_hw_constraint_list constraints_channels = {
+	.count = ARRAY_SIZE(channels),
+	.list = channels,
+	.mask = 0,
+};
+#define ES8336_MCLK_FREQ (48000 * 1000)
+
+static int acp3x_es8336_codec_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime;
+	struct snd_soc_pcm_runtime *rtd;
+	struct acp3x_platform_info *machine;
+	struct acp3x_es8336_private *priv;
+	struct snd_soc_dai *codec_dai;
+	int ret;
+
+	runtime = substream->runtime;
+	rtd = asoc_substream_to_rtd(substream);
+	priv = snd_soc_card_get_drvdata(rtd->card);
+	machine = &priv->machine;
+	codec_dai = asoc_rtd_to_codec(rtd, 0);
+
+	ret = snd_soc_dai_set_sysclk(codec_dai, 0, ES8336_MCLK_FREQ, SND_SOC_CLOCK_OUT);
+	if (ret < 0) {
+		dev_err(rtd->dev, "can't set codec sysclk: %d\n", ret);
+		return ret;
+	}
+
+	ret =  snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+	                           | SND_SOC_DAIFMT_CBP_CFP);
+	if (ret < 0) {
+		dev_err(rtd->dev, "failed to set DAI fmt: %d\n", ret);
+		return ret;
+	}
+	/* Report to userspace ALSA that we don't support suspending and resuming pcm streams,
+	 * this means that during suspends and resumes of the PC, pulseaudio will not try to resume
+	 * the substream, but will drop the connection and establish a new one.
+	 * This is needed because sometimes after resume pulseaudio is unable to resume the stream
+	 * and no sound can be heard. As a workaround for this issue, pulseaudio needs to be restarted.
+	 */
+	runtime->hw.info &= ~(SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME);
+
+	runtime->hw.channels_max = DUAL_CHANNEL;
+	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+	                           &constraints_channels);
+	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+	                           &constraints_rates);
+	runtime->hw.formats = SNDRV_PCM_FMTBIT_S32_LE;
+	machine->play_i2s_instance = I2S_SP_INSTANCE;
+
+	return 0;
+}
+
+static int acp3x_es8336_speaker_power_event(struct snd_soc_dapm_widget *w,
+                                            struct snd_kcontrol *kcontrol, int event);
+
+static struct snd_soc_jack es8336_jack;
+
+static struct snd_soc_jack_pin es8336_jack_pins[] = {
+	{
+		.pin	= "Headphone",
+		.mask	= SND_JACK_HEADPHONE,
+	},
+	{
+		.pin	= "Headset Mic",
+		.mask	= SND_JACK_MICROPHONE,
+	 },
+};
+
+static const struct snd_soc_dapm_widget acp3x_es8336_widgets[] = {
+	SND_SOC_DAPM_SPK("Speaker", NULL),
+	SND_SOC_DAPM_HP("Headphone", NULL),
+	SND_SOC_DAPM_MIC("Headset Mic", NULL),
+	SND_SOC_DAPM_MIC("Internal Mic", NULL),
+
+	SND_SOC_DAPM_SUPPLY("Speaker Power", SND_SOC_NOPM, 0, 0,
+	                    acp3x_es8336_speaker_power_event,
+	                    SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+};
+
+static const struct snd_soc_dapm_route acp3x_es8336_audio_map[] = {
+	{"Headphone", NULL, "HPOL"},
+	{"Headphone", NULL, "HPOR"},
+
+	/*
+	 * There is no separate speaker output instead the speakers are muxed to
+	 * the HP outputs. The mux is controlled Speaker and/or headphone switch.
+	 */
+	{"Speaker", NULL, "HPOL"},
+	{"Speaker", NULL, "HPOR"},
+	{"MIC1", NULL, "Headset Mic"},
+	{"Speaker", NULL, "Speaker Power"},
+};
+
+
+static const struct snd_kcontrol_new acp3x_es8336_controls[] = {
+	SOC_DAPM_PIN_SWITCH("Speaker"),
+	SOC_DAPM_PIN_SWITCH("Headphone"),
+	SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+static const struct acpi_gpio_params enable_gpio0 = { 0, 0, true };
+
+static const struct acpi_gpio_mapping acpi_speakers_enable_gpio0[] = {
+	{ "speakers-enable-gpios", &enable_gpio0, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO },
+	{ }
+};
+
+static int acp3x_es8336_speaker_power_event(struct snd_soc_dapm_widget *w,
+                                            struct snd_kcontrol *kcontrol, int event)
+{
+	struct acp3x_es8336_private *priv = snd_soc_card_get_drvdata(w->dapm->card);
+
+	if (priv->speaker_en == !SND_SOC_DAPM_EVENT_ON(event))
+		return 0;
+
+	priv->speaker_en = !SND_SOC_DAPM_EVENT_ON(event);
+
+	if (SND_SOC_DAPM_EVENT_ON(event))
+		msleep(70);
+
+	gpiod_set_value_cansleep(priv->gpio_speakers, priv->speaker_en);
+
+	return 0;
+}
+
+/*
+  static int acp3x_es8336_hw_params(struct snd_pcm_substream *substream,
+  struct snd_pcm_hw_params *params)
+  {
+  struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+  struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+  struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+  printk(KERN_INFO"mysound1: entered card set hw params\n");
+
+  //snd_mask_none(fmt);
+  //snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE);
+
+  return 0;
+  }
+*/
+
+static int acp3x_es8336_init(struct snd_soc_pcm_runtime *runtime)
+{
+	struct snd_soc_component *codec = asoc_rtd_to_codec(runtime, 0)->component;
+	struct snd_soc_card *card = runtime->card;
+	struct acp3x_es8336_private *priv = snd_soc_card_get_drvdata(card);
+	int ret;
+
+	ret = snd_soc_card_jack_new(card, "Headset",
+	                                 SND_JACK_HEADSET | SND_JACK_BTN_0,
+	                                 &es8336_jack, es8336_jack_pins,
+	                                 ARRAY_SIZE(es8336_jack_pins));
+	if (ret) {
+		dev_err(card->dev, "jack creation failed %d\n", ret);
+		return ret;
+	}
+
+	snd_jack_set_key(es8336_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+
+	snd_soc_component_set_jack(codec, &es8336_jack, NULL);
+
+	ret = devm_acpi_dev_add_driver_gpios(codec->dev, acpi_speakers_enable_gpio0);
+	if (ret)
+		dev_warn(codec->dev, "failed to add speaker gpio\n");
+
+	priv->codec_dev = codec->dev;
+	priv->gpio_speakers = gpiod_get_optional(codec->dev, "speakers-enable", GPIOD_OUT_LOW);
+	if (IS_ERR(priv->gpio_speakers)) {
+		dev_err(codec->dev, "could not get speakers-enable GPIO\n");
+		return PTR_ERR(priv->gpio_speakers);
+	}
+
+	return 0;
+}
+
+static struct snd_soc_ops acp3x_es8336_ops = {
+	//	.hw_params = acp3x_es8336_hw_params,
+	.startup = acp3x_es8336_codec_startup,
+};
+
+
+SND_SOC_DAILINK_DEF(acp3x_i2s,
+                    DAILINK_COMP_ARRAY(COMP_CPU("acp3x_i2s_playcap.0")));
+SND_SOC_DAILINK_DEF(codec,
+                    DAILINK_COMP_ARRAY(COMP_CODEC("i2c-ESSX8336:00", "ES8316 HiFi")));
+SND_SOC_DAILINK_DEF(platform,
+                    DAILINK_COMP_ARRAY(COMP_PLATFORM("acp3x_rv_i2s_dma.0")));
+
+static struct snd_soc_dai_link acp3x_dai_es8336[] = {
+	{
+		.name = "amd-acp3x-es8336-dai",
+		.stream_name = "ES8336 HiFi Play",
+		.stop_dma_first = 1,
+		.dpcm_capture = 1,
+		.dpcm_playback = 1,
+		.init = acp3x_es8336_init,
+		.ops = &acp3x_es8336_ops,
+		SND_SOC_DAILINK_REG(acp3x_i2s, codec, platform),
+	},
+};
+
+static struct snd_soc_card acp3x_es8336 = {
+	.name = SND_CARD_NAME,
+	.owner = THIS_MODULE,
+	.dai_link = acp3x_dai_es8336,
+	.num_links = ARRAY_SIZE(acp3x_dai_es8336),
+	.dapm_widgets = acp3x_es8336_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(acp3x_es8336_widgets),
+	.dapm_routes = acp3x_es8336_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(acp3x_es8336_audio_map),
+	.controls = acp3x_es8336_controls,
+	.num_controls = ARRAY_SIZE(acp3x_es8336_controls),
+};
+
+static const struct dmi_system_id acp3x_es8336_dmi_table[] = {
+	{
+		.matches = {
+			DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "HUAWEI"),
+			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "KLVL-WXXW"),
+			DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "M1010"),
+		},
+		.driver_data = &acp3x_es8336,
+	},
+	{
+		.matches = {
+			DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "HUAWEI"),
+			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "KLVL-WXX9"),
+			DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "M1010"),
+		},
+		.driver_data = &acp3x_es8336,
+	},
+	{
+		.matches = {
+			DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "HUAWEI"),
+			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "BOM-WXX9"),
+			DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "M1010"),
+		},
+		.driver_data = &acp3x_es8336,
+	},
+		{
+		.matches = {
+			DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "HUAWEI"),
+			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "HVY-WXX9"),
+			DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "M1040"),
+		},
+		.driver_data = &acp3x_es8336,
+	},
+	{}
+};
+
+
+static int acp3x_probe(struct platform_device *pdev)
+{
+	int ret = -ENODEV;
+	struct device *dev = &pdev->dev;
+	const struct dmi_system_id *dmi_id;
+
+	dmi_id = dmi_first_match(acp3x_es8336_dmi_table);
+	if (dmi_id && dmi_id->driver_data) {
+		struct acp3x_es8336_private *priv;
+		struct snd_soc_card *card;
+
+		dev_info(dev, "matched DMI table with this system, trying to register sound card\n");
+
+		priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+		if (!priv) {
+			dev_err(dev, "can't alloc priv structure\n");
+			return -ENOMEM;
+		}
+
+		card = (struct snd_soc_card *)dmi_id->driver_data;
+
+		card->dev = &pdev->dev;
+		platform_set_drvdata(pdev, card);
+		snd_soc_card_set_drvdata(card, priv);
+		ret = devm_snd_soc_register_card(&pdev->dev, card);
+		if (ret) {
+			dev_err(dev, "failed to register sound card, ret = %d\n", ret);
+			return dev_err_probe(&pdev->dev, ret,
+			                     "devm_snd_soc_register_card(%s) failed\n",
+			                     card->name);
+		} else {
+			dev_info(dev, "successfully registered the sound card\n");
+		}
+	}
+	else {
+		dev_warn(dev, "this system has a ES8336 codec defined in ACPI, "
+		         "but the driver doesn't have this system registered in DMI table\n");
+	}
+	return ret;
+}
+
+
+static int acp3x_remove(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = platform_get_drvdata(pdev);
+	struct acp3x_es8336_private *priv = snd_soc_card_get_drvdata(card);
+	struct device *dev = &pdev->dev;
+
+	gpiod_put(priv->gpio_speakers);
+
+	dev_info(dev, "removing sound card\n");
+	return 0;
+}
+
+/*
+  static const struct platform_device_id board_ids[] = {
+  {
+  .name = "acp3x-essx8336",
+  },
+  { }
+  };
+*/
+//MODULE_DEVICE_TABLE(platform, board_ids);
+
+
+
+static const struct acpi_device_id acp3x_audio_acpi_match[] = {
+	{"ESSX8336", 0},
+	{},
+};
+MODULE_DEVICE_TABLE(acpi, acp3x_audio_acpi_match);
+
+
+static struct platform_driver acp3x_audio = {
+	.driver = {
+		.name = DRV_NAME,
+		.owner = THIS_MODULE,
+		//.acpi_match_table = ACPI_PTR(acp3x_audio_acpi_match),
+		.pm = &snd_soc_pm_ops,
+	},
+	.probe = acp3x_probe,
+	.remove = acp3x_remove,
+	//.id_table = board_ids,
+};
+
+static struct platform_device *acp3x_es8336_snd_device;
+
+static int __init acp3x_es8336_module_init(void)
+{
+	int ret = -ENODEV;
+
+	msleep(5000);
+	ret = platform_driver_register(&acp3x_audio);
+	if (ret < 0) {
+		printk(KERN_ERR DRV_NAME": can't register platform driver\n");
+		return ret;
+	}
+
+	acp3x_es8336_snd_device = platform_device_register_simple(DRV_NAME, 0, NULL, 0);
+	if (IS_ERR(acp3x_es8336_snd_device)) {
+		printk(KERN_ERR DRV_NAME": couldn't register platform device\n");
+		platform_driver_unregister(&acp3x_audio);
+		return PTR_ERR(acp3x_es8336_snd_device);
+	}
+
+	if (!platform_get_drvdata(acp3x_es8336_snd_device)) {
+		printk(KERN_ERR DRV_NAME": probe of hw failed\n");
+		platform_device_unregister(acp3x_es8336_snd_device);
+		platform_driver_unregister(&acp3x_audio);
+		return -ENODEV;
+	}
+	printk(KERN_INFO DRV_NAME": platform device registered successfully\n");
+
+	return ret;
+}
+module_init(acp3x_es8336_module_init);
+
+static void __exit acp3x_es8336_module_exit(void)
+{
+	printk(KERN_INFO DRV_NAME": module unloading\n");
+	platform_device_unregister(acp3x_es8336_snd_device);
+	platform_driver_unregister(&acp3x_audio);
+}
+module_exit(acp3x_es8336_module_exit);
+
+MODULE_AUTHOR("posteuca@mutex.one");
+MODULE_DESCRIPTION("ACP3x rev 1 ES8336 audio support");
+MODULE_LICENSE("GPL v2");
+//MODULE_ALIAS("dmi:bvnHUAWEI:*:*:*:*:*:pnKLVL-WXXW:pvrM1010:rvnHUAWEI:rnKLVL-WXXW-PCB:rvrM1010:*:*:*:skuC100:*")
+//MODULE_ALIAS("platform:acp3x-essx8336");
diff --git a/sound/soc/amd/raven/pci-acp3x.c b/sound/soc/amd/raven/pci-acp3x.c
index a013a607b3d47..cdb8773b11f13 100644
--- a/sound/soc/amd/raven/pci-acp3x.c
+++ b/sound/soc/amd/raven/pci-acp3x.c
@@ -133,8 +133,8 @@ static int snd_acp3x_probe(struct pci_dev *pci,
 	int ret, i;
 	u32 addr, val;
 
-	/* Raven device detection */
-	if (pci->revision != 0x00)
+	/* Raven and lucienne device detection */
+	if (pci->revision != 0x00 && pci->revision != 0x01)
 		return -ENODEV;
 
 	if (pci_enable_device(pci)) {
diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c
index 9778c988e49e1..d3afbfbe0758c 100644
--- a/sound/soc/codecs/es8316.c
+++ b/sound/soc/codecs/es8316.c
@@ -27,9 +27,9 @@
  * MCLK/LRCK ratios, but we also add ratio 400, which is commonly used on
  * Intel Cherry Trail platforms (19.2MHz MCLK, 48kHz LRCK).
  */
-#define NR_SUPPORTED_MCLK_LRCK_RATIOS 6
+#define NR_SUPPORTED_MCLK_LRCK_RATIOS 7
 static const unsigned int supported_mclk_lrck_ratios[] = {
-	256, 384, 400, 512, 768, 1024
+	256, 384, 400, 512, 768, 1000, 1024
 };
 
 struct es8316_priv {
@@ -401,10 +401,8 @@ static int es8316_set_dai_fmt(struct snd_soc_dai *codec_dai,
 	u8 clksw;
 	u8 mask;
 
-	if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) {
-		dev_err(component->dev, "Codec driver only supports slave mode\n");
-		return -EINVAL;
-	}
+	if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBP_CFP)
+		serdata1 |= ES8316_SERDATA1_MASTER;
 
 	if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_I2S) {
 		dev_err(component->dev, "Codec driver only supports I2S format\n");
@@ -464,11 +462,15 @@ static int es8316_pcm_hw_params(struct snd_pcm_substream *substream,
 	struct snd_soc_component *component = dai->component;
 	struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component);
 	u8 wordlen = 0;
+	u8 bclk_divider;
+	u16 lrck_divider;
 	int i;
+	int mclk_div = 1;
+	unsigned int ratio;
 
 	/* Validate supported sample rates that are autodetected from MCLK */
 	for (i = 0; i < NR_SUPPORTED_MCLK_LRCK_RATIOS; i++) {
-		const unsigned int ratio = supported_mclk_lrck_ratios[i];
+		ratio = supported_mclk_lrck_ratios[i];
 
 		if (es8316->sysclk % ratio != 0)
 			continue;
@@ -478,27 +480,52 @@ static int es8316_pcm_hw_params(struct snd_pcm_substream *substream,
 	if (i == NR_SUPPORTED_MCLK_LRCK_RATIOS)
 		return -EINVAL;
 
+	if (ratio == 1000) {
+		snd_soc_component_update_bits(component, 0x01, 0x80, 0x80);
+		mclk_div = 2;
+	}
+
+	lrck_divider = es8316->sysclk / params_rate(params) / mclk_div;
+	bclk_divider = lrck_divider / 4;
 	switch (params_format(params)) {
 	case SNDRV_PCM_FORMAT_S16_LE:
 		wordlen = ES8316_SERDATA2_LEN_16;
+		bclk_divider /= 16;
 		break;
 	case SNDRV_PCM_FORMAT_S20_3LE:
 		wordlen = ES8316_SERDATA2_LEN_20;
+		bclk_divider /= 20;
 		break;
 	case SNDRV_PCM_FORMAT_S24_LE:
 		wordlen = ES8316_SERDATA2_LEN_24;
+		bclk_divider /= 24;
 		break;
 	case SNDRV_PCM_FORMAT_S32_LE:
 		wordlen = ES8316_SERDATA2_LEN_32;
+		bclk_divider /= 32;
 		break;
 	default:
 		return -EINVAL;
 	}
 
+	static u8 only_one = 0;
+	if (!only_one) {
+		only_one = 1;
+		if (mclk_div == 2)
+			dev_info(component->dev, "Activating MCLK div by 2\n");
+
+		dev_info(component->dev, "Using lrck div = %d, bclk div = %d, wordlen = %d\n", lrck_divider, bclk_divider, wordlen);
+	}
+
 	snd_soc_component_update_bits(component, ES8316_SERDATA_DAC,
 			    ES8316_SERDATA2_LEN_MASK, wordlen);
 	snd_soc_component_update_bits(component, ES8316_SERDATA_ADC,
 			    ES8316_SERDATA2_LEN_MASK, wordlen);
+	snd_soc_component_update_bits(component, ES8316_SERDATA1, 0x1f, bclk_divider);
+	snd_soc_component_update_bits(component, ES8316_CLKMGR_ADCDIV1, 0x0f, lrck_divider >> 8);
+	snd_soc_component_update_bits(component, ES8316_CLKMGR_ADCDIV2, 0xff, lrck_divider & 0xff);
+	snd_soc_component_update_bits(component, ES8316_CLKMGR_DACDIV1, 0x0f, lrck_divider >> 8);
+	snd_soc_component_update_bits(component, ES8316_CLKMGR_DACDIV2, 0xff, lrck_divider & 0xff);
 	return 0;
 }
 
@@ -510,7 +537,7 @@ static int es8316_mute(struct snd_soc_dai *dai, int mute, int direction)
 }
 
 #define ES8316_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
-			SNDRV_PCM_FMTBIT_S24_LE)
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
 static const struct snd_soc_dai_ops es8316_ops = {
 	.startup = es8316_pcm_startup,
@@ -707,6 +734,41 @@ static int es8316_set_jack(struct snd_soc_component *component,
 	return 0;
 }
 
+#ifdef CONFIG_PM
+
+static int es8316_suspend(struct snd_soc_component *component)
+{
+	struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component);
+	regcache_cache_only(es8316->regmap, true);
+
+	return 0;
+}
+
+static int es8316_resume(struct snd_soc_component *component)
+{
+	struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component);
+
+	regcache_cache_only(es8316->regmap, false);
+	/* Reset codec and enable current state machine */
+	snd_soc_component_write(component, ES8316_RESET, 0x3f);
+	usleep_range(5000, 5500);
+	snd_soc_component_write(component, ES8316_RESET, ES8316_RESET_CSM_ON);
+	msleep(30);
+
+	snd_soc_component_write(component, ES8316_SYS_VMIDSEL, 0xff);
+
+	snd_soc_component_write(component, ES8316_CLKMGR_ADCOSR, 0x32);
+
+	regcache_mark_dirty(es8316->regmap);
+	regcache_sync(es8316->regmap);
+
+	return 0;
+}
+#else
+#define es8316_suspend NULL
+#define es8316_resume NULL
+#endif
+
 static int es8316_probe(struct snd_soc_component *component)
 {
 	struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component);
@@ -728,8 +790,6 @@ static int es8316_probe(struct snd_soc_component *component)
 		return ret;
 	}
 
-	snd_soc_component_init_regmap(component, es8316->regmap);
-
 	/* Reset codec and enable current state machine */
 	snd_soc_component_write(component, ES8316_RESET, 0x3f);
 	usleep_range(5000, 5500);
@@ -756,46 +816,14 @@ static void es8316_remove(struct snd_soc_component *component)
 {
 	struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component);
 
-	snd_soc_component_exit_regmap(component);
-
 	clk_disable_unprepare(es8316->mclk);
 }
 
-#ifdef CONFIG_PM_SLEEP
-static int es8316_suspend(struct device *dev)
-{
-	struct es8316_priv *es8316 = dev_get_drvdata(dev);
-
-	dev_dbg(dev, "%s: Enter\n", __func__);
-
-	regcache_cache_only(es8316->regmap, true);
-	regcache_mark_dirty(es8316->regmap);
-
-	return 0;
-}
-
-static int es8316_resume(struct device *dev)
-{
-	struct es8316_priv *es8316 = dev_get_drvdata(dev);
-
-	dev_dbg(dev, "%s: Enter\n", __func__);
-
-	regcache_cache_only(es8316->regmap, false);
-	regcache_sync(es8316->regmap);
-
-	es8316_irq(es8316->irq, es8316);
-
-	return 0;
-}
-#endif
-
-static const struct dev_pm_ops es8316_pm = {
-	SET_SYSTEM_SLEEP_PM_OPS(es8316_suspend, es8316_resume)
-};
-
 static const struct snd_soc_component_driver soc_component_dev_es8316 = {
 	.probe			= es8316_probe,
 	.remove			= es8316_remove,
+	.resume			= es8316_resume,
+	.suspend		= es8316_suspend,
 	.set_jack		= es8316_set_jack,
 	.controls		= es8316_snd_controls,
 	.num_controls		= ARRAY_SIZE(es8316_snd_controls),
@@ -805,11 +833,13 @@ static const struct snd_soc_component_driver soc_component_dev_es8316 = {
 	.num_dapm_routes	= ARRAY_SIZE(es8316_dapm_routes),
 	.use_pmdown_time	= 1,
 	.endianness		= 1,
-	.non_legacy_dai_naming	= 1,
 };
 
 static const struct regmap_range es8316_volatile_ranges[] = {
 	regmap_reg_range(ES8316_GPIO_FLAG, ES8316_GPIO_FLAG),
+	regmap_reg_range(ES8316_RESET, ES8316_RESET),
+	regmap_reg_range(ES8316_SYS_VMIDSEL,ES8316_SYS_VMIDSEL),
+	regmap_reg_range(ES8316_CLKMGR_ADCOSR,ES8316_CLKMGR_ADCOSR),
 };
 
 static const struct regmap_access_table es8316_volatile_table = {
@@ -820,15 +850,14 @@ static const struct regmap_access_table es8316_volatile_table = {
 static const struct regmap_config es8316_regmap = {
 	.reg_bits = 8,
 	.val_bits = 8,
+	.use_single_read = true,
+	.use_single_write = true,
 	.max_register = 0x53,
 	.volatile_table	= &es8316_volatile_table,
 	.cache_type = REGCACHE_RBTREE,
-	.use_single_read = true,
-	.use_single_write = true,
 };
 
-static int es8316_i2c_probe(struct i2c_client *i2c_client,
-			    const struct i2c_device_id *id)
+static int es8316_i2c_probe(struct i2c_client *i2c_client)
 {
 	struct device *dev = &i2c_client->dev;
 	struct es8316_priv *es8316;
@@ -889,9 +918,8 @@ static struct i2c_driver es8316_i2c_driver = {
 		.name			= "es8316",
 		.acpi_match_table	= ACPI_PTR(es8316_acpi_match),
 		.of_match_table		= of_match_ptr(es8316_of_match),
-		.pm			= &es8316_pm,
 	},
-	.probe		= es8316_i2c_probe,
+	.probe_new	= es8316_i2c_probe,
 	.id_table	= es8316_i2c_id,
 };
 module_i2c_driver(es8316_i2c_driver);
-- 
2.33.6



^ permalink raw reply	[flat|nested] 4+ messages in thread

* [d-kernel] [PATCH 2/2] ASoC: AMD: acp3x-es8336-mach: add quirk override mclk freq
  2023-03-02 11:58 [d-kernel] [PATCH 0/2] Add support for ES8336 codecs on Ryzen machines in 5.15 nickel
  2023-03-02 11:58 ` [d-kernel] [PATCH 1/2] ASoC: AMD: add ACP machine driver for ES8336 nickel
@ 2023-03-02 11:58 ` nickel
  2023-03-02 16:03 ` [d-kernel] [PATCH 0/2] Add support for ES8336 codecs on Ryzen machines in 5.15 Vitaly Chikunov
  2 siblings, 0 replies; 4+ messages in thread
From: nickel @ 2023-03-02 11:58 UTC (permalink / raw)
  To: devel-kernel; +Cc: Vasiliy Kovalev

From: Vasiliy Kovalev <kovalev@altlinux.org>

add quirk for driver snd_soc_acp3x_es8336_mach and changed the contents
of the driver data to store the MCLK coefficient from the ACPI table
according to:
https://github.com/codepayne/linux-sound-huawei/issues/5#issuecomment-1383126104

also add the possibility of using this driver for models not listed in
the DMI match table when using quirk

the quirk is not limited to changing only the frequency, it can also be
used afterwards

example:
use "options snd_soc_acp3x_es8336_mach quirk=0x4"
for set MCLK FREQ 48 MHz

Signed-off-by: Vasiliy Kovalev <kovalev@altlinux.org>
Signed-off-by: Nikolai Kostrigin <nickel@altlinux.org>
---
 sound/soc/amd/acp3x-es8336.c | 65 +++++++++++++++++++++++++++++++-----
 1 file changed, 57 insertions(+), 8 deletions(-)

diff --git a/sound/soc/amd/acp3x-es8336.c b/sound/soc/amd/acp3x-es8336.c
index f930cc258dfc9..7ee75d85382b6 100644
--- a/sound/soc/amd/acp3x-es8336.c
+++ b/sound/soc/amd/acp3x-es8336.c
@@ -26,6 +26,22 @@
 #define SND_CARD_NAME   DRV_NAME
 #define DUAL_CHANNEL	2
 
+#define SOC_ES8336_ACPI_MCLK_MASK	(GENMASK(2, 0))
+
+#define SOC_ES8336_ACPI_MCLK_0		0	// 12.288 MHz	- default
+#define SOC_ES8336_ACPI_MCLK_1		1	// 24.576 MHz
+#define SOC_ES8336_ACPI_MCLK_2		2	// 19.2   MHz
+#define SOC_ES8336_ACPI_MCLK_3		3	// 24     MHz
+#define SOC_ES8336_ACPI_MCLK_4		4	// 48     MHz
+
+#define ES8336_MCLK_FREQ (48000 * 256)
+
+static unsigned long quirk;
+static unsigned long quirk_mclk;
+static int quirk_override = -1;
+module_param_named(quirk, quirk_override, int, 0444);
+MODULE_PARM_DESC(quirk, "Board-specific quirk override");
+
 struct acp3x_es8336_private {
 	/* struct acp3x_platform_info machine must always be
 	 * the first entry in the structure,
@@ -57,7 +73,6 @@ static const struct snd_pcm_hw_constraint_list constraints_channels = {
 	.list = channels,
 	.mask = 0,
 };
-#define ES8336_MCLK_FREQ (48000 * 1000)
 
 static int acp3x_es8336_codec_startup(struct snd_pcm_substream *substream)
 {
@@ -74,7 +89,18 @@ static int acp3x_es8336_codec_startup(struct snd_pcm_substream *substream)
 	machine = &priv->machine;
 	codec_dai = asoc_rtd_to_codec(rtd, 0);
 
-	ret = snd_soc_dai_set_sysclk(codec_dai, 0, ES8336_MCLK_FREQ, SND_SOC_CLOCK_OUT);
+	unsigned int mclk_hz = ES8336_MCLK_FREQ;
+	static u8 only_one = 0;
+	if (quirk_mclk) {
+		if (!only_one) {
+			only_one = 1;
+			dev_info(rtd->dev, "overriding mclk %d Hz => %d Hz\n",
+				mclk_hz, (unsigned int)quirk_mclk);
+		}
+		mclk_hz = (unsigned int) quirk_mclk;
+	}
+
+	ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk_hz, SND_SOC_CLOCK_OUT);
 	if (ret < 0) {
 		dev_err(rtd->dev, "can't set codec sysclk: %d\n", ret);
 		return ret;
@@ -275,7 +301,6 @@ static const struct dmi_system_id acp3x_es8336_dmi_table[] = {
 			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "KLVL-WXXW"),
 			DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "M1010"),
 		},
-		.driver_data = &acp3x_es8336,
 	},
 	{
 		.matches = {
@@ -283,7 +308,6 @@ static const struct dmi_system_id acp3x_es8336_dmi_table[] = {
 			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "KLVL-WXX9"),
 			DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "M1010"),
 		},
-		.driver_data = &acp3x_es8336,
 	},
 	{
 		.matches = {
@@ -291,7 +315,7 @@ static const struct dmi_system_id acp3x_es8336_dmi_table[] = {
 			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "BOM-WXX9"),
 			DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "M1010"),
 		},
-		.driver_data = &acp3x_es8336,
+		.driver_data = (void *)(SOC_ES8336_ACPI_MCLK_4),
 	},
 		{
 		.matches = {
@@ -299,7 +323,6 @@ static const struct dmi_system_id acp3x_es8336_dmi_table[] = {
 			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "HVY-WXX9"),
 			DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "M1040"),
 		},
-		.driver_data = &acp3x_es8336,
 	},
 	{}
 };
@@ -312,7 +335,7 @@ static int acp3x_probe(struct platform_device *pdev)
 	const struct dmi_system_id *dmi_id;
 
 	dmi_id = dmi_first_match(acp3x_es8336_dmi_table);
-	if (dmi_id && dmi_id->driver_data) {
+	if (dmi_id || quirk_override != -1) {
 		struct acp3x_es8336_private *priv;
 		struct snd_soc_card *card;
 
@@ -324,7 +347,33 @@ static int acp3x_probe(struct platform_device *pdev)
 			return -ENOMEM;
 		}
 
-		card = (struct snd_soc_card *)dmi_id->driver_data;
+		if(dmi_id && dmi_id->driver_data)
+			quirk = (unsigned long)dmi_id->driver_data;
+		if(quirk_override != -1) {
+			dev_info(dev, "Overriding quirk 0x%lx => 0x%x\n",
+				quirk, quirk_override);
+			quirk = (unsigned long)quirk_override;
+		}
+		switch(quirk & SOC_ES8336_ACPI_MCLK_MASK) {
+		case SOC_ES8336_ACPI_MCLK_0:
+			break;
+		case SOC_ES8336_ACPI_MCLK_1:
+			quirk_mclk = 48000 * 512;
+			break;
+		case SOC_ES8336_ACPI_MCLK_2:
+			quirk_mclk = 48000 * 400;
+			break;
+		case SOC_ES8336_ACPI_MCLK_3:
+			quirk_mclk = 48000 * 500;
+			break;
+		case SOC_ES8336_ACPI_MCLK_4:
+			quirk_mclk = 48000 * 1000;
+			break;
+		default:
+			dev_warn(dev, "unexpected driver data, use mclk default\n");
+		}
+
+		card = &acp3x_es8336;
 
 		card->dev = &pdev->dev;
 		platform_set_drvdata(pdev, card);
-- 
2.33.6



^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [d-kernel] [PATCH 0/2] Add support for ES8336 codecs on Ryzen machines in 5.15
  2023-03-02 11:58 [d-kernel] [PATCH 0/2] Add support for ES8336 codecs on Ryzen machines in 5.15 nickel
  2023-03-02 11:58 ` [d-kernel] [PATCH 1/2] ASoC: AMD: add ACP machine driver for ES8336 nickel
  2023-03-02 11:58 ` [d-kernel] [PATCH 2/2] ASoC: AMD: acp3x-es8336-mach: add quirk override mclk freq nickel
@ 2023-03-02 16:03 ` Vitaly Chikunov
  2 siblings, 0 replies; 4+ messages in thread
From: Vitaly Chikunov @ 2023-03-02 16:03 UTC (permalink / raw)
  To: ALT Linux kernel packages development

On Thu, Mar 02, 2023 at 02:58:19PM +0300, nickel@altlinux.org wrote:
> These patches are intended for both p10 un-def and Sisyphus std-def 5.15 kernels.
> For full featured support one needs to update alsa-ucm-conf up to at least 1.2.8-alt5.
> 
> [PATCH 1/2] ASoC: AMD: add ACP machine driver for ES8336
> [PATCH 2/2] ASoC: AMD: acp3x-es8336-mach: add quirk override mclk

Applied, thanks.

> 
> _______________________________________________
> devel-kernel mailing list
> devel-kernel@lists.altlinux.org
> https://lists.altlinux.org/mailman/listinfo/devel-kernel


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2023-03-02 16:03 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-03-02 11:58 [d-kernel] [PATCH 0/2] Add support for ES8336 codecs on Ryzen machines in 5.15 nickel
2023-03-02 11:58 ` [d-kernel] [PATCH 1/2] ASoC: AMD: add ACP machine driver for ES8336 nickel
2023-03-02 11:58 ` [d-kernel] [PATCH 2/2] ASoC: AMD: acp3x-es8336-mach: add quirk override mclk freq nickel
2023-03-02 16:03 ` [d-kernel] [PATCH 0/2] Add support for ES8336 codecs on Ryzen machines in 5.15 Vitaly Chikunov

ALT Linux kernel packages development

This inbox may be cloned and mirrored by anyone:

	git clone --mirror http://lore.altlinux.org/devel-kernel/0 devel-kernel/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 devel-kernel devel-kernel/ http://lore.altlinux.org/devel-kernel \
		devel-kernel@altlinux.org devel-kernel@altlinux.ru devel-kernel@altlinux.com
	public-inbox-index devel-kernel

Example config snippet for mirrors.
Newsgroup available over NNTP:
	nntp://lore.altlinux.org/org.altlinux.lists.devel-kernel


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git