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