1 // SPDX-License-Identifier: GPL-2.0 1 // SPDX-License-Identifier: GPL-2.0 2 // 2 // 3 // soc-link.c 3 // soc-link.c 4 // 4 // 5 // Copyright (C) 2019 Renesas Electronics Corp 5 // Copyright (C) 2019 Renesas Electronics Corp. 6 // Kuninori Morimoto <kuninori.morimoto.gx@ren 6 // Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> 7 // 7 // 8 #include <sound/soc.h> 8 #include <sound/soc.h> 9 #include <sound/soc-link.h> 9 #include <sound/soc-link.h> 10 10 11 #define soc_link_ret(rtd, ret) _soc_link_ret(r 11 #define soc_link_ret(rtd, ret) _soc_link_ret(rtd, __func__, ret) 12 static inline int _soc_link_ret(struct snd_soc 12 static inline int _soc_link_ret(struct snd_soc_pcm_runtime *rtd, 13 const char *fu 13 const char *func, int ret) 14 { 14 { 15 /* Positive, Zero values are not error 15 /* Positive, Zero values are not errors */ 16 if (ret >= 0) 16 if (ret >= 0) 17 return ret; 17 return ret; 18 18 19 /* Negative values might be errors */ 19 /* Negative values might be errors */ 20 switch (ret) { 20 switch (ret) { 21 case -EPROBE_DEFER: 21 case -EPROBE_DEFER: 22 case -ENOTSUPP: 22 case -ENOTSUPP: 23 break; 23 break; 24 default: 24 default: 25 dev_err(rtd->dev, 25 dev_err(rtd->dev, 26 "ASoC: error at %s on 26 "ASoC: error at %s on %s: %d\n", 27 func, rtd->dai_link->n 27 func, rtd->dai_link->name, ret); 28 } 28 } 29 29 30 return ret; 30 return ret; 31 } 31 } 32 32 33 /* 33 /* 34 * We might want to check substream by using l 34 * We might want to check substream by using list. 35 * In such case, we can update these macros. 35 * In such case, we can update these macros. 36 */ 36 */ 37 #define soc_link_mark_push(rtd, substream, tgt 37 #define soc_link_mark_push(rtd, substream, tgt) ((rtd)->mark_##tgt = substream) 38 #define soc_link_mark_pop(rtd, substream, tgt) 38 #define soc_link_mark_pop(rtd, substream, tgt) ((rtd)->mark_##tgt = NULL) 39 #define soc_link_mark_match(rtd, substream, tg 39 #define soc_link_mark_match(rtd, substream, tgt) ((rtd)->mark_##tgt == substream) 40 40 41 int snd_soc_link_init(struct snd_soc_pcm_runti 41 int snd_soc_link_init(struct snd_soc_pcm_runtime *rtd) 42 { 42 { 43 int ret = 0; 43 int ret = 0; 44 44 45 if (rtd->dai_link->init) 45 if (rtd->dai_link->init) 46 ret = rtd->dai_link->init(rtd) 46 ret = rtd->dai_link->init(rtd); 47 47 48 return soc_link_ret(rtd, ret); 48 return soc_link_ret(rtd, ret); 49 } 49 } 50 50 51 void snd_soc_link_exit(struct snd_soc_pcm_runt 51 void snd_soc_link_exit(struct snd_soc_pcm_runtime *rtd) 52 { 52 { 53 if (rtd->dai_link->exit) 53 if (rtd->dai_link->exit) 54 rtd->dai_link->exit(rtd); 54 rtd->dai_link->exit(rtd); 55 } 55 } 56 56 57 int snd_soc_link_be_hw_params_fixup(struct snd 57 int snd_soc_link_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, 58 struct snd 58 struct snd_pcm_hw_params *params) 59 { 59 { 60 int ret = 0; 60 int ret = 0; 61 61 62 if (rtd->dai_link->be_hw_params_fixup) 62 if (rtd->dai_link->be_hw_params_fixup) 63 ret = rtd->dai_link->be_hw_par 63 ret = rtd->dai_link->be_hw_params_fixup(rtd, params); 64 64 65 return soc_link_ret(rtd, ret); 65 return soc_link_ret(rtd, ret); 66 } 66 } 67 67 68 int snd_soc_link_startup(struct snd_pcm_substr 68 int snd_soc_link_startup(struct snd_pcm_substream *substream) 69 { 69 { 70 struct snd_soc_pcm_runtime *rtd = snd_ !! 70 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 71 int ret = 0; 71 int ret = 0; 72 72 73 if (rtd->dai_link->ops && 73 if (rtd->dai_link->ops && 74 rtd->dai_link->ops->startup) 74 rtd->dai_link->ops->startup) 75 ret = rtd->dai_link->ops->star 75 ret = rtd->dai_link->ops->startup(substream); 76 76 77 /* mark substream if succeeded */ 77 /* mark substream if succeeded */ 78 if (ret == 0) 78 if (ret == 0) 79 soc_link_mark_push(rtd, substr 79 soc_link_mark_push(rtd, substream, startup); 80 80 81 return soc_link_ret(rtd, ret); 81 return soc_link_ret(rtd, ret); 82 } 82 } 83 83 84 void snd_soc_link_shutdown(struct snd_pcm_subs 84 void snd_soc_link_shutdown(struct snd_pcm_substream *substream, 85 int rollback) 85 int rollback) 86 { 86 { 87 struct snd_soc_pcm_runtime *rtd = snd_ !! 87 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 88 88 89 if (rollback && !soc_link_mark_match(r 89 if (rollback && !soc_link_mark_match(rtd, substream, startup)) 90 return; 90 return; 91 91 92 if (rtd->dai_link->ops && 92 if (rtd->dai_link->ops && 93 rtd->dai_link->ops->shutdown) 93 rtd->dai_link->ops->shutdown) 94 rtd->dai_link->ops->shutdown(s 94 rtd->dai_link->ops->shutdown(substream); 95 95 96 /* remove marked substream */ 96 /* remove marked substream */ 97 soc_link_mark_pop(rtd, substream, star 97 soc_link_mark_pop(rtd, substream, startup); 98 } 98 } 99 99 100 int snd_soc_link_prepare(struct snd_pcm_substr 100 int snd_soc_link_prepare(struct snd_pcm_substream *substream) 101 { 101 { 102 struct snd_soc_pcm_runtime *rtd = snd_ !! 102 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 103 int ret = 0; 103 int ret = 0; 104 104 105 if (rtd->dai_link->ops && 105 if (rtd->dai_link->ops && 106 rtd->dai_link->ops->prepare) 106 rtd->dai_link->ops->prepare) 107 ret = rtd->dai_link->ops->prep 107 ret = rtd->dai_link->ops->prepare(substream); 108 108 109 return soc_link_ret(rtd, ret); 109 return soc_link_ret(rtd, ret); 110 } 110 } 111 111 112 int snd_soc_link_hw_params(struct snd_pcm_subs 112 int snd_soc_link_hw_params(struct snd_pcm_substream *substream, 113 struct snd_pcm_hw_p 113 struct snd_pcm_hw_params *params) 114 { 114 { 115 struct snd_soc_pcm_runtime *rtd = snd_ !! 115 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 116 int ret = 0; 116 int ret = 0; 117 117 118 if (rtd->dai_link->ops && 118 if (rtd->dai_link->ops && 119 rtd->dai_link->ops->hw_params) 119 rtd->dai_link->ops->hw_params) 120 ret = rtd->dai_link->ops->hw_p 120 ret = rtd->dai_link->ops->hw_params(substream, params); 121 121 122 /* mark substream if succeeded */ 122 /* mark substream if succeeded */ 123 if (ret == 0) 123 if (ret == 0) 124 soc_link_mark_push(rtd, substr 124 soc_link_mark_push(rtd, substream, hw_params); 125 125 126 return soc_link_ret(rtd, ret); 126 return soc_link_ret(rtd, ret); 127 } 127 } 128 128 129 void snd_soc_link_hw_free(struct snd_pcm_subst 129 void snd_soc_link_hw_free(struct snd_pcm_substream *substream, int rollback) 130 { 130 { 131 struct snd_soc_pcm_runtime *rtd = snd_ !! 131 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 132 132 133 if (rollback && !soc_link_mark_match(r 133 if (rollback && !soc_link_mark_match(rtd, substream, hw_params)) 134 return; 134 return; 135 135 136 if (rtd->dai_link->ops && 136 if (rtd->dai_link->ops && 137 rtd->dai_link->ops->hw_free) 137 rtd->dai_link->ops->hw_free) 138 rtd->dai_link->ops->hw_free(su 138 rtd->dai_link->ops->hw_free(substream); 139 139 140 /* remove marked substream */ 140 /* remove marked substream */ 141 soc_link_mark_pop(rtd, substream, hw_p 141 soc_link_mark_pop(rtd, substream, hw_params); 142 } 142 } 143 143 144 static int soc_link_trigger(struct snd_pcm_sub 144 static int soc_link_trigger(struct snd_pcm_substream *substream, int cmd) 145 { 145 { 146 struct snd_soc_pcm_runtime *rtd = snd_ !! 146 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 147 int ret = 0; 147 int ret = 0; 148 148 149 if (rtd->dai_link->ops && 149 if (rtd->dai_link->ops && 150 rtd->dai_link->ops->trigger) 150 rtd->dai_link->ops->trigger) 151 ret = rtd->dai_link->ops->trig 151 ret = rtd->dai_link->ops->trigger(substream, cmd); 152 152 153 return soc_link_ret(rtd, ret); 153 return soc_link_ret(rtd, ret); 154 } 154 } 155 155 156 int snd_soc_link_trigger(struct snd_pcm_substr 156 int snd_soc_link_trigger(struct snd_pcm_substream *substream, int cmd, 157 int rollback) 157 int rollback) 158 { 158 { 159 struct snd_soc_pcm_runtime *rtd = snd_ !! 159 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 160 int ret = 0; 160 int ret = 0; 161 161 162 switch (cmd) { 162 switch (cmd) { 163 case SNDRV_PCM_TRIGGER_START: 163 case SNDRV_PCM_TRIGGER_START: 164 case SNDRV_PCM_TRIGGER_RESUME: 164 case SNDRV_PCM_TRIGGER_RESUME: 165 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 165 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 166 ret = soc_link_trigger(substre 166 ret = soc_link_trigger(substream, cmd); 167 if (ret < 0) 167 if (ret < 0) 168 break; 168 break; 169 soc_link_mark_push(rtd, substr 169 soc_link_mark_push(rtd, substream, trigger); 170 break; 170 break; 171 case SNDRV_PCM_TRIGGER_STOP: 171 case SNDRV_PCM_TRIGGER_STOP: 172 case SNDRV_PCM_TRIGGER_SUSPEND: 172 case SNDRV_PCM_TRIGGER_SUSPEND: 173 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 173 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 174 if (rollback && !soc_link_mark 174 if (rollback && !soc_link_mark_match(rtd, substream, trigger)) 175 break; 175 break; 176 176 177 ret = soc_link_trigger(substre 177 ret = soc_link_trigger(substream, cmd); 178 soc_link_mark_pop(rtd, substre 178 soc_link_mark_pop(rtd, substream, startup); 179 } 179 } 180 180 181 return ret; 181 return ret; 182 } 182 } 183 183 184 int snd_soc_link_compr_startup(struct snd_comp 184 int snd_soc_link_compr_startup(struct snd_compr_stream *cstream) 185 { 185 { 186 struct snd_soc_pcm_runtime *rtd = cstr 186 struct snd_soc_pcm_runtime *rtd = cstream->private_data; 187 int ret = 0; 187 int ret = 0; 188 188 189 if (rtd->dai_link->compr_ops && 189 if (rtd->dai_link->compr_ops && 190 rtd->dai_link->compr_ops->startup) 190 rtd->dai_link->compr_ops->startup) 191 ret = rtd->dai_link->compr_ops 191 ret = rtd->dai_link->compr_ops->startup(cstream); 192 192 193 if (ret == 0) 193 if (ret == 0) 194 soc_link_mark_push(rtd, cstrea 194 soc_link_mark_push(rtd, cstream, compr_startup); 195 195 196 return soc_link_ret(rtd, ret); 196 return soc_link_ret(rtd, ret); 197 } 197 } 198 EXPORT_SYMBOL_GPL(snd_soc_link_compr_startup); 198 EXPORT_SYMBOL_GPL(snd_soc_link_compr_startup); 199 199 200 void snd_soc_link_compr_shutdown(struct snd_co 200 void snd_soc_link_compr_shutdown(struct snd_compr_stream *cstream, 201 int rollback) 201 int rollback) 202 { 202 { 203 struct snd_soc_pcm_runtime *rtd = cstr 203 struct snd_soc_pcm_runtime *rtd = cstream->private_data; 204 204 205 if (rollback && !soc_link_mark_match(r 205 if (rollback && !soc_link_mark_match(rtd, cstream, compr_startup)) 206 return; 206 return; 207 207 208 if (rtd->dai_link->compr_ops && 208 if (rtd->dai_link->compr_ops && 209 rtd->dai_link->compr_ops->shutdown 209 rtd->dai_link->compr_ops->shutdown) 210 rtd->dai_link->compr_ops->shut 210 rtd->dai_link->compr_ops->shutdown(cstream); 211 211 212 soc_link_mark_pop(rtd, cstream, compr_ 212 soc_link_mark_pop(rtd, cstream, compr_startup); 213 } 213 } 214 EXPORT_SYMBOL_GPL(snd_soc_link_compr_shutdown) 214 EXPORT_SYMBOL_GPL(snd_soc_link_compr_shutdown); 215 215 216 int snd_soc_link_compr_set_params(struct snd_c 216 int snd_soc_link_compr_set_params(struct snd_compr_stream *cstream) 217 { 217 { 218 struct snd_soc_pcm_runtime *rtd = cstr 218 struct snd_soc_pcm_runtime *rtd = cstream->private_data; 219 int ret = 0; 219 int ret = 0; 220 220 221 if (rtd->dai_link->compr_ops && 221 if (rtd->dai_link->compr_ops && 222 rtd->dai_link->compr_ops->set_para 222 rtd->dai_link->compr_ops->set_params) 223 ret = rtd->dai_link->compr_ops 223 ret = rtd->dai_link->compr_ops->set_params(cstream); 224 224 225 return soc_link_ret(rtd, ret); 225 return soc_link_ret(rtd, ret); 226 } 226 } 227 EXPORT_SYMBOL_GPL(snd_soc_link_compr_set_param 227 EXPORT_SYMBOL_GPL(snd_soc_link_compr_set_params); 228 228
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.