1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // |
3 | // Copyright(c) 2021-2022 Intel Corporation. All rights reserved. |
4 | // |
5 | // Author: Cezary Rojewski <cezary.rojewski@intel.com> |
6 | // |
7 | |
8 | #include <sound/soc.h> |
9 | #include <sound/hda_codec.h> |
10 | #include "hda.h" |
11 | |
12 | static int hda_codec_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) |
13 | { |
14 | struct hda_pcm_stream *stream_info; |
15 | struct hda_codec *codec; |
16 | struct hda_pcm *pcm; |
17 | int ret; |
18 | |
19 | codec = dev_to_hda_codec(dai->dev); |
20 | stream_info = snd_soc_dai_get_dma_data(dai, substream); |
21 | pcm = container_of(stream_info, struct hda_pcm, stream[substream->stream]); |
22 | |
23 | dev_dbg(dai->dev, "open stream codec: %08x, info: %p, pcm: %p %s substream: %p\n" , |
24 | codec->core.vendor_id, stream_info, pcm, pcm->name, substream); |
25 | |
26 | snd_hda_codec_pcm_get(pcm); |
27 | |
28 | ret = stream_info->ops.open(stream_info, codec, substream); |
29 | if (ret < 0) { |
30 | dev_err(dai->dev, "codec open failed: %d\n" , ret); |
31 | snd_hda_codec_pcm_put(pcm); |
32 | return ret; |
33 | } |
34 | |
35 | return 0; |
36 | } |
37 | |
38 | static void hda_codec_dai_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) |
39 | { |
40 | struct hda_pcm_stream *stream_info; |
41 | struct hda_codec *codec; |
42 | struct hda_pcm *pcm; |
43 | int ret; |
44 | |
45 | codec = dev_to_hda_codec(dai->dev); |
46 | stream_info = snd_soc_dai_get_dma_data(dai, substream); |
47 | pcm = container_of(stream_info, struct hda_pcm, stream[substream->stream]); |
48 | |
49 | dev_dbg(dai->dev, "close stream codec: %08x, info: %p, pcm: %p %s substream: %p\n" , |
50 | codec->core.vendor_id, stream_info, pcm, pcm->name, substream); |
51 | |
52 | ret = stream_info->ops.close(stream_info, codec, substream); |
53 | if (ret < 0) |
54 | dev_err(dai->dev, "codec close failed: %d\n" , ret); |
55 | |
56 | snd_hda_codec_pcm_put(pcm); |
57 | } |
58 | |
59 | static int hda_codec_dai_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) |
60 | { |
61 | struct hda_pcm_stream *stream_info; |
62 | struct hda_codec *codec; |
63 | |
64 | codec = dev_to_hda_codec(dai->dev); |
65 | stream_info = snd_soc_dai_get_dma_data(dai, substream); |
66 | |
67 | snd_hda_codec_cleanup(codec, hinfo: stream_info, substream); |
68 | |
69 | return 0; |
70 | } |
71 | |
72 | static int hda_codec_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) |
73 | { |
74 | struct snd_pcm_runtime *runtime = substream->runtime; |
75 | struct hda_pcm_stream *stream_info; |
76 | struct hdac_stream *stream; |
77 | struct hda_codec *codec; |
78 | unsigned int format; |
79 | unsigned int bits; |
80 | int ret; |
81 | |
82 | codec = dev_to_hda_codec(dai->dev); |
83 | stream = substream->runtime->private_data; |
84 | stream_info = snd_soc_dai_get_dma_data(dai, substream); |
85 | |
86 | bits = snd_hdac_stream_format_bits(format: runtime->format, subformat: runtime->subformat, |
87 | maxbits: stream_info->maxbps); |
88 | format = snd_hdac_stream_format(channels: runtime->channels, bits, rate: runtime->rate); |
89 | |
90 | ret = snd_hda_codec_prepare(codec, hinfo: stream_info, stream: stream->stream_tag, format, substream); |
91 | if (ret < 0) { |
92 | dev_err(dai->dev, "codec prepare failed: %d\n" , ret); |
93 | return ret; |
94 | } |
95 | |
96 | return 0; |
97 | } |
98 | |
99 | const struct snd_soc_dai_ops snd_soc_hda_codec_dai_ops = { |
100 | .startup = hda_codec_dai_startup, |
101 | .shutdown = hda_codec_dai_shutdown, |
102 | .hw_free = hda_codec_dai_hw_free, |
103 | .prepare = hda_codec_dai_prepare, |
104 | }; |
105 | EXPORT_SYMBOL_GPL(snd_soc_hda_codec_dai_ops); |
106 | |