soc-link.c (5750B)
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) 12static 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 41int 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 51void 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 57int 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 68int 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 84void 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 100int 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 112int 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 /* mark substream if succeeded */ 123 if (ret == 0) 124 soc_link_mark_push(rtd, substream, hw_params); 125 126 return soc_link_ret(rtd, ret); 127} 128 129void snd_soc_link_hw_free(struct snd_pcm_substream *substream, int rollback) 130{ 131 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 132 133 if (rollback && !soc_link_mark_match(rtd, substream, hw_params)) 134 return; 135 136 if (rtd->dai_link->ops && 137 rtd->dai_link->ops->hw_free) 138 rtd->dai_link->ops->hw_free(substream); 139 140 /* remove marked substream */ 141 soc_link_mark_pop(rtd, substream, hw_params); 142} 143 144static int soc_link_trigger(struct snd_pcm_substream *substream, int cmd) 145{ 146 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 147 int ret = 0; 148 149 if (rtd->dai_link->ops && 150 rtd->dai_link->ops->trigger) 151 ret = rtd->dai_link->ops->trigger(substream, cmd); 152 153 return soc_link_ret(rtd, ret); 154} 155 156int snd_soc_link_trigger(struct snd_pcm_substream *substream, int cmd, 157 int rollback) 158{ 159 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 160 int ret = 0; 161 162 switch (cmd) { 163 case SNDRV_PCM_TRIGGER_START: 164 case SNDRV_PCM_TRIGGER_RESUME: 165 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 166 ret = soc_link_trigger(substream, cmd); 167 if (ret < 0) 168 break; 169 soc_link_mark_push(rtd, substream, trigger); 170 break; 171 case SNDRV_PCM_TRIGGER_STOP: 172 case SNDRV_PCM_TRIGGER_SUSPEND: 173 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 174 if (rollback && !soc_link_mark_match(rtd, substream, trigger)) 175 break; 176 177 ret = soc_link_trigger(substream, cmd); 178 soc_link_mark_pop(rtd, substream, startup); 179 } 180 181 return ret; 182} 183 184int snd_soc_link_compr_startup(struct snd_compr_stream *cstream) 185{ 186 struct snd_soc_pcm_runtime *rtd = cstream->private_data; 187 int ret = 0; 188 189 if (rtd->dai_link->compr_ops && 190 rtd->dai_link->compr_ops->startup) 191 ret = rtd->dai_link->compr_ops->startup(cstream); 192 193 if (ret == 0) 194 soc_link_mark_push(rtd, cstream, compr_startup); 195 196 return soc_link_ret(rtd, ret); 197} 198EXPORT_SYMBOL_GPL(snd_soc_link_compr_startup); 199 200void snd_soc_link_compr_shutdown(struct snd_compr_stream *cstream, 201 int rollback) 202{ 203 struct snd_soc_pcm_runtime *rtd = cstream->private_data; 204 205 if (rollback && !soc_link_mark_match(rtd, cstream, compr_startup)) 206 return; 207 208 if (rtd->dai_link->compr_ops && 209 rtd->dai_link->compr_ops->shutdown) 210 rtd->dai_link->compr_ops->shutdown(cstream); 211 212 soc_link_mark_pop(rtd, cstream, compr_startup); 213} 214EXPORT_SYMBOL_GPL(snd_soc_link_compr_shutdown); 215 216int snd_soc_link_compr_set_params(struct snd_compr_stream *cstream) 217{ 218 struct snd_soc_pcm_runtime *rtd = cstream->private_data; 219 int ret = 0; 220 221 if (rtd->dai_link->compr_ops && 222 rtd->dai_link->compr_ops->set_params) 223 ret = rtd->dai_link->compr_ops->set_params(cstream); 224 225 return soc_link_ret(rtd, ret); 226} 227EXPORT_SYMBOL_GPL(snd_soc_link_compr_set_params);