All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/14] ASoC: Intel: avs: Machine boards and HDA codec support
@ 2022-04-27  8:18 Cezary Rojewski
  2022-04-27  8:18 ` [PATCH 01/14] ALSA: Add snd_pcm_direction_name() helper Cezary Rojewski
                   ` (13 more replies)
  0 siblings, 14 replies; 25+ messages in thread
From: Cezary Rojewski @ 2022-04-27  8:18 UTC (permalink / raw)
  To: alsa-devel, broonie
  Cc: Cezary Rojewski, upstream, harshapriya.n, rad,
	pierre-louis.bossart, tiwai, hdegoede, amadeuszx.slawinski,
	cujomalainey, lma

This series focuses on populating boards/ subdirectory with supported
configurations by the avs-driver. Note: it is independent of recently
provided "Driver code and PCM operations" series [1], that is, code
found here should not collide with it.

Series starts with a small change that adds a helper to sound pcm
header, allowing for retrieving string naming a direction without the
need of substream pointer. Said helper is used by codec driver code that
follows it but I believe it's generic and helpful enough that it can be
called an independent addition to the sound core.

Code for generic HD-Audio codec driver follows. It is a ASoC wrapper for
existing HD-Audio codec code found in sound/pci/hda/. There is basically
no custom logic involved up to the point that driver follows
HDA_DEV_LEGACY convention, rather than the HDA_DEV_ASOC one. Commit
message for the given patch iterates on this and explains crucial parts
of the implementation.

From there on is a range of boards appended. All of them follow the same
scheme:

- define avs_create_dai_link() so DAI-LINKs can be created dynamically,
  based on the link_mask (I2S) or the number of entries in the
  ->pcm_list_head list (HDA)
- define avs_create_dapm_routes() so DAPM routes can be created
  dynamically, same rules as above apply
- define probe() function that creates new ASoC card, assign all
  required operations and resources along with calling the two above


[1]: https://lore.kernel.org/all/20220426172346.3508411-1-cezary.rojewski@intel.com/

Amadeusz Sławiński (1):
  ASoC: Intel: avs: Add max98373 machine board

Cezary Rojewski (13):
  ALSA: Add snd_pcm_direction_name() helper
  ASoC: codecs: Add HD-Audio codec driver
  ASoC: Intel: avs: Add HDAudio machine board
  ASoC: Intel: avs: Add DMIC machine board
  ASoC: Intel: avs: Add ssp-test machine board
  ASoC: Intel: avs: Add rt274 machine board
  ASoC: Intel: avs: Add rt286 machine board
  ASoC: Intel: avs: Add rt298 machine board
  ASoC: Intel: avs: Add rt5682 machine board
  ASoC: Intel: avs: Add nau8825 machine board
  ASoC: Intel: avs: Add ssm4567 machine board
  ASoC: Intel: avs: Add max98357a machine board
  ASoC: Intel: avs: Add da7219 machine board

 include/sound/pcm.h                    |  19 +-
 sound/soc/codecs/Kconfig               |   5 +
 sound/soc/codecs/Makefile              |   2 +
 sound/soc/codecs/hda-dai.c             | 102 +++++++
 sound/soc/codecs/hda.c                 | 395 +++++++++++++++++++++++++
 sound/soc/codecs/hda.h                 |  19 ++
 sound/soc/intel/Kconfig                |   3 +
 sound/soc/intel/avs/Makefile           |   3 +
 sound/soc/intel/avs/boards/Kconfig     | 121 ++++++++
 sound/soc/intel/avs/boards/Makefile    |  27 ++
 sound/soc/intel/avs/boards/da7219.c    | 281 ++++++++++++++++++
 sound/soc/intel/avs/boards/dmic.c      |  93 ++++++
 sound/soc/intel/avs/boards/hdaudio.c   | 294 ++++++++++++++++++
 sound/soc/intel/avs/boards/max98357a.c | 153 ++++++++++
 sound/soc/intel/avs/boards/max98373.c  | 238 +++++++++++++++
 sound/soc/intel/avs/boards/nau8825.c   | 352 ++++++++++++++++++++++
 sound/soc/intel/avs/boards/rt274.c     | 309 +++++++++++++++++++
 sound/soc/intel/avs/boards/rt286.c     | 280 ++++++++++++++++++
 sound/soc/intel/avs/boards/rt298.c     | 280 ++++++++++++++++++
 sound/soc/intel/avs/boards/rt5682.c    | 339 +++++++++++++++++++++
 sound/soc/intel/avs/boards/ssm4567.c   | 270 +++++++++++++++++
 sound/soc/intel/avs/boards/ssp_test.c  | 178 +++++++++++
 22 files changed, 3759 insertions(+), 4 deletions(-)
 create mode 100644 sound/soc/codecs/hda-dai.c
 create mode 100644 sound/soc/codecs/hda.c
 create mode 100644 sound/soc/codecs/hda.h
 create mode 100644 sound/soc/intel/avs/boards/Kconfig
 create mode 100644 sound/soc/intel/avs/boards/Makefile
 create mode 100644 sound/soc/intel/avs/boards/da7219.c
 create mode 100644 sound/soc/intel/avs/boards/dmic.c
 create mode 100644 sound/soc/intel/avs/boards/hdaudio.c
 create mode 100644 sound/soc/intel/avs/boards/max98357a.c
 create mode 100644 sound/soc/intel/avs/boards/max98373.c
 create mode 100644 sound/soc/intel/avs/boards/nau8825.c
 create mode 100644 sound/soc/intel/avs/boards/rt274.c
 create mode 100644 sound/soc/intel/avs/boards/rt286.c
 create mode 100644 sound/soc/intel/avs/boards/rt298.c
 create mode 100644 sound/soc/intel/avs/boards/rt5682.c
 create mode 100644 sound/soc/intel/avs/boards/ssm4567.c
 create mode 100644 sound/soc/intel/avs/boards/ssp_test.c


base-commit: fa96ec9fa9f8f0c80e8a0129a819f592a39b1044
-- 
2.25.1


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

* [PATCH 01/14] ALSA: Add snd_pcm_direction_name() helper
  2022-04-27  8:18 [PATCH 00/14] ASoC: Intel: avs: Machine boards and HDA codec support Cezary Rojewski
@ 2022-04-27  8:18 ` Cezary Rojewski
  2022-04-27  8:18 ` [PATCH 02/14] ASoC: codecs: Add HD-Audio codec driver Cezary Rojewski
                   ` (12 subsequent siblings)
  13 siblings, 0 replies; 25+ messages in thread
From: Cezary Rojewski @ 2022-04-27  8:18 UTC (permalink / raw)
  To: alsa-devel, broonie
  Cc: Cezary Rojewski, upstream, harshapriya.n, rad,
	pierre-louis.bossart, tiwai, hdegoede, amadeuszx.slawinski,
	cujomalainey, lma

Allow for retrieving string naming a direction of a stream without the
need of substream pointer.

Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
---
 include/sound/pcm.h | 19 +++++++++++++++----
 1 file changed, 15 insertions(+), 4 deletions(-)

diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index 6b99310b5b88..26523cfe428d 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -1392,6 +1392,20 @@ static inline void snd_pcm_limit_isa_dma_size(int dma, size_t *max)
 
 const char *snd_pcm_format_name(snd_pcm_format_t format);
 
+/**
+ * snd_pcm_direction_name - Get a string naming the direction of a stream
+ * @direction: Stream's direction, one of SNDRV_PCM_STREAM_XXX
+ *
+ * Returns a string naming the direction of the stream.
+ */
+static inline const char *snd_pcm_direction_name(int direction)
+{
+	if (direction == SNDRV_PCM_STREAM_PLAYBACK)
+		return "Playback";
+	else
+		return "Capture";
+}
+
 /**
  * snd_pcm_stream_str - Get a string naming the direction of a stream
  * @substream: the pcm substream instance
@@ -1400,10 +1414,7 @@ const char *snd_pcm_format_name(snd_pcm_format_t format);
  */
 static inline const char *snd_pcm_stream_str(struct snd_pcm_substream *substream)
 {
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-		return "Playback";
-	else
-		return "Capture";
+	return snd_pcm_direction_name(substream->stream);
 }
 
 /*
-- 
2.25.1


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

* [PATCH 02/14] ASoC: codecs: Add HD-Audio codec driver
  2022-04-27  8:18 [PATCH 00/14] ASoC: Intel: avs: Machine boards and HDA codec support Cezary Rojewski
  2022-04-27  8:18 ` [PATCH 01/14] ALSA: Add snd_pcm_direction_name() helper Cezary Rojewski
@ 2022-04-27  8:18 ` Cezary Rojewski
  2022-04-27 15:47   ` Pierre-Louis Bossart
  2022-04-27  8:18 ` [PATCH 03/14] ASoC: Intel: avs: Add HDAudio machine board Cezary Rojewski
                   ` (11 subsequent siblings)
  13 siblings, 1 reply; 25+ messages in thread
From: Cezary Rojewski @ 2022-04-27  8:18 UTC (permalink / raw)
  To: alsa-devel, broonie
  Cc: Cezary Rojewski, upstream, harshapriya.n, rad,
	pierre-louis.bossart, tiwai, hdegoede, amadeuszx.slawinski,
	cujomalainey, lma

Add generic ASoC equivalent of ALSA HD-Audio codec. This codec is
designed to follow HDA_DEV_LEGACY convention. Driver wrapps existing
hda_codec.c handlers to prevent code duplication within the newly added
code. Number of DAIs created is dependent on capabilities exposed by the
codec itself. Because of this, single solution can be applied to support
every single HD-Audio codec type.

At the same, through the ASoC topology, platform drivers may limit the
number of endpoints available to the userspace as codec driver exposes
BE DAIs only.

Both hda_codec_probe() and hda_codec_remove() declare their expectations
on device's usage_count and suspended-status. This is to catch any
unexpected behavior as PM-related code for HD-Audio has been changing
quite a bit throughout the years.

In order for codec DAI list to reflect its actual PCM capabilities, PCMs
need to be built and that can only happen once codec device is
constructed. To do that, a valid component->card->snd_card pointer is
needed. Said pointer will be provided by the framework once all card
components are accounted for and their probing can begin. Usage of
"binder" BE DAI solves the problem - codec can be listed as one of
HD-Audio card components without declaring any actual BE DAIs
statically.

Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
---
 sound/soc/codecs/Kconfig   |   5 +
 sound/soc/codecs/Makefile  |   2 +
 sound/soc/codecs/hda-dai.c | 102 ++++++++++
 sound/soc/codecs/hda.c     | 395 +++++++++++++++++++++++++++++++++++++
 sound/soc/codecs/hda.h     |  19 ++
 5 files changed, 523 insertions(+)
 create mode 100644 sound/soc/codecs/hda-dai.c
 create mode 100644 sound/soc/codecs/hda.c
 create mode 100644 sound/soc/codecs/hda.h

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index b106e5517090..23fdbf97e453 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -937,6 +937,11 @@ config SND_SOC_HDAC_HDA
 	tristate
 	select SND_HDA
 
+config SND_SOC_HDA
+	tristate "HD-Audio codec driver"
+	select SND_HDA_EXT_CORE
+	select SND_HDA
+
 config SND_SOC_ICS43432
 	tristate "ICS43423 and compatible i2s microphones"
 
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 28dc4edfd01f..d32026ae326f 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -106,6 +106,7 @@ snd-soc-es8328-spi-objs := es8328-spi.o
 snd-soc-gtm601-objs := gtm601.o
 snd-soc-hdac-hdmi-objs := hdac_hdmi.o
 snd-soc-hdac-hda-objs := hdac_hda.o
+snd-soc-hda-codec-objs := hda.o hda-dai.o
 snd-soc-ics43432-objs := ics43432.o
 snd-soc-inno-rk3036-objs := inno_rk3036.o
 snd-soc-isabelle-objs := isabelle.o
@@ -458,6 +459,7 @@ obj-$(CONFIG_SND_SOC_ES8328_SPI)+= snd-soc-es8328-spi.o
 obj-$(CONFIG_SND_SOC_GTM601)    += snd-soc-gtm601.o
 obj-$(CONFIG_SND_SOC_HDAC_HDMI) += snd-soc-hdac-hdmi.o
 obj-$(CONFIG_SND_SOC_HDAC_HDA) += snd-soc-hdac-hda.o
+obj-$(CONFIG_SND_SOC_HDA) += snd-soc-hda-codec.o
 obj-$(CONFIG_SND_SOC_ICS43432)	+= snd-soc-ics43432.o
 obj-$(CONFIG_SND_SOC_INNO_RK3036)	+= snd-soc-inno-rk3036.o
 obj-$(CONFIG_SND_SOC_ISABELLE)	+= snd-soc-isabelle.o
diff --git a/sound/soc/codecs/hda-dai.c b/sound/soc/codecs/hda-dai.c
new file mode 100644
index 000000000000..5371ff086261
--- /dev/null
+++ b/sound/soc/codecs/hda-dai.c
@@ -0,0 +1,102 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Author: Cezary Rojewski <cezary.rojewski@intel.com>
+//
+
+#include <sound/soc.h>
+#include <sound/hda_codec.h>
+#include "hda.h"
+
+static int hda_codec_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+	struct hda_pcm_stream *stream_info;
+	struct hda_codec *codec;
+	struct hda_pcm *pcm;
+	int ret;
+
+	codec = dev_to_hda_codec(dai->dev);
+	stream_info = snd_soc_dai_get_dma_data(dai, substream);
+	pcm = container_of(stream_info, struct hda_pcm, stream[substream->stream]);
+
+	dev_dbg(dai->dev, "open stream codec: %08x, info: %p, pcm: %p %s substream: %p\n",
+		codec->core.vendor_id, stream_info, pcm, pcm->name, substream);
+
+	snd_hda_codec_pcm_get(pcm);
+
+	ret = stream_info->ops.open(stream_info, codec, substream);
+	if (ret < 0) {
+		dev_err(dai->dev, "codec open failed: %d\n", ret);
+		snd_hda_codec_pcm_put(pcm);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void hda_codec_dai_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+	struct hda_pcm_stream *stream_info;
+	struct hda_codec *codec;
+	struct hda_pcm *pcm;
+	int ret;
+
+	codec = dev_to_hda_codec(dai->dev);
+	stream_info = snd_soc_dai_get_dma_data(dai, substream);
+	pcm = container_of(stream_info, struct hda_pcm, stream[substream->stream]);
+
+	dev_dbg(dai->dev, "close stream codec: %08x, info: %p, pcm: %p %s substream: %p\n",
+		codec->core.vendor_id, stream_info, pcm, pcm->name, substream);
+
+	ret = stream_info->ops.close(stream_info, codec, substream);
+	if (ret < 0)
+		dev_err(dai->dev, "codec close failed: %d\n", ret);
+
+	snd_hda_codec_pcm_put(pcm);
+}
+
+static int hda_codec_dai_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+	struct hda_pcm_stream *stream_info;
+	struct hda_codec *codec;
+
+	codec = dev_to_hda_codec(dai->dev);
+	stream_info = snd_soc_dai_get_dma_data(dai, substream);
+
+	snd_hda_codec_cleanup(codec, stream_info, substream);
+
+	return 0;
+}
+
+static int hda_codec_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct hda_pcm_stream *stream_info;
+	struct hdac_stream *stream;
+	struct hda_codec *codec;
+	unsigned int format;
+	int ret;
+
+	codec = dev_to_hda_codec(dai->dev);
+	stream = substream->runtime->private_data;
+	stream_info = snd_soc_dai_get_dma_data(dai, substream);
+	format = snd_hdac_calc_stream_format(runtime->rate, runtime->channels, runtime->format,
+					     runtime->sample_bits, 0);
+
+	ret = snd_hda_codec_prepare(codec, stream_info, stream->stream_tag, format, substream);
+	if (ret < 0) {
+		dev_err(dai->dev, "codec prepare failed: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+const struct snd_soc_dai_ops snd_soc_hda_codec_dai_ops = {
+	.startup = hda_codec_dai_startup,
+	.shutdown = hda_codec_dai_shutdown,
+	.hw_free = hda_codec_dai_hw_free,
+	.prepare = hda_codec_dai_prepare,
+};
+EXPORT_SYMBOL_GPL(snd_soc_hda_codec_dai_ops);
diff --git a/sound/soc/codecs/hda.c b/sound/soc/codecs/hda.c
new file mode 100644
index 000000000000..edcb8bc6806b
--- /dev/null
+++ b/sound/soc/codecs/hda.c
@@ -0,0 +1,395 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Author: Cezary Rojewski <cezary.rojewski@intel.com>
+//
+
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <sound/soc.h>
+#include <sound/hdaudio_ext.h>
+#include <sound/hda_i915.h>
+#include <sound/hda_codec.h>
+#include "hda.h"
+
+static int hda_codec_create_dais(struct hda_codec *codec, int pcm_count,
+				 struct snd_soc_dai_driver **drivers)
+{
+	struct device *dev = &codec->core.dev;
+	struct snd_soc_dai_driver *drvs;
+	struct hda_pcm *pcm;
+	int i;
+
+	drvs = devm_kcalloc(dev, pcm_count, sizeof(*drvs), GFP_KERNEL);
+	if (!drvs)
+		return -ENOMEM;
+
+	pcm = list_first_entry(&codec->pcm_list_head, struct hda_pcm, list);
+
+	for (i = 0; i < pcm_count; i++, pcm = list_next_entry(pcm, list)) {
+		struct snd_soc_pcm_stream *stream;
+		int dir;
+
+		dev_info(dev, "creating for %s %d\n", pcm->name, i);
+		drvs[i].id = i;
+		drvs[i].name = pcm->name;
+		drvs[i].ops = &snd_soc_hda_codec_dai_ops;
+
+		dir = SNDRV_PCM_STREAM_PLAYBACK;
+		stream = &drvs[i].playback;
+		if (!pcm->stream[dir].substreams) {
+			dev_info(dev, "skipping playback dai for %s\n", pcm->name);
+			goto capture_dais;
+		}
+
+		stream->stream_name =
+			devm_kasprintf(dev, GFP_KERNEL, "%s %s", pcm->name,
+				       snd_pcm_direction_name(dir));
+		if (!stream->stream_name)
+			return -ENOMEM;
+		stream->channels_min = pcm->stream[dir].channels_min;
+		stream->channels_max = pcm->stream[dir].channels_max;
+		stream->rates = pcm->stream[dir].rates;
+		stream->formats = pcm->stream[dir].formats;
+		stream->sig_bits = pcm->stream[dir].maxbps;
+
+capture_dais:
+		dir = SNDRV_PCM_STREAM_CAPTURE;
+		stream = &drvs[i].capture;
+		if (!pcm->stream[dir].substreams) {
+			dev_info(dev, "skipping capture dai for %s\n", pcm->name);
+			continue;
+		}
+
+		stream->stream_name =
+			devm_kasprintf(dev, GFP_KERNEL, "%s %s", pcm->name,
+				       snd_pcm_direction_name(dir));
+		if (!stream->stream_name)
+			return -ENOMEM;
+		stream->channels_min = pcm->stream[dir].channels_min;
+		stream->channels_max = pcm->stream[dir].channels_max;
+		stream->rates = pcm->stream[dir].rates;
+		stream->formats = pcm->stream[dir].formats;
+		stream->sig_bits = pcm->stream[dir].maxbps;
+	}
+
+	*drivers = drvs;
+	return 0;
+}
+
+static int hda_codec_register_dais(struct hda_codec *codec, struct snd_soc_component *component)
+{
+	struct snd_soc_dai_driver *drvs = NULL;
+	struct snd_soc_dapm_context *dapm;
+	struct hda_pcm *pcm;
+	int ret, pcm_count = 0;
+
+	if (list_empty(&codec->pcm_list_head))
+		return -EINVAL;
+	list_for_each_entry(pcm, &codec->pcm_list_head, list)
+		pcm_count++;
+
+	ret = hda_codec_create_dais(codec, pcm_count, &drvs);
+	if (ret < 0)
+		return ret;
+
+	dapm = snd_soc_component_get_dapm(component);
+
+	list_for_each_entry(pcm, &codec->pcm_list_head, list) {
+		struct snd_soc_dai *dai;
+
+		dai = snd_soc_register_dai(component, drvs, false);
+		if (!dai) {
+			dev_err(component->dev, "register dai for %s failed\n", pcm->name);
+			return -EINVAL;
+		}
+
+		ret = snd_soc_dapm_new_dai_widgets(dapm, dai);
+		if (ret < 0) {
+			dev_err(component->dev, "create widgets failed: %d\n", ret);
+			snd_soc_unregister_dai(dai);
+			return ret;
+		}
+
+		snd_soc_dai_init_dma_data(dai, &pcm->stream[0], &pcm->stream[1]);
+		drvs++;
+	}
+
+	return 0;
+}
+
+static void hda_codec_unregister_dais(struct hda_codec *codec,
+				      struct snd_soc_component *component)
+{
+	struct snd_soc_dai *dai, *save;
+	struct hda_pcm *pcm;
+
+	for_each_component_dais_safe(component, dai, save) {
+		list_for_each_entry(pcm, &codec->pcm_list_head, list) {
+			if (strcmp(dai->driver->name, pcm->name))
+				continue;
+
+			if (dai->playback_widget)
+				snd_soc_dapm_free_widget(dai->playback_widget);
+			if (dai->capture_widget)
+				snd_soc_dapm_free_widget(dai->capture_widget);
+			snd_soc_unregister_dai(dai);
+			break;
+		}
+	}
+}
+
+int hda_codec_probe_complete(struct hda_codec *codec)
+{
+	struct hdac_device *hdev = &codec->core;
+	struct hdac_bus *bus = hdev->bus;
+	int ret;
+
+	ret = snd_hda_codec_build_controls(codec);
+	if (ret < 0) {
+		dev_err(&hdev->dev, "unable to create controls %d\n", ret);
+		goto out;
+	}
+
+	/* Bus suspended codecs as it does not manage their pm */
+	pm_runtime_set_active(&hdev->dev);
+	/* rpm was forbidden in snd_hda_codec_device_new() */
+	snd_hda_codec_set_power_save(codec, 2000);
+	snd_hda_codec_register(codec);
+out:
+	/* Complement pm_runtime_get_sync(bus) in probe */
+	pm_runtime_mark_last_busy(bus->dev);
+	pm_runtime_put_autosuspend(bus->dev);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(hda_codec_probe_complete);
+
+/* Expects codec with usage_count=1 and status=suspended */
+static int hda_codec_probe(struct snd_soc_component *component)
+{
+	struct hda_codec *codec = dev_to_hda_codec(component->dev);
+	struct hdac_device *hdev = &codec->core;
+	struct hdac_bus *bus = hdev->bus;
+	struct hdac_ext_link *hlink;
+	hda_codec_patch_t patch;
+	int ret;
+
+#ifdef CONFIG_PM
+	WARN_ON(atomic_read(&hdev->dev.power.usage_count) != 1 ||
+		!pm_runtime_status_suspended(&hdev->dev));
+#endif
+
+	hlink = snd_hdac_ext_bus_link_at(bus, hdev->addr);
+	if (!hlink) {
+		dev_err(&hdev->dev, "hdac link not found\n");
+		return -EIO;
+	}
+
+	pm_runtime_get_sync(bus->dev);
+	if (hda_codec_is_display(codec))
+		snd_hdac_display_power(bus, hdev->addr, true);
+	snd_hdac_ext_bus_link_get(bus, hlink);
+
+	ret = snd_hda_codec_device_new(codec->bus, component->card->snd_card, hdev->addr, codec,
+				       false);
+	if (ret < 0) {
+		dev_err(&hdev->dev, "create hda codec failed: %d\n", ret);
+		goto device_new_err;
+	}
+
+	ret = snd_hda_codec_set_name(codec, codec->preset->name);
+	if (ret < 0) {
+		dev_err(&hdev->dev, "name failed %s\n", codec->preset->name);
+		goto err;
+	}
+
+	ret = snd_hdac_regmap_init(&codec->core);
+	if (ret < 0) {
+		dev_err(&hdev->dev, "regmap init failed\n");
+		goto err;
+	}
+
+	patch = (hda_codec_patch_t)codec->preset->driver_data;
+	if (!patch) {
+		dev_err(&hdev->dev, "no patch specified?\n");
+		ret = -EINVAL;
+		goto err;
+	}
+
+	ret = patch(codec);
+	if (ret < 0) {
+		dev_err(&hdev->dev, "patch failed %d\n", ret);
+		goto err;
+	}
+
+	/* configure codec for 1:1 PCM:DAI mapping */
+	codec->mst_no_extra_pcms = 1;
+
+	ret = snd_hda_codec_parse_pcms(codec);
+	if (ret < 0) {
+		dev_err(&hdev->dev, "unable to map pcms to dai %d\n", ret);
+		goto parse_pcms_err;
+	}
+
+	ret = hda_codec_register_dais(codec, component);
+	if (ret < 0) {
+		dev_err(&hdev->dev, "update dais failed: %d\n", ret);
+		goto parse_pcms_err;
+	}
+
+	if (!hda_codec_is_display(codec)) {
+		ret = hda_codec_probe_complete(codec);
+		if (ret < 0)
+			goto complete_err;
+	}
+
+	codec->core.lazy_cache = true;
+
+	return 0;
+
+complete_err:
+	hda_codec_unregister_dais(codec, component);
+parse_pcms_err:
+	if (codec->patch_ops.free)
+		codec->patch_ops.free(codec);
+err:
+	snd_hda_codec_cleanup_for_unbind(codec);
+device_new_err:
+	if (hda_codec_is_display(codec))
+		snd_hdac_display_power(bus, hdev->addr, false);
+
+	snd_hdac_ext_bus_link_put(bus, hlink);
+
+	pm_runtime_mark_last_busy(bus->dev);
+	pm_runtime_put_autosuspend(bus->dev);
+	return ret;
+}
+
+/* Leaves codec with usage_count=1 and status=suspended */
+static void hda_codec_remove(struct snd_soc_component *component)
+{
+	struct hda_codec *codec = dev_to_hda_codec(component->dev);
+	struct hdac_device *hdev = &codec->core;
+	struct hdac_bus *bus = hdev->bus;
+	struct hdac_ext_link *hlink;
+	bool was_registered = codec->registered;
+
+	/* Don't allow any more runtime suspends */
+	pm_runtime_forbid(&hdev->dev);
+
+	hda_codec_unregister_dais(codec, component);
+
+	if (codec->patch_ops.free)
+		codec->patch_ops.free(codec);
+
+	snd_hda_codec_cleanup_for_unbind(codec);
+	pm_runtime_put_noidle(&hdev->dev);
+	/* snd_hdac_device_exit() is only called on bus remove */
+	pm_runtime_set_suspended(&hdev->dev);
+
+	if (hda_codec_is_display(codec))
+		snd_hdac_display_power(bus, hdev->addr, false);
+
+	hlink = snd_hdac_ext_bus_link_at(bus, hdev->addr);
+	if (hlink)
+		snd_hdac_ext_bus_link_put(bus, hlink);
+	/*
+	 * HDMI card's hda_codec_probe_complete() (see late_probe()) may
+	 * not be called due to early error, leaving bus uc unbalanced
+	 */
+	if (!was_registered) {
+		pm_runtime_mark_last_busy(bus->dev);
+		pm_runtime_put_autosuspend(bus->dev);
+	}
+
+#ifdef CONFIG_PM
+	WARN_ON(atomic_read(&hdev->dev.power.usage_count) != 1 ||
+		!pm_runtime_status_suspended(&hdev->dev));
+#endif
+}
+
+static const struct snd_soc_dapm_route hda_dapm_routes[] = {
+	{"AIF1TX", NULL, "Codec Input Pin1"},
+	{"AIF2TX", NULL, "Codec Input Pin2"},
+	{"AIF3TX", NULL, "Codec Input Pin3"},
+
+	{"Codec Output Pin1", NULL, "AIF1RX"},
+	{"Codec Output Pin2", NULL, "AIF2RX"},
+	{"Codec Output Pin3", NULL, "AIF3RX"},
+};
+
+static const struct snd_soc_dapm_widget hda_dapm_widgets[] = {
+	/* Audio Interface */
+	SND_SOC_DAPM_AIF_IN("AIF1RX", "Analog Codec Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("AIF2RX", "Digital Codec Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("AIF3RX", "Alt Analog Codec Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF1TX", "Analog Codec Capture", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF2TX", "Digital Codec Capture", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIF3TX", "Alt Analog Codec Capture", 0, SND_SOC_NOPM, 0, 0),
+
+	/* Input Pins */
+	SND_SOC_DAPM_INPUT("Codec Input Pin1"),
+	SND_SOC_DAPM_INPUT("Codec Input Pin2"),
+	SND_SOC_DAPM_INPUT("Codec Input Pin3"),
+
+	/* Output Pins */
+	SND_SOC_DAPM_OUTPUT("Codec Output Pin1"),
+	SND_SOC_DAPM_OUTPUT("Codec Output Pin2"),
+	SND_SOC_DAPM_OUTPUT("Codec Output Pin3"),
+};
+
+static struct snd_soc_dai_driver card_binder_dai = {
+	.id = -1,
+	.name = "codec-probing-DAI",
+};
+
+static int hda_hdev_attach(struct hdac_device *hdev)
+{
+	struct hda_codec *codec = dev_to_hda_codec(&hdev->dev);
+	struct snd_soc_component_driver *comp_drv;
+
+	comp_drv = devm_kzalloc(&hdev->dev, sizeof(*comp_drv), GFP_KERNEL);
+	if (!comp_drv)
+		return -ENOMEM;
+
+	/*
+	 * It's save to rely on dev_name() rather than a copy as component
+	 * driver's lifetime is directly tied to hda codec one
+	 */
+	comp_drv->name = dev_name(&hdev->dev);
+	comp_drv->probe = hda_codec_probe;
+	comp_drv->remove = hda_codec_remove;
+	comp_drv->idle_bias_on = false;
+	if (!hda_codec_is_display(codec)) {
+		comp_drv->dapm_widgets = hda_dapm_widgets;
+		comp_drv->num_dapm_widgets = ARRAY_SIZE(hda_dapm_widgets);
+		comp_drv->dapm_routes = hda_dapm_routes;
+		comp_drv->num_dapm_routes = ARRAY_SIZE(hda_dapm_routes);
+	}
+
+	return snd_soc_register_component(&hdev->dev, comp_drv, &card_binder_dai, 1);
+}
+
+static int hda_hdev_detach(struct hdac_device *hdev)
+{
+	struct hda_codec *codec = dev_to_hda_codec(&hdev->dev);
+
+	if (codec->registered)
+		cancel_delayed_work_sync(&codec->jackpoll_work);
+
+	snd_soc_unregister_component(&hdev->dev);
+
+	return 0;
+}
+
+const struct hdac_ext_bus_ops soc_hda_ext_bus_ops = {
+	.hdev_attach = hda_hdev_attach,
+	.hdev_detach = hda_hdev_detach,
+};
+EXPORT_SYMBOL_GPL(soc_hda_ext_bus_ops);
+
+MODULE_DESCRIPTION("HD-Audio codec driver");
+MODULE_AUTHOR("Cezary Rojewski <cezary.rojewski@intel.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/hda.h b/sound/soc/codecs/hda.h
new file mode 100644
index 000000000000..78a2be4945b1
--- /dev/null
+++ b/sound/soc/codecs/hda.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+ *
+ * Author: Cezary Rojewski <cezary.rojewski@intel.com>
+ */
+
+#ifndef SND_SOC_CODECS_HDA_H
+#define SND_SOC_CODECS_HDA_H
+
+#define hda_codec_is_display(codec) \
+	((((codec)->core.vendor_id >> 16) & 0xFFFF) == 0x8086)
+
+extern const struct snd_soc_dai_ops snd_soc_hda_codec_dai_ops;
+
+extern const struct hdac_ext_bus_ops soc_hda_ext_bus_ops;
+int hda_codec_probe_complete(struct hda_codec *codec);
+
+#endif
-- 
2.25.1


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

* [PATCH 03/14] ASoC: Intel: avs: Add HDAudio machine board
  2022-04-27  8:18 [PATCH 00/14] ASoC: Intel: avs: Machine boards and HDA codec support Cezary Rojewski
  2022-04-27  8:18 ` [PATCH 01/14] ALSA: Add snd_pcm_direction_name() helper Cezary Rojewski
  2022-04-27  8:18 ` [PATCH 02/14] ASoC: codecs: Add HD-Audio codec driver Cezary Rojewski
@ 2022-04-27  8:18 ` Cezary Rojewski
  2022-04-27  8:18 ` [PATCH 04/14] ASoC: Intel: avs: Add DMIC " Cezary Rojewski
                   ` (10 subsequent siblings)
  13 siblings, 0 replies; 25+ messages in thread
From: Cezary Rojewski @ 2022-04-27  8:18 UTC (permalink / raw)
  To: alsa-devel, broonie
  Cc: Cezary Rojewski, upstream, harshapriya.n, rad,
	pierre-louis.bossart, tiwai, hdegoede, amadeuszx.slawinski,
	cujomalainey, lma

Connect AVS driver with ASoC HDAudio codec with help of this machine
board. Similarly to its platform and codec components, DAI links and
routes are being created dynamically so single board can be used across
all HDAudio codec types.

Card makes use of "binder" BE DAI Link so HDAudio codec driver can be
listed as one of its components. This allows for BE DAIs to be created
dynamically, based on HDAudio codec capabilities.

Signed-off-by: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
---
 sound/soc/intel/Kconfig              |   3 +
 sound/soc/intel/avs/Makefile         |   3 +
 sound/soc/intel/avs/boards/Kconfig   |  15 ++
 sound/soc/intel/avs/boards/Makefile  |   5 +
 sound/soc/intel/avs/boards/hdaudio.c | 294 +++++++++++++++++++++++++++
 5 files changed, 320 insertions(+)
 create mode 100644 sound/soc/intel/avs/boards/Kconfig
 create mode 100644 sound/soc/intel/avs/boards/Makefile
 create mode 100644 sound/soc/intel/avs/boards/hdaudio.c

diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig
index be42c4eff165..851e8053e2fa 100644
--- a/sound/soc/intel/Kconfig
+++ b/sound/soc/intel/Kconfig
@@ -224,5 +224,8 @@ config SND_SOC_INTEL_AVS
 	  capabilities. This includes Skylake, Kabylake, Amberlake and
 	  Apollolake.
 
+# Machine board drivers
+source "sound/soc/intel/avs/boards/Kconfig"
+
 # ASoC codec drivers
 source "sound/soc/intel/boards/Kconfig"
diff --git a/sound/soc/intel/avs/Makefile b/sound/soc/intel/avs/Makefile
index 952f51977656..abd51fb6b55d 100644
--- a/sound/soc/intel/avs/Makefile
+++ b/sound/soc/intel/avs/Makefile
@@ -5,3 +5,6 @@ snd-soc-avs-objs := dsp.o ipc.o messages.o utils.o core.o loader.o \
 snd-soc-avs-objs += cldma.o
 
 obj-$(CONFIG_SND_SOC_INTEL_AVS) += snd-soc-avs.o
+
+# Machine support
+obj-$(CONFIG_SND_SOC) += boards/
diff --git a/sound/soc/intel/avs/boards/Kconfig b/sound/soc/intel/avs/boards/Kconfig
new file mode 100644
index 000000000000..de62c0437f6e
--- /dev/null
+++ b/sound/soc/intel/avs/boards/Kconfig
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: GPL-2.0-only
+menu "Intel AVS Machine drivers"
+	depends on SND_SOC_INTEL_AVS
+
+comment "Available DSP configurations"
+
+config SND_SOC_INTEL_AVS_MACH_HDAUDIO
+	tristate "HD-Audio generic board"
+	select SND_SOC_HDA
+	help
+	  This adds support for AVS with HDAudio codec configuration.
+	  Say Y or m if you have such a device. This is a recommended option.
+	  If unsure select "N".
+
+endmenu
diff --git a/sound/soc/intel/avs/boards/Makefile b/sound/soc/intel/avs/boards/Makefile
new file mode 100644
index 000000000000..e5281148e5d4
--- /dev/null
+++ b/sound/soc/intel/avs/boards/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+snd-soc-avs-hdaudio-objs := hdaudio.o
+
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_HDAUDIO) += snd-soc-avs-hdaudio.o
diff --git a/sound/soc/intel/avs/boards/hdaudio.c b/sound/soc/intel/avs/boards/hdaudio.c
new file mode 100644
index 000000000000..d2fc41d39448
--- /dev/null
+++ b/sound/soc/intel/avs/boards/hdaudio.c
@@ -0,0 +1,294 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+//          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/platform_device.h>
+#include <sound/hda_codec.h>
+#include <sound/hda_i915.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include "../../../codecs/hda.h"
+
+static int avs_create_dai_links(struct device *dev, struct hda_codec *codec, int pcm_count,
+				const char *platform_name, struct snd_soc_dai_link **links)
+{
+	struct snd_soc_dai_link_component *platform;
+	struct snd_soc_dai_link *dl;
+	struct hda_pcm *pcm;
+	const char *cname = dev_name(&codec->core.dev);
+	int i;
+
+	dl = devm_kcalloc(dev, pcm_count, sizeof(*dl), GFP_KERNEL);
+	platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+	if (!dl || !platform)
+		return -ENOMEM;
+
+	platform->name = platform_name;
+	pcm = list_first_entry(&codec->pcm_list_head, struct hda_pcm, list);
+
+	for (i = 0; i < pcm_count; i++, pcm = list_next_entry(pcm, list)) {
+		dl[i].name = devm_kasprintf(dev, GFP_KERNEL, "%s link%d", cname, i);
+		if (!dl[i].name)
+			return -ENOMEM;
+
+		dl[i].id = i;
+		dl[i].nonatomic = 1;
+		dl[i].no_pcm = 1;
+		dl[i].dpcm_playback = 1;
+		dl[i].dpcm_capture = 1;
+		dl[i].platforms = platform;
+		dl[i].num_platforms = 1;
+
+		dl[i].codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL);
+		dl[i].cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
+		if (!dl[i].codecs || !dl[i].cpus)
+			return -ENOMEM;
+
+		dl[i].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "%s-cpu%d", cname, i);
+		if (!dl[i].cpus->dai_name)
+			return -ENOMEM;
+
+		dl[i].codecs->name = devm_kstrdup(dev, cname, GFP_KERNEL);
+		dl[i].codecs->dai_name = pcm->name;
+		dl[i].num_codecs = 1;
+		dl[i].num_cpus = 1;
+	}
+
+	*links = dl;
+	return 0;
+}
+
+static int avs_create_dapm_routes(struct device *dev, struct hda_codec *codec, int pcm_count,
+				  struct snd_soc_dapm_route **routes, int *num_routes)
+{
+	struct snd_soc_dapm_route *dr;
+	struct hda_pcm *pcm;
+	const char *cname = dev_name(&codec->core.dev);
+	int i, n = 0;
+
+	/* at max twice the number of pcms */
+	dr = devm_kcalloc(dev, pcm_count * 2, sizeof(*dr), GFP_KERNEL);
+	if (!dr)
+		return -ENOMEM;
+
+	pcm = list_first_entry(&codec->pcm_list_head, struct hda_pcm, list);
+
+	for (i = 0; i < pcm_count; i++, pcm = list_next_entry(pcm, list)) {
+		struct hda_pcm_stream *stream;
+		int dir;
+
+		dir = SNDRV_PCM_STREAM_PLAYBACK;
+		stream = &pcm->stream[dir];
+		if (!stream->substreams)
+			goto capture_routes;
+
+		dr[n].sink = devm_kasprintf(dev, GFP_KERNEL, "%s %s", pcm->name,
+					    snd_pcm_direction_name(dir));
+		dr[n].source = devm_kasprintf(dev, GFP_KERNEL, "%s-cpu%d Tx", cname, i);
+		if (!dr[n].sink || !dr[n].source)
+			return -ENOMEM;
+		n++;
+
+capture_routes:
+		dir = SNDRV_PCM_STREAM_CAPTURE;
+		stream = &pcm->stream[dir];
+		if (!stream->substreams)
+			continue;
+
+		dr[n].sink = devm_kasprintf(dev, GFP_KERNEL, "%s-cpu%d Rx", cname, i);
+		dr[n].source = devm_kasprintf(dev, GFP_KERNEL, "%s %s", pcm->name,
+					      snd_pcm_direction_name(dir));
+		if (!dr[n].sink || !dr[n].source)
+			return -ENOMEM;
+		n++;
+	}
+
+	*routes = dr;
+	*num_routes = n;
+	return 0;
+}
+
+/* Should be aligned with SectionPCM's name from topology */
+#define FEDAI_NAME_PREFIX "HDMI"
+
+static struct snd_pcm *
+avs_card_hdmi_pcm_at(struct snd_soc_card *card, int hdmi_idx)
+{
+	struct snd_soc_pcm_runtime *rtd;
+	int dir = SNDRV_PCM_STREAM_PLAYBACK;
+
+	for_each_card_rtds(card, rtd) {
+		struct snd_pcm *spcm;
+		int ret, n;
+
+		spcm = rtd->pcm ? rtd->pcm->streams[dir].pcm : NULL;
+		if (!spcm || !strstr(spcm->id, FEDAI_NAME_PREFIX))
+			continue;
+
+		ret = sscanf(spcm->id, FEDAI_NAME_PREFIX "%d", &n);
+		if (ret != 1)
+			continue;
+		if (n == hdmi_idx)
+			return rtd->pcm;
+	}
+
+	return NULL;
+}
+
+static int avs_card_late_probe(struct snd_soc_card *card)
+{
+	struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev);
+	struct hda_codec *codec = mach->pdata;
+	struct hda_pcm *hpcm;
+	/* Topology pcm indexing is 1-based */
+	int i = 1;
+
+	list_for_each_entry(hpcm, &codec->pcm_list_head, list) {
+		struct snd_pcm *spcm;
+
+		spcm = avs_card_hdmi_pcm_at(card, i);
+		if (spcm) {
+			hpcm->pcm = spcm;
+			hpcm->device = spcm->device;
+			dev_info(card->dev, "%s: mapping HDMI converter %d to PCM %d (%p)\n",
+				 __func__, i, hpcm->device, spcm);
+		} else {
+			hpcm->pcm = NULL;
+			hpcm->device = SNDRV_PCM_INVALID_DEVICE;
+			dev_warn(card->dev, "%s: no PCM in topology for HDMI converter %d\n",
+				 __func__, i);
+		}
+		i++;
+	}
+
+	return hda_codec_probe_complete(codec);
+}
+
+static int avs_probing_link_init(struct snd_soc_pcm_runtime *rtm)
+{
+	struct snd_soc_dapm_route *routes;
+	struct snd_soc_acpi_mach *mach;
+	struct snd_soc_dai_link *links = NULL;
+	struct snd_soc_card *card = rtm->card;
+	struct hda_codec *codec;
+	struct hda_pcm *pcm;
+	int ret, n, pcm_count = 0;
+
+	mach = dev_get_platdata(card->dev);
+	codec = mach->pdata;
+
+	if (list_empty(&codec->pcm_list_head))
+		return -EINVAL;
+	list_for_each_entry(pcm, &codec->pcm_list_head, list)
+		pcm_count++;
+
+	ret = avs_create_dai_links(card->dev, codec, pcm_count, mach->mach_params.platform, &links);
+	if (ret < 0) {
+		dev_err(card->dev, "create links failed: %d\n", ret);
+		return ret;
+	}
+
+	for (n = 0; n < pcm_count; n++) {
+		ret = snd_soc_add_pcm_runtime(card, &links[n]);
+		if (ret < 0) {
+			dev_err(card->dev, "add links failed: %d\n", ret);
+			return ret;
+		}
+	}
+
+	ret = avs_create_dapm_routes(card->dev, codec, pcm_count, &routes, &n);
+	if (ret < 0) {
+		dev_err(card->dev, "create routes failed: %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_dapm_add_routes(&card->dapm, routes, n);
+	if (ret < 0) {
+		dev_err(card->dev, "add routes failed: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+SND_SOC_DAILINK_DEF(dummy, DAILINK_COMP_ARRAY(COMP_DUMMY()));
+
+static struct snd_soc_dai_link probing_link = {
+	.name = "probing-LINK",
+	.id = -1,
+	.nonatomic = 1,
+	.no_pcm = 1,
+	.dpcm_playback = 1,
+	.dpcm_capture = 1,
+	.cpus = dummy,
+	.num_cpus = ARRAY_SIZE(dummy),
+	.init = avs_probing_link_init,
+};
+
+static int avs_hdaudio_probe(struct platform_device *pdev)
+{
+	struct snd_soc_dai_link *binder;
+	struct snd_soc_acpi_mach *mach;
+	struct snd_soc_card *card;
+	struct device *dev = &pdev->dev;
+	struct hda_codec *codec;
+
+	mach = dev_get_platdata(dev);
+	codec = mach->pdata;
+
+	/* codec may be unloaded before card's probe() fires */
+	if (!device_is_registered(&codec->core.dev))
+		return -ENODEV;
+
+	binder = devm_kmemdup(dev, &probing_link, sizeof(probing_link), GFP_KERNEL);
+	if (!binder)
+		return -ENOMEM;
+
+	binder->platforms = devm_kzalloc(dev, sizeof(*binder->platforms), GFP_KERNEL);
+	binder->codecs = devm_kzalloc(dev, sizeof(*binder->codecs), GFP_KERNEL);
+	if (!binder->platforms || !binder->codecs)
+		return -ENOMEM;
+
+	binder->codecs->name = devm_kstrdup(dev, dev_name(&codec->core.dev), GFP_KERNEL);
+	if (!binder->codecs->name)
+		return -ENOMEM;
+
+	binder->platforms->name = mach->mach_params.platform;
+	binder->num_platforms = 1;
+	binder->codecs->dai_name = "codec-probing-DAI";
+	binder->num_codecs = 1;
+
+	card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+	if (!card)
+		return -ENOMEM;
+
+	card->name = binder->codecs->name;
+	card->dev = dev;
+	card->owner = THIS_MODULE;
+	card->dai_link = binder;
+	card->num_links = 1;
+	card->fully_routed = true;
+	if (hda_codec_is_display(codec))
+		card->late_probe = avs_card_late_probe;
+
+	return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_hdaudio_driver = {
+	.probe = avs_hdaudio_probe,
+	.driver = {
+		.name = "avs_hdaudio",
+		.pm = &snd_soc_pm_ops,
+	},
+};
+
+module_platform_driver(avs_hdaudio_driver)
+
+MODULE_DESCRIPTION("Intel HD-Audio machine driver");
+MODULE_AUTHOR("Cezary Rojewski <cezary.rojewski@intel.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_hdaudio");
-- 
2.25.1


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

* [PATCH 04/14] ASoC: Intel: avs: Add DMIC machine board
  2022-04-27  8:18 [PATCH 00/14] ASoC: Intel: avs: Machine boards and HDA codec support Cezary Rojewski
                   ` (2 preceding siblings ...)
  2022-04-27  8:18 ` [PATCH 03/14] ASoC: Intel: avs: Add HDAudio machine board Cezary Rojewski
@ 2022-04-27  8:18 ` Cezary Rojewski
  2022-04-27  8:18 ` [PATCH 05/14] ASoC: Intel: avs: Add ssp-test " Cezary Rojewski
                   ` (9 subsequent siblings)
  13 siblings, 0 replies; 25+ messages in thread
From: Cezary Rojewski @ 2022-04-27  8:18 UTC (permalink / raw)
  To: alsa-devel, broonie
  Cc: Cezary Rojewski, upstream, harshapriya.n, rad,
	pierre-louis.bossart, tiwai, hdegoede, amadeuszx.slawinski,
	cujomalainey, lma

Support AVS-DMIC configuration by implementing board connecting AVS
platform component with DMIC codec one.

Signed-off-by: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
---
 sound/soc/intel/avs/boards/Kconfig  |  8 +++
 sound/soc/intel/avs/boards/Makefile |  2 +
 sound/soc/intel/avs/boards/dmic.c   | 93 +++++++++++++++++++++++++++++
 3 files changed, 103 insertions(+)
 create mode 100644 sound/soc/intel/avs/boards/dmic.c

diff --git a/sound/soc/intel/avs/boards/Kconfig b/sound/soc/intel/avs/boards/Kconfig
index de62c0437f6e..1d4597fa9814 100644
--- a/sound/soc/intel/avs/boards/Kconfig
+++ b/sound/soc/intel/avs/boards/Kconfig
@@ -4,6 +4,14 @@ menu "Intel AVS Machine drivers"
 
 comment "Available DSP configurations"
 
+config SND_SOC_INTEL_AVS_MACH_DMIC
+	tristate "DMIC generic board"
+	select SND_SOC_DMIC
+	help
+	  This adds support for AVS with Digital Mic array configuration.
+	  Say Y or m if you have such a device. This is a recommended option.
+	  If unsure select "N".
+
 config SND_SOC_INTEL_AVS_MACH_HDAUDIO
 	tristate "HD-Audio generic board"
 	select SND_SOC_HDA
diff --git a/sound/soc/intel/avs/boards/Makefile b/sound/soc/intel/avs/boards/Makefile
index e5281148e5d4..2ff35d4d97d8 100644
--- a/sound/soc/intel/avs/boards/Makefile
+++ b/sound/soc/intel/avs/boards/Makefile
@@ -1,5 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0-only
 
+snd-soc-avs-dmic-objs := dmic.o
 snd-soc-avs-hdaudio-objs := hdaudio.o
 
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_DMIC) += snd-soc-avs-dmic.o
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_HDAUDIO) += snd-soc-avs-hdaudio.o
diff --git a/sound/soc/intel/avs/boards/dmic.c b/sound/soc/intel/avs/boards/dmic.c
new file mode 100644
index 000000000000..90a921638572
--- /dev/null
+++ b/sound/soc/intel/avs/boards/dmic.c
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+//          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+
+SND_SOC_DAILINK_DEF(dmic_pin, DAILINK_COMP_ARRAY(COMP_CPU("DMIC Pin")));
+SND_SOC_DAILINK_DEF(dmic_wov_pin, DAILINK_COMP_ARRAY(COMP_CPU("DMIC WoV Pin")));
+SND_SOC_DAILINK_DEF(dmic_codec, DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi")));
+/* Name overridden on probe */
+SND_SOC_DAILINK_DEF(platform, DAILINK_COMP_ARRAY(COMP_PLATFORM("")));
+
+static struct snd_soc_dai_link card_dai_links[] = {
+	/* Back ends */
+	{
+		.name = "DMIC",
+		.id = 0,
+		.dpcm_capture = 1,
+		.nonatomic = 1,
+		.no_pcm = 1,
+		SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform),
+	},
+	{
+		.name = "DMIC WoV",
+		.id = 1,
+		.dpcm_capture = 1,
+		.nonatomic = 1,
+		.no_pcm = 1,
+		.ignore_suspend = 1,
+		SND_SOC_DAILINK_REG(dmic_wov_pin, dmic_codec, platform),
+	},
+};
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+	SND_SOC_DAPM_MIC("SoC DMIC", NULL),
+};
+
+static const struct snd_soc_dapm_route card_routes[] = {
+	{"DMic", NULL, "SoC DMIC"},
+	{"DMIC Rx", NULL, "Capture"},
+	{"DMIC WoV Rx", NULL, "Capture"},
+};
+
+static int avs_dmic_probe(struct platform_device *pdev)
+{
+	struct snd_soc_acpi_mach *mach;
+	struct snd_soc_card *card;
+	struct device *dev = &pdev->dev;
+	int ret;
+
+	mach = dev_get_platdata(dev);
+
+	card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+	if (!card)
+		return -ENOMEM;
+
+	card->name = "avs_dmic";
+	card->dev = dev;
+	card->owner = THIS_MODULE;
+	card->dai_link = card_dai_links;
+	card->num_links = ARRAY_SIZE(card_dai_links);
+	card->dapm_widgets = card_widgets;
+	card->num_dapm_widgets = ARRAY_SIZE(card_widgets);
+	card->dapm_routes = card_routes;
+	card->num_dapm_routes = ARRAY_SIZE(card_routes);
+	card->fully_routed = true;
+
+	ret = snd_soc_fixup_dai_links_platform_name(card, mach->mach_params.platform);
+	if (ret)
+		return ret;
+
+	return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_dmic_driver = {
+	.probe = avs_dmic_probe,
+	.driver = {
+		.name = "avs_dmic",
+		.pm = &snd_soc_pm_ops,
+	},
+};
+
+module_platform_driver(avs_dmic_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_dmic");
-- 
2.25.1


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

* [PATCH 05/14] ASoC: Intel: avs: Add ssp-test machine board
  2022-04-27  8:18 [PATCH 00/14] ASoC: Intel: avs: Machine boards and HDA codec support Cezary Rojewski
                   ` (3 preceding siblings ...)
  2022-04-27  8:18 ` [PATCH 04/14] ASoC: Intel: avs: Add DMIC " Cezary Rojewski
@ 2022-04-27  8:18 ` Cezary Rojewski
  2022-05-10 11:12   ` Cezary Rojewski
  2022-04-27  8:18 ` [PATCH 06/14] ASoC: Intel: avs: Add rt274 " Cezary Rojewski
                   ` (8 subsequent siblings)
  13 siblings, 1 reply; 25+ messages in thread
From: Cezary Rojewski @ 2022-04-27  8:18 UTC (permalink / raw)
  To: alsa-devel, broonie
  Cc: Cezary Rojewski, upstream, harshapriya.n, rad,
	pierre-louis.bossart, tiwai, hdegoede, amadeuszx.slawinski,
	cujomalainey, lma

Allow for testing audio streaming over I2S interface through SSP-test
board. No actual codec is needed here as board is intended for SSP
loopback scenarios only. One playback and one capture endpoint is
exposed per SSP port.

Signed-off-by: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
---
 sound/soc/intel/avs/boards/Kconfig    |   6 +
 sound/soc/intel/avs/boards/Makefile   |   2 +
 sound/soc/intel/avs/boards/ssp_test.c | 178 ++++++++++++++++++++++++++
 3 files changed, 186 insertions(+)
 create mode 100644 sound/soc/intel/avs/boards/ssp_test.c

diff --git a/sound/soc/intel/avs/boards/Kconfig b/sound/soc/intel/avs/boards/Kconfig
index 1d4597fa9814..ea2f094758f9 100644
--- a/sound/soc/intel/avs/boards/Kconfig
+++ b/sound/soc/intel/avs/boards/Kconfig
@@ -20,4 +20,10 @@ config SND_SOC_INTEL_AVS_MACH_HDAUDIO
 	  Say Y or m if you have such a device. This is a recommended option.
 	  If unsure select "N".
 
+config SND_SOC_INTEL_AVS_MACH_SSP_TEST
+	tristate "SSP test board"
+	help
+	   This adds support for SSP test board which can be used to verify
+	   transfer over I2S interface with loopback scenarios.
+
 endmenu
diff --git a/sound/soc/intel/avs/boards/Makefile b/sound/soc/intel/avs/boards/Makefile
index 2ff35d4d97d8..1c860ca165de 100644
--- a/sound/soc/intel/avs/boards/Makefile
+++ b/sound/soc/intel/avs/boards/Makefile
@@ -2,6 +2,8 @@
 
 snd-soc-avs-dmic-objs := dmic.o
 snd-soc-avs-hdaudio-objs := hdaudio.o
+snd-soc-avs-ssp-test-objs := ssp_test.o
 
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_DMIC) += snd-soc-avs-dmic.o
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_HDAUDIO) += snd-soc-avs-hdaudio.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_SSP_TEST) += snd-soc-avs-ssp-test.o
diff --git a/sound/soc/intel/avs/boards/ssp_test.c b/sound/soc/intel/avs/boards/ssp_test.c
new file mode 100644
index 000000000000..cabaf615b9ae
--- /dev/null
+++ b/sound/soc/intel/avs/boards/ssp_test.c
@@ -0,0 +1,178 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+//          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/module.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include <sound/soc-dapm.h>
+
+static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+			       struct snd_soc_dai_link **dai_link)
+{
+	struct snd_soc_dai_link_component *platform;
+	struct snd_soc_dai_link *dl;
+
+	dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL);
+	platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+	if (!dl || !platform)
+		return -ENOMEM;
+
+	platform->name = platform_name;
+
+	dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+	dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
+	dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL);
+	if (!dl->name || !dl->cpus || !dl->codecs)
+		return -ENOMEM;
+
+	dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+	dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "snd-soc-dummy");
+	dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, "snd-soc-dummy-dai");
+	if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
+		return -ENOMEM;
+
+	dl->num_cpus = 1;
+	dl->num_codecs = 1;
+	dl->platforms = platform;
+	dl->num_platforms = 1;
+	dl->id = 0;
+	dl->nonatomic = 1;
+	dl->no_pcm = 1;
+	dl->dpcm_capture = 1;
+	dl->dpcm_playback = 1;
+
+	*dai_link = dl;
+
+	return 0;
+}
+
+static int avs_create_dapm_routes(struct device *dev, int ssp_port,
+				  struct snd_soc_dapm_route **routes, int *num_routes)
+{
+	struct snd_soc_dapm_route *dr;
+	const int num_dr = 2;
+
+	dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL);
+	if (!dr)
+		return -ENOMEM;
+
+	dr[0].sink = devm_kasprintf(dev, GFP_KERNEL, "ssp%dpb", ssp_port);
+	dr[0].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+	if (!dr[0].sink || !dr[0].source)
+		return -ENOMEM;
+
+	dr[1].sink = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Rx", ssp_port);
+	dr[1].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%dcp", ssp_port);
+	if (!dr[1].sink || !dr[1].source)
+		return -ENOMEM;
+
+	*routes = dr;
+	*num_routes = num_dr;
+
+	return 0;
+}
+
+static int avs_create_dapm_widgets(struct device *dev, int ssp_port,
+				   struct snd_soc_dapm_widget **widgets, int *num_widgets)
+{
+	struct snd_soc_dapm_widget *dw;
+	const int num_dw = 2;
+
+	dw = devm_kcalloc(dev, num_dw, sizeof(*dw), GFP_KERNEL);
+	if (!dw)
+		return -ENOMEM;
+
+	dw[0].id = snd_soc_dapm_hp;
+	dw[0].reg = SND_SOC_NOPM;
+	dw[0].name = devm_kasprintf(dev, GFP_KERNEL, "ssp%dpb", ssp_port);
+	if (!dw[0].name)
+		return -ENOMEM;
+
+	dw[1].id = snd_soc_dapm_mic;
+	dw[1].reg = SND_SOC_NOPM;
+	dw[1].name = devm_kasprintf(dev, GFP_KERNEL, "ssp%dcp", ssp_port);
+	if (!dw[1].name)
+		return -ENOMEM;
+
+	*widgets = dw;
+	*num_widgets = num_dw;
+
+	return 0;
+}
+
+static int avs_ssp_test_probe(struct platform_device *pdev)
+{
+	struct snd_soc_dapm_widget *widgets;
+	struct snd_soc_dapm_route *routes;
+	struct snd_soc_dai_link *dai_link;
+	struct snd_soc_acpi_mach *mach;
+	struct snd_soc_card *card;
+	struct device *dev = &pdev->dev;
+	const char *pname;
+	int num_routes, num_widgets, ret;
+
+	mach = dev_get_platdata(dev);
+	pname = mach->mach_params.platform;
+
+	card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+	if (!card)
+		return -ENOMEM;
+
+	card->name = devm_kasprintf(dev, GFP_KERNEL, "ssp%ld-loopback", __ffs(mach->link_mask));
+	if (!card->name)
+		return -ENOMEM;
+
+	ret = avs_create_dai_link(dev, pname, __ffs(mach->link_mask), &dai_link);
+	if (ret) {
+		dev_err(dev, "Failed to create dai link: %d\n", ret);
+		return ret;
+	}
+
+	ret = avs_create_dapm_routes(dev, __ffs(mach->link_mask), &routes, &num_routes);
+	if (ret) {
+		dev_err(dev, "Failed to create dapm routes: %d\n", ret);
+		return ret;
+	}
+
+	ret = avs_create_dapm_widgets(dev, __ffs(mach->link_mask), &widgets, &num_widgets);
+	if (ret) {
+		dev_err(dev, "Failed to create dapm widgets: %d\n", ret);
+		return ret;
+	}
+
+	card->dev = dev;
+	card->owner = THIS_MODULE;
+	card->dai_link = dai_link;
+	card->num_links = 1;
+	card->dapm_routes = routes;
+	card->num_dapm_routes = num_routes;
+	card->dapm_widgets = widgets;
+	card->num_dapm_widgets = num_widgets;
+	card->fully_routed = true;
+
+	ret = snd_soc_fixup_dai_links_platform_name(card, pname);
+	if (ret)
+		return ret;
+
+	return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_ssp_test_driver = {
+	.probe = avs_ssp_test_probe,
+	.driver = {
+		.name = "avs_ssp_test",
+		.pm = &snd_soc_pm_ops,
+	},
+};
+
+module_platform_driver(avs_ssp_test_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_ssp_test");
-- 
2.25.1


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

* [PATCH 06/14] ASoC: Intel: avs: Add rt274 machine board
  2022-04-27  8:18 [PATCH 00/14] ASoC: Intel: avs: Machine boards and HDA codec support Cezary Rojewski
                   ` (4 preceding siblings ...)
  2022-04-27  8:18 ` [PATCH 05/14] ASoC: Intel: avs: Add ssp-test " Cezary Rojewski
@ 2022-04-27  8:18 ` Cezary Rojewski
  2022-04-27  8:18 ` [PATCH 07/14] ASoC: Intel: avs: Add rt286 " Cezary Rojewski
                   ` (7 subsequent siblings)
  13 siblings, 0 replies; 25+ messages in thread
From: Cezary Rojewski @ 2022-04-27  8:18 UTC (permalink / raw)
  To: alsa-devel, broonie
  Cc: Cezary Rojewski, upstream, harshapriya.n, rad,
	pierre-louis.bossart, tiwai, hdegoede, amadeuszx.slawinski,
	cujomalainey, lma

To support AVS-rt274 configuration add machine board connecting AVS
platform component driver with rt274 codec one.

Signed-off-by: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
---
 sound/soc/intel/avs/boards/Kconfig  |  10 +
 sound/soc/intel/avs/boards/Makefile |   2 +
 sound/soc/intel/avs/boards/rt274.c  | 309 ++++++++++++++++++++++++++++
 3 files changed, 321 insertions(+)
 create mode 100644 sound/soc/intel/avs/boards/rt274.c

diff --git a/sound/soc/intel/avs/boards/Kconfig b/sound/soc/intel/avs/boards/Kconfig
index ea2f094758f9..a8f598247548 100644
--- a/sound/soc/intel/avs/boards/Kconfig
+++ b/sound/soc/intel/avs/boards/Kconfig
@@ -20,6 +20,16 @@ config SND_SOC_INTEL_AVS_MACH_HDAUDIO
 	  Say Y or m if you have such a device. This is a recommended option.
 	  If unsure select "N".
 
+config SND_SOC_INTEL_AVS_MACH_RT274
+	tristate "rt274 in I2S mode"
+	depends on I2C
+	depends on MFD_INTEL_LPSS || COMPILE_TEST
+	select SND_SOC_RT274
+	help
+	   This adds support for ASoC machine driver with RT274 I2S audio codec.
+	   Say Y or m if you have such a device. This is a recommended option.
+	   If unsure select "N".
+
 config SND_SOC_INTEL_AVS_MACH_SSP_TEST
 	tristate "SSP test board"
 	help
diff --git a/sound/soc/intel/avs/boards/Makefile b/sound/soc/intel/avs/boards/Makefile
index 1c860ca165de..dbefc519e1e0 100644
--- a/sound/soc/intel/avs/boards/Makefile
+++ b/sound/soc/intel/avs/boards/Makefile
@@ -2,8 +2,10 @@
 
 snd-soc-avs-dmic-objs := dmic.o
 snd-soc-avs-hdaudio-objs := hdaudio.o
+snd-soc-avs-rt274-objs := rt274.o
 snd-soc-avs-ssp-test-objs := ssp_test.o
 
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_DMIC) += snd-soc-avs-dmic.o
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_HDAUDIO) += snd-soc-avs-hdaudio.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT274) += snd-soc-avs-rt274.o
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_SSP_TEST) += snd-soc-avs-ssp-test.o
diff --git a/sound/soc/intel/avs/boards/rt274.c b/sound/soc/intel/avs/boards/rt274.c
new file mode 100644
index 000000000000..3d4d0aa1f2a2
--- /dev/null
+++ b/sound/soc/intel/avs/boards/rt274.c
@@ -0,0 +1,309 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+//          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/module.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include "../../../codecs/rt274.h"
+
+#define AVS_RT274_FREQ_OUT	24000000
+#define AVS_RT274_BE_FIXUP_RATE	48000
+#define RT274_CODEC_DAI		"rt274-aif1"
+
+static const struct snd_kcontrol_new card_controls[] = {
+	SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+	SOC_DAPM_PIN_SWITCH("Mic Jack"),
+};
+
+static int
+avs_rt274_clock_control(struct snd_soc_dapm_widget *w, struct snd_kcontrol *control, int event)
+{
+	struct snd_soc_dapm_context *dapm = w->dapm;
+	struct snd_soc_card *card = dapm->card;
+	struct snd_soc_dai *codec_dai;
+	int ret;
+
+	codec_dai = snd_soc_card_get_codec_dai(card, RT274_CODEC_DAI);
+	if (!codec_dai)
+		return -EINVAL;
+
+	/* Codec needs clock for Jack detection and button press */
+	ret = snd_soc_dai_set_sysclk(codec_dai, RT274_SCLK_S_PLL2, AVS_RT274_FREQ_OUT,
+				     SND_SOC_CLOCK_IN);
+	if (ret < 0) {
+		dev_err(codec_dai->dev, "set codec sysclk failed: %d\n", ret);
+		return ret;
+	}
+
+	if (SND_SOC_DAPM_EVENT_ON(event)) {
+		int ratio = 100;
+
+		snd_soc_dai_set_bclk_ratio(codec_dai, ratio);
+
+		ret = snd_soc_dai_set_pll(codec_dai, 0, RT274_PLL2_S_BCLK,
+					  AVS_RT274_BE_FIXUP_RATE * ratio, AVS_RT274_FREQ_OUT);
+		if (ret) {
+			dev_err(codec_dai->dev, "failed to enable PLL2: %d\n", ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+	SND_SOC_DAPM_HP("Headphone Jack", NULL),
+	SND_SOC_DAPM_MIC("Mic Jack", NULL),
+	SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, avs_rt274_clock_control,
+			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route card_base_routes[] = {
+	{"Headphone Jack", NULL, "HPO Pin"},
+	{"MIC", NULL, "Mic Jack"},
+
+	{"Headphone Jack", NULL, "Platform Clock"},
+	{"MIC", NULL, "Platform Clock"},
+};
+
+static struct snd_soc_jack_pin card_headset_pins[] = {
+	{
+		.pin = "Headphone Jack",
+		.mask = SND_JACK_HEADPHONE,
+	},
+	{
+		.pin = "Mic Jack",
+		.mask = SND_JACK_MICROPHONE,
+	},
+};
+
+static int avs_rt274_codec_init(struct snd_soc_pcm_runtime *runtime)
+{
+	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0);
+	struct snd_soc_component *component = codec_dai->component;
+	struct snd_soc_jack_pin *pins;
+	struct snd_soc_jack *jack;
+	struct snd_soc_card *card = runtime->card;
+	int num_pins, ret;
+
+	jack = snd_soc_card_get_drvdata(card);
+	num_pins = ARRAY_SIZE(card_headset_pins);
+
+	pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL);
+	if (!pins)
+		return -ENOMEM;
+
+	ret = snd_soc_card_jack_new_pins(card, "Headset", SND_JACK_HEADSET, jack, pins, num_pins);
+	if (ret)
+		return ret;
+
+	snd_soc_component_set_jack(component, jack, NULL);
+
+	/* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */
+	ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0xF, 4, 24);
+	if (ret < 0) {
+		dev_err(card->dev, "can't set codec pcm format %d\n", ret);
+		return ret;
+	}
+
+	card->dapm.idle_bias_off = true;
+
+	return 0;
+}
+
+static int avs_rt274_be_fixup(struct snd_soc_pcm_runtime *runtime, struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate, *channels;
+	struct snd_mask *fmt;
+
+	rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+	channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+	fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+	/* The ADSP will convert the FE rate to 48k, stereo */
+	rate->min = rate->max = AVS_RT274_BE_FIXUP_RATE;
+	channels->min = channels->max = 2;
+
+	/* set SSPN to 24 bit */
+	snd_mask_none(fmt);
+	snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
+
+	return 0;
+}
+
+static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+			       struct snd_soc_dai_link **dai_link)
+{
+	struct snd_soc_dai_link_component *platform;
+	struct snd_soc_dai_link *dl;
+
+	dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL);
+	platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+	if (!dl || !platform)
+		return -ENOMEM;
+
+	platform->name = platform_name;
+
+	dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+	dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
+	dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL);
+	if (!dl->name || !dl->cpus || !dl->codecs)
+		return -ENOMEM;
+
+	dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+	dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-INT34C2:00");
+	dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, "rt274-aif1");
+	if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
+		return -ENOMEM;
+
+	dl->num_cpus = 1;
+	dl->num_codecs = 1;
+	dl->platforms = platform;
+	dl->num_platforms = 1;
+	dl->id = 0;
+	dl->dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+	dl->init = avs_rt274_codec_init;
+	dl->be_hw_params_fixup = avs_rt274_be_fixup;
+	dl->nonatomic = 1;
+	dl->no_pcm = 1;
+	dl->dpcm_capture = 1;
+	dl->dpcm_playback = 1;
+
+	*dai_link = dl;
+
+	return 0;
+}
+
+static int avs_create_dapm_routes(struct device *dev, int ssp_port,
+				  struct snd_soc_dapm_route **routes, int *num_routes)
+{
+	struct snd_soc_dapm_route *dr;
+	const int num_base = ARRAY_SIZE(card_base_routes);
+	const int num_dr = num_base + 2;
+	int idx;
+
+	dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL);
+	if (!dr)
+		return -ENOMEM;
+
+	memcpy(dr, card_base_routes, num_base * sizeof(*dr));
+
+	idx = num_base;
+	dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "AIF1 Playback");
+	dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+	if (!dr[idx].sink || !dr[idx].source)
+		return -ENOMEM;
+
+	idx++;
+	dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Rx", ssp_port);
+	dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "AIF1 Capture");
+	if (!dr[idx].sink || !dr[idx].source)
+		return -ENOMEM;
+
+	*routes = dr;
+	*num_routes = num_dr;
+
+	return 0;
+}
+
+static int avs_card_set_jack(struct snd_soc_card *card, struct snd_soc_jack *jack)
+{
+	struct snd_soc_component *component;
+
+	for_each_card_components(card, component)
+		snd_soc_component_set_jack(component, jack, NULL);
+	return 0;
+}
+
+static int avs_card_remove(struct snd_soc_card *card)
+{
+	return avs_card_set_jack(card, NULL);
+}
+
+static int avs_card_suspend_pre(struct snd_soc_card *card)
+{
+	return avs_card_set_jack(card, NULL);
+}
+
+static int avs_card_resume_post(struct snd_soc_card *card)
+{
+	struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card);
+
+	return avs_card_set_jack(card, jack);
+}
+
+static int avs_rt274_probe(struct platform_device *pdev)
+{
+	struct snd_soc_dapm_route *routes;
+	struct snd_soc_dai_link *dai_link;
+	struct snd_soc_acpi_mach *mach;
+	struct snd_soc_card *card;
+	struct snd_soc_jack *jack;
+	struct device *dev = &pdev->dev;
+	const char *pname;
+	int ret, num_routes;
+
+	mach = dev_get_platdata(dev);
+	pname = mach->mach_params.platform;
+
+	ret = avs_create_dai_link(dev, pname, __ffs(mach->link_mask), &dai_link);
+	if (ret) {
+		dev_err(dev, "Failed to create dai link: %d", ret);
+		return ret;
+	}
+
+	ret = avs_create_dapm_routes(dev, __ffs(mach->link_mask), &routes, &num_routes);
+	if (ret) {
+		dev_err(dev, "Failed to create dapm routes: %d", ret);
+		return ret;
+	}
+
+	jack = devm_kzalloc(dev, sizeof(*jack), GFP_KERNEL);
+	card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+	if (!jack || !card)
+		return -ENOMEM;
+
+	card->name = "avs_rt274";
+	card->dev = dev;
+	card->owner = THIS_MODULE;
+	card->remove = avs_card_remove;
+	card->suspend_pre = avs_card_suspend_pre;
+	card->resume_post = avs_card_resume_post;
+	card->dai_link = dai_link;
+	card->num_links = 1;
+	card->controls = card_controls;
+	card->num_controls = ARRAY_SIZE(card_controls);
+	card->dapm_widgets = card_widgets;
+	card->num_dapm_widgets = ARRAY_SIZE(card_widgets);
+	card->dapm_routes = routes;
+	card->num_dapm_routes = num_routes;
+	card->fully_routed = true;
+	snd_soc_card_set_drvdata(card, jack);
+
+	ret = snd_soc_fixup_dai_links_platform_name(card, pname);
+	if (ret)
+		return ret;
+
+	return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_rt274_driver = {
+	.probe = avs_rt274_probe,
+	.driver = {
+		.name = "avs_rt274",
+		.pm = &snd_soc_pm_ops,
+	},
+};
+
+module_platform_driver(avs_rt274_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_rt274");
-- 
2.25.1


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

* [PATCH 07/14] ASoC: Intel: avs: Add rt286 machine board
  2022-04-27  8:18 [PATCH 00/14] ASoC: Intel: avs: Machine boards and HDA codec support Cezary Rojewski
                   ` (5 preceding siblings ...)
  2022-04-27  8:18 ` [PATCH 06/14] ASoC: Intel: avs: Add rt274 " Cezary Rojewski
@ 2022-04-27  8:18 ` Cezary Rojewski
  2022-04-27  8:18 ` [PATCH 08/14] ASoC: Intel: avs: Add rt298 " Cezary Rojewski
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 25+ messages in thread
From: Cezary Rojewski @ 2022-04-27  8:18 UTC (permalink / raw)
  To: alsa-devel, broonie
  Cc: Cezary Rojewski, upstream, harshapriya.n, rad,
	pierre-louis.bossart, tiwai, hdegoede, amadeuszx.slawinski,
	cujomalainey, lma

To support AVS-rt286 configuration add machine board connecting AVS
platform component driver with rt286 codec one.

Signed-off-by: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
---
 sound/soc/intel/avs/boards/Kconfig  |  10 +
 sound/soc/intel/avs/boards/Makefile |   2 +
 sound/soc/intel/avs/boards/rt286.c  | 280 ++++++++++++++++++++++++++++
 3 files changed, 292 insertions(+)
 create mode 100644 sound/soc/intel/avs/boards/rt286.c

diff --git a/sound/soc/intel/avs/boards/Kconfig b/sound/soc/intel/avs/boards/Kconfig
index a8f598247548..7c29eb8cee70 100644
--- a/sound/soc/intel/avs/boards/Kconfig
+++ b/sound/soc/intel/avs/boards/Kconfig
@@ -30,6 +30,16 @@ config SND_SOC_INTEL_AVS_MACH_RT274
 	   Say Y or m if you have such a device. This is a recommended option.
 	   If unsure select "N".
 
+config SND_SOC_INTEL_AVS_MACH_RT286
+	tristate "rt286 in I2S mode"
+	depends on I2C
+	depends on MFD_INTEL_LPSS || COMPILE_TEST
+	select SND_SOC_RT286
+	help
+	   This adds support for ASoC machine driver with RT286 I2S audio codec.
+	   Say Y or m if you have such a device. This is a recommended option.
+	   If unsure select "N".
+
 config SND_SOC_INTEL_AVS_MACH_SSP_TEST
 	tristate "SSP test board"
 	help
diff --git a/sound/soc/intel/avs/boards/Makefile b/sound/soc/intel/avs/boards/Makefile
index dbefc519e1e0..25631c03ffec 100644
--- a/sound/soc/intel/avs/boards/Makefile
+++ b/sound/soc/intel/avs/boards/Makefile
@@ -3,9 +3,11 @@
 snd-soc-avs-dmic-objs := dmic.o
 snd-soc-avs-hdaudio-objs := hdaudio.o
 snd-soc-avs-rt274-objs := rt274.o
+snd-soc-avs-rt286-objs := rt286.o
 snd-soc-avs-ssp-test-objs := ssp_test.o
 
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_DMIC) += snd-soc-avs-dmic.o
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_HDAUDIO) += snd-soc-avs-hdaudio.o
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT274) += snd-soc-avs-rt274.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT286) += snd-soc-avs-rt286.o
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_SSP_TEST) += snd-soc-avs-ssp-test.o
diff --git a/sound/soc/intel/avs/boards/rt286.c b/sound/soc/intel/avs/boards/rt286.c
new file mode 100644
index 000000000000..58863cdcefd5
--- /dev/null
+++ b/sound/soc/intel/avs/boards/rt286.c
@@ -0,0 +1,280 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+//          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/module.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include "../../../codecs/rt286.h"
+
+static const struct snd_kcontrol_new card_controls[] = {
+	SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+	SOC_DAPM_PIN_SWITCH("Mic Jack"),
+	SOC_DAPM_PIN_SWITCH("Speaker"),
+};
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+	SND_SOC_DAPM_HP("Headphone Jack", NULL),
+	SND_SOC_DAPM_MIC("Mic Jack", NULL),
+	SND_SOC_DAPM_SPK("Speaker", NULL),
+};
+
+static const struct snd_soc_dapm_route card_base_routes[] = {
+	/* HP jack connectors - unknown if we have jack detect */
+	{"Headphone Jack", NULL, "HPO Pin"},
+	{"MIC1", NULL, "Mic Jack"},
+
+	{"Speaker", NULL, "SPOR"},
+	{"Speaker", NULL, "SPOL"},
+};
+
+static struct snd_soc_jack_pin card_headset_pins[] = {
+	{
+		.pin = "Headphone Jack",
+		.mask = SND_JACK_HEADPHONE,
+	},
+	{
+		.pin = "Mic Jack",
+		.mask = SND_JACK_MICROPHONE,
+	},
+};
+
+static int avs_rt286_codec_init(struct snd_soc_pcm_runtime *runtime)
+{
+	struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component;
+	struct snd_soc_jack_pin *pins;
+	struct snd_soc_jack *jack;
+	struct snd_soc_card *card = runtime->card;
+	int num_pins, ret;
+
+	jack = snd_soc_card_get_drvdata(card);
+	num_pins = ARRAY_SIZE(card_headset_pins);
+
+	pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL);
+	if (!pins)
+		return -ENOMEM;
+
+	ret = snd_soc_card_jack_new_pins(card, "Headset", SND_JACK_HEADSET | SND_JACK_BTN_0, jack,
+					 pins, num_pins);
+	if (ret)
+		return ret;
+
+	snd_soc_component_set_jack(component, jack, NULL);
+
+	return 0;
+}
+
+static int avs_rt286_be_fixup(struct snd_soc_pcm_runtime *runtime, struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate, *channels;
+	struct snd_mask *fmt;
+
+	rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+	channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+	fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+	/* The ADSP will convert the FE rate to 48k, stereo */
+	rate->min = rate->max = 48000;
+	channels->min = channels->max = 2;
+
+	/* set SSP0 to 24 bit */
+	snd_mask_none(fmt);
+	snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
+
+	return 0;
+}
+
+static int
+avs_rt286_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *runtime = substream->private_data;
+	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0);
+	int ret;
+
+	ret = snd_soc_dai_set_sysclk(codec_dai, RT286_SCLK_S_PLL, 24000000, SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		dev_err(runtime->dev, "Set codec sysclk failed: %d\n", ret);
+
+	return ret;
+}
+
+static const struct snd_soc_ops avs_rt286_ops = {
+	.hw_params = avs_rt286_hw_params,
+};
+
+static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+			       struct snd_soc_dai_link **dai_link)
+{
+	struct snd_soc_dai_link_component *platform;
+	struct snd_soc_dai_link *dl;
+
+	dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL);
+	platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+	if (!dl || !platform)
+		return -ENOMEM;
+
+	platform->name = platform_name;
+
+	dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+	dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
+	dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL);
+	if (!dl->name || !dl->cpus || !dl->codecs)
+		return -ENOMEM;
+
+	dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+	dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-INT343A:00");
+	dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, "rt286-aif1");
+	if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
+		return -ENOMEM;
+
+	dl->num_cpus = 1;
+	dl->num_codecs = 1;
+	dl->platforms = platform;
+	dl->num_platforms = 1;
+	dl->id = 0;
+	dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+	dl->init = avs_rt286_codec_init;
+	dl->be_hw_params_fixup = avs_rt286_be_fixup;
+	dl->ops = &avs_rt286_ops;
+	dl->nonatomic = 1;
+	dl->no_pcm = 1;
+	dl->dpcm_capture = 1;
+	dl->dpcm_playback = 1;
+
+	*dai_link = dl;
+
+	return 0;
+}
+
+static int avs_create_dapm_routes(struct device *dev, int ssp_port,
+				  struct snd_soc_dapm_route **routes, int *num_routes)
+{
+	struct snd_soc_dapm_route *dr;
+	const int num_base = ARRAY_SIZE(card_base_routes);
+	const int num_dr = num_base + 2;
+	int idx;
+
+	dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL);
+	if (!dr)
+		return -ENOMEM;
+
+	memcpy(dr, card_base_routes, num_base * sizeof(*dr));
+
+	idx = num_base;
+	dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "AIF1 Playback");
+	dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+	if (!dr[idx].sink || !dr[idx].source)
+		return -ENOMEM;
+
+	idx++;
+	dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Rx", ssp_port);
+	dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "AIF1 Capture");
+	if (!dr[idx].sink || !dr[idx].source)
+		return -ENOMEM;
+
+	*routes = dr;
+	*num_routes = num_dr;
+
+	return 0;
+}
+
+static int avs_card_set_jack(struct snd_soc_card *card, struct snd_soc_jack *jack)
+{
+	struct snd_soc_component *component;
+
+	for_each_card_components(card, component)
+		snd_soc_component_set_jack(component, jack, NULL);
+	return 0;
+}
+
+static int avs_card_remove(struct snd_soc_card *card)
+{
+	return avs_card_set_jack(card, NULL);
+}
+
+static int avs_card_suspend_pre(struct snd_soc_card *card)
+{
+	return avs_card_set_jack(card, NULL);
+}
+
+static int avs_card_resume_post(struct snd_soc_card *card)
+{
+	struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card);
+
+	return avs_card_set_jack(card, jack);
+}
+
+static int avs_rt286_probe(struct platform_device *pdev)
+{
+	struct snd_soc_dapm_route *routes;
+	struct snd_soc_dai_link *dai_link;
+	struct snd_soc_acpi_mach *mach;
+	struct snd_soc_card *card;
+	struct snd_soc_jack *jack;
+	struct device *dev = &pdev->dev;
+	const char *pname;
+	int ret, num_routes;
+
+	mach = dev_get_platdata(dev);
+	pname = mach->mach_params.platform;
+
+	ret = avs_create_dai_link(dev, pname, __ffs(mach->link_mask), &dai_link);
+	if (ret) {
+		dev_err(dev, "Failed to create dai link: %d", ret);
+		return ret;
+	}
+
+	ret = avs_create_dapm_routes(dev, __ffs(mach->link_mask), &routes, &num_routes);
+	if (ret) {
+		dev_err(dev, "Failed to create dapm routes: %d", ret);
+		return ret;
+	}
+
+	jack = devm_kzalloc(dev, sizeof(*jack), GFP_KERNEL);
+	card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+	if (!jack || !card)
+		return -ENOMEM;
+
+	card->name = "avs_rt286";
+	card->dev = dev;
+	card->owner = THIS_MODULE;
+	card->remove = avs_card_remove;
+	card->suspend_pre = avs_card_suspend_pre;
+	card->resume_post = avs_card_resume_post;
+	card->dai_link = dai_link;
+	card->num_links = 1;
+	card->controls = card_controls;
+	card->num_controls = ARRAY_SIZE(card_controls);
+	card->dapm_widgets = card_widgets;
+	card->num_dapm_widgets = ARRAY_SIZE(card_widgets);
+	card->dapm_routes = routes;
+	card->num_dapm_routes = num_routes;
+	card->fully_routed = true;
+	snd_soc_card_set_drvdata(card, jack);
+
+	ret = snd_soc_fixup_dai_links_platform_name(card, pname);
+	if (ret)
+		return ret;
+
+	return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_rt286_driver = {
+	.probe = avs_rt286_probe,
+	.driver = {
+		.name = "avs_rt286",
+		.pm = &snd_soc_pm_ops,
+	},
+};
+
+module_platform_driver(avs_rt286_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_rt286");
-- 
2.25.1


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

* [PATCH 08/14] ASoC: Intel: avs: Add rt298 machine board
  2022-04-27  8:18 [PATCH 00/14] ASoC: Intel: avs: Machine boards and HDA codec support Cezary Rojewski
                   ` (6 preceding siblings ...)
  2022-04-27  8:18 ` [PATCH 07/14] ASoC: Intel: avs: Add rt286 " Cezary Rojewski
@ 2022-04-27  8:18 ` Cezary Rojewski
  2022-04-27  8:18 ` [PATCH 09/14] ASoC: Intel: avs: Add rt5682 " Cezary Rojewski
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 25+ messages in thread
From: Cezary Rojewski @ 2022-04-27  8:18 UTC (permalink / raw)
  To: alsa-devel, broonie
  Cc: Cezary Rojewski, upstream, harshapriya.n, rad,
	pierre-louis.bossart, tiwai, hdegoede, amadeuszx.slawinski,
	cujomalainey, lma

To support AVS-rt298 configuration add machine board connecting AVS
platform component driver with rt298 codec one.

Signed-off-by: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
---
 sound/soc/intel/avs/boards/Kconfig  |  10 +
 sound/soc/intel/avs/boards/Makefile |   2 +
 sound/soc/intel/avs/boards/rt298.c  | 280 ++++++++++++++++++++++++++++
 3 files changed, 292 insertions(+)
 create mode 100644 sound/soc/intel/avs/boards/rt298.c

diff --git a/sound/soc/intel/avs/boards/Kconfig b/sound/soc/intel/avs/boards/Kconfig
index 7c29eb8cee70..ae83e930aa35 100644
--- a/sound/soc/intel/avs/boards/Kconfig
+++ b/sound/soc/intel/avs/boards/Kconfig
@@ -40,6 +40,16 @@ config SND_SOC_INTEL_AVS_MACH_RT286
 	   Say Y or m if you have such a device. This is a recommended option.
 	   If unsure select "N".
 
+config SND_SOC_INTEL_AVS_MACH_RT298
+	tristate "rt298 in I2S mode"
+	depends on I2C
+	depends on MFD_INTEL_LPSS || COMPILE_TEST
+	select SND_SOC_RT298
+	help
+	   This adds support for ASoC machine driver with RT298 I2S audio codec.
+	   Say Y or m if you have such a device. This is a recommended option.
+	   If unsure select "N".
+
 config SND_SOC_INTEL_AVS_MACH_SSP_TEST
 	tristate "SSP test board"
 	help
diff --git a/sound/soc/intel/avs/boards/Makefile b/sound/soc/intel/avs/boards/Makefile
index 25631c03ffec..d1d261192d96 100644
--- a/sound/soc/intel/avs/boards/Makefile
+++ b/sound/soc/intel/avs/boards/Makefile
@@ -4,10 +4,12 @@ snd-soc-avs-dmic-objs := dmic.o
 snd-soc-avs-hdaudio-objs := hdaudio.o
 snd-soc-avs-rt274-objs := rt274.o
 snd-soc-avs-rt286-objs := rt286.o
+snd-soc-avs-rt298-objs := rt298.o
 snd-soc-avs-ssp-test-objs := ssp_test.o
 
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_DMIC) += snd-soc-avs-dmic.o
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_HDAUDIO) += snd-soc-avs-hdaudio.o
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT274) += snd-soc-avs-rt274.o
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT286) += snd-soc-avs-rt286.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT298) += snd-soc-avs-rt298.o
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_SSP_TEST) += snd-soc-avs-ssp-test.o
diff --git a/sound/soc/intel/avs/boards/rt298.c b/sound/soc/intel/avs/boards/rt298.c
new file mode 100644
index 000000000000..e241455dd72f
--- /dev/null
+++ b/sound/soc/intel/avs/boards/rt298.c
@@ -0,0 +1,280 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+//          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/module.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include "../../../codecs/rt298.h"
+
+static const struct snd_kcontrol_new card_controls[] = {
+	SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+	SOC_DAPM_PIN_SWITCH("Mic Jack"),
+	SOC_DAPM_PIN_SWITCH("Speaker"),
+};
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+	SND_SOC_DAPM_HP("Headphone Jack", NULL),
+	SND_SOC_DAPM_MIC("Mic Jack", NULL),
+	SND_SOC_DAPM_SPK("Speaker", NULL),
+};
+
+static const struct snd_soc_dapm_route card_base_routes[] = {
+	/* HP jack connectors - unknown if we have jack detect */
+	{"Headphone Jack", NULL, "HPO Pin"},
+	{"MIC1", NULL, "Mic Jack"},
+
+	{"Speaker", NULL, "SPOR"},
+	{"Speaker", NULL, "SPOL"},
+};
+
+static struct snd_soc_jack_pin card_headset_pins[] = {
+	{
+		.pin = "Headphone Jack",
+		.mask = SND_JACK_HEADPHONE,
+	},
+	{
+		.pin = "Mic Jack",
+		.mask = SND_JACK_MICROPHONE,
+	},
+};
+
+static int avs_rt298_codec_init(struct snd_soc_pcm_runtime *runtime)
+{
+	struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component;
+	struct snd_soc_jack_pin *pins;
+	struct snd_soc_jack *jack;
+	struct snd_soc_card *card = runtime->card;
+	int num_pins, ret;
+
+	jack = snd_soc_card_get_drvdata(card);
+	num_pins = ARRAY_SIZE(card_headset_pins);
+
+	pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL);
+	if (!pins)
+		return -ENOMEM;
+
+	ret = snd_soc_card_jack_new_pins(card, "Headset", SND_JACK_HEADSET | SND_JACK_BTN_0, jack,
+					 pins, num_pins);
+	if (ret)
+		return ret;
+
+	snd_soc_component_set_jack(component, jack, NULL);
+
+	return 0;
+}
+
+static int avs_rt298_be_fixup(struct snd_soc_pcm_runtime *runtime, struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate, *channels;
+	struct snd_mask *fmt;
+
+	rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+	channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+	fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+	/* The ADSP will convert the FE rate to 48k, stereo */
+	rate->min = rate->max = 48000;
+	channels->min = channels->max = 2;
+
+	/* set SSP0 to 24 bit */
+	snd_mask_none(fmt);
+	snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
+
+	return 0;
+}
+
+static int
+avs_rt298_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+	int ret;
+
+	ret = snd_soc_dai_set_sysclk(codec_dai, RT298_SCLK_S_PLL, 19200000, SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		dev_err(rtd->dev, "Set codec sysclk failed: %d\n", ret);
+
+	return ret;
+}
+
+static const struct snd_soc_ops avs_rt298_ops = {
+	.hw_params = avs_rt298_hw_params,
+};
+
+static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+			       struct snd_soc_dai_link **dai_link)
+{
+	struct snd_soc_dai_link_component *platform;
+	struct snd_soc_dai_link *dl;
+
+	dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL);
+	platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+	if (!dl || !platform)
+		return -ENOMEM;
+
+	platform->name = platform_name;
+
+	dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+	dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
+	dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL);
+	if (!dl->name || !dl->cpus || !dl->codecs)
+		return -ENOMEM;
+
+	dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+	dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-INT343A:00");
+	dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, "rt298-aif1");
+	if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
+		return -ENOMEM;
+
+	dl->num_cpus = 1;
+	dl->num_codecs = 1;
+	dl->platforms = platform;
+	dl->num_platforms = 1;
+	dl->id = 0;
+	dl->dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+	dl->init = avs_rt298_codec_init;
+	dl->be_hw_params_fixup = avs_rt298_be_fixup;
+	dl->ops = &avs_rt298_ops;
+	dl->nonatomic = 1;
+	dl->no_pcm = 1;
+	dl->dpcm_capture = 1;
+	dl->dpcm_playback = 1;
+
+	*dai_link = dl;
+
+	return 0;
+}
+
+static int avs_create_dapm_routes(struct device *dev, int ssp_port,
+				  struct snd_soc_dapm_route **routes, int *num_routes)
+{
+	struct snd_soc_dapm_route *dr;
+	const int num_base = ARRAY_SIZE(card_base_routes);
+	const int num_dr = num_base + 2;
+	int idx;
+
+	dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL);
+	if (!dr)
+		return -ENOMEM;
+
+	memcpy(dr, card_base_routes, num_base * sizeof(*dr));
+
+	idx = num_base;
+	dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "AIF1 Playback");
+	dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+	if (!dr[idx].sink || !dr[idx].source)
+		return -ENOMEM;
+
+	idx++;
+	dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Rx", ssp_port);
+	dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "AIF1 Capture");
+	if (!dr[idx].sink || !dr[idx].source)
+		return -ENOMEM;
+
+	*routes = dr;
+	*num_routes = num_dr;
+
+	return 0;
+}
+
+static int avs_card_set_jack(struct snd_soc_card *card, struct snd_soc_jack *jack)
+{
+	struct snd_soc_component *component;
+
+	for_each_card_components(card, component)
+		snd_soc_component_set_jack(component, jack, NULL);
+	return 0;
+}
+
+static int avs_card_remove(struct snd_soc_card *card)
+{
+	return avs_card_set_jack(card, NULL);
+}
+
+static int avs_card_suspend_pre(struct snd_soc_card *card)
+{
+	return avs_card_set_jack(card, NULL);
+}
+
+static int avs_card_resume_post(struct snd_soc_card *card)
+{
+	struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card);
+
+	return avs_card_set_jack(card, jack);
+}
+
+static int avs_rt298_probe(struct platform_device *pdev)
+{
+	struct snd_soc_dapm_route *routes;
+	struct snd_soc_dai_link *dai_link;
+	struct snd_soc_acpi_mach *mach;
+	struct snd_soc_card *card;
+	struct snd_soc_jack *jack;
+	struct device *dev = &pdev->dev;
+	const char *pname;
+	int ret, num_routes;
+
+	mach = dev_get_platdata(dev);
+	pname = mach->mach_params.platform;
+
+	ret = avs_create_dai_link(dev, pname, __ffs(mach->link_mask), &dai_link);
+	if (ret) {
+		dev_err(dev, "Failed to create dai link: %d", ret);
+		return ret;
+	}
+
+	ret = avs_create_dapm_routes(dev, __ffs(mach->link_mask), &routes, &num_routes);
+	if (ret) {
+		dev_err(dev, "Failed to create dapm routes: %d", ret);
+		return ret;
+	}
+
+	jack = devm_kzalloc(dev, sizeof(*jack), GFP_KERNEL);
+	card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+	if (!jack || !card)
+		return -ENOMEM;
+
+	card->name = "avs_rt298";
+	card->dev = dev;
+	card->owner = THIS_MODULE;
+	card->remove = avs_card_remove;
+	card->suspend_pre = avs_card_suspend_pre;
+	card->resume_post = avs_card_resume_post;
+	card->dai_link = dai_link;
+	card->num_links = 1;
+	card->controls = card_controls;
+	card->num_controls = ARRAY_SIZE(card_controls);
+	card->dapm_widgets = card_widgets;
+	card->num_dapm_widgets = ARRAY_SIZE(card_widgets);
+	card->dapm_routes = routes;
+	card->num_dapm_routes = num_routes;
+	card->fully_routed = true;
+	snd_soc_card_set_drvdata(card, jack);
+
+	ret = snd_soc_fixup_dai_links_platform_name(card, pname);
+	if (ret)
+		return ret;
+
+	return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_rt298_driver = {
+	.probe = avs_rt298_probe,
+	.driver = {
+		.name = "avs_rt298",
+		.pm = &snd_soc_pm_ops,
+	},
+};
+
+module_platform_driver(avs_rt298_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_rt298");
-- 
2.25.1


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

* [PATCH 09/14] ASoC: Intel: avs: Add rt5682 machine board
  2022-04-27  8:18 [PATCH 00/14] ASoC: Intel: avs: Machine boards and HDA codec support Cezary Rojewski
                   ` (7 preceding siblings ...)
  2022-04-27  8:18 ` [PATCH 08/14] ASoC: Intel: avs: Add rt298 " Cezary Rojewski
@ 2022-04-27  8:18 ` Cezary Rojewski
  2022-04-27  8:18 ` [PATCH 10/14] ASoC: Intel: avs: Add nau8825 " Cezary Rojewski
                   ` (4 subsequent siblings)
  13 siblings, 0 replies; 25+ messages in thread
From: Cezary Rojewski @ 2022-04-27  8:18 UTC (permalink / raw)
  To: alsa-devel, broonie
  Cc: Cezary Rojewski, upstream, harshapriya.n, rad,
	pierre-louis.bossart, tiwai, hdegoede, amadeuszx.slawinski,
	cujomalainey, lma

To support AVS-rt5682 configuration add machine board connecting AVS
platform component driver with rt5682 codec one.

Signed-off-by: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
---
 sound/soc/intel/avs/boards/Kconfig  |  10 +
 sound/soc/intel/avs/boards/Makefile |   2 +
 sound/soc/intel/avs/boards/rt5682.c | 339 ++++++++++++++++++++++++++++
 3 files changed, 351 insertions(+)
 create mode 100644 sound/soc/intel/avs/boards/rt5682.c

diff --git a/sound/soc/intel/avs/boards/Kconfig b/sound/soc/intel/avs/boards/Kconfig
index ae83e930aa35..f735b8c0898f 100644
--- a/sound/soc/intel/avs/boards/Kconfig
+++ b/sound/soc/intel/avs/boards/Kconfig
@@ -50,6 +50,16 @@ config SND_SOC_INTEL_AVS_MACH_RT298
 	   Say Y or m if you have such a device. This is a recommended option.
 	   If unsure select "N".
 
+config SND_SOC_INTEL_AVS_MACH_RT5682
+	tristate "rt5682 in I2S mode"
+	depends on I2C
+	depends on MFD_INTEL_LPSS || COMPILE_TEST
+	select SND_SOC_RT5682_I2C
+	help
+	   This adds support for ASoC machine driver with RT5682 I2S audio codec.
+	   Say Y or m if you have such a device. This is a recommended option.
+	   If unsure select "N".
+
 config SND_SOC_INTEL_AVS_MACH_SSP_TEST
 	tristate "SSP test board"
 	help
diff --git a/sound/soc/intel/avs/boards/Makefile b/sound/soc/intel/avs/boards/Makefile
index d1d261192d96..a36f38ef87de 100644
--- a/sound/soc/intel/avs/boards/Makefile
+++ b/sound/soc/intel/avs/boards/Makefile
@@ -5,6 +5,7 @@ snd-soc-avs-hdaudio-objs := hdaudio.o
 snd-soc-avs-rt274-objs := rt274.o
 snd-soc-avs-rt286-objs := rt286.o
 snd-soc-avs-rt298-objs := rt298.o
+snd-soc-avs-rt5682-objs := rt5682.o
 snd-soc-avs-ssp-test-objs := ssp_test.o
 
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_DMIC) += snd-soc-avs-dmic.o
@@ -12,4 +13,5 @@ obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_HDAUDIO) += snd-soc-avs-hdaudio.o
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT274) += snd-soc-avs-rt274.o
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT286) += snd-soc-avs-rt286.o
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT298) += snd-soc-avs-rt298.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT5682) += snd-soc-avs-rt5682.o
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_SSP_TEST) += snd-soc-avs-ssp-test.o
diff --git a/sound/soc/intel/avs/boards/rt5682.c b/sound/soc/intel/avs/boards/rt5682.c
new file mode 100644
index 000000000000..25321c2d6003
--- /dev/null
+++ b/sound/soc/intel/avs/boards/rt5682.c
@@ -0,0 +1,339 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+//          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/clk.h>
+#include <linux/dmi.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/rt5682.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include "../../common/soc-intel-quirks.h"
+#include "../../../codecs/rt5682.h"
+
+#define AVS_RT5682_SSP_CODEC(quirk)	((quirk) & GENMASK(2, 0))
+#define AVS_RT5682_SSP_CODEC_MASK	(GENMASK(2, 0))
+#define AVS_RT5682_MCLK_EN		BIT(3)
+#define AVS_RT5682_MCLK_24MHZ		BIT(4)
+
+/* Default: MCLK on, MCLK 19.2M, SSP0 */
+static unsigned long avs_rt5682_quirk = AVS_RT5682_MCLK_EN | AVS_RT5682_SSP_CODEC(0);
+
+static int avs_rt5682_quirk_cb(const struct dmi_system_id *id)
+{
+	avs_rt5682_quirk = (unsigned long)id->driver_data;
+	return 1;
+}
+
+static const struct dmi_system_id avs_rt5682_quirk_table[] = {
+	{
+		.callback = avs_rt5682_quirk_cb,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "WhiskeyLake Client"),
+		},
+		.driver_data = (void *)(AVS_RT5682_MCLK_EN |
+					AVS_RT5682_MCLK_24MHZ |
+					AVS_RT5682_SSP_CODEC(1)),
+	},
+	{
+		.callback = avs_rt5682_quirk_cb,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Ice Lake Client"),
+		},
+		.driver_data = (void *)(AVS_RT5682_MCLK_EN |
+					AVS_RT5682_SSP_CODEC(0)),
+	},
+	{}
+};
+
+static const struct snd_kcontrol_new card_controls[] = {
+	SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+	SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+	SND_SOC_DAPM_HP("Headphone Jack", NULL),
+	SND_SOC_DAPM_MIC("Headset Mic", NULL),
+};
+
+static const struct snd_soc_dapm_route card_base_routes[] = {
+	/* HP jack connectors - unknown if we have jack detect */
+	{ "Headphone Jack", NULL, "HPOL" },
+	{ "Headphone Jack", NULL, "HPOR" },
+
+	/* other jacks */
+	{ "IN1P", NULL, "Headset Mic" },
+};
+
+static int avs_rt5682_codec_init(struct snd_soc_pcm_runtime *runtime)
+{
+	struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component;
+	struct snd_soc_jack *jack;
+	struct snd_soc_card *card = runtime->card;
+	int ret;
+
+	jack = snd_soc_card_get_drvdata(card);
+
+	/* Need to enable ASRC function for 24MHz mclk rate */
+	if ((avs_rt5682_quirk & AVS_RT5682_MCLK_EN) &&
+	    (avs_rt5682_quirk & AVS_RT5682_MCLK_24MHZ)) {
+		rt5682_sel_asrc_clk_src(component, RT5682_DA_STEREO1_FILTER |
+					RT5682_AD_STEREO1_FILTER, RT5682_CLK_SEL_I2S1_ASRC);
+	}
+
+	/*
+	 * Headset buttons map to the google Reference headset.
+	 * These can be configured by userspace.
+	 */
+	ret = snd_soc_card_jack_new(card, "Headset", SND_JACK_HEADSET | SND_JACK_BTN_0 |
+				    SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3, jack);
+	if (ret) {
+		dev_err(card->dev, "Headset Jack creation failed: %d\n", ret);
+		return ret;
+	}
+
+	snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+	snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
+	snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
+	snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
+
+	ret = snd_soc_component_set_jack(component, jack, NULL);
+	if (ret) {
+		dev_err(card->dev, "Headset Jack call-back failed: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+};
+
+static int
+avs_rt5682_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *runtime = asoc_substream_to_rtd(substream);
+	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0);
+	int clk_id, clk_freq;
+	int pll_out, ret;
+
+	if (avs_rt5682_quirk & AVS_RT5682_MCLK_EN) {
+		clk_id = RT5682_PLL1_S_MCLK;
+		if (avs_rt5682_quirk & AVS_RT5682_MCLK_24MHZ)
+			clk_freq = 24000000;
+		else
+			clk_freq = 19200000;
+	} else {
+		clk_id = RT5682_PLL1_S_BCLK1;
+		clk_freq = params_rate(params) * 50;
+	}
+
+	pll_out = params_rate(params) * 512;
+
+	ret = snd_soc_dai_set_pll(codec_dai, 0, clk_id, clk_freq, pll_out);
+	if (ret < 0)
+		dev_err(runtime->dev, "snd_soc_dai_set_pll err = %d\n", ret);
+
+	/* Configure sysclk for codec */
+	ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL1, pll_out, SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		dev_err(runtime->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
+
+	/* slot_width should equal or large than data length, set them be the same */
+	ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x0, 0x0, 2, params_width(params));
+	if (ret < 0) {
+		dev_err(runtime->dev, "set TDM slot err:%d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_ops avs_rt5682_ops = {
+	.hw_params = avs_rt5682_hw_params,
+};
+
+static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+			       struct snd_soc_dai_link **dai_link)
+{
+	struct snd_soc_dai_link_component *platform;
+	struct snd_soc_dai_link *dl;
+
+	dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL);
+	platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+	if (!dl || !platform)
+		return -ENOMEM;
+
+	platform->name = platform_name;
+
+	dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+	dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
+	dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL);
+	if (!dl->name || !dl->cpus || !dl->codecs)
+		return -ENOMEM;
+
+	dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+	dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-10EC5682:00");
+	dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, "rt5682-aif1");
+	if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
+		return -ENOMEM;
+
+	dl->num_cpus = 1;
+	dl->num_codecs = 1;
+	dl->platforms = platform;
+	dl->num_platforms = 1;
+	dl->id = 0;
+	dl->init = avs_rt5682_codec_init;
+	dl->ops = &avs_rt5682_ops;
+	dl->nonatomic = 1;
+	dl->no_pcm = 1;
+	dl->dpcm_capture = 1;
+	dl->dpcm_playback = 1;
+
+	*dai_link = dl;
+
+	return 0;
+}
+
+static int avs_create_dapm_routes(struct device *dev, int ssp_port,
+				  struct snd_soc_dapm_route **routes, int *num_routes)
+{
+	struct snd_soc_dapm_route *dr;
+	const int num_base = ARRAY_SIZE(card_base_routes);
+	const int num_dr = num_base + 2;
+	int idx;
+
+	dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL);
+	if (!dr)
+		return -ENOMEM;
+
+	memcpy(dr, card_base_routes, num_base * sizeof(*dr));
+
+	idx = num_base;
+	dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "AIF1 Playback");
+	dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+	if (!dr[idx].sink || !dr[idx].source)
+		return -ENOMEM;
+
+	idx++;
+	dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Rx", ssp_port);
+	dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "AIF1 Capture");
+	if (!dr[idx].sink || !dr[idx].source)
+		return -ENOMEM;
+
+	*routes = dr;
+	*num_routes = num_dr;
+
+	return 0;
+}
+
+static int avs_card_set_jack(struct snd_soc_card *card, struct snd_soc_jack *jack)
+{
+	struct snd_soc_component *component;
+
+	for_each_card_components(card, component)
+		snd_soc_component_set_jack(component, jack, NULL);
+	return 0;
+}
+
+static int avs_card_remove(struct snd_soc_card *card)
+{
+	return avs_card_set_jack(card, NULL);
+}
+
+static int avs_card_suspend_pre(struct snd_soc_card *card)
+{
+	return avs_card_set_jack(card, NULL);
+}
+
+static int avs_card_resume_post(struct snd_soc_card *card)
+{
+	struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card);
+
+	return avs_card_set_jack(card, jack);
+}
+
+static int avs_rt5682_probe(struct platform_device *pdev)
+{
+	struct snd_soc_dapm_route *routes;
+	struct snd_soc_dai_link *dai_link;
+	struct snd_soc_acpi_mach *mach;
+	struct snd_soc_card *card;
+	struct snd_soc_jack *jack;
+	struct device *dev = &pdev->dev;
+	const char *pname;
+	int ret, num_routes;
+
+	if (pdev->id_entry && pdev->id_entry->driver_data)
+		avs_rt5682_quirk = (unsigned long)pdev->id_entry->driver_data;
+
+	dmi_check_system(avs_rt5682_quirk_table);
+	dev_dbg(dev, "avs_rt5682_quirk = %lx\n", avs_rt5682_quirk);
+
+	mach = dev_get_platdata(dev);
+	pname = mach->mach_params.platform;
+
+	ret = avs_create_dai_link(dev, pname, __ffs(mach->link_mask), &dai_link);
+	if (ret) {
+		dev_err(dev, "Failed to create dai link: %d", ret);
+		return ret;
+	}
+
+	ret = avs_create_dapm_routes(dev, __ffs(mach->link_mask), &routes, &num_routes);
+	if (ret) {
+		dev_err(dev, "Failed to create dapm routes: %d", ret);
+		return ret;
+	}
+
+	jack = devm_kzalloc(dev, sizeof(*jack), GFP_KERNEL);
+	card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+	if (!jack || !card)
+		return -ENOMEM;
+
+	card->name = "avs_rt5682";
+	card->dev = dev;
+	card->owner = THIS_MODULE;
+	card->remove = avs_card_remove;
+	card->suspend_pre = avs_card_suspend_pre;
+	card->resume_post = avs_card_resume_post;
+	card->dai_link = dai_link;
+	card->num_links = 1;
+	card->controls = card_controls;
+	card->num_controls = ARRAY_SIZE(card_controls);
+	card->dapm_widgets = card_widgets;
+	card->num_dapm_widgets = ARRAY_SIZE(card_widgets);
+	card->dapm_routes = routes;
+	card->num_dapm_routes = num_routes;
+	card->fully_routed = true;
+	snd_soc_card_set_drvdata(card, jack);
+
+	ret = snd_soc_fixup_dai_links_platform_name(card, pname);
+	if (ret)
+		return ret;
+
+	return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_rt5682_driver = {
+	.probe = avs_rt5682_probe,
+	.driver = {
+		.name = "avs_rt5682",
+		.pm = &snd_soc_pm_ops,
+	},
+};
+
+module_platform_driver(avs_rt5682_driver)
+
+MODULE_AUTHOR("Cezary Rojewski <cezary.rojewski@intel.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_rt5682");
-- 
2.25.1


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

* [PATCH 10/14] ASoC: Intel: avs: Add nau8825 machine board
  2022-04-27  8:18 [PATCH 00/14] ASoC: Intel: avs: Machine boards and HDA codec support Cezary Rojewski
                   ` (8 preceding siblings ...)
  2022-04-27  8:18 ` [PATCH 09/14] ASoC: Intel: avs: Add rt5682 " Cezary Rojewski
@ 2022-04-27  8:18 ` Cezary Rojewski
  2022-04-27  8:18 ` [PATCH 11/14] ASoC: Intel: avs: Add ssm4567 " Cezary Rojewski
                   ` (3 subsequent siblings)
  13 siblings, 0 replies; 25+ messages in thread
From: Cezary Rojewski @ 2022-04-27  8:18 UTC (permalink / raw)
  To: alsa-devel, broonie
  Cc: Cezary Rojewski, upstream, harshapriya.n, rad,
	pierre-louis.bossart, tiwai, hdegoede, amadeuszx.slawinski,
	cujomalainey, lma

To support AVS-nau8825 configuration add machine board connecting AVS
platform component driver with nau8825 codec one.

Signed-off-by: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
---
 sound/soc/intel/avs/boards/Kconfig   |  11 +
 sound/soc/intel/avs/boards/Makefile  |   2 +
 sound/soc/intel/avs/boards/nau8825.c | 352 +++++++++++++++++++++++++++
 3 files changed, 365 insertions(+)
 create mode 100644 sound/soc/intel/avs/boards/nau8825.c

diff --git a/sound/soc/intel/avs/boards/Kconfig b/sound/soc/intel/avs/boards/Kconfig
index f735b8c0898f..f9ecee648830 100644
--- a/sound/soc/intel/avs/boards/Kconfig
+++ b/sound/soc/intel/avs/boards/Kconfig
@@ -20,6 +20,17 @@ config SND_SOC_INTEL_AVS_MACH_HDAUDIO
 	  Say Y or m if you have such a device. This is a recommended option.
 	  If unsure select "N".
 
+config SND_SOC_INTEL_AVS_MACH_NAU8825
+	tristate "nau8825 I2S board"
+	depends on I2C
+	depends on MFD_INTEL_LPSS || COMPILE_TEST
+	select SND_SOC_NAU8825
+	help
+	   This adds support for ASoC machine driver with NAU8825 I2S audio codec.
+	   It is meant to be used with AVS driver.
+	   Say Y or m if you have such a device. This is a recommended option.
+	   If unsure select "N".
+
 config SND_SOC_INTEL_AVS_MACH_RT274
 	tristate "rt274 in I2S mode"
 	depends on I2C
diff --git a/sound/soc/intel/avs/boards/Makefile b/sound/soc/intel/avs/boards/Makefile
index a36f38ef87de..ece733a96c1e 100644
--- a/sound/soc/intel/avs/boards/Makefile
+++ b/sound/soc/intel/avs/boards/Makefile
@@ -2,6 +2,7 @@
 
 snd-soc-avs-dmic-objs := dmic.o
 snd-soc-avs-hdaudio-objs := hdaudio.o
+snd-soc-avs-nau8825-objs := nau8825.o
 snd-soc-avs-rt274-objs := rt274.o
 snd-soc-avs-rt286-objs := rt286.o
 snd-soc-avs-rt298-objs := rt298.o
@@ -10,6 +11,7 @@ snd-soc-avs-ssp-test-objs := ssp_test.o
 
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_DMIC) += snd-soc-avs-dmic.o
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_HDAUDIO) += snd-soc-avs-hdaudio.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_NAU8825) += snd-soc-avs-nau8825.o
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT274) += snd-soc-avs-rt274.o
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT286) += snd-soc-avs-rt286.o
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT298) += snd-soc-avs-rt298.o
diff --git a/sound/soc/intel/avs/boards/nau8825.c b/sound/soc/intel/avs/boards/nau8825.c
new file mode 100644
index 000000000000..970ccfed9392
--- /dev/null
+++ b/sound/soc/intel/avs/boards/nau8825.c
@@ -0,0 +1,352 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+//          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include "../../../codecs/nau8825.h"
+
+#define SKL_NUVOTON_CODEC_DAI	"nau8825-hifi"
+
+static int
+avs_nau8825_clock_control(struct snd_soc_dapm_widget *w, struct snd_kcontrol *control, int event)
+{
+	struct snd_soc_dapm_context *dapm = w->dapm;
+	struct snd_soc_card *card = dapm->card;
+	struct snd_soc_dai *codec_dai;
+	int ret;
+
+	codec_dai = snd_soc_card_get_codec_dai(card, SKL_NUVOTON_CODEC_DAI);
+	if (!codec_dai) {
+		dev_err(card->dev, "Codec dai not found\n");
+		return -EINVAL;
+	}
+
+	if (!SND_SOC_DAPM_EVENT_ON(event)) {
+		ret = snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_INTERNAL, 0, SND_SOC_CLOCK_IN);
+		if (ret < 0) {
+			dev_err(card->dev, "set sysclk err = %d\n", ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new card_controls[] = {
+	SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+	SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+	SND_SOC_DAPM_HP("Headphone Jack", NULL),
+	SND_SOC_DAPM_MIC("Headset Mic", NULL),
+	SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, avs_nau8825_clock_control,
+			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route card_base_routes[] = {
+	{ "Headphone Jack", NULL, "HPOL" },
+	{ "Headphone Jack", NULL, "HPOR" },
+
+	{ "MIC", NULL, "Headset Mic" },
+
+	{ "Headphone Jack", NULL, "Platform Clock" },
+	{ "Headset Mic", NULL, "Platform Clock" },
+};
+
+static struct snd_soc_jack_pin card_headset_pins[] = {
+	{
+		.pin = "Headphone Jack",
+		.mask = SND_JACK_HEADPHONE,
+	},
+	{
+		.pin = "Headset Mic",
+		.mask = SND_JACK_MICROPHONE,
+	},
+};
+
+static int avs_nau8825_codec_init(struct snd_soc_pcm_runtime *runtime)
+{
+	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0);
+	struct snd_soc_component *component = codec_dai->component;
+	struct snd_soc_jack_pin *pins;
+	struct snd_soc_jack *jack;
+	struct snd_soc_card *card = runtime->card;
+	int num_pins, ret;
+
+	jack = snd_soc_card_get_drvdata(card);
+	num_pins = ARRAY_SIZE(card_headset_pins);
+
+	pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL);
+	if (!pins)
+		return -ENOMEM;
+
+	/*
+	 * 4 buttons here map to the google Reference headset.
+	 * The use of these buttons can be decided by the user space.
+	 */
+	ret = snd_soc_card_jack_new_pins(card, "Headset", SND_JACK_HEADSET | SND_JACK_BTN_0 |
+					 SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3,
+					 jack, pins, num_pins);
+	if (ret)
+		return ret;
+
+	snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+	snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
+	snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
+	snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
+
+	//snd_soc_component_set_jack(component, jack, NULL);
+	// TODO: Fix nau8825 codec to use .set_jack, like everyone else
+	nau8825_enable_jack_detect(component, jack);
+
+	return 0;
+}
+
+static int
+avs_nau8825_be_fixup(struct snd_soc_pcm_runtime *runtime, struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate, *channels;
+	struct snd_mask *fmt;
+
+	rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+	channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+	fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+	/* The ADSP will convert the FE rate to 48k, stereo */
+	rate->min = rate->max = 48000;
+	channels->min = channels->max = 2;
+
+	/* set SSP to 24 bit */
+	snd_mask_none(fmt);
+	snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
+
+	return 0;
+}
+
+static int avs_nau8825_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *rtm = asoc_substream_to_rtd(substream);
+	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtm, 0);
+	int ret = 0;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		ret = snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_FLL_FS, 0, SND_SOC_CLOCK_IN);
+		if (ret < 0) {
+			dev_err(codec_dai->dev, "can't set FS clock %d\n", ret);
+			break;
+		}
+
+		ret = snd_soc_dai_set_pll(codec_dai, 0, 0, runtime->rate, runtime->rate * 256);
+		if (ret < 0)
+			dev_err(codec_dai->dev, "can't set FLL: %d\n", ret);
+		break;
+
+	case SNDRV_PCM_TRIGGER_RESUME:
+		ret = snd_soc_dai_set_pll(codec_dai, 0, 0, runtime->rate, runtime->rate * 256);
+		if (ret < 0)
+			dev_err(codec_dai->dev, "can't set FLL: %d\n", ret);
+		break;
+	}
+
+	return ret;
+}
+
+
+static const struct snd_soc_ops avs_nau8825_ops = {
+	.trigger = avs_nau8825_trigger,
+};
+
+static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+			       struct snd_soc_dai_link **dai_link)
+{
+	struct snd_soc_dai_link_component *platform;
+	struct snd_soc_dai_link *dl;
+
+	dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL);
+	platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+	if (!dl || !platform)
+		return -ENOMEM;
+
+	platform->name = platform_name;
+
+	dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+	dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
+	dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL);
+	if (!dl->name || !dl->cpus || !dl->codecs)
+		return -ENOMEM;
+
+	dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+	dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-10508825:00");
+	dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, SKL_NUVOTON_CODEC_DAI);
+	if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
+		return -ENOMEM;
+
+	dl->num_cpus = 1;
+	dl->num_codecs = 1;
+	dl->platforms = platform;
+	dl->num_platforms = 1;
+	dl->id = 0;
+	dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+	dl->init = avs_nau8825_codec_init;
+	dl->be_hw_params_fixup = avs_nau8825_be_fixup;
+	dl->ops = &avs_nau8825_ops;
+	dl->nonatomic = 1;
+	dl->no_pcm = 1;
+	dl->dpcm_capture = 1;
+	dl->dpcm_playback = 1;
+
+	*dai_link = dl;
+
+	return 0;
+}
+
+static int avs_create_dapm_routes(struct device *dev, int ssp_port,
+				  struct snd_soc_dapm_route **routes, int *num_routes)
+{
+	struct snd_soc_dapm_route *dr;
+	const int num_base = ARRAY_SIZE(card_base_routes);
+	const int num_dr = num_base + 2;
+	int idx;
+
+	dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL);
+	if (!dr)
+		return -ENOMEM;
+
+	memcpy(dr, card_base_routes, num_base * sizeof(*dr));
+
+	idx = num_base;
+	dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "Playback");
+	dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+	if (!dr[idx].sink || !dr[idx].source)
+		return -ENOMEM;
+
+	idx++;
+	dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Rx", ssp_port);
+	dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "Capture");
+	if (!dr[idx].sink || !dr[idx].source)
+		return -ENOMEM;
+
+	*routes = dr;
+	*num_routes = num_dr;
+
+	return 0;
+}
+
+static int avs_card_set_jack(struct snd_soc_card *card, struct snd_soc_jack *jack)
+{
+	struct snd_soc_component *component;
+
+	for_each_card_components(card, component)
+		snd_soc_component_set_jack(component, jack, NULL);
+	return 0;
+}
+
+static int avs_card_remove(struct snd_soc_card *card)
+{
+	return avs_card_set_jack(card, NULL);
+}
+
+static int avs_card_suspend_pre(struct snd_soc_card *card)
+{
+	return avs_card_set_jack(card, NULL);
+}
+
+static int avs_card_resume_post(struct snd_soc_card *card)
+{
+	struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, SKL_NUVOTON_CODEC_DAI);
+	struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card);
+
+	if (!codec_dai) {
+		dev_err(card->dev, "Codec dai not found\n");
+		return -EINVAL;
+	}
+
+	if (codec_dai->stream_active[SNDRV_PCM_STREAM_PLAYBACK] &&
+	    codec_dai->playback_widget->active)
+		snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_FLL_FS, 0, SND_SOC_CLOCK_IN);
+
+	return avs_card_set_jack(card, jack);
+}
+
+static int avs_nau8825_probe(struct platform_device *pdev)
+{
+	struct snd_soc_dapm_route *routes;
+	struct snd_soc_dai_link *dai_link;
+	struct snd_soc_acpi_mach *mach;
+	struct snd_soc_card *card;
+	struct snd_soc_jack *jack;
+	struct device *dev = &pdev->dev;
+	const char *pname;
+	int ret, num_routes;
+
+	mach = dev_get_platdata(dev);
+	pname = mach->mach_params.platform;
+
+	ret = avs_create_dai_link(dev, pname, __ffs(mach->link_mask), &dai_link);
+	if (ret) {
+		dev_err(dev, "Failed to create dai link: %d", ret);
+		return ret;
+	}
+
+	ret = avs_create_dapm_routes(dev, __ffs(mach->link_mask), &routes, &num_routes);
+	if (ret) {
+		dev_err(dev, "Failed to create dapm routes: %d", ret);
+		return ret;
+	}
+
+	jack = devm_kzalloc(dev, sizeof(*jack), GFP_KERNEL);
+	card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+	if (!jack || !card)
+		return -ENOMEM;
+
+	card->name = "avs_nau8825";
+	card->dev = dev;
+	card->owner = THIS_MODULE;
+	card->remove = avs_card_remove;
+	card->suspend_pre = avs_card_suspend_pre;
+	card->resume_post = avs_card_resume_post;
+	card->dai_link = dai_link;
+	card->num_links = 1;
+	card->controls = card_controls;
+	card->num_controls = ARRAY_SIZE(card_controls);
+	card->dapm_widgets = card_widgets;
+	card->num_dapm_widgets = ARRAY_SIZE(card_widgets);
+	card->dapm_routes = routes;
+	card->num_dapm_routes = num_routes;
+	card->fully_routed = true;
+	snd_soc_card_set_drvdata(card, jack);
+
+	ret = snd_soc_fixup_dai_links_platform_name(card, pname);
+	if (ret)
+		return ret;
+
+	return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_nau8825_driver = {
+	.probe = avs_nau8825_probe,
+	.driver = {
+		.name = "avs_nau8825",
+		.pm = &snd_soc_pm_ops,
+	},
+};
+
+module_platform_driver(avs_nau8825_driver)
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_nau8825");
-- 
2.25.1


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

* [PATCH 11/14] ASoC: Intel: avs: Add ssm4567 machine board
  2022-04-27  8:18 [PATCH 00/14] ASoC: Intel: avs: Machine boards and HDA codec support Cezary Rojewski
                   ` (9 preceding siblings ...)
  2022-04-27  8:18 ` [PATCH 10/14] ASoC: Intel: avs: Add nau8825 " Cezary Rojewski
@ 2022-04-27  8:18 ` Cezary Rojewski
  2022-04-27  8:19 ` [PATCH 12/14] ASoC: Intel: avs: Add max98357a " Cezary Rojewski
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 25+ messages in thread
From: Cezary Rojewski @ 2022-04-27  8:18 UTC (permalink / raw)
  To: alsa-devel, broonie
  Cc: Cezary Rojewski, upstream, harshapriya.n, rad,
	pierre-louis.bossart, tiwai, hdegoede, amadeuszx.slawinski,
	cujomalainey, lma

To support AVS-ssm4567 configuration add machine board connecting AVS
platform component driver with ssm4567 codec one.

Signed-off-by: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
---
 sound/soc/intel/avs/boards/Kconfig   |  11 ++
 sound/soc/intel/avs/boards/Makefile  |   2 +
 sound/soc/intel/avs/boards/ssm4567.c | 270 +++++++++++++++++++++++++++
 3 files changed, 283 insertions(+)
 create mode 100644 sound/soc/intel/avs/boards/ssm4567.c

diff --git a/sound/soc/intel/avs/boards/Kconfig b/sound/soc/intel/avs/boards/Kconfig
index f9ecee648830..8af85953adac 100644
--- a/sound/soc/intel/avs/boards/Kconfig
+++ b/sound/soc/intel/avs/boards/Kconfig
@@ -71,6 +71,17 @@ config SND_SOC_INTEL_AVS_MACH_RT5682
 	   Say Y or m if you have such a device. This is a recommended option.
 	   If unsure select "N".
 
+config SND_SOC_INTEL_AVS_MACH_SSM4567
+	tristate "ssm4567 I2S board"
+	depends on I2C
+	depends on MFD_INTEL_LPSS || COMPILE_TEST
+	select SND_SOC_SSM4567
+	help
+	   This adds support for ASoC machine driver with SSM4567 I2S audio codec.
+	   It is meant to be used with AVS driver.
+	   Say Y or m if you have such a device. This is a recommended option.
+	   If unsure select "N".
+
 config SND_SOC_INTEL_AVS_MACH_SSP_TEST
 	tristate "SSP test board"
 	help
diff --git a/sound/soc/intel/avs/boards/Makefile b/sound/soc/intel/avs/boards/Makefile
index ece733a96c1e..30d0eac6c22a 100644
--- a/sound/soc/intel/avs/boards/Makefile
+++ b/sound/soc/intel/avs/boards/Makefile
@@ -7,6 +7,7 @@ snd-soc-avs-rt274-objs := rt274.o
 snd-soc-avs-rt286-objs := rt286.o
 snd-soc-avs-rt298-objs := rt298.o
 snd-soc-avs-rt5682-objs := rt5682.o
+snd-soc-avs-ssm4567-objs := ssm4567.o
 snd-soc-avs-ssp-test-objs := ssp_test.o
 
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_DMIC) += snd-soc-avs-dmic.o
@@ -16,4 +17,5 @@ obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT274) += snd-soc-avs-rt274.o
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT286) += snd-soc-avs-rt286.o
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT298) += snd-soc-avs-rt298.o
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT5682) += snd-soc-avs-rt5682.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_SSM4567) += snd-soc-avs-ssm4567.o
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_SSP_TEST) += snd-soc-avs-ssp-test.o
diff --git a/sound/soc/intel/avs/boards/ssm4567.c b/sound/soc/intel/avs/boards/ssm4567.c
new file mode 100644
index 000000000000..d17f36701bc3
--- /dev/null
+++ b/sound/soc/intel/avs/boards/ssm4567.c
@@ -0,0 +1,270 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+//          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include "../../../codecs/nau8825.h"
+
+#define SKL_NUVOTON_CODEC_DAI	"nau8825-hifi"
+#define SKL_SSM_CODEC_DAI	"ssm4567-hifi"
+
+static struct snd_soc_codec_conf card_codec_conf[] = {
+	{
+		.dlc = COMP_CODEC_CONF("i2c-INT343B:00"),
+		.name_prefix = "Left",
+	},
+	{
+		.dlc = COMP_CODEC_CONF("i2c-INT343B:01"),
+		.name_prefix = "Right",
+	},
+};
+
+static const struct snd_kcontrol_new card_controls[] = {
+	SOC_DAPM_PIN_SWITCH("Left Speaker"),
+	SOC_DAPM_PIN_SWITCH("Right Speaker"),
+};
+
+static int
+platform_clock_control(struct snd_soc_dapm_widget *w, struct snd_kcontrol *control, int event)
+{
+	struct snd_soc_dapm_context *dapm = w->dapm;
+	struct snd_soc_card *card = dapm->card;
+	struct snd_soc_dai *codec_dai;
+	int ret;
+
+	codec_dai = snd_soc_card_get_codec_dai(card, SKL_NUVOTON_CODEC_DAI);
+	if (!codec_dai) {
+		dev_err(card->dev, "Codec dai not found\n");
+		return -EINVAL;
+	}
+
+	if (SND_SOC_DAPM_EVENT_ON(event)) {
+		ret = snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_MCLK, 24000000,
+					     SND_SOC_CLOCK_IN);
+		if (ret < 0)
+			dev_err(card->dev, "set sysclk err = %d\n", ret);
+	} else {
+		ret = snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_INTERNAL, 0, SND_SOC_CLOCK_IN);
+		if (ret < 0)
+			dev_err(card->dev, "set sysclk err = %d\n", ret);
+	}
+
+	return ret;
+}
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+	SND_SOC_DAPM_SPK("Left Speaker", NULL),
+	SND_SOC_DAPM_SPK("Right Speaker", NULL),
+	SND_SOC_DAPM_SPK("DP1", NULL),
+	SND_SOC_DAPM_SPK("DP2", NULL),
+	SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, platform_clock_control,
+			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route card_base_routes[] = {
+	{"Left Speaker", NULL, "Left OUT"},
+	{"Right Speaker", NULL, "Right OUT"},
+};
+
+static int avs_ssm4567_codec_init(struct snd_soc_pcm_runtime *runtime)
+{
+	int ret;
+
+	/* Slot 1 for left */
+	ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_codec(runtime, 0), 0x01, 0x01, 2, 48);
+	if (ret < 0)
+		return ret;
+
+	/* Slot 2 for right */
+	ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_codec(runtime, 1), 0x02, 0x02, 2, 48);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int
+avs_ssm4567_be_fixup(struct snd_soc_pcm_runtime *runrime, struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate, *channels;
+	struct snd_mask *fmt;
+
+	rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+	channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+	fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+	/* The ADSP will covert the FE rate to 48k, stereo */
+	rate->min = rate->max = 48000;
+	channels->min = channels->max = 2;
+
+	/* set SSP0 to 24 bit */
+	snd_mask_none(fmt);
+	snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
+	return 0;
+}
+
+static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+			       struct snd_soc_dai_link **dai_link)
+{
+	struct snd_soc_dai_link_component *platform;
+	struct snd_soc_dai_link *dl;
+
+	dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL);
+	platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+	if (!dl || !platform)
+		return -ENOMEM;
+
+	platform->name = platform_name;
+
+	dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+	dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
+	dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs) * 2, GFP_KERNEL);
+	if (!dl->name || !dl->cpus || !dl->codecs)
+		return -ENOMEM;
+
+	dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+	dl->codecs[0].name = devm_kasprintf(dev, GFP_KERNEL, "i2c-INT343B:00");
+	dl->codecs[0].dai_name = devm_kasprintf(dev, GFP_KERNEL, "ssm4567-hifi");
+	dl->codecs[1].name = devm_kasprintf(dev, GFP_KERNEL, "i2c-INT343B:01");
+	dl->codecs[1].dai_name = devm_kasprintf(dev, GFP_KERNEL, "ssm4567-hifi");
+	if (!dl->cpus->dai_name || !dl->codecs[0].name || !dl->codecs[0].dai_name ||
+	    !dl->codecs[1].name || !dl->codecs[1].dai_name)
+		return -ENOMEM;
+
+	dl->num_cpus = 1;
+	dl->num_codecs = 2;
+	dl->platforms = platform;
+	dl->num_platforms = 1;
+	dl->id = 0;
+	dl->dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBS_CFS;
+	dl->init = avs_ssm4567_codec_init;
+	dl->be_hw_params_fixup = avs_ssm4567_be_fixup;
+	dl->nonatomic = 1;
+	dl->no_pcm = 1;
+	dl->dpcm_capture = 1;
+	dl->dpcm_playback = 1;
+	dl->ignore_pmdown_time = 1;
+
+	*dai_link = dl;
+
+	return 0;
+}
+
+static int avs_create_dapm_routes(struct device *dev, int ssp_port,
+				  struct snd_soc_dapm_route **routes, int *num_routes)
+{
+	struct snd_soc_dapm_route *dr;
+	const int num_base = ARRAY_SIZE(card_base_routes);
+	const int num_dr = num_base + 4;
+	int idx;
+
+	dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL);
+	if (!dr)
+		return -ENOMEM;
+
+	memcpy(dr, card_base_routes, num_base * sizeof(*dr));
+
+	idx = num_base;
+	dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "Left Playback");
+	dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+	if (!dr[idx].sink || !dr[idx].source)
+		return -ENOMEM;
+
+	idx++;
+	dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "Right Playback");
+	dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+	if (!dr[idx].sink || !dr[idx].source)
+		return -ENOMEM;
+
+	idx++;
+	dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Rx", ssp_port);
+	dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "Left Capture Sense");
+	if (!dr[idx].sink || !dr[idx].source)
+		return -ENOMEM;
+
+	idx++;
+	dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Rx", ssp_port);
+	dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "Right Capture Sense");
+	if (!dr[idx].sink || !dr[idx].source)
+		return -ENOMEM;
+
+	*routes = dr;
+	*num_routes = num_dr;
+
+	return 0;
+}
+
+static int avs_ssm4567_probe(struct platform_device *pdev)
+{
+	struct snd_soc_dapm_route *routes;
+	struct snd_soc_dai_link *dai_link;
+	struct snd_soc_acpi_mach *mach;
+	struct snd_soc_card *card;
+	struct device *dev = &pdev->dev;
+	const char *pname;
+	int ret, num_routes;
+
+	mach = dev_get_platdata(dev);
+	pname = mach->mach_params.platform;
+
+	ret = avs_create_dai_link(dev, pname, __ffs(mach->link_mask), &dai_link);
+	if (ret) {
+		dev_err(dev, "Failed to create dai link: %d", ret);
+		return ret;
+	}
+
+	ret = avs_create_dapm_routes(dev, __ffs(mach->link_mask), &routes, &num_routes);
+	if (ret) {
+		dev_err(dev, "Failed to create dapm routes: %d", ret);
+		return ret;
+	}
+
+	card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+	if (!card)
+		return -ENOMEM;
+
+	card->name = "avs_ssm4567-adi";
+	card->dev = dev;
+	card->owner = THIS_MODULE;
+	card->dai_link = dai_link;
+	card->num_links = 1;
+	card->codec_conf = card_codec_conf;
+	card->num_configs = ARRAY_SIZE(card_codec_conf);
+	card->controls = card_controls;
+	card->num_controls = ARRAY_SIZE(card_controls);
+	card->dapm_widgets = card_widgets;
+	card->num_dapm_widgets = ARRAY_SIZE(card_widgets);
+	card->dapm_routes = routes;
+	card->num_dapm_routes = num_routes;
+	card->fully_routed = true;
+	card->disable_route_checks = true;
+
+	ret = snd_soc_fixup_dai_links_platform_name(card, pname);
+	if (ret)
+		return ret;
+
+	return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_ssm4567_driver = {
+	.probe = avs_ssm4567_probe,
+	.driver = {
+		.name = "avs_ssm4567",
+		.pm = &snd_soc_pm_ops,
+	},
+};
+
+module_platform_driver(avs_ssm4567_driver)
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_ssm4567");
-- 
2.25.1


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

* [PATCH 12/14] ASoC: Intel: avs: Add max98357a machine board
  2022-04-27  8:18 [PATCH 00/14] ASoC: Intel: avs: Machine boards and HDA codec support Cezary Rojewski
                   ` (10 preceding siblings ...)
  2022-04-27  8:18 ` [PATCH 11/14] ASoC: Intel: avs: Add ssm4567 " Cezary Rojewski
@ 2022-04-27  8:19 ` Cezary Rojewski
  2022-04-27  8:19 ` [PATCH 13/14] ASoC: Intel: avs: Add max98373 " Cezary Rojewski
  2022-04-27  8:19 ` [PATCH 14/14] ASoC: Intel: avs: Add da7219 " Cezary Rojewski
  13 siblings, 0 replies; 25+ messages in thread
From: Cezary Rojewski @ 2022-04-27  8:19 UTC (permalink / raw)
  To: alsa-devel, broonie
  Cc: Cezary Rojewski, upstream, harshapriya.n, rad,
	pierre-louis.bossart, tiwai, hdegoede, amadeuszx.slawinski,
	cujomalainey, lma

To support AVS-max98357a configuration add machine board connecting AVS
platform component driver with max98357a codec one.

Signed-off-by: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
---
 sound/soc/intel/avs/boards/Kconfig     |  10 ++
 sound/soc/intel/avs/boards/Makefile    |   2 +
 sound/soc/intel/avs/boards/max98357a.c | 153 +++++++++++++++++++++++++
 3 files changed, 165 insertions(+)
 create mode 100644 sound/soc/intel/avs/boards/max98357a.c

diff --git a/sound/soc/intel/avs/boards/Kconfig b/sound/soc/intel/avs/boards/Kconfig
index 8af85953adac..6865dc904326 100644
--- a/sound/soc/intel/avs/boards/Kconfig
+++ b/sound/soc/intel/avs/boards/Kconfig
@@ -20,6 +20,16 @@ config SND_SOC_INTEL_AVS_MACH_HDAUDIO
 	  Say Y or m if you have such a device. This is a recommended option.
 	  If unsure select "N".
 
+config SND_SOC_INTEL_AVS_MACH_MAX98357A
+	tristate "max98357A I2S board"
+	depends on I2C
+	depends on MFD_INTEL_LPSS || COMPILE_TEST
+	select SND_SOC_MAX98357A
+	help
+	  This adds support for AVS with MAX98357A I2S codec configuration.
+	  Say Y or m if you have such a device. This is a recommended option.
+	  If unsure select "N".
+
 config SND_SOC_INTEL_AVS_MACH_NAU8825
 	tristate "nau8825 I2S board"
 	depends on I2C
diff --git a/sound/soc/intel/avs/boards/Makefile b/sound/soc/intel/avs/boards/Makefile
index 30d0eac6c22a..ae890ad747ba 100644
--- a/sound/soc/intel/avs/boards/Makefile
+++ b/sound/soc/intel/avs/boards/Makefile
@@ -2,6 +2,7 @@
 
 snd-soc-avs-dmic-objs := dmic.o
 snd-soc-avs-hdaudio-objs := hdaudio.o
+snd-soc-avs-max98357a-objs := max98357a.o
 snd-soc-avs-nau8825-objs := nau8825.o
 snd-soc-avs-rt274-objs := rt274.o
 snd-soc-avs-rt286-objs := rt286.o
@@ -12,6 +13,7 @@ snd-soc-avs-ssp-test-objs := ssp_test.o
 
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_DMIC) += snd-soc-avs-dmic.o
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_HDAUDIO) += snd-soc-avs-hdaudio.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_MAX98357A) += snd-soc-avs-max98357a.o
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_NAU8825) += snd-soc-avs-nau8825.o
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT274) += snd-soc-avs-rt274.o
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT286) += snd-soc-avs-rt286.o
diff --git a/sound/soc/intel/avs/boards/max98357a.c b/sound/soc/intel/avs/boards/max98357a.c
new file mode 100644
index 000000000000..68ac47c675bd
--- /dev/null
+++ b/sound/soc/intel/avs/boards/max98357a.c
@@ -0,0 +1,153 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+//          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include <sound/soc-dapm.h>
+
+static const struct snd_kcontrol_new card_controls[] = {
+	SOC_DAPM_PIN_SWITCH("Spk"),
+};
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+	SND_SOC_DAPM_SPK("Spk", NULL),
+};
+
+static const struct snd_soc_dapm_route card_base_routes[] = {
+	{ "Spk", NULL, "Speaker" },
+};
+
+static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+			       struct snd_soc_dai_link **dai_link)
+{
+	struct snd_soc_dai_link_component *platform;
+	struct snd_soc_dai_link *dl;
+
+	dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL);
+	platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+	if (!dl || !platform)
+		return -ENOMEM;
+
+	platform->name = platform_name;
+
+	dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+	dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
+	dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL);
+	if (!dl->name || !dl->cpus || !dl->codecs)
+		return -ENOMEM;
+
+	dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+	dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "MX98357A:00");
+	dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, "HiFi");
+	if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
+		return -ENOMEM;
+
+	dl->num_cpus = 1;
+	dl->num_codecs = 1;
+	dl->platforms = platform;
+	dl->num_platforms = 1;
+	dl->id = 0;
+	dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+	dl->nonatomic = 1;
+	dl->no_pcm = 1;
+	dl->dpcm_playback = 1;
+
+	*dai_link = dl;
+
+	return 0;
+}
+
+static int avs_create_dapm_routes(struct device *dev, int ssp_port,
+				  struct snd_soc_dapm_route **routes, int *num_routes)
+{
+	struct snd_soc_dapm_route *dr;
+	const int num_base = ARRAY_SIZE(card_base_routes);
+	const int num_dr = num_base + 1;
+	int idx;
+
+	dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL);
+	if (!dr)
+		return -ENOMEM;
+
+	memcpy(dr, card_base_routes, num_base * sizeof(*dr));
+
+	idx = num_base;
+	dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "HiFi Playback");
+	dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+	if (!dr[idx].sink || !dr[idx].source)
+		return -ENOMEM;
+
+	*routes = dr;
+	*num_routes = num_dr;
+
+	return 0;
+}
+
+static int avs_max98357a_probe(struct platform_device *pdev)
+{
+	struct snd_soc_dapm_route *routes;
+	struct snd_soc_dai_link *dai_link;
+	struct snd_soc_acpi_mach *mach;
+	struct snd_soc_card *card;
+	struct device *dev = &pdev->dev;
+	const char *pname;
+	int ret, num_routes;
+
+	mach = dev_get_platdata(dev);
+	pname = mach->mach_params.platform;
+
+	ret = avs_create_dai_link(dev, pname, __ffs(mach->link_mask), &dai_link);
+	if (ret) {
+		dev_err(dev, "Failed to create dai link: %d", ret);
+		return ret;
+	}
+
+	ret = avs_create_dapm_routes(dev, __ffs(mach->link_mask), &routes, &num_routes);
+	if (ret) {
+		dev_err(dev, "Failed to create dapm routes: %d", ret);
+		return ret;
+	}
+
+	card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+	if (!card)
+		return -ENOMEM;
+
+	card->name = "avs_max98357a";
+	card->dev = dev;
+	card->owner = THIS_MODULE;
+	card->dai_link = dai_link;
+	card->num_links = 1;
+	card->controls = card_controls;
+	card->num_controls = ARRAY_SIZE(card_controls);
+	card->dapm_widgets = card_widgets;
+	card->num_dapm_widgets = ARRAY_SIZE(card_widgets);
+	card->dapm_routes = routes;
+	card->num_dapm_routes = num_routes;
+	card->fully_routed = true;
+
+	ret = snd_soc_fixup_dai_links_platform_name(card, pname);
+	if (ret)
+		return ret;
+
+	return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_max98357a_driver = {
+	.probe = avs_max98357a_probe,
+	.driver = {
+		.name = "avs_max98357a",
+		.pm = &snd_soc_pm_ops,
+	},
+};
+
+module_platform_driver(avs_max98357a_driver)
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_max98357a");
-- 
2.25.1


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

* [PATCH 13/14] ASoC: Intel: avs: Add max98373 machine board
  2022-04-27  8:18 [PATCH 00/14] ASoC: Intel: avs: Machine boards and HDA codec support Cezary Rojewski
                   ` (11 preceding siblings ...)
  2022-04-27  8:19 ` [PATCH 12/14] ASoC: Intel: avs: Add max98357a " Cezary Rojewski
@ 2022-04-27  8:19 ` Cezary Rojewski
  2022-04-27  8:19 ` [PATCH 14/14] ASoC: Intel: avs: Add da7219 " Cezary Rojewski
  13 siblings, 0 replies; 25+ messages in thread
From: Cezary Rojewski @ 2022-04-27  8:19 UTC (permalink / raw)
  To: alsa-devel, broonie
  Cc: Cezary Rojewski, upstream, harshapriya.n, rad,
	pierre-louis.bossart, tiwai, hdegoede, amadeuszx.slawinski,
	cujomalainey, lma

From: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>

To support AVS-max98373 configuration add machine board connecting AVS
platform component driver with max98373 codec one.

Signed-off-by: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
---
 sound/soc/intel/avs/boards/Kconfig    |  10 ++
 sound/soc/intel/avs/boards/Makefile   |   2 +
 sound/soc/intel/avs/boards/max98373.c | 238 ++++++++++++++++++++++++++
 3 files changed, 250 insertions(+)
 create mode 100644 sound/soc/intel/avs/boards/max98373.c

diff --git a/sound/soc/intel/avs/boards/Kconfig b/sound/soc/intel/avs/boards/Kconfig
index 6865dc904326..38a76f486d91 100644
--- a/sound/soc/intel/avs/boards/Kconfig
+++ b/sound/soc/intel/avs/boards/Kconfig
@@ -30,6 +30,16 @@ config SND_SOC_INTEL_AVS_MACH_MAX98357A
 	  Say Y or m if you have such a device. This is a recommended option.
 	  If unsure select "N".
 
+config SND_SOC_INTEL_AVS_MACH_MAX98373
+	tristate "max98373 I2S board"
+	depends on I2C
+	depends on MFD_INTEL_LPSS || COMPILE_TEST
+	select SND_SOC_MAX98373
+	help
+	  This adds support for AVS with MAX98373 I2S codec configuration.
+	  Say Y or m if you have such a device. This is a recommended option.
+	  If unsure select "N".
+
 config SND_SOC_INTEL_AVS_MACH_NAU8825
 	tristate "nau8825 I2S board"
 	depends on I2C
diff --git a/sound/soc/intel/avs/boards/Makefile b/sound/soc/intel/avs/boards/Makefile
index ae890ad747ba..a9e27638d23c 100644
--- a/sound/soc/intel/avs/boards/Makefile
+++ b/sound/soc/intel/avs/boards/Makefile
@@ -3,6 +3,7 @@
 snd-soc-avs-dmic-objs := dmic.o
 snd-soc-avs-hdaudio-objs := hdaudio.o
 snd-soc-avs-max98357a-objs := max98357a.o
+snd-soc-avs-max98373-objs := max98373.o
 snd-soc-avs-nau8825-objs := nau8825.o
 snd-soc-avs-rt274-objs := rt274.o
 snd-soc-avs-rt286-objs := rt286.o
@@ -14,6 +15,7 @@ snd-soc-avs-ssp-test-objs := ssp_test.o
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_DMIC) += snd-soc-avs-dmic.o
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_HDAUDIO) += snd-soc-avs-hdaudio.o
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_MAX98357A) += snd-soc-avs-max98357a.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_MAX98373) += snd-soc-avs-max98373.o
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_NAU8825) += snd-soc-avs-nau8825.o
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT274) += snd-soc-avs-rt274.o
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT286) += snd-soc-avs-rt286.o
diff --git a/sound/soc/intel/avs/boards/max98373.c b/sound/soc/intel/avs/boards/max98373.c
new file mode 100644
index 000000000000..ced3549291f2
--- /dev/null
+++ b/sound/soc/intel/avs/boards/max98373.c
@@ -0,0 +1,238 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+//          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include <sound/soc-dapm.h>
+
+#define MAX98373_DEV0_NAME	"i2c-MX98373:00"
+#define MAX98373_DEV1_NAME	"i2c-MX98373:01"
+#define MAX98373_CODEC_NAME	"max98373-aif1"
+
+static struct snd_soc_codec_conf card_codec_conf[] = {
+	{
+		.dlc = COMP_CODEC_CONF(MAX98373_DEV0_NAME),
+		.name_prefix = "Right",
+	},
+	{
+		.dlc = COMP_CODEC_CONF(MAX98373_DEV1_NAME),
+		.name_prefix = "Left",
+	},
+};
+
+static const struct snd_kcontrol_new card_controls[] = {
+	SOC_DAPM_PIN_SWITCH("Left Spk"),
+	SOC_DAPM_PIN_SWITCH("Right Spk"),
+};
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+	SND_SOC_DAPM_SPK("Left Spk", NULL),
+	SND_SOC_DAPM_SPK("Right Spk", NULL),
+};
+
+static const struct snd_soc_dapm_route card_base_routes[] = {
+	{ "Left Spk", NULL, "Left BE_OUT" },
+	{ "Right Spk", NULL, "Right BE_OUT" },
+};
+
+static int
+avs_max98373_be_fixup(struct snd_soc_pcm_runtime *runrime, struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate, *channels;
+	struct snd_mask *fmt;
+
+	rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+	channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+	fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+	/* The ADSP will covert the FE rate to 48k, stereo */
+	rate->min = rate->max = 48000;
+	channels->min = channels->max = 2;
+
+	/* set SSP0 to 16 bit */
+	snd_mask_none(fmt);
+	snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
+	return 0;
+}
+
+static int avs_max98373_hw_params(struct snd_pcm_substream *substream,
+				  struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *runtime = asoc_substream_to_rtd(substream);
+	struct snd_soc_dai *codec_dai;
+	int ret, i;
+
+	for_each_rtd_codec_dais(runtime, i, codec_dai) {
+		if (!strcmp(codec_dai->component->name, MAX98373_DEV0_NAME)) {
+			ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x30, 3, 8, 16);
+			if (ret < 0) {
+				dev_err(runtime->dev, "DEV0 TDM slot err:%d\n", ret);
+				return ret;
+			}
+		}
+		if (!strcmp(codec_dai->component->name, MAX98373_DEV1_NAME)) {
+			ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xC0, 3, 8, 16);
+			if (ret < 0) {
+				dev_err(runtime->dev, "DEV1 TDM slot err:%d\n", ret);
+				return ret;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_ops avs_max98373_ops = {
+	.hw_params = avs_max98373_hw_params,
+};
+
+static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+			       struct snd_soc_dai_link **dai_link)
+{
+	struct snd_soc_dai_link_component *platform;
+	struct snd_soc_dai_link *dl;
+
+	dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL);
+	platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+	if (!dl || !platform)
+		return -ENOMEM;
+
+	platform->name = platform_name;
+
+	dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+	dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
+	dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs) * 2, GFP_KERNEL);
+	if (!dl->name || !dl->cpus || !dl->codecs)
+		return -ENOMEM;
+
+	dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+	dl->codecs[0].name = devm_kasprintf(dev, GFP_KERNEL, MAX98373_DEV0_NAME);
+	dl->codecs[0].dai_name = devm_kasprintf(dev, GFP_KERNEL, MAX98373_CODEC_NAME);
+	dl->codecs[1].name = devm_kasprintf(dev, GFP_KERNEL, MAX98373_DEV1_NAME);
+	dl->codecs[1].dai_name = devm_kasprintf(dev, GFP_KERNEL, MAX98373_CODEC_NAME);
+	if (!dl->cpus->dai_name || !dl->codecs[0].name || !dl->codecs[0].dai_name ||
+	    !dl->codecs[1].name || !dl->codecs[1].dai_name)
+		return -ENOMEM;
+
+	dl->num_cpus = 1;
+	dl->num_codecs = 2;
+	dl->platforms = platform;
+	dl->num_platforms = 1;
+	dl->id = 0;
+	dl->dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC;
+	dl->be_hw_params_fixup = avs_max98373_be_fixup;
+	dl->nonatomic = 1;
+	dl->no_pcm = 1;
+	dl->dpcm_capture = 1;
+	dl->dpcm_playback = 1;
+	dl->ignore_pmdown_time = 1;
+	dl->ops = &avs_max98373_ops;
+
+	*dai_link = dl;
+
+	return 0;
+}
+
+static int avs_create_dapm_routes(struct device *dev, int ssp_port,
+				  struct snd_soc_dapm_route **routes, int *num_routes)
+{
+	struct snd_soc_dapm_route *dr;
+	const int num_base = ARRAY_SIZE(card_base_routes);
+	const int num_dr = num_base + 2;
+	int idx;
+
+	dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL);
+	if (!dr)
+		return -ENOMEM;
+
+	memcpy(dr, card_base_routes, num_base * sizeof(*dr));
+
+	idx = num_base;
+	dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "Left HiFi Playback");
+	dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+	if (!dr[idx].sink || !dr[idx].source)
+		return -ENOMEM;
+
+	idx++;
+	dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "Right HiFi Playback");
+	dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+	if (!dr[idx].sink || !dr[idx].source)
+		return -ENOMEM;
+
+	*routes = dr;
+	*num_routes = num_dr;
+
+	return 0;
+}
+
+static int avs_max98373_probe(struct platform_device *pdev)
+{
+	struct snd_soc_dapm_route *routes;
+	struct snd_soc_dai_link *dai_link;
+	struct snd_soc_acpi_mach *mach;
+	struct snd_soc_card *card;
+	struct device *dev = &pdev->dev;
+	const char *pname;
+	int ret, num_routes;
+
+	mach = dev_get_platdata(dev);
+	pname = mach->mach_params.platform;
+
+	ret = avs_create_dai_link(dev, pname, __ffs(mach->link_mask), &dai_link);
+	if (ret) {
+		dev_err(dev, "Failed to create dai link: %d", ret);
+		return ret;
+	}
+
+	ret = avs_create_dapm_routes(dev, __ffs(mach->link_mask), &routes, &num_routes);
+	if (ret) {
+		dev_err(dev, "Failed to create dapm routes: %d", ret);
+		return ret;
+	}
+
+	card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+	if (!card)
+		return -ENOMEM;
+
+	card->name = "avs_max98373";
+	card->dev = dev;
+	card->owner = THIS_MODULE;
+	card->dai_link = dai_link;
+	card->num_links = 1;
+	card->codec_conf = card_codec_conf;
+	card->num_configs = ARRAY_SIZE(card_codec_conf);
+	card->controls = card_controls;
+	card->num_controls = ARRAY_SIZE(card_controls);
+	card->dapm_widgets = card_widgets;
+	card->num_dapm_widgets = ARRAY_SIZE(card_widgets);
+	card->dapm_routes = routes;
+	card->num_dapm_routes = num_routes;
+	card->fully_routed = true;
+
+	ret = snd_soc_fixup_dai_links_platform_name(card, pname);
+	if (ret)
+		return ret;
+
+	return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_max98373_driver = {
+	.probe = avs_max98373_probe,
+	.driver = {
+		.name = "avs_max98373",
+		.pm = &snd_soc_pm_ops,
+	},
+};
+
+module_platform_driver(avs_max98373_driver)
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_max98373");
-- 
2.25.1


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

* [PATCH 14/14] ASoC: Intel: avs: Add da7219 machine board
  2022-04-27  8:18 [PATCH 00/14] ASoC: Intel: avs: Machine boards and HDA codec support Cezary Rojewski
                   ` (12 preceding siblings ...)
  2022-04-27  8:19 ` [PATCH 13/14] ASoC: Intel: avs: Add max98373 " Cezary Rojewski
@ 2022-04-27  8:19 ` Cezary Rojewski
  13 siblings, 0 replies; 25+ messages in thread
From: Cezary Rojewski @ 2022-04-27  8:19 UTC (permalink / raw)
  To: alsa-devel, broonie
  Cc: Cezary Rojewski, upstream, harshapriya.n, rad,
	pierre-louis.bossart, tiwai, hdegoede, amadeuszx.slawinski,
	cujomalainey, lma

To support AVS-da7219 configuration add machine board connecting AVS
platform component driver with da7219 codec one.

Signed-off-by: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
---
 sound/soc/intel/avs/boards/Kconfig  |  10 +
 sound/soc/intel/avs/boards/Makefile |   2 +
 sound/soc/intel/avs/boards/da7219.c | 281 ++++++++++++++++++++++++++++
 3 files changed, 293 insertions(+)
 create mode 100644 sound/soc/intel/avs/boards/da7219.c

diff --git a/sound/soc/intel/avs/boards/Kconfig b/sound/soc/intel/avs/boards/Kconfig
index 38a76f486d91..3a24cc9ec64d 100644
--- a/sound/soc/intel/avs/boards/Kconfig
+++ b/sound/soc/intel/avs/boards/Kconfig
@@ -4,6 +4,16 @@ menu "Intel AVS Machine drivers"
 
 comment "Available DSP configurations"
 
+config SND_SOC_INTEL_AVS_MACH_DA7219
+	tristate "da7219 I2S board"
+	depends on I2C
+	depends on MFD_INTEL_LPSS || COMPILE_TEST
+	select SND_SOC_DA7219
+	help
+	  This adds support for AVS with DA7219 I2S codec configuration.
+	  Say Y or m if you have such a device. This is a recommended option.
+	  If unsure select "N".
+
 config SND_SOC_INTEL_AVS_MACH_DMIC
 	tristate "DMIC generic board"
 	select SND_SOC_DMIC
diff --git a/sound/soc/intel/avs/boards/Makefile b/sound/soc/intel/avs/boards/Makefile
index a9e27638d23c..5d8ddd1e08c5 100644
--- a/sound/soc/intel/avs/boards/Makefile
+++ b/sound/soc/intel/avs/boards/Makefile
@@ -1,5 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-only
 
+snd-soc-avs-da7219-objs := da7219.o
 snd-soc-avs-dmic-objs := dmic.o
 snd-soc-avs-hdaudio-objs := hdaudio.o
 snd-soc-avs-max98357a-objs := max98357a.o
@@ -12,6 +13,7 @@ snd-soc-avs-rt5682-objs := rt5682.o
 snd-soc-avs-ssm4567-objs := ssm4567.o
 snd-soc-avs-ssp-test-objs := ssp_test.o
 
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_DA7219) += snd-soc-avs-da7219.o
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_DMIC) += snd-soc-avs-dmic.o
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_HDAUDIO) += snd-soc-avs-hdaudio.o
 obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_MAX98357A) += snd-soc-avs-max98357a.o
diff --git a/sound/soc/intel/avs/boards/da7219.c b/sound/soc/intel/avs/boards/da7219.c
new file mode 100644
index 000000000000..80ef0642649b
--- /dev/null
+++ b/sound/soc/intel/avs/boards/da7219.c
@@ -0,0 +1,281 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Author: Cezary Rojewski <cezary.rojewski@intel.com>
+//
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include <sound/soc-dapm.h>
+#include <uapi/linux/input-event-codes.h>
+#include "../../../codecs/da7219.h"
+#include "../../../codecs/da7219-aad.h"
+
+#define DA7219_DAI_NAME		"da7219-hifi"
+
+static const struct snd_kcontrol_new card_controls[] = {
+	SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+	SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+static int platform_clock_control(struct snd_soc_dapm_widget *w,
+				  struct snd_kcontrol *k, int  event)
+{
+	struct snd_soc_dapm_context *dapm = w->dapm;
+	struct snd_soc_card *card = dapm->card;
+	struct snd_soc_dai *codec_dai;
+	int ret = 0;
+
+	codec_dai = snd_soc_card_get_codec_dai(card, DA7219_DAI_NAME);
+	if (!codec_dai) {
+		dev_err(card->dev, "Codec dai not found. Unable to set/unset codec pll\n");
+		return -EIO;
+	}
+
+	if (SND_SOC_DAPM_EVENT_OFF(event)) {
+		ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_MCLK, 0, 0);
+		if (ret)
+			dev_err(card->dev, "failed to stop PLL: %d\n", ret);
+	} else if (SND_SOC_DAPM_EVENT_ON(event)) {
+		ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_PLL_SRM,
+					  0, DA7219_PLL_FREQ_OUT_98304);
+		if (ret)
+			dev_err(card->dev, "failed to start PLL: %d\n", ret);
+	}
+
+	return ret;
+}
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+	SND_SOC_DAPM_HP("Headphone Jack", NULL),
+	SND_SOC_DAPM_MIC("Headset Mic", NULL),
+	SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, platform_clock_control,
+			    SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_PRE_PMU),
+};
+
+static const struct snd_soc_dapm_route card_base_routes[] = {
+	/* HP jack connectors - unknown if we have jack detection */
+	{"Headphone Jack", NULL, "HPL"},
+	{"Headphone Jack", NULL, "HPR"},
+
+	{"MIC", NULL, "Headset Mic"},
+
+	{ "Headphone Jack", NULL, "Platform Clock" },
+	{ "Headset Mic", NULL, "Platform Clock" },
+};
+
+static int avs_da7219_codec_init(struct snd_soc_pcm_runtime *runtime)
+{
+	struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component;
+	struct snd_soc_card *card = runtime->card;
+	struct snd_soc_jack *jack;
+	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0);
+	int clk_freq;
+	int ret;
+
+	jack = snd_soc_card_get_drvdata(card);
+	clk_freq = 19200000;
+
+	ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK, clk_freq, SND_SOC_CLOCK_IN);
+	if (ret) {
+		dev_err(card->dev, "can't set codec sysclk configuration\n");
+		return ret;
+	}
+
+	/*
+	 * Headset buttons map to the google Reference headset.
+	 * These can be configured by userspace.
+	 */
+	ret = snd_soc_card_jack_new(card, "Headset Jack",
+				    SND_JACK_HEADSET | SND_JACK_BTN_0 |
+				    SND_JACK_BTN_1 | SND_JACK_BTN_2 |
+				    SND_JACK_BTN_3 | SND_JACK_LINEOUT, jack);
+	if (ret) {
+		dev_err(card->dev, "Headset Jack creation failed: %d\n", ret);
+		return ret;
+	}
+
+	snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+	snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
+	snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
+	snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
+
+	da7219_aad_jack_det(component, jack);
+
+	return 0;
+}
+
+static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+			       struct snd_soc_dai_link **dai_link)
+{
+	struct snd_soc_dai_link_component *platform;
+	struct snd_soc_dai_link *dl;
+
+	dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL);
+	platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+	if (!dl || !platform)
+		return -ENOMEM;
+
+	platform->name = platform_name;
+
+	dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+	dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
+	dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL);
+	if (!dl->name || !dl->cpus || !dl->codecs)
+		return -ENOMEM;
+
+	dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+	dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-DLGS7219:00");
+	dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, DA7219_DAI_NAME);
+	if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
+		return -ENOMEM;
+
+	dl->num_cpus = 1;
+	dl->num_codecs = 1;
+	dl->platforms = platform;
+	dl->num_platforms = 1;
+	dl->id = 0;
+	dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+	dl->init = avs_da7219_codec_init;
+	dl->nonatomic = 1;
+	dl->no_pcm = 1;
+	dl->dpcm_capture = 1;
+	dl->dpcm_playback = 1;
+
+	*dai_link = dl;
+
+	return 0;
+}
+
+static int avs_create_dapm_routes(struct device *dev, int ssp_port,
+				  struct snd_soc_dapm_route **routes, int *num_routes)
+{
+	struct snd_soc_dapm_route *dr;
+	const int num_base = ARRAY_SIZE(card_base_routes);
+	const int num_dr = num_base + 2;
+	int idx;
+
+	dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL);
+	if (!dr)
+		return -ENOMEM;
+
+	memcpy(dr, card_base_routes, num_base * sizeof(*dr));
+
+	idx = num_base;
+	dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "Playback");
+	dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+	if (!dr[idx].sink || !dr[idx].source)
+		return -ENOMEM;
+
+	idx++;
+	dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Rx", ssp_port);
+	dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "Capture");
+	if (!dr[idx].sink || !dr[idx].source)
+		return -ENOMEM;
+
+	*routes = dr;
+	*num_routes = num_dr;
+
+	return 0;
+}
+
+static int avs_card_set_jack(struct snd_soc_card *card, struct snd_soc_jack *jack)
+{
+	struct snd_soc_component *component;
+
+	for_each_card_components(card, component)
+		snd_soc_component_set_jack(component, jack, NULL);
+	return 0;
+}
+
+static int avs_card_remove(struct snd_soc_card *card)
+{
+	return avs_card_set_jack(card, NULL);
+}
+
+static int avs_card_suspend_pre(struct snd_soc_card *card)
+{
+	return avs_card_set_jack(card, NULL);
+}
+
+static int avs_card_resume_post(struct snd_soc_card *card)
+{
+	struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card);
+
+	return avs_card_set_jack(card, jack);
+}
+
+static int avs_da7219_probe(struct platform_device *pdev)
+{
+	struct snd_soc_dapm_route *routes;
+	struct snd_soc_dai_link *dai_link;
+	struct snd_soc_acpi_mach *mach;
+	struct snd_soc_card *card;
+	struct snd_soc_jack *jack;
+	struct device *dev = &pdev->dev;
+	const char *pname;
+	int ret, num_routes;
+
+	mach = dev_get_platdata(dev);
+	pname = mach->mach_params.platform;
+
+	ret = avs_create_dai_link(dev, pname, __ffs(mach->link_mask), &dai_link);
+	if (ret) {
+		dev_err(dev, "Failed to create dai link: %d", ret);
+		return ret;
+	}
+
+	ret = avs_create_dapm_routes(dev, __ffs(mach->link_mask), &routes, &num_routes);
+	if (ret) {
+		dev_err(dev, "Failed to create dapm routes: %d", ret);
+		return ret;
+	}
+
+	jack = devm_kzalloc(dev, sizeof(*jack), GFP_KERNEL);
+	card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+	if (!jack || !card)
+		return -ENOMEM;
+
+	card->name = "avs_da7219";
+	card->dev = dev;
+	card->owner = THIS_MODULE;
+	card->remove = avs_card_remove;
+	card->suspend_pre = avs_card_suspend_pre;
+	card->resume_post = avs_card_resume_post;
+	card->dai_link = dai_link;
+	card->num_links = 1;
+	card->controls = card_controls;
+	card->num_controls = ARRAY_SIZE(card_controls);
+	card->dapm_widgets = card_widgets;
+	card->num_dapm_widgets = ARRAY_SIZE(card_widgets);
+	card->dapm_routes = routes;
+	card->num_dapm_routes = num_routes;
+	card->fully_routed = true;
+	snd_soc_card_set_drvdata(card, jack);
+
+	ret = snd_soc_fixup_dai_links_platform_name(card, pname);
+	if (ret)
+		return ret;
+
+	return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_da7219_driver = {
+	.probe = avs_da7219_probe,
+	.driver = {
+		.name = "avs_da7219",
+		.pm = &snd_soc_pm_ops,
+	},
+};
+
+module_platform_driver(avs_da7219_driver);
+
+MODULE_AUTHOR("Cezary Rojewski <cezary.rojewski@intel.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_da7219");
-- 
2.25.1


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

* Re: [PATCH 02/14] ASoC: codecs: Add HD-Audio codec driver
  2022-04-27  8:18 ` [PATCH 02/14] ASoC: codecs: Add HD-Audio codec driver Cezary Rojewski
@ 2022-04-27 15:47   ` Pierre-Louis Bossart
  2022-05-06 13:12     ` Mark Brown
  0 siblings, 1 reply; 25+ messages in thread
From: Pierre-Louis Bossart @ 2022-04-27 15:47 UTC (permalink / raw)
  To: Cezary Rojewski, alsa-devel, broonie
  Cc: upstream, Kai Vehmanen, harshapriya.n, rad, tiwai, hdegoede,
	amadeuszx.slawinski, cujomalainey, lma



On 4/27/22 03:18, Cezary Rojewski wrote:
> Add generic ASoC equivalent of ALSA HD-Audio codec. This codec is
> designed to follow HDA_DEV_LEGACY convention. Driver wrapps existing
> hda_codec.c handlers to prevent code duplication within the newly added
> code. Number of DAIs created is dependent on capabilities exposed by the
> codec itself. Because of this, single solution can be applied to support
> every single HD-Audio codec type.
> 
> At the same, through the ASoC topology, platform drivers may limit the
> number of endpoints available to the userspace as codec driver exposes
> BE DAIs only.
> 
> Both hda_codec_probe() and hda_codec_remove() declare their expectations
> on device's usage_count and suspended-status. This is to catch any
> unexpected behavior as PM-related code for HD-Audio has been changing
> quite a bit throughout the years.
> 
> In order for codec DAI list to reflect its actual PCM capabilities, PCMs
> need to be built and that can only happen once codec device is
> constructed. To do that, a valid component->card->snd_card pointer is
> needed. Said pointer will be provided by the framework once all card
> components are accounted for and their probing can begin. Usage of
> "binder" BE DAI solves the problem - codec can be listed as one of
> HD-Audio card components without declaring any actual BE DAIs
> statically.

I am surprised the explanations don't even mention the existence of hdac_hda.c

/*

 * hdac_hda.c - ASoC extensions to reuse the legacy HDA codec drivers

 * with ASoC platform drivers. These APIs are called by the legacy HDA

 * codec drivers using hdac_ext_bus_ops ops.

 */


I thought the series was about adding machine drivers, but this also adds code on the sound/soc/codecs/ side which I didn't see coming.

I am not qualified to review this part of the code, I just wonder about duplication of functionality.

At the very least an explanation on why you decided to NOT use hdac_hda.c would be useful to reviewers and maintainers.

Thanks.


> 
> Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
> ---
>  sound/soc/codecs/Kconfig   |   5 +
>  sound/soc/codecs/Makefile  |   2 +
>  sound/soc/codecs/hda-dai.c | 102 ++++++++++
>  sound/soc/codecs/hda.c     | 395 +++++++++++++++++++++++++++++++++++++
>  sound/soc/codecs/hda.h     |  19 ++
>  5 files changed, 523 insertions(+)
>  create mode 100644 sound/soc/codecs/hda-dai.c
>  create mode 100644 sound/soc/codecs/hda.c
>  create mode 100644 sound/soc/codecs/hda.h
> 
> diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
> index b106e5517090..23fdbf97e453 100644
> --- a/sound/soc/codecs/Kconfig
> +++ b/sound/soc/codecs/Kconfig
> @@ -937,6 +937,11 @@ config SND_SOC_HDAC_HDA
>  	tristate
>  	select SND_HDA
>  
> +config SND_SOC_HDA
> +	tristate "HD-Audio codec driver"
> +	select SND_HDA_EXT_CORE
> +	select SND_HDA
> +
>  config SND_SOC_ICS43432
>  	tristate "ICS43423 and compatible i2s microphones"
>  
> diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
> index 28dc4edfd01f..d32026ae326f 100644
> --- a/sound/soc/codecs/Makefile
> +++ b/sound/soc/codecs/Makefile
> @@ -106,6 +106,7 @@ snd-soc-es8328-spi-objs := es8328-spi.o
>  snd-soc-gtm601-objs := gtm601.o
>  snd-soc-hdac-hdmi-objs := hdac_hdmi.o
>  snd-soc-hdac-hda-objs := hdac_hda.o
> +snd-soc-hda-codec-objs := hda.o hda-dai.o
>  snd-soc-ics43432-objs := ics43432.o
>  snd-soc-inno-rk3036-objs := inno_rk3036.o
>  snd-soc-isabelle-objs := isabelle.o
> @@ -458,6 +459,7 @@ obj-$(CONFIG_SND_SOC_ES8328_SPI)+= snd-soc-es8328-spi.o
>  obj-$(CONFIG_SND_SOC_GTM601)    += snd-soc-gtm601.o
>  obj-$(CONFIG_SND_SOC_HDAC_HDMI) += snd-soc-hdac-hdmi.o
>  obj-$(CONFIG_SND_SOC_HDAC_HDA) += snd-soc-hdac-hda.o
> +obj-$(CONFIG_SND_SOC_HDA) += snd-soc-hda-codec.o
>  obj-$(CONFIG_SND_SOC_ICS43432)	+= snd-soc-ics43432.o
>  obj-$(CONFIG_SND_SOC_INNO_RK3036)	+= snd-soc-inno-rk3036.o
>  obj-$(CONFIG_SND_SOC_ISABELLE)	+= snd-soc-isabelle.o
> diff --git a/sound/soc/codecs/hda-dai.c b/sound/soc/codecs/hda-dai.c
> new file mode 100644
> index 000000000000..5371ff086261
> --- /dev/null
> +++ b/sound/soc/codecs/hda-dai.c
> @@ -0,0 +1,102 @@
> +// SPDX-License-Identifier: GPL-2.0
> +//
> +// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
> +//
> +// Author: Cezary Rojewski <cezary.rojewski@intel.com>
> +//
> +
> +#include <sound/soc.h>
> +#include <sound/hda_codec.h>
> +#include "hda.h"
> +
> +static int hda_codec_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
> +{
> +	struct hda_pcm_stream *stream_info;
> +	struct hda_codec *codec;
> +	struct hda_pcm *pcm;
> +	int ret;
> +
> +	codec = dev_to_hda_codec(dai->dev);
> +	stream_info = snd_soc_dai_get_dma_data(dai, substream);
> +	pcm = container_of(stream_info, struct hda_pcm, stream[substream->stream]);
> +
> +	dev_dbg(dai->dev, "open stream codec: %08x, info: %p, pcm: %p %s substream: %p\n",
> +		codec->core.vendor_id, stream_info, pcm, pcm->name, substream);
> +
> +	snd_hda_codec_pcm_get(pcm);
> +
> +	ret = stream_info->ops.open(stream_info, codec, substream);
> +	if (ret < 0) {
> +		dev_err(dai->dev, "codec open failed: %d\n", ret);
> +		snd_hda_codec_pcm_put(pcm);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static void hda_codec_dai_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
> +{
> +	struct hda_pcm_stream *stream_info;
> +	struct hda_codec *codec;
> +	struct hda_pcm *pcm;
> +	int ret;
> +
> +	codec = dev_to_hda_codec(dai->dev);
> +	stream_info = snd_soc_dai_get_dma_data(dai, substream);
> +	pcm = container_of(stream_info, struct hda_pcm, stream[substream->stream]);
> +
> +	dev_dbg(dai->dev, "close stream codec: %08x, info: %p, pcm: %p %s substream: %p\n",
> +		codec->core.vendor_id, stream_info, pcm, pcm->name, substream);
> +
> +	ret = stream_info->ops.close(stream_info, codec, substream);
> +	if (ret < 0)
> +		dev_err(dai->dev, "codec close failed: %d\n", ret);
> +
> +	snd_hda_codec_pcm_put(pcm);
> +}
> +
> +static int hda_codec_dai_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
> +{
> +	struct hda_pcm_stream *stream_info;
> +	struct hda_codec *codec;
> +
> +	codec = dev_to_hda_codec(dai->dev);
> +	stream_info = snd_soc_dai_get_dma_data(dai, substream);
> +
> +	snd_hda_codec_cleanup(codec, stream_info, substream);
> +
> +	return 0;
> +}
> +
> +static int hda_codec_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
> +{
> +	struct snd_pcm_runtime *runtime = substream->runtime;
> +	struct hda_pcm_stream *stream_info;
> +	struct hdac_stream *stream;
> +	struct hda_codec *codec;
> +	unsigned int format;
> +	int ret;
> +
> +	codec = dev_to_hda_codec(dai->dev);
> +	stream = substream->runtime->private_data;
> +	stream_info = snd_soc_dai_get_dma_data(dai, substream);
> +	format = snd_hdac_calc_stream_format(runtime->rate, runtime->channels, runtime->format,
> +					     runtime->sample_bits, 0);
> +
> +	ret = snd_hda_codec_prepare(codec, stream_info, stream->stream_tag, format, substream);
> +	if (ret < 0) {
> +		dev_err(dai->dev, "codec prepare failed: %d\n", ret);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +const struct snd_soc_dai_ops snd_soc_hda_codec_dai_ops = {
> +	.startup = hda_codec_dai_startup,
> +	.shutdown = hda_codec_dai_shutdown,
> +	.hw_free = hda_codec_dai_hw_free,
> +	.prepare = hda_codec_dai_prepare,
> +};
> +EXPORT_SYMBOL_GPL(snd_soc_hda_codec_dai_ops);
> diff --git a/sound/soc/codecs/hda.c b/sound/soc/codecs/hda.c
> new file mode 100644
> index 000000000000..edcb8bc6806b
> --- /dev/null
> +++ b/sound/soc/codecs/hda.c
> @@ -0,0 +1,395 @@
> +// SPDX-License-Identifier: GPL-2.0
> +//
> +// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
> +//
> +// Author: Cezary Rojewski <cezary.rojewski@intel.com>
> +//
> +
> +#include <linux/module.h>
> +#include <linux/pm_runtime.h>
> +#include <sound/soc.h>
> +#include <sound/hdaudio_ext.h>
> +#include <sound/hda_i915.h>
> +#include <sound/hda_codec.h>
> +#include "hda.h"
> +
> +static int hda_codec_create_dais(struct hda_codec *codec, int pcm_count,
> +				 struct snd_soc_dai_driver **drivers)
> +{
> +	struct device *dev = &codec->core.dev;
> +	struct snd_soc_dai_driver *drvs;
> +	struct hda_pcm *pcm;
> +	int i;
> +
> +	drvs = devm_kcalloc(dev, pcm_count, sizeof(*drvs), GFP_KERNEL);
> +	if (!drvs)
> +		return -ENOMEM;
> +
> +	pcm = list_first_entry(&codec->pcm_list_head, struct hda_pcm, list);
> +
> +	for (i = 0; i < pcm_count; i++, pcm = list_next_entry(pcm, list)) {
> +		struct snd_soc_pcm_stream *stream;
> +		int dir;
> +
> +		dev_info(dev, "creating for %s %d\n", pcm->name, i);
> +		drvs[i].id = i;
> +		drvs[i].name = pcm->name;
> +		drvs[i].ops = &snd_soc_hda_codec_dai_ops;
> +
> +		dir = SNDRV_PCM_STREAM_PLAYBACK;
> +		stream = &drvs[i].playback;
> +		if (!pcm->stream[dir].substreams) {
> +			dev_info(dev, "skipping playback dai for %s\n", pcm->name);
> +			goto capture_dais;
> +		}
> +
> +		stream->stream_name =
> +			devm_kasprintf(dev, GFP_KERNEL, "%s %s", pcm->name,
> +				       snd_pcm_direction_name(dir));
> +		if (!stream->stream_name)
> +			return -ENOMEM;
> +		stream->channels_min = pcm->stream[dir].channels_min;
> +		stream->channels_max = pcm->stream[dir].channels_max;
> +		stream->rates = pcm->stream[dir].rates;
> +		stream->formats = pcm->stream[dir].formats;
> +		stream->sig_bits = pcm->stream[dir].maxbps;
> +
> +capture_dais:
> +		dir = SNDRV_PCM_STREAM_CAPTURE;
> +		stream = &drvs[i].capture;
> +		if (!pcm->stream[dir].substreams) {
> +			dev_info(dev, "skipping capture dai for %s\n", pcm->name);
> +			continue;
> +		}
> +
> +		stream->stream_name =
> +			devm_kasprintf(dev, GFP_KERNEL, "%s %s", pcm->name,
> +				       snd_pcm_direction_name(dir));
> +		if (!stream->stream_name)
> +			return -ENOMEM;
> +		stream->channels_min = pcm->stream[dir].channels_min;
> +		stream->channels_max = pcm->stream[dir].channels_max;
> +		stream->rates = pcm->stream[dir].rates;
> +		stream->formats = pcm->stream[dir].formats;
> +		stream->sig_bits = pcm->stream[dir].maxbps;
> +	}
> +
> +	*drivers = drvs;
> +	return 0;
> +}
> +
> +static int hda_codec_register_dais(struct hda_codec *codec, struct snd_soc_component *component)
> +{
> +	struct snd_soc_dai_driver *drvs = NULL;
> +	struct snd_soc_dapm_context *dapm;
> +	struct hda_pcm *pcm;
> +	int ret, pcm_count = 0;
> +
> +	if (list_empty(&codec->pcm_list_head))
> +		return -EINVAL;
> +	list_for_each_entry(pcm, &codec->pcm_list_head, list)
> +		pcm_count++;
> +
> +	ret = hda_codec_create_dais(codec, pcm_count, &drvs);
> +	if (ret < 0)
> +		return ret;
> +
> +	dapm = snd_soc_component_get_dapm(component);
> +
> +	list_for_each_entry(pcm, &codec->pcm_list_head, list) {
> +		struct snd_soc_dai *dai;
> +
> +		dai = snd_soc_register_dai(component, drvs, false);
> +		if (!dai) {
> +			dev_err(component->dev, "register dai for %s failed\n", pcm->name);
> +			return -EINVAL;
> +		}
> +
> +		ret = snd_soc_dapm_new_dai_widgets(dapm, dai);
> +		if (ret < 0) {
> +			dev_err(component->dev, "create widgets failed: %d\n", ret);
> +			snd_soc_unregister_dai(dai);
> +			return ret;
> +		}
> +
> +		snd_soc_dai_init_dma_data(dai, &pcm->stream[0], &pcm->stream[1]);
> +		drvs++;
> +	}
> +
> +	return 0;
> +}
> +
> +static void hda_codec_unregister_dais(struct hda_codec *codec,
> +				      struct snd_soc_component *component)
> +{
> +	struct snd_soc_dai *dai, *save;
> +	struct hda_pcm *pcm;
> +
> +	for_each_component_dais_safe(component, dai, save) {
> +		list_for_each_entry(pcm, &codec->pcm_list_head, list) {
> +			if (strcmp(dai->driver->name, pcm->name))
> +				continue;
> +
> +			if (dai->playback_widget)
> +				snd_soc_dapm_free_widget(dai->playback_widget);
> +			if (dai->capture_widget)
> +				snd_soc_dapm_free_widget(dai->capture_widget);
> +			snd_soc_unregister_dai(dai);
> +			break;
> +		}
> +	}
> +}
> +
> +int hda_codec_probe_complete(struct hda_codec *codec)
> +{
> +	struct hdac_device *hdev = &codec->core;
> +	struct hdac_bus *bus = hdev->bus;
> +	int ret;
> +
> +	ret = snd_hda_codec_build_controls(codec);
> +	if (ret < 0) {
> +		dev_err(&hdev->dev, "unable to create controls %d\n", ret);
> +		goto out;
> +	}
> +
> +	/* Bus suspended codecs as it does not manage their pm */
> +	pm_runtime_set_active(&hdev->dev);
> +	/* rpm was forbidden in snd_hda_codec_device_new() */
> +	snd_hda_codec_set_power_save(codec, 2000);
> +	snd_hda_codec_register(codec);
> +out:
> +	/* Complement pm_runtime_get_sync(bus) in probe */
> +	pm_runtime_mark_last_busy(bus->dev);
> +	pm_runtime_put_autosuspend(bus->dev);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(hda_codec_probe_complete);
> +
> +/* Expects codec with usage_count=1 and status=suspended */
> +static int hda_codec_probe(struct snd_soc_component *component)
> +{
> +	struct hda_codec *codec = dev_to_hda_codec(component->dev);
> +	struct hdac_device *hdev = &codec->core;
> +	struct hdac_bus *bus = hdev->bus;
> +	struct hdac_ext_link *hlink;
> +	hda_codec_patch_t patch;
> +	int ret;
> +
> +#ifdef CONFIG_PM
> +	WARN_ON(atomic_read(&hdev->dev.power.usage_count) != 1 ||
> +		!pm_runtime_status_suspended(&hdev->dev));
> +#endif
> +
> +	hlink = snd_hdac_ext_bus_link_at(bus, hdev->addr);
> +	if (!hlink) {
> +		dev_err(&hdev->dev, "hdac link not found\n");
> +		return -EIO;
> +	}
> +
> +	pm_runtime_get_sync(bus->dev);
> +	if (hda_codec_is_display(codec))
> +		snd_hdac_display_power(bus, hdev->addr, true);
> +	snd_hdac_ext_bus_link_get(bus, hlink);
> +
> +	ret = snd_hda_codec_device_new(codec->bus, component->card->snd_card, hdev->addr, codec,
> +				       false);
> +	if (ret < 0) {
> +		dev_err(&hdev->dev, "create hda codec failed: %d\n", ret);
> +		goto device_new_err;
> +	}
> +
> +	ret = snd_hda_codec_set_name(codec, codec->preset->name);
> +	if (ret < 0) {
> +		dev_err(&hdev->dev, "name failed %s\n", codec->preset->name);
> +		goto err;
> +	}
> +
> +	ret = snd_hdac_regmap_init(&codec->core);
> +	if (ret < 0) {
> +		dev_err(&hdev->dev, "regmap init failed\n");
> +		goto err;
> +	}
> +
> +	patch = (hda_codec_patch_t)codec->preset->driver_data;
> +	if (!patch) {
> +		dev_err(&hdev->dev, "no patch specified?\n");
> +		ret = -EINVAL;
> +		goto err;
> +	}
> +
> +	ret = patch(codec);
> +	if (ret < 0) {
> +		dev_err(&hdev->dev, "patch failed %d\n", ret);
> +		goto err;
> +	}
> +
> +	/* configure codec for 1:1 PCM:DAI mapping */
> +	codec->mst_no_extra_pcms = 1;
> +
> +	ret = snd_hda_codec_parse_pcms(codec);
> +	if (ret < 0) {
> +		dev_err(&hdev->dev, "unable to map pcms to dai %d\n", ret);
> +		goto parse_pcms_err;
> +	}
> +
> +	ret = hda_codec_register_dais(codec, component);
> +	if (ret < 0) {
> +		dev_err(&hdev->dev, "update dais failed: %d\n", ret);
> +		goto parse_pcms_err;
> +	}
> +
> +	if (!hda_codec_is_display(codec)) {
> +		ret = hda_codec_probe_complete(codec);
> +		if (ret < 0)
> +			goto complete_err;
> +	}
> +
> +	codec->core.lazy_cache = true;
> +
> +	return 0;
> +
> +complete_err:
> +	hda_codec_unregister_dais(codec, component);
> +parse_pcms_err:
> +	if (codec->patch_ops.free)
> +		codec->patch_ops.free(codec);
> +err:
> +	snd_hda_codec_cleanup_for_unbind(codec);
> +device_new_err:
> +	if (hda_codec_is_display(codec))
> +		snd_hdac_display_power(bus, hdev->addr, false);
> +
> +	snd_hdac_ext_bus_link_put(bus, hlink);
> +
> +	pm_runtime_mark_last_busy(bus->dev);
> +	pm_runtime_put_autosuspend(bus->dev);
> +	return ret;
> +}
> +
> +/* Leaves codec with usage_count=1 and status=suspended */
> +static void hda_codec_remove(struct snd_soc_component *component)
> +{
> +	struct hda_codec *codec = dev_to_hda_codec(component->dev);
> +	struct hdac_device *hdev = &codec->core;
> +	struct hdac_bus *bus = hdev->bus;
> +	struct hdac_ext_link *hlink;
> +	bool was_registered = codec->registered;
> +
> +	/* Don't allow any more runtime suspends */
> +	pm_runtime_forbid(&hdev->dev);
> +
> +	hda_codec_unregister_dais(codec, component);
> +
> +	if (codec->patch_ops.free)
> +		codec->patch_ops.free(codec);
> +
> +	snd_hda_codec_cleanup_for_unbind(codec);
> +	pm_runtime_put_noidle(&hdev->dev);
> +	/* snd_hdac_device_exit() is only called on bus remove */
> +	pm_runtime_set_suspended(&hdev->dev);
> +
> +	if (hda_codec_is_display(codec))
> +		snd_hdac_display_power(bus, hdev->addr, false);
> +
> +	hlink = snd_hdac_ext_bus_link_at(bus, hdev->addr);
> +	if (hlink)
> +		snd_hdac_ext_bus_link_put(bus, hlink);
> +	/*
> +	 * HDMI card's hda_codec_probe_complete() (see late_probe()) may
> +	 * not be called due to early error, leaving bus uc unbalanced
> +	 */
> +	if (!was_registered) {
> +		pm_runtime_mark_last_busy(bus->dev);
> +		pm_runtime_put_autosuspend(bus->dev);
> +	}
> +
> +#ifdef CONFIG_PM
> +	WARN_ON(atomic_read(&hdev->dev.power.usage_count) != 1 ||
> +		!pm_runtime_status_suspended(&hdev->dev));
> +#endif
> +}
> +
> +static const struct snd_soc_dapm_route hda_dapm_routes[] = {
> +	{"AIF1TX", NULL, "Codec Input Pin1"},
> +	{"AIF2TX", NULL, "Codec Input Pin2"},
> +	{"AIF3TX", NULL, "Codec Input Pin3"},
> +
> +	{"Codec Output Pin1", NULL, "AIF1RX"},
> +	{"Codec Output Pin2", NULL, "AIF2RX"},
> +	{"Codec Output Pin3", NULL, "AIF3RX"},
> +};
> +
> +static const struct snd_soc_dapm_widget hda_dapm_widgets[] = {
> +	/* Audio Interface */
> +	SND_SOC_DAPM_AIF_IN("AIF1RX", "Analog Codec Playback", 0, SND_SOC_NOPM, 0, 0),
> +	SND_SOC_DAPM_AIF_IN("AIF2RX", "Digital Codec Playback", 0, SND_SOC_NOPM, 0, 0),
> +	SND_SOC_DAPM_AIF_IN("AIF3RX", "Alt Analog Codec Playback", 0, SND_SOC_NOPM, 0, 0),
> +	SND_SOC_DAPM_AIF_OUT("AIF1TX", "Analog Codec Capture", 0, SND_SOC_NOPM, 0, 0),
> +	SND_SOC_DAPM_AIF_OUT("AIF2TX", "Digital Codec Capture", 0, SND_SOC_NOPM, 0, 0),
> +	SND_SOC_DAPM_AIF_OUT("AIF3TX", "Alt Analog Codec Capture", 0, SND_SOC_NOPM, 0, 0),
> +
> +	/* Input Pins */
> +	SND_SOC_DAPM_INPUT("Codec Input Pin1"),
> +	SND_SOC_DAPM_INPUT("Codec Input Pin2"),
> +	SND_SOC_DAPM_INPUT("Codec Input Pin3"),
> +
> +	/* Output Pins */
> +	SND_SOC_DAPM_OUTPUT("Codec Output Pin1"),
> +	SND_SOC_DAPM_OUTPUT("Codec Output Pin2"),
> +	SND_SOC_DAPM_OUTPUT("Codec Output Pin3"),
> +};
> +
> +static struct snd_soc_dai_driver card_binder_dai = {
> +	.id = -1,
> +	.name = "codec-probing-DAI",
> +};
> +
> +static int hda_hdev_attach(struct hdac_device *hdev)
> +{
> +	struct hda_codec *codec = dev_to_hda_codec(&hdev->dev);
> +	struct snd_soc_component_driver *comp_drv;
> +
> +	comp_drv = devm_kzalloc(&hdev->dev, sizeof(*comp_drv), GFP_KERNEL);
> +	if (!comp_drv)
> +		return -ENOMEM;
> +
> +	/*
> +	 * It's save to rely on dev_name() rather than a copy as component
> +	 * driver's lifetime is directly tied to hda codec one
> +	 */
> +	comp_drv->name = dev_name(&hdev->dev);
> +	comp_drv->probe = hda_codec_probe;
> +	comp_drv->remove = hda_codec_remove;
> +	comp_drv->idle_bias_on = false;
> +	if (!hda_codec_is_display(codec)) {
> +		comp_drv->dapm_widgets = hda_dapm_widgets;
> +		comp_drv->num_dapm_widgets = ARRAY_SIZE(hda_dapm_widgets);
> +		comp_drv->dapm_routes = hda_dapm_routes;
> +		comp_drv->num_dapm_routes = ARRAY_SIZE(hda_dapm_routes);
> +	}
> +
> +	return snd_soc_register_component(&hdev->dev, comp_drv, &card_binder_dai, 1);
> +}
> +
> +static int hda_hdev_detach(struct hdac_device *hdev)
> +{
> +	struct hda_codec *codec = dev_to_hda_codec(&hdev->dev);
> +
> +	if (codec->registered)
> +		cancel_delayed_work_sync(&codec->jackpoll_work);
> +
> +	snd_soc_unregister_component(&hdev->dev);
> +
> +	return 0;
> +}
> +
> +const struct hdac_ext_bus_ops soc_hda_ext_bus_ops = {
> +	.hdev_attach = hda_hdev_attach,
> +	.hdev_detach = hda_hdev_detach,
> +};
> +EXPORT_SYMBOL_GPL(soc_hda_ext_bus_ops);
> +
> +MODULE_DESCRIPTION("HD-Audio codec driver");
> +MODULE_AUTHOR("Cezary Rojewski <cezary.rojewski@intel.com>");
> +MODULE_LICENSE("GPL");
> diff --git a/sound/soc/codecs/hda.h b/sound/soc/codecs/hda.h
> new file mode 100644
> index 000000000000..78a2be4945b1
> --- /dev/null
> +++ b/sound/soc/codecs/hda.h
> @@ -0,0 +1,19 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
> + *
> + * Author: Cezary Rojewski <cezary.rojewski@intel.com>
> + */
> +
> +#ifndef SND_SOC_CODECS_HDA_H
> +#define SND_SOC_CODECS_HDA_H
> +
> +#define hda_codec_is_display(codec) \
> +	((((codec)->core.vendor_id >> 16) & 0xFFFF) == 0x8086)
> +
> +extern const struct snd_soc_dai_ops snd_soc_hda_codec_dai_ops;
> +
> +extern const struct hdac_ext_bus_ops soc_hda_ext_bus_ops;
> +int hda_codec_probe_complete(struct hda_codec *codec);
> +
> +#endif

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

* Re: [PATCH 02/14] ASoC: codecs: Add HD-Audio codec driver
  2022-04-27 15:47   ` Pierre-Louis Bossart
@ 2022-05-06 13:12     ` Mark Brown
  2022-05-06 13:39       ` Cezary Rojewski
  0 siblings, 1 reply; 25+ messages in thread
From: Mark Brown @ 2022-05-06 13:12 UTC (permalink / raw)
  To: Pierre-Louis Bossart
  Cc: Cezary Rojewski, rad, upstream, Kai Vehmanen, harshapriya.n,
	tiwai, alsa-devel, hdegoede, amadeuszx.slawinski, cujomalainey,
	lma

[-- Attachment #1: Type: text/plain, Size: 938 bytes --]

On Wed, Apr 27, 2022 at 10:47:12AM -0500, Pierre-Louis Bossart wrote:
> On 4/27/22 03:18, Cezary Rojewski wrote:

> > Add generic ASoC equivalent of ALSA HD-Audio codec. This codec is
> > designed to follow HDA_DEV_LEGACY convention. Driver wrapps existing
> > hda_codec.c handlers to prevent code duplication within the newly added

> I am surprised the explanations don't even mention the existence of hdac_hda.c

> I thought the series was about adding machine drivers, but this
> also adds code on the sound/soc/codecs/ side which I didn't see
> coming.

> I am not qualified to review this part of the code, I just
> wonder about duplication of functionality.

> At the very least an explanation on why you decided to NOT use
> hdac_hda.c would be useful to reviewers and maintainers.

Right, why the duplication here?  Can't we fix or extend the
existing code to do whatever it's not currently doing which
compels reimplementation?

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

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

* Re: [PATCH 02/14] ASoC: codecs: Add HD-Audio codec driver
  2022-05-06 13:12     ` Mark Brown
@ 2022-05-06 13:39       ` Cezary Rojewski
  2022-05-06 14:56         ` Pierre-Louis Bossart
  0 siblings, 1 reply; 25+ messages in thread
From: Cezary Rojewski @ 2022-05-06 13:39 UTC (permalink / raw)
  To: Mark Brown, Pierre-Louis Bossart
  Cc: alsa-devel, upstream, Kai Vehmanen, harshapriya.n, rad, tiwai,
	hdegoede, amadeuszx.slawinski, cujomalainey, lma

On 2022-05-06 3:12 PM, Mark Brown wrote:
> On Wed, Apr 27, 2022 at 10:47:12AM -0500, Pierre-Louis Bossart wrote:
>> On 4/27/22 03:18, Cezary Rojewski wrote:
> 
>>> Add generic ASoC equivalent of ALSA HD-Audio codec. This codec is
>>> designed to follow HDA_DEV_LEGACY convention. Driver wrapps existing
>>> hda_codec.c handlers to prevent code duplication within the newly added
> 
>> I am surprised the explanations don't even mention the existence of hdac_hda.c
> 
>> I thought the series was about adding machine drivers, but this
>> also adds code on the sound/soc/codecs/ side which I didn't see
>> coming.
> 
>> I am not qualified to review this part of the code, I just
>> wonder about duplication of functionality.
> 
>> At the very least an explanation on why you decided to NOT use
>> hdac_hda.c would be useful to reviewers and maintainers.
> 
> Right, why the duplication here?  Can't we fix or extend the
> existing code to do whatever it's not currently doing which
> compels reimplementation?

Sorry for the late response, did not realize there is an unanswered 
comment here.

So, the rough list goes as:
- hdac_hda.c hardcodes codec capabilities rather than aligning with what 
sound/pci/hda/ code does
- merges HDMI (i.e. Intel i915 audio component) and HDA DAIs together 
whereas these are two separate devices
- because of above, implements custom search/matching mechanism for PCM/DAI
- cont. because of above, its header hosts private data struct, 
unnecessary complication
- follows HDA_DEV_ASOC convention rather than HDA_DEV_LEGACY causing 
misalignments between sound/pci/hda and sound/soc/ behaviour
- has basic PM runtime support and does not survive scenarios where 
resume/suspend + denylist + rmmod/modprobe are mixed together or invoked 
in unordered fashion between this module and several others in the audio 
stack

My suggestion is different: have all HD-Audio ASoC users switch to this 
implementation when possible and remove the existing code along with 
skylake-driver.


Regards,
Czarek

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

* Re: [PATCH 02/14] ASoC: codecs: Add HD-Audio codec driver
  2022-05-06 13:39       ` Cezary Rojewski
@ 2022-05-06 14:56         ` Pierre-Louis Bossart
  2022-05-06 15:28           ` Cezary Rojewski
  0 siblings, 1 reply; 25+ messages in thread
From: Pierre-Louis Bossart @ 2022-05-06 14:56 UTC (permalink / raw)
  To: Cezary Rojewski, Mark Brown
  Cc: alsa-devel, upstream, Kai Vehmanen, harshapriya.n, rad, tiwai,
	hdegoede, amadeuszx.slawinski, cujomalainey, lma



On 5/6/22 08:39, Cezary Rojewski wrote:
> On 2022-05-06 3:12 PM, Mark Brown wrote:
>> On Wed, Apr 27, 2022 at 10:47:12AM -0500, Pierre-Louis Bossart wrote:
>>> On 4/27/22 03:18, Cezary Rojewski wrote:
>>
>>>> Add generic ASoC equivalent of ALSA HD-Audio codec. This codec is
>>>> designed to follow HDA_DEV_LEGACY convention. Driver wrapps existing
>>>> hda_codec.c handlers to prevent code duplication within the newly added
>>
>>> I am surprised the explanations don't even mention the existence of
>>> hdac_hda.c
>>
>>> I thought the series was about adding machine drivers, but this
>>> also adds code on the sound/soc/codecs/ side which I didn't see
>>> coming.
>>
>>> I am not qualified to review this part of the code, I just
>>> wonder about duplication of functionality.
>>
>>> At the very least an explanation on why you decided to NOT use
>>> hdac_hda.c would be useful to reviewers and maintainers.
>>
>> Right, why the duplication here?  Can't we fix or extend the
>> existing code to do whatever it's not currently doing which
>> compels reimplementation?
> 
> Sorry for the late response, did not realize there is an unanswered
> comment here.
> 
> So, the rough list goes as:
> - hdac_hda.c hardcodes codec capabilities rather than aligning with what
> sound/pci/hda/ code does
> - merges HDMI (i.e. Intel i915 audio component) and HDA DAIs together
> whereas these are two separate devices
> - because of above, implements custom search/matching mechanism for PCM/DAI
> - cont. because of above, its header hosts private data struct,
> unnecessary complication
> - follows HDA_DEV_ASOC convention rather than HDA_DEV_LEGACY causing
> misalignments between sound/pci/hda and sound/soc/ behaviour
> - has basic PM runtime support and does not survive scenarios where
> resume/suspend + denylist + rmmod/modprobe are mixed together or invoked
> in unordered fashion between this module and several others in the audio
> stack
> 
> My suggestion is different: have all HD-Audio ASoC users switch to this
> implementation when possible and remove the existing code along with
> skylake-driver.

I am not against change and will agree that HDaudio support is far from
perfect, but it's been released for multiple generations from dozens of
OEMs and mostly works. All the issues reported to us are related to
codec configurations that also don't work with the legacy HDaudio
driver, DMIC configurations, CSME authentication or system hangs that
have not been root-caused [1]. HDaudio/ASoC interfaces are not on our
radar as problematic.

Disrupting basic HDaudio support to do things better has to be handled
with extreme caution and a ton of testing involving distro maintainers
and community members, so we are talking about an opt-in transition, not
an immediate switch. We've done a similar transition in the past to stop
using a dedicated hdac_hdmi.c codec, see all references to the
'use_common_hdmi' parameter in the SOF code. That transition seems to go
exactly against your second point above on HDMI and HDA being different
devices, so this could be an interesting debate.

Changes to the HDAudio/ASoC support would need to be handled with a
separate patchset anyways, and the SOF side changes done after we are
finished with the IPC4 and MeteorLake upstreaming. No one in our team
has any bandwidth to help with reviews or tests on this topic at the moment.

I will also re-state that the removal of the skylake driver can only
happen after a long period of deprecation, when firmware and topologies
have been picked by distributions and all users are known to have
switched, so it's very likely that any alignment between "all HD-Audio
ASoC users" mentioned above does include the Skylake driver, doesn't it?

So to circle back: is there anything preventing the use of the existing
hdac_hda.c codec in this "ASoC: Intel: avs: Machine boards and HDA codec
support" series and can the HDaudio codec change be done "later" in a
more organized way?

Thanks!
-Pierre

[1]
https://github.com/thesofproject/linux/issues?q=is%3Aissue+is%3Aopen+label%3ACommunity+-label%3A%22codec+ES8336%22

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

* Re: [PATCH 02/14] ASoC: codecs: Add HD-Audio codec driver
  2022-05-06 14:56         ` Pierre-Louis Bossart
@ 2022-05-06 15:28           ` Cezary Rojewski
  2022-05-06 16:17             ` Pierre-Louis Bossart
  0 siblings, 1 reply; 25+ messages in thread
From: Cezary Rojewski @ 2022-05-06 15:28 UTC (permalink / raw)
  To: Pierre-Louis Bossart, Mark Brown
  Cc: alsa-devel, upstream, Kai Vehmanen, harshapriya.n, rad, tiwai,
	hdegoede, amadeuszx.slawinski, cujomalainey, lma

On 2022-05-06 4:56 PM, Pierre-Louis Bossart wrote:
> On 5/6/22 08:39, Cezary Rojewski wrote:

...

>> Sorry for the late response, did not realize there is an unanswered
>> comment here.
>>
>> So, the rough list goes as:
>> - hdac_hda.c hardcodes codec capabilities rather than aligning with what
>> sound/pci/hda/ code does
>> - merges HDMI (i.e. Intel i915 audio component) and HDA DAIs together
>> whereas these are two separate devices
>> - because of above, implements custom search/matching mechanism for PCM/DAI
>> - cont. because of above, its header hosts private data struct,
>> unnecessary complication
>> - follows HDA_DEV_ASOC convention rather than HDA_DEV_LEGACY causing
>> misalignments between sound/pci/hda and sound/soc/ behaviour
>> - has basic PM runtime support and does not survive scenarios where
>> resume/suspend + denylist + rmmod/modprobe are mixed together or invoked
>> in unordered fashion between this module and several others in the audio
>> stack
>>
>> My suggestion is different: have all HD-Audio ASoC users switch to this
>> implementation when possible and remove the existing code along with
>> skylake-driver.
> 
> I am not against change and will agree that HDaudio support is far from
> perfect, but it's been released for multiple generations from dozens of
> OEMs and mostly works. All the issues reported to us are related to
> codec configurations that also don't work with the legacy HDaudio
> driver, DMIC configurations, CSME authentication or system hangs that
> have not been root-caused [1]. HDaudio/ASoC interfaces are not on our
> radar as problematic.


That's why aligning with sound/pci/hda behavior is better for both, ALSA 
and ASoC users -> one place to fix the problems, both clients happy.

> Disrupting basic HDaudio support to do things better has to be handled
> with extreme caution and a ton of testing involving distro maintainers
> and community members, so we are talking about an opt-in transition, not
> an immediate switch. We've done a similar transition in the past to stop
> using a dedicated hdac_hdmi.c codec, see all references to the
> 'use_common_hdmi' parameter in the SOF code. That transition seems to go
> exactly against your second point above on HDMI and HDA being different
> devices, so this could be an interesting debate.
> 
> Changes to the HDAudio/ASoC support would need to be handled with a
> separate patchset anyways, and the SOF side changes done after we are
> finished with the IPC4 and MeteorLake upstreaming. No one in our team
> has any bandwidth to help with reviews or tests on this topic at the moment.


Agree. This won't be forced on anyone and that's why separate 
implementation needed to be provided. There is too much to cover if we 
were to refactor hdac_hda.c

> I will also re-state that the removal of the skylake driver can only
> happen after a long period of deprecation, when firmware and topologies
> have been picked by distributions and all users are known to have
> switched, so it's very likely that any alignment between "all HD-Audio
> ASoC users" mentioned above does include the Skylake driver, doesn't it?


Nah, I don't believe we need to be saving skylake-driver here. By "all 
HD-Audio ASoC users" I meant sof-driver as it isn't going anywhere - 
what cannot be said about the skylake-driver :)

> So to circle back: is there anything preventing the use of the existing
> hdac_hda.c codec in this "ASoC: Intel: avs: Machine boards and HDA codec
> support" series and can the HDaudio codec change be done "later" in a
> more organized way?


Yeah, all the pm scenarios will fail when paired with the avs-driver. 
The expectations are different. We'd have to fix probe() and remove() 
(and related) sequences for the hdac_hda.c, and given that its users did 
not notice prompts further problems with the refactor. This is very 
similar to the skylake-driver vs avs-driver case. We could have applied 
~300 patches we had internally that prepare skylake-driver to be 
re-modeled and then apply patchsets which look more or less like the 
avs-driver series instead of providing a parallel driver.

But the reality shows that such approach applies too much pressure on 
the reviewers and leaves no fallback option for the end users if 
anything fails along the way.


Regards,
Czarek

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

* Re: [PATCH 02/14] ASoC: codecs: Add HD-Audio codec driver
  2022-05-06 15:28           ` Cezary Rojewski
@ 2022-05-06 16:17             ` Pierre-Louis Bossart
  2022-05-09 14:33               ` Kai Vehmanen
  0 siblings, 1 reply; 25+ messages in thread
From: Pierre-Louis Bossart @ 2022-05-06 16:17 UTC (permalink / raw)
  To: Cezary Rojewski, Mark Brown
  Cc: alsa-devel, upstream, Kai Vehmanen, harshapriya.n, rad, tiwai,
	hdegoede, amadeuszx.slawinski, cujomalainey, lma



On 5/6/22 10:28, Cezary Rojewski wrote:
> On 2022-05-06 4:56 PM, Pierre-Louis Bossart wrote:
>> On 5/6/22 08:39, Cezary Rojewski wrote:
> 
> ...
> 
>>> Sorry for the late response, did not realize there is an unanswered
>>> comment here.
>>>
>>> So, the rough list goes as:
>>> - hdac_hda.c hardcodes codec capabilities rather than aligning with what
>>> sound/pci/hda/ code does
>>> - merges HDMI (i.e. Intel i915 audio component) and HDA DAIs together
>>> whereas these are two separate devices
>>> - because of above, implements custom search/matching mechanism for
>>> PCM/DAI
>>> - cont. because of above, its header hosts private data struct,
>>> unnecessary complication
>>> - follows HDA_DEV_ASOC convention rather than HDA_DEV_LEGACY causing
>>> misalignments between sound/pci/hda and sound/soc/ behaviour
>>> - has basic PM runtime support and does not survive scenarios where
>>> resume/suspend + denylist + rmmod/modprobe are mixed together or invoked
>>> in unordered fashion between this module and several others in the audio
>>> stack
>>>
>>> My suggestion is different: have all HD-Audio ASoC users switch to this
>>> implementation when possible and remove the existing code along with
>>> skylake-driver.
>>
>> I am not against change and will agree that HDaudio support is far from
>> perfect, but it's been released for multiple generations from dozens of
>> OEMs and mostly works. All the issues reported to us are related to
>> codec configurations that also don't work with the legacy HDaudio
>> driver, DMIC configurations, CSME authentication or system hangs that
>> have not been root-caused [1]. HDaudio/ASoC interfaces are not on our
>> radar as problematic.
> 
> 
> That's why aligning with sound/pci/hda behavior is better for both, ALSA
> and ASoC users -> one place to fix the problems, both clients happy.
> 
>> Disrupting basic HDaudio support to do things better has to be handled
>> with extreme caution and a ton of testing involving distro maintainers
>> and community members, so we are talking about an opt-in transition, not
>> an immediate switch. We've done a similar transition in the past to stop
>> using a dedicated hdac_hdmi.c codec, see all references to the
>> 'use_common_hdmi' parameter in the SOF code. That transition seems to go
>> exactly against your second point above on HDMI and HDA being different
>> devices, so this could be an interesting debate.
>>
>> Changes to the HDAudio/ASoC support would need to be handled with a
>> separate patchset anyways, and the SOF side changes done after we are
>> finished with the IPC4 and MeteorLake upstreaming. No one in our team
>> has any bandwidth to help with reviews or tests on this topic at the
>> moment.
> 
> 
> Agree. This won't be forced on anyone and that's why separate
> implementation needed to be provided. There is too much to cover if we
> were to refactor hdac_hda.c
> 
>> I will also re-state that the removal of the skylake driver can only
>> happen after a long period of deprecation, when firmware and topologies
>> have been picked by distributions and all users are known to have
>> switched, so it's very likely that any alignment between "all HD-Audio
>> ASoC users" mentioned above does include the Skylake driver, doesn't it?
> 
> 
> Nah, I don't believe we need to be saving skylake-driver here. By "all
> HD-Audio ASoC users" I meant sof-driver as it isn't going anywhere -
> what cannot be said about the skylake-driver :)
> 
>> So to circle back: is there anything preventing the use of the existing
>> hdac_hda.c codec in this "ASoC: Intel: avs: Machine boards and HDA codec
>> support" series and can the HDaudio codec change be done "later" in a
>> more organized way?
> 
> 
> Yeah, all the pm scenarios will fail when paired with the avs-driver.
> The expectations are different. We'd have to fix probe() and remove()
> (and related) sequences for the hdac_hda.c, and given that its users did
> not notice prompts further problems with the refactor. This is very
> similar to the skylake-driver vs avs-driver case. We could have applied
> ~300 patches we had internally that prepare skylake-driver to be
> re-modeled and then apply patchsets which look more or less like the
> avs-driver series instead of providing a parallel driver.
> 
> But the reality shows that such approach applies too much pressure on
> the reviewers and leaves no fallback option for the end users if
> anything fails along the way.

I will stop commenting here to let others chime in, I don't have the
background to provide useful technical feedback on this complicated
HDaudio/ASoC interface.

I am however concerned about the lack of long-term plans and confusion
coming having 3 different ways of dealing with HDaudio codecs on the
same hardware platform (legacy, ASoC/SOF-Skylake, ASoC-AVS). 2 was
already bad, I don't see how 3 is better?

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

* Re: [PATCH 02/14] ASoC: codecs: Add HD-Audio codec driver
  2022-05-06 16:17             ` Pierre-Louis Bossart
@ 2022-05-09 14:33               ` Kai Vehmanen
  2022-05-09 15:55                 ` Pierre-Louis Bossart
  0 siblings, 1 reply; 25+ messages in thread
From: Kai Vehmanen @ 2022-05-09 14:33 UTC (permalink / raw)
  To: Pierre-Louis Bossart, Cezary Rojewski
  Cc: alsa-devel, upstream, Kai Vehmanen, harshapriya.n, rad, tiwai,
	hdegoede, Mark Brown, amadeuszx.slawinski, cujomalainey, lma

Hi,

On Fri, 6 May 2022, Pierre-Louis Bossart wrote:

>>> On 5/6/22 10:28, Cezary Rojewski wrote:
>>>> My suggestion is different: have all HD-Audio ASoC users switch to this
>>>> implementation when possible and remove the existing code along with
>>>> skylake-driver.
[...]
> I am however concerned about the lack of long-term plans and confusion
> coming having 3 different ways of dealing with HDaudio codecs on the
> same hardware platform (legacy, ASoC/SOF-Skylake, ASoC-AVS). 2 was
> already bad, I don't see how 3 is better?

fortunately most of the actual logic is in the codec drivers (in 
sound/pci/hda/), so redundancy in the asoc-to-hda wrappers is not that 
bad.

As a slight correction to the thread, hdac_hda.c does support HDMI and all 
SOF machine drivers transitioned to this a few years back (and dropped 
use of hdac_hdmi.c which is mostly duplicating code in patch_hdmi.c).

In last few years, most of the changes have been to the actual codec 
drivers and we've not really had many fixes to hdac_hda.c anymore (there 
has been a few, and indeed PM related). So in this sense this has worked 
well enough. Patches to fix bugs and add support for new hardware, have 
benefitted all users (DSP and no-DSP) and changes have been only needed at 
a single location. So this is all good.

The fixed DAI capabilities of hdac_hda.c are indeed not ideal (although in 
practise hasn't really been an issue so far) and the approach in the new 
hda.c seems indeed more robust. We do have a lot of existing machine 
drivers (and shipping DSP topologies that we need to keep working), so 
transitioning e.g. SOF machine drivers is not going to be straightforward.
For new mach drivers, this could be considered.

So while not ideal, maybe it makes sense to have two wrappers, hdac_hda.c 
for mach drivers with fixed DAI configuration, and the new hda.c that 
supports dynamic configuration (but requires mach drivers that match 
this). If the old SST driver is deprecated, we can then proceed to remove 
hdac_hdmi.c from the tree, so there's some savings.

Please do add some description to the commit+code+kconfig on how this new 
codec driver relates to hdac_hda. Otherwise it's very confusing to have 
two asoc codec drivers for the same thing.

Br, Kai

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

* Re: [PATCH 02/14] ASoC: codecs: Add HD-Audio codec driver
  2022-05-09 14:33               ` Kai Vehmanen
@ 2022-05-09 15:55                 ` Pierre-Louis Bossart
  2022-05-10  7:36                   ` Cezary Rojewski
  0 siblings, 1 reply; 25+ messages in thread
From: Pierre-Louis Bossart @ 2022-05-09 15:55 UTC (permalink / raw)
  To: Kai Vehmanen, Cezary Rojewski
  Cc: alsa-devel, upstream, harshapriya.n, rad, tiwai, hdegoede,
	Mark Brown, amadeuszx.slawinski, cujomalainey, lma



On 5/9/22 09:33, Kai Vehmanen wrote:
> Hi,
> 
> On Fri, 6 May 2022, Pierre-Louis Bossart wrote:
> 
>>>> On 5/6/22 10:28, Cezary Rojewski wrote:
>>>>> My suggestion is different: have all HD-Audio ASoC users switch to this
>>>>> implementation when possible and remove the existing code along with
>>>>> skylake-driver.
> [...]
>> I am however concerned about the lack of long-term plans and confusion
>> coming having 3 different ways of dealing with HDaudio codecs on the
>> same hardware platform (legacy, ASoC/SOF-Skylake, ASoC-AVS). 2 was
>> already bad, I don't see how 3 is better?
> 
> fortunately most of the actual logic is in the codec drivers (in 
> sound/pci/hda/), so redundancy in the asoc-to-hda wrappers is not that 
> bad.
> 
> As a slight correction to the thread, hdac_hda.c does support HDMI and all 
> SOF machine drivers transitioned to this a few years back (and dropped 
> use of hdac_hdmi.c which is mostly duplicating code in patch_hdmi.c).
> 
> In last few years, most of the changes have been to the actual codec 
> drivers and we've not really had many fixes to hdac_hda.c anymore (there 
> has been a few, and indeed PM related). So in this sense this has worked 
> well enough. Patches to fix bugs and add support for new hardware, have 
> benefitted all users (DSP and no-DSP) and changes have been only needed at 
> a single location. So this is all good.
> 
> The fixed DAI capabilities of hdac_hda.c are indeed not ideal (although in 
> practise hasn't really been an issue so far) and the approach in the new 
> hda.c seems indeed more robust. We do have a lot of existing machine 
> drivers (and shipping DSP topologies that we need to keep working), so 
> transitioning e.g. SOF machine drivers is not going to be straightforward.
> For new mach drivers, this could be considered.

We've just simplified the HDAudio topologies to support the Analog
playback and capture only, for both IPC3 and IPC4 cases, so there's
really no plan to support such dynamic capabilities. I am not even aware
of a single device available in our team where the digital inputs and
outputs are exposed on a connector, so even if we wanted we couldn't
test this dynamic part.

> So while not ideal, maybe it makes sense to have two wrappers, hdac_hda.c 
> for mach drivers with fixed DAI configuration, and the new hda.c that 
> supports dynamic configuration (but requires mach drivers that match 
> this). If the old SST driver is deprecated, we can then proceed to remove 
> hdac_hdmi.c from the tree, so there's some savings.

Such removal isn't going to happen for at least 3+ years, the time it
takes for the slowest distros and users to switch kernels.

that means we're going to have to maintain for the foreseeable future:

hdac_hdmi.c: used only by SST
hdac_hda.c: used by both SST and SOF
hda.c: used only by AVS.



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

* Re: [PATCH 02/14] ASoC: codecs: Add HD-Audio codec driver
  2022-05-09 15:55                 ` Pierre-Louis Bossart
@ 2022-05-10  7:36                   ` Cezary Rojewski
  0 siblings, 0 replies; 25+ messages in thread
From: Cezary Rojewski @ 2022-05-10  7:36 UTC (permalink / raw)
  To: Pierre-Louis Bossart, Kai Vehmanen
  Cc: alsa-devel, upstream, harshapriya.n, rad, tiwai, hdegoede,
	Mark Brown, amadeuszx.slawinski, cujomalainey, lma

On 2022-05-09 5:55 PM, Pierre-Louis Bossart wrote:> On 5/9/22 09:33, Kai 
Vehmanen wrote:

>> The fixed DAI capabilities of hdac_hda.c are indeed not ideal (although in
>> practise hasn't really been an issue so far) and the approach in the new
>> hda.c seems indeed more robust. We do have a lot of existing machine
>> drivers (and shipping DSP topologies that we need to keep working), so
>> transitioning e.g. SOF machine drivers is not going to be straightforward.
>> For new mach drivers, this could be considered.
> 
> We've just simplified the HDAudio topologies to support the Analog
> playback and capture only, for both IPC3 and IPC4 cases, so there's
> really no plan to support such dynamic capabilities. I am not even aware
> of a single device available in our team where the digital inputs and
> outputs are exposed on a connector, so even if we wanted we couldn't
> test this dynamic part.


As I've explained in one of the previous posts, you can always use 
topology to limit the number of FE(s) available while still adhering to 
behavior found in sound/pci/hda. hda.c is a prime example of how ASoC 
HD-Audio can align with ALSA HD-Audio in 1:1 fashion. hdac_hda.c does 
not do that a) because of hardcodes b) following HDA_DEV_ASOC.

Having no behavioral differences is a major gain here, fix one place, 
enjoy both solutions. By 'one place' I mean sound/pci/hda of course as 
there should be no logic outside of that directory.

>> So while not ideal, maybe it makes sense to have two wrappers, hdac_hda.c
>> for mach drivers with fixed DAI configuration, and the new hda.c that
>> supports dynamic configuration (but requires mach drivers that match
>> this). If the old SST driver is deprecated, we can then proceed to remove
>> hdac_hdmi.c from the tree, so there's some savings.
> 
> Such removal isn't going to happen for at least 3+ years, the time it
> takes for the slowest distros and users to switch kernels.
> 
> that means we're going to have to maintain for the foreseeable future:
> 
> hdac_hdmi.c: used only by SST
> hdac_hda.c: used by both SST and SOF
> hda.c: used only by AVS.


I and the team maintained almost all the solutions found in 
sound/soc/intel for couple of years already, doing couple more with the 
old stuff is not a problem. Don't believe 'sit and do nothing' is the 
answer here, not sure if this is even an option - but I'm sure that the 
final effect is going to be worth the initial cost.


Regards,
Czarek

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

* Re: [PATCH 05/14] ASoC: Intel: avs: Add ssp-test machine board
  2022-04-27  8:18 ` [PATCH 05/14] ASoC: Intel: avs: Add ssp-test " Cezary Rojewski
@ 2022-05-10 11:12   ` Cezary Rojewski
  0 siblings, 0 replies; 25+ messages in thread
From: Cezary Rojewski @ 2022-05-10 11:12 UTC (permalink / raw)
  To: alsa-devel, broonie
  Cc: upstream, harshapriya.n, rad, pierre-louis.bossart, tiwai,
	hdegoede, amadeuszx.slawinski, cujomalainey, lma

On 2022-04-27 10:18 AM, Cezary Rojewski wrote:
> Allow for testing audio streaming over I2S interface through SSP-test
> board. No actual codec is needed here as board is intended for SSP
> loopback scenarios only. One playback and one capture endpoint is
> exposed per SSP port.
> 
> Signed-off-by: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
> Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
> ---
>   sound/soc/intel/avs/boards/Kconfig    |   6 +
>   sound/soc/intel/avs/boards/Makefile   |   2 +
>   sound/soc/intel/avs/boards/ssp_test.c | 178 ++++++++++++++++++++++++++
>   3 files changed, 186 insertions(+)
>   create mode 100644 sound/soc/intel/avs/boards/ssp_test.c

I'll send v2 later today that renames this board from ssp_test to 
i2s_test - so it matches naming convention used for all other boards.


Regards,
Czarek

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

end of thread, other threads:[~2022-05-10 11:15 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-04-27  8:18 [PATCH 00/14] ASoC: Intel: avs: Machine boards and HDA codec support Cezary Rojewski
2022-04-27  8:18 ` [PATCH 01/14] ALSA: Add snd_pcm_direction_name() helper Cezary Rojewski
2022-04-27  8:18 ` [PATCH 02/14] ASoC: codecs: Add HD-Audio codec driver Cezary Rojewski
2022-04-27 15:47   ` Pierre-Louis Bossart
2022-05-06 13:12     ` Mark Brown
2022-05-06 13:39       ` Cezary Rojewski
2022-05-06 14:56         ` Pierre-Louis Bossart
2022-05-06 15:28           ` Cezary Rojewski
2022-05-06 16:17             ` Pierre-Louis Bossart
2022-05-09 14:33               ` Kai Vehmanen
2022-05-09 15:55                 ` Pierre-Louis Bossart
2022-05-10  7:36                   ` Cezary Rojewski
2022-04-27  8:18 ` [PATCH 03/14] ASoC: Intel: avs: Add HDAudio machine board Cezary Rojewski
2022-04-27  8:18 ` [PATCH 04/14] ASoC: Intel: avs: Add DMIC " Cezary Rojewski
2022-04-27  8:18 ` [PATCH 05/14] ASoC: Intel: avs: Add ssp-test " Cezary Rojewski
2022-05-10 11:12   ` Cezary Rojewski
2022-04-27  8:18 ` [PATCH 06/14] ASoC: Intel: avs: Add rt274 " Cezary Rojewski
2022-04-27  8:18 ` [PATCH 07/14] ASoC: Intel: avs: Add rt286 " Cezary Rojewski
2022-04-27  8:18 ` [PATCH 08/14] ASoC: Intel: avs: Add rt298 " Cezary Rojewski
2022-04-27  8:18 ` [PATCH 09/14] ASoC: Intel: avs: Add rt5682 " Cezary Rojewski
2022-04-27  8:18 ` [PATCH 10/14] ASoC: Intel: avs: Add nau8825 " Cezary Rojewski
2022-04-27  8:18 ` [PATCH 11/14] ASoC: Intel: avs: Add ssm4567 " Cezary Rojewski
2022-04-27  8:19 ` [PATCH 12/14] ASoC: Intel: avs: Add max98357a " Cezary Rojewski
2022-04-27  8:19 ` [PATCH 13/14] ASoC: Intel: avs: Add max98373 " Cezary Rojewski
2022-04-27  8:19 ` [PATCH 14/14] ASoC: Intel: avs: Add da7219 " Cezary Rojewski

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.