summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCezary Rojewski <cezary.rojewski@intel.com>2023-09-26 10:06:21 +0200
committerTakashi Iwai <tiwai@suse.de>2023-10-06 11:11:39 +0200
commit88320b74ef95b678e2e1d091c5220589facab185 (patch)
treecf89da1e25a00deeebfd4ae9f1f55a3729c89749
parent2ee2c75c589acff83e987abfa74b6d81d237d92f (diff)
ALSA: hda: Introduce HOST stream setup mechanism
HDAudio stream setup procedure differs between revisions of the controller device. Currently the differences are handled directly within AudioDSP platform drivers with if-statements. Implement a more generic approach and expose a function that a platform driver may use to ensure the correct procedure is followed each time. Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com> Link: https://lore.kernel.org/r/20230926080623.43927-3-cezary.rojewski@intel.com Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r--include/sound/hdaudio_ext.h3
-rw-r--r--sound/hda/ext/hdac_ext_stream.c41
2 files changed, 44 insertions, 0 deletions
diff --git a/include/sound/hdaudio_ext.h b/include/sound/hdaudio_ext.h
index 511211f4a2b6..d32959cb71d2 100644
--- a/include/sound/hdaudio_ext.h
+++ b/include/sound/hdaudio_ext.h
@@ -60,6 +60,8 @@ struct hdac_ext_stream {
bool link_locked:1;
bool link_prepared;
+ int (*host_setup)(struct hdac_stream *);
+
struct snd_pcm_substream *link_substream;
};
@@ -86,6 +88,7 @@ void snd_hdac_ext_stream_start(struct hdac_ext_stream *hext_stream);
void snd_hdac_ext_stream_clear(struct hdac_ext_stream *hext_stream);
void snd_hdac_ext_stream_reset(struct hdac_ext_stream *hext_stream);
int snd_hdac_ext_stream_setup(struct hdac_ext_stream *hext_stream, int fmt);
+int snd_hdac_ext_host_stream_setup(struct hdac_ext_stream *hext_stream);
struct hdac_ext_link {
struct hdac_bus *bus;
diff --git a/sound/hda/ext/hdac_ext_stream.c b/sound/hda/ext/hdac_ext_stream.c
index 11b7119cc47e..186e95bffb28 100644
--- a/sound/hda/ext/hdac_ext_stream.c
+++ b/sound/hda/ext/hdac_ext_stream.c
@@ -10,6 +10,8 @@
*/
#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
#include <linux/slab.h>
#include <sound/pcm.h>
#include <sound/hda_register.h>
@@ -17,6 +19,37 @@
#include <sound/compress_driver.h>
/**
+ * snd_hdac_ext_host_stream_setup - Setup a HOST stream.
+ * @hext_stream: HDAudio stream to set up.
+ *
+ * Return: Zero on success or negative error code.
+ */
+int snd_hdac_ext_host_stream_setup(struct hdac_ext_stream *hext_stream)
+{
+ return hext_stream->host_setup(hdac_stream(hext_stream));
+}
+EXPORT_SYMBOL_GPL(snd_hdac_ext_host_stream_setup);
+
+/**
+ * snd_hdac_apl_host_stream_setup - Setup a HOST stream following procedure
+ * recommended for ApolloLake devices.
+ * @hstream: HDAudio stream to set up.
+ *
+ * Return: Zero on success or negative error code.
+ */
+static int snd_hdac_apl_host_stream_setup(struct hdac_stream *hstream)
+{
+ struct hdac_ext_stream *hext_stream = stream_to_hdac_ext_stream(hstream);
+ int ret;
+
+ snd_hdac_ext_stream_decouple(hstream->bus, hext_stream, false);
+ ret = snd_hdac_stream_setup(hstream);
+ snd_hdac_ext_stream_decouple(hstream->bus, hext_stream, true);
+
+ return ret;
+}
+
+/**
* snd_hdac_ext_stream_init - initialize each stream (aka device)
* @bus: HD-audio core bus
* @hext_stream: HD-audio ext core stream object to initialize
@@ -55,9 +88,16 @@ static void snd_hdac_ext_stream_init(struct hdac_bus *bus,
int snd_hdac_ext_stream_init_all(struct hdac_bus *bus, int start_idx,
int num_stream, int dir)
{
+ struct pci_dev *pci = to_pci_dev(bus->dev);
+ int (*setup_op)(struct hdac_stream *);
int stream_tag = 0;
int i, tag, idx = start_idx;
+ if (pci->device == PCI_DEVICE_ID_INTEL_HDA_APL)
+ setup_op = snd_hdac_apl_host_stream_setup;
+ else
+ setup_op = snd_hdac_stream_setup;
+
for (i = 0; i < num_stream; i++) {
struct hdac_ext_stream *hext_stream =
kzalloc(sizeof(*hext_stream), GFP_KERNEL);
@@ -66,6 +106,7 @@ int snd_hdac_ext_stream_init_all(struct hdac_bus *bus, int start_idx,
tag = ++stream_tag;
snd_hdac_ext_stream_init(bus, hext_stream, idx, dir, tag);
idx++;
+ hext_stream->host_setup = setup_op;
}
return 0;