linux/sound/soc/soc-link.c
<<
>>
Prefs
   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);
 228