228 lines · c
1// SPDX-License-Identifier: GPL-2.02//3// soc-link.c4//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 = snd_soc_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 = snd_soc_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 = snd_soc_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 = snd_soc_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 = snd_soc_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 = snd_soc_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 = snd_soc_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);228