linux/sound/soc/soc-card.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2//
   3// soc-card.c
   4//
   5// Copyright (C) 2019 Renesas Electronics Corp.
   6// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
   7//
   8
   9#include <linux/lockdep.h>
  10#include <linux/rwsem.h>
  11#include <sound/soc.h>
  12#include <sound/jack.h>
  13
  14#define soc_card_ret(dai, ret) _soc_card_ret(dai, __func__, ret)
  15static inline int _soc_card_ret(struct snd_soc_card *card,
  16                                const char *func, int ret)
  17{
  18        return snd_soc_ret(card->dev, ret,
  19                           "at %s() on %s\n", func, card->name);
  20}
  21
  22struct snd_kcontrol *snd_soc_card_get_kcontrol(struct snd_soc_card *soc_card,
  23                                               const char *name)
  24{
  25        if (unlikely(!name))
  26                return NULL;
  27
  28        return snd_ctl_find_id_mixer(soc_card->snd_card, name);
  29}
  30EXPORT_SYMBOL_GPL(snd_soc_card_get_kcontrol);
  31
  32static int jack_new(struct snd_soc_card *card, const char *id, int type,
  33                    struct snd_soc_jack *jack, bool initial_kctl)
  34{
  35        mutex_init(&jack->mutex);
  36        jack->card = card;
  37        INIT_LIST_HEAD(&jack->pins);
  38        INIT_LIST_HEAD(&jack->jack_zones);
  39        BLOCKING_INIT_NOTIFIER_HEAD(&jack->notifier);
  40
  41        return snd_jack_new(card->snd_card, id, type, &jack->jack, initial_kctl, false);
  42}
  43
  44/**
  45 * snd_soc_card_jack_new - Create a new jack without pins
  46 * @card:  ASoC card
  47 * @id:    an identifying string for this jack
  48 * @type:  a bitmask of enum snd_jack_type values that can be detected by
  49 *         this jack
  50 * @jack:  structure to use for the jack
  51 *
  52 * Creates a new jack object without pins. If adding pins later,
  53 * snd_soc_card_jack_new_pins() should be used instead with 0 as num_pins
  54 * argument.
  55 *
  56 * Returns zero if successful, or a negative error code on failure.
  57 * On success jack will be initialised.
  58 */
  59int snd_soc_card_jack_new(struct snd_soc_card *card, const char *id, int type,
  60                          struct snd_soc_jack *jack)
  61{
  62        return soc_card_ret(card, jack_new(card, id, type, jack, true));
  63}
  64EXPORT_SYMBOL_GPL(snd_soc_card_jack_new);
  65
  66/**
  67 * snd_soc_card_jack_new_pins - Create a new jack with pins
  68 * @card:  ASoC card
  69 * @id:    an identifying string for this jack
  70 * @type:  a bitmask of enum snd_jack_type values that can be detected by
  71 *         this jack
  72 * @jack:  structure to use for the jack
  73 * @pins:  Array of jack pins to be added to the jack or NULL
  74 * @num_pins: Number of elements in the @pins array
  75 *
  76 * Creates a new jack object with pins. If not adding pins,
  77 * snd_soc_card_jack_new() should be used instead.
  78 *
  79 * Returns zero if successful, or a negative error code on failure.
  80 * On success jack will be initialised.
  81 */
  82int snd_soc_card_jack_new_pins(struct snd_soc_card *card, const char *id,
  83                               int type, struct snd_soc_jack *jack,
  84                               struct snd_soc_jack_pin *pins,
  85                               unsigned int num_pins)
  86{
  87        int ret;
  88
  89        ret = jack_new(card, id, type, jack, false);
  90        if (ret)
  91                goto end;
  92
  93        if (num_pins)
  94                ret = snd_soc_jack_add_pins(jack, num_pins, pins);
  95end:
  96        return soc_card_ret(card, ret);
  97}
  98EXPORT_SYMBOL_GPL(snd_soc_card_jack_new_pins);
  99
 100int snd_soc_card_suspend_pre(struct snd_soc_card *card)
 101{
 102        int ret = 0;
 103
 104        if (card->suspend_pre)
 105                ret = card->suspend_pre(card);
 106
 107        return soc_card_ret(card, ret);
 108}
 109
 110int snd_soc_card_suspend_post(struct snd_soc_card *card)
 111{
 112        int ret = 0;
 113
 114        if (card->suspend_post)
 115                ret = card->suspend_post(card);
 116
 117        return soc_card_ret(card, ret);
 118}
 119
 120int snd_soc_card_resume_pre(struct snd_soc_card *card)
 121{
 122        int ret = 0;
 123
 124        if (card->resume_pre)
 125                ret = card->resume_pre(card);
 126
 127        return soc_card_ret(card, ret);
 128}
 129
 130int snd_soc_card_resume_post(struct snd_soc_card *card)
 131{
 132        int ret = 0;
 133
 134        if (card->resume_post)
 135                ret = card->resume_post(card);
 136
 137        return soc_card_ret(card, ret);
 138}
 139
 140int snd_soc_card_probe(struct snd_soc_card *card)
 141{
 142        if (card->probe) {
 143                int ret = card->probe(card);
 144
 145                if (ret < 0)
 146                        return soc_card_ret(card, ret);
 147
 148                /*
 149                 * It has "card->probe" and "card->late_probe" callbacks.
 150                 * So, set "probed" flag here, because it needs to care
 151                 * about "late_probe".
 152                 *
 153                 * see
 154                 *      snd_soc_bind_card()
 155                 *      snd_soc_card_late_probe()
 156                 */
 157                card->probed = 1;
 158        }
 159
 160        return 0;
 161}
 162
 163int snd_soc_card_late_probe(struct snd_soc_card *card)
 164{
 165        if (card->late_probe) {
 166                int ret = card->late_probe(card);
 167
 168                if (ret < 0)
 169                        return soc_card_ret(card, ret);
 170        }
 171
 172        /*
 173         * It has "card->probe" and "card->late_probe" callbacks,
 174         * and "late_probe" callback is called after "probe".
 175         * This means, we can set "card->probed" flag afer "late_probe"
 176         * for all cases.
 177         *
 178         * see
 179         *      snd_soc_bind_card()
 180         *      snd_soc_card_probe()
 181         */
 182        card->probed = 1;
 183
 184        return 0;
 185}
 186
 187void snd_soc_card_fixup_controls(struct snd_soc_card *card)
 188{
 189        if (card->fixup_controls)
 190                card->fixup_controls(card);
 191}
 192
 193int snd_soc_card_remove(struct snd_soc_card *card)
 194{
 195        int ret = 0;
 196
 197        if (card->probed &&
 198            card->remove)
 199                ret = card->remove(card);
 200
 201        card->probed = 0;
 202
 203        return soc_card_ret(card, ret);
 204}
 205
 206int snd_soc_card_set_bias_level(struct snd_soc_card *card,
 207                                struct snd_soc_dapm_context *dapm,
 208                                enum snd_soc_bias_level level)
 209{
 210        int ret = 0;
 211
 212        if (card->set_bias_level)
 213                ret = card->set_bias_level(card, dapm, level);
 214
 215        return soc_card_ret(card, ret);
 216}
 217
 218int snd_soc_card_set_bias_level_post(struct snd_soc_card *card,
 219                                     struct snd_soc_dapm_context *dapm,
 220                                     enum snd_soc_bias_level level)
 221{
 222        int ret = 0;
 223
 224        if (card->set_bias_level_post)
 225                ret = card->set_bias_level_post(card, dapm, level);
 226
 227        return soc_card_ret(card, ret);
 228}
 229
 230int snd_soc_card_add_dai_link(struct snd_soc_card *card,
 231                              struct snd_soc_dai_link *dai_link)
 232{
 233        int ret = 0;
 234
 235        if (card->add_dai_link)
 236                ret = card->add_dai_link(card, dai_link);
 237
 238        return soc_card_ret(card, ret);
 239}
 240EXPORT_SYMBOL_GPL(snd_soc_card_add_dai_link);
 241
 242void snd_soc_card_remove_dai_link(struct snd_soc_card *card,
 243                                  struct snd_soc_dai_link *dai_link)
 244{
 245        if (card->remove_dai_link)
 246                card->remove_dai_link(card, dai_link);
 247}
 248EXPORT_SYMBOL_GPL(snd_soc_card_remove_dai_link);
 249