162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci//
362306a36Sopenharmony_ci// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
462306a36Sopenharmony_ci//
562306a36Sopenharmony_ci// Author: Cezary Rojewski <cezary.rojewski@intel.com>
662306a36Sopenharmony_ci//
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <sound/soc.h>
962306a36Sopenharmony_ci#include <sound/hda_codec.h>
1062306a36Sopenharmony_ci#include "hda.h"
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_cistatic int hda_codec_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
1362306a36Sopenharmony_ci{
1462306a36Sopenharmony_ci	struct hda_pcm_stream *stream_info;
1562306a36Sopenharmony_ci	struct hda_codec *codec;
1662306a36Sopenharmony_ci	struct hda_pcm *pcm;
1762306a36Sopenharmony_ci	int ret;
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci	codec = dev_to_hda_codec(dai->dev);
2062306a36Sopenharmony_ci	stream_info = snd_soc_dai_get_dma_data(dai, substream);
2162306a36Sopenharmony_ci	pcm = container_of(stream_info, struct hda_pcm, stream[substream->stream]);
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci	dev_dbg(dai->dev, "open stream codec: %08x, info: %p, pcm: %p %s substream: %p\n",
2462306a36Sopenharmony_ci		codec->core.vendor_id, stream_info, pcm, pcm->name, substream);
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci	snd_hda_codec_pcm_get(pcm);
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci	ret = stream_info->ops.open(stream_info, codec, substream);
2962306a36Sopenharmony_ci	if (ret < 0) {
3062306a36Sopenharmony_ci		dev_err(dai->dev, "codec open failed: %d\n", ret);
3162306a36Sopenharmony_ci		snd_hda_codec_pcm_put(pcm);
3262306a36Sopenharmony_ci		return ret;
3362306a36Sopenharmony_ci	}
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	return 0;
3662306a36Sopenharmony_ci}
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_cistatic void hda_codec_dai_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
3962306a36Sopenharmony_ci{
4062306a36Sopenharmony_ci	struct hda_pcm_stream *stream_info;
4162306a36Sopenharmony_ci	struct hda_codec *codec;
4262306a36Sopenharmony_ci	struct hda_pcm *pcm;
4362306a36Sopenharmony_ci	int ret;
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	codec = dev_to_hda_codec(dai->dev);
4662306a36Sopenharmony_ci	stream_info = snd_soc_dai_get_dma_data(dai, substream);
4762306a36Sopenharmony_ci	pcm = container_of(stream_info, struct hda_pcm, stream[substream->stream]);
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	dev_dbg(dai->dev, "close stream codec: %08x, info: %p, pcm: %p %s substream: %p\n",
5062306a36Sopenharmony_ci		codec->core.vendor_id, stream_info, pcm, pcm->name, substream);
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	ret = stream_info->ops.close(stream_info, codec, substream);
5362306a36Sopenharmony_ci	if (ret < 0)
5462306a36Sopenharmony_ci		dev_err(dai->dev, "codec close failed: %d\n", ret);
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	snd_hda_codec_pcm_put(pcm);
5762306a36Sopenharmony_ci}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistatic int hda_codec_dai_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	struct hda_pcm_stream *stream_info;
6262306a36Sopenharmony_ci	struct hda_codec *codec;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	codec = dev_to_hda_codec(dai->dev);
6562306a36Sopenharmony_ci	stream_info = snd_soc_dai_get_dma_data(dai, substream);
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	snd_hda_codec_cleanup(codec, stream_info, substream);
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	return 0;
7062306a36Sopenharmony_ci}
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_cistatic int hda_codec_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
7362306a36Sopenharmony_ci{
7462306a36Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
7562306a36Sopenharmony_ci	struct hda_pcm_stream *stream_info;
7662306a36Sopenharmony_ci	struct hdac_stream *stream;
7762306a36Sopenharmony_ci	struct hda_codec *codec;
7862306a36Sopenharmony_ci	unsigned int format;
7962306a36Sopenharmony_ci	int ret;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	codec = dev_to_hda_codec(dai->dev);
8262306a36Sopenharmony_ci	stream = substream->runtime->private_data;
8362306a36Sopenharmony_ci	stream_info = snd_soc_dai_get_dma_data(dai, substream);
8462306a36Sopenharmony_ci	format = snd_hdac_calc_stream_format(runtime->rate, runtime->channels, runtime->format,
8562306a36Sopenharmony_ci					     runtime->sample_bits, 0);
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	ret = snd_hda_codec_prepare(codec, stream_info, stream->stream_tag, format, substream);
8862306a36Sopenharmony_ci	if (ret < 0) {
8962306a36Sopenharmony_ci		dev_err(dai->dev, "codec prepare failed: %d\n", ret);
9062306a36Sopenharmony_ci		return ret;
9162306a36Sopenharmony_ci	}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	return 0;
9462306a36Sopenharmony_ci}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ciconst struct snd_soc_dai_ops snd_soc_hda_codec_dai_ops = {
9762306a36Sopenharmony_ci	.startup = hda_codec_dai_startup,
9862306a36Sopenharmony_ci	.shutdown = hda_codec_dai_shutdown,
9962306a36Sopenharmony_ci	.hw_free = hda_codec_dai_hw_free,
10062306a36Sopenharmony_ci	.prepare = hda_codec_dai_prepare,
10162306a36Sopenharmony_ci};
10262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_hda_codec_dai_ops);
103