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