forked from Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
102 lines
2.9 KiB
102 lines
2.9 KiB
// SPDX-License-Identifier: GPL-2.0 |
|
// |
|
// Copyright(c) 2021-2022 Intel Corporation. All rights reserved. |
|
// |
|
// Author: Cezary Rojewski <[email protected]> |
|
// |
|
|
|
#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);
|
|
|