d5c00ab2f5
To provide option for selecting different bit-per-sample than just the maximum one, use the new format calculation mechanism. While at it, complete PCM stream initialization with subformat options. Acked-by: Mark Brown <broonie@kernel.org> Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com> Acked-by: Jaroslav Kysela <perex@perex.cz> Link: https://lore.kernel.org/r/20231117120610.1755254-9-cezary.rojewski@intel.com Signed-off-by: Takashi Iwai <tiwai@suse.de>
106 lines
3.0 KiB
C
106 lines
3.0 KiB
C
// 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;
|
|
unsigned int bits;
|
|
int ret;
|
|
|
|
codec = dev_to_hda_codec(dai->dev);
|
|
stream = substream->runtime->private_data;
|
|
stream_info = snd_soc_dai_get_dma_data(dai, substream);
|
|
|
|
bits = snd_hdac_stream_format_bits(runtime->format, runtime->subformat,
|
|
stream_info->maxbps);
|
|
format = snd_hdac_stream_format(runtime->channels, bits, runtime->rate);
|
|
|
|
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);
|