1 // SPDX-License-Identifier: GPL-2.0 2 // 3 // soc-link.c 4 // 5 // Copyright (C) 2019 Renesas Electronics Corp. 6 // Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> 7 // 8 #include <sound/soc.h> 9 #include <sound/soc-link.h> 10 11 #define soc_link_ret(rtd, ret) _soc_link_ret(rtd, __func__, ret) 12 static inline int _soc_link_ret(struct snd_soc_pcm_runtime *rtd, 13 const char *func, int ret) 14 { 15 /* Positive, Zero values are not errors */ 16 if (ret >= 0) 17 return ret; 18 19 /* Negative values might be errors */ 20 switch (ret) { 21 case -EPROBE_DEFER: 22 case -ENOTSUPP: 23 break; 24 default: 25 dev_err(rtd->dev, 26 "ASoC: error at %s on %s: %d\n", 27 func, rtd->dai_link->name, ret); 28 } 29 30 return ret; 31 } 32 33 /* 34 * We might want to check substream by using list. 35 * In such case, we can update these macros. 36 */ 37 #define soc_link_mark_push(rtd, substream, tgt) ((rtd)->mark_##tgt = substream) 38 #define soc_link_mark_pop(rtd, substream, tgt) ((rtd)->mark_##tgt = NULL) 39 #define soc_link_mark_match(rtd, substream, tgt) ((rtd)->mark_##tgt == substream) 40 41 int snd_soc_link_init(struct snd_soc_pcm_runtime *rtd) 42 { 43 int ret = 0; 44 45 if (rtd->dai_link->init) 46 ret = rtd->dai_link->init(rtd); 47 48 return soc_link_ret(rtd, ret); 49 } 50 51 void snd_soc_link_exit(struct snd_soc_pcm_runtime *rtd) 52 { 53 if (rtd->dai_link->exit) 54 rtd->dai_link->exit(rtd); 55 } 56 57 int snd_soc_link_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, 58 struct snd_pcm_hw_params *params) 59 { 60 int ret = 0; 61 62 if (rtd->dai_link->be_hw_params_fixup) 63 ret = rtd->dai_link->be_hw_params_fixup(rtd, params); 64 65 return soc_link_ret(rtd, ret); 66 } 67 68 int snd_soc_link_startup(struct snd_pcm_substream *substream) 69 { 70 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 71 int ret = 0; 72 73 if (rtd->dai_link->ops && 74 rtd->dai_link->ops->startup) 75 ret = rtd->dai_link->ops->startup(substream); 76 77 /* mark substream if succeeded */ 78 if (ret == 0) 79 soc_link_mark_push(rtd, substream, startup); 80 81 return soc_link_ret(rtd, ret); 82 } 83 84 void snd_soc_link_shutdown(struct snd_pcm_substream *substream, 85 int rollback) 86 { 87 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 88 89 if (rollback && !soc_link_mark_match(rtd, substream, startup)) 90 return; 91 92 if (rtd->dai_link->ops && 93 rtd->dai_link->ops->shutdown) 94 rtd->dai_link->ops->shutdown(substream); 95 96 /* remove marked substream */ 97 soc_link_mark_pop(rtd, substream, startup); 98 } 99 100 int snd_soc_link_prepare(struct snd_pcm_substream *substream) 101 { 102 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 103 int ret = 0; 104 105 if (rtd->dai_link->ops && 106 rtd->dai_link->ops->prepare) 107 ret = rtd->dai_link->ops->prepare(substream); 108 109 return soc_link_ret(rtd, ret); 110 } 111 112 int snd_soc_link_hw_params(struct snd_pcm_substream *substream, 113 struct snd_pcm_hw_params *params) 114 { 115 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 116 int ret = 0; 117 118 if (rtd->dai_link->ops && 119 rtd->dai_link->ops->hw_params) 120 ret = rtd->dai_link->ops->hw_params(substream, params); 121 122 return soc_link_ret(rtd, ret); 123 } 124 125 void snd_soc_link_hw_free(struct snd_pcm_substream *substream) 126 { 127 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 128 129 if (rtd->dai_link->ops && 130 rtd->dai_link->ops->hw_free) 131 rtd->dai_link->ops->hw_free(substream); 132 } 133 134 int snd_soc_link_trigger(struct snd_pcm_substream *substream, int cmd) 135 { 136 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 137 int ret = 0; 138 139 if (rtd->dai_link->ops && 140 rtd->dai_link->ops->trigger) 141 ret = rtd->dai_link->ops->trigger(substream, cmd); 142 143 return soc_link_ret(rtd, ret); 144 } 145 146 int snd_soc_link_compr_startup(struct snd_compr_stream *cstream) 147 { 148 struct snd_soc_pcm_runtime *rtd = cstream->private_data; 149 int ret = 0; 150 151 if (rtd->dai_link->compr_ops && 152 rtd->dai_link->compr_ops->startup) 153 ret = rtd->dai_link->compr_ops->startup(cstream); 154 155 return soc_link_ret(rtd, ret); 156 } 157 EXPORT_SYMBOL_GPL(snd_soc_link_compr_startup); 158 159 void snd_soc_link_compr_shutdown(struct snd_compr_stream *cstream) 160 { 161 struct snd_soc_pcm_runtime *rtd = cstream->private_data; 162 163 if (rtd->dai_link->compr_ops && 164 rtd->dai_link->compr_ops->shutdown) 165 rtd->dai_link->compr_ops->shutdown(cstream); 166 } 167 EXPORT_SYMBOL_GPL(snd_soc_link_compr_shutdown); 168 169 int snd_soc_link_compr_set_params(struct snd_compr_stream *cstream) 170 { 171 struct snd_soc_pcm_runtime *rtd = cstream->private_data; 172 int ret = 0; 173 174 if (rtd->dai_link->compr_ops && 175 rtd->dai_link->compr_ops->set_params) 176 ret = rtd->dai_link->compr_ops->set_params(cstream); 177 178 return soc_link_ret(rtd, ret); 179 } 180 EXPORT_SYMBOL_GPL(snd_soc_link_compr_set_params); 181