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        return snd_soc_ret(rtd->dev, ret,
  16                           "at %s() on %s\n", func, rtd->dai_link->name);
  17}
  18
  19/*
  20 * We might want to check substream by using list.
  21 * In such case, we can update these macros.
  22 */
  23#define soc_link_mark_push(rtd, substream, tgt)         ((rtd)->mark_##tgt = substream)
  24#define soc_link_mark_pop(rtd, tgt)             ((rtd)->mark_##tgt = NULL)
  25#define soc_link_mark_match(rtd, substream, tgt)        ((rtd)->mark_##tgt == substream)
  26
  27int snd_soc_link_init(struct snd_soc_pcm_runtime *rtd)
  28{
  29        int ret = 0;
  30
  31        if (rtd->dai_link->init)
  32                ret = rtd->dai_link->init(rtd);
  33
  34        return soc_link_ret(rtd, ret);
  35}
  36
  37void snd_soc_link_exit(struct snd_soc_pcm_runtime *rtd)
  38{
  39        if (rtd->dai_link->exit)
  40                rtd->dai_link->exit(rtd);
  41}
  42
  43int snd_soc_link_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
  44                                    struct snd_pcm_hw_params *params)
  45{
  46        int ret = 0;
  47
  48        if (rtd->dai_link->be_hw_params_fixup)
  49                ret = rtd->dai_link->be_hw_params_fixup(rtd, params);
  50
  51        return soc_link_ret(rtd, ret);
  52}
  53
  54int snd_soc_link_startup(struct snd_pcm_substream *substream)
  55{
  56        struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
  57        int ret = 0;
  58
  59        if (rtd->dai_link->ops &&
  60            rtd->dai_link->ops->startup)
  61                ret = rtd->dai_link->ops->startup(substream);
  62
  63        /* mark substream if succeeded */
  64        if (ret == 0)
  65                soc_link_mark_push(rtd, substream, startup);
  66
  67        return soc_link_ret(rtd, ret);
  68}
  69
  70void snd_soc_link_shutdown(struct snd_pcm_substream *substream,
  71                           int rollback)
  72{
  73        struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
  74
  75        if (rollback && !soc_link_mark_match(rtd, substream, startup))
  76                return;
  77
  78        if (rtd->dai_link->ops &&
  79            rtd->dai_link->ops->shutdown)
  80                rtd->dai_link->ops->shutdown(substream);
  81
  82        /* remove marked substream */
  83        soc_link_mark_pop(rtd, startup);
  84}
  85
  86int snd_soc_link_prepare(struct snd_pcm_substream *substream)
  87{
  88        struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
  89        int ret = 0;
  90
  91        if (rtd->dai_link->ops &&
  92            rtd->dai_link->ops->prepare)
  93                ret = rtd->dai_link->ops->prepare(substream);
  94
  95        return soc_link_ret(rtd, ret);
  96}
  97
  98int snd_soc_link_hw_params(struct snd_pcm_substream *substream,
  99                           struct snd_pcm_hw_params *params)
 100{
 101        struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
 102        int ret = 0;
 103
 104        if (rtd->dai_link->ops &&
 105            rtd->dai_link->ops->hw_params)
 106                ret = rtd->dai_link->ops->hw_params(substream, params);
 107
 108        /* mark substream if succeeded */
 109        if (ret == 0)
 110                soc_link_mark_push(rtd, substream, hw_params);
 111
 112        return soc_link_ret(rtd, ret);
 113}
 114
 115void snd_soc_link_hw_free(struct snd_pcm_substream *substream, int rollback)
 116{
 117        struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
 118
 119        if (rollback && !soc_link_mark_match(rtd, substream, hw_params))
 120                return;
 121
 122        if (rtd->dai_link->ops &&
 123            rtd->dai_link->ops->hw_free)
 124                rtd->dai_link->ops->hw_free(substream);
 125
 126        /* remove marked substream */
 127        soc_link_mark_pop(rtd, hw_params);
 128}
 129
 130static int soc_link_trigger(struct snd_pcm_substream *substream, int cmd)
 131{
 132        struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
 133        int ret = 0;
 134
 135        if (rtd->dai_link->ops &&
 136            rtd->dai_link->ops->trigger)
 137                ret = rtd->dai_link->ops->trigger(substream, cmd);
 138
 139        return soc_link_ret(rtd, ret);
 140}
 141
 142int snd_soc_link_trigger(struct snd_pcm_substream *substream, int cmd,
 143                         int rollback)
 144{
 145        struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
 146        int ret = 0;
 147
 148        switch (cmd) {
 149        case SNDRV_PCM_TRIGGER_START:
 150        case SNDRV_PCM_TRIGGER_RESUME:
 151        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 152                ret = soc_link_trigger(substream, cmd);
 153                if (ret < 0)
 154                        break;
 155                soc_link_mark_push(rtd, substream, trigger);
 156                break;
 157        case SNDRV_PCM_TRIGGER_STOP:
 158        case SNDRV_PCM_TRIGGER_SUSPEND:
 159        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 160                if (rollback && !soc_link_mark_match(rtd, substream, trigger))
 161                        break;
 162
 163                ret = soc_link_trigger(substream, cmd);
 164                soc_link_mark_pop(rtd, startup);
 165        }
 166
 167        return ret;
 168}
 169
 170int snd_soc_link_compr_startup(struct snd_compr_stream *cstream)
 171{
 172        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 173        int ret = 0;
 174
 175        if (rtd->dai_link->compr_ops &&
 176            rtd->dai_link->compr_ops->startup)
 177                ret = rtd->dai_link->compr_ops->startup(cstream);
 178
 179        if (ret == 0)
 180                soc_link_mark_push(rtd, cstream, compr_startup);
 181
 182        return soc_link_ret(rtd, ret);
 183}
 184EXPORT_SYMBOL_GPL(snd_soc_link_compr_startup);
 185
 186void snd_soc_link_compr_shutdown(struct snd_compr_stream *cstream,
 187                                 int rollback)
 188{
 189        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 190
 191        if (rollback && !soc_link_mark_match(rtd, cstream, compr_startup))
 192                return;
 193
 194        if (rtd->dai_link->compr_ops &&
 195            rtd->dai_link->compr_ops->shutdown)
 196                rtd->dai_link->compr_ops->shutdown(cstream);
 197
 198        soc_link_mark_pop(rtd, compr_startup);
 199}
 200EXPORT_SYMBOL_GPL(snd_soc_link_compr_shutdown);
 201
 202int snd_soc_link_compr_set_params(struct snd_compr_stream *cstream)
 203{
 204        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 205        int ret = 0;
 206
 207        if (rtd->dai_link->compr_ops &&
 208            rtd->dai_link->compr_ops->set_params)
 209                ret = rtd->dai_link->compr_ops->set_params(cstream);
 210
 211        return soc_link_ret(rtd, ret);
 212}
 213EXPORT_SYMBOL_GPL(snd_soc_link_compr_set_params);
 214