123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261 |
- // SPDX-License-Identifier: GPL-2.0
- //
- // soc-card.c
- //
- // Copyright (C) 2019 Renesas Electronics Corp.
- // Kuninori Morimoto <[email protected]>
- //
- #include <sound/soc.h>
- #include <sound/jack.h>
- #define soc_card_ret(dai, ret) _soc_card_ret(dai, __func__, ret)
- static inline int _soc_card_ret(struct snd_soc_card *card,
- const char *func, int ret)
- {
- switch (ret) {
- case -EPROBE_DEFER:
- case -ENOTSUPP:
- case 0:
- break;
- default:
- dev_err(card->dev,
- "ASoC: error at %s on %s: %d\n",
- func, card->name, ret);
- }
- return ret;
- }
- struct snd_kcontrol *snd_soc_card_get_kcontrol(struct snd_soc_card *soc_card,
- const char *name)
- {
- struct snd_card *card = soc_card->snd_card;
- struct snd_kcontrol *kctl;
- if (unlikely(!name))
- return NULL;
- list_for_each_entry(kctl, &card->controls, list)
- if (!strncmp(kctl->id.name, name, sizeof(kctl->id.name)))
- return kctl;
- return NULL;
- }
- EXPORT_SYMBOL_GPL(snd_soc_card_get_kcontrol);
- static int jack_new(struct snd_soc_card *card, const char *id, int type,
- struct snd_soc_jack *jack, bool initial_kctl)
- {
- mutex_init(&jack->mutex);
- jack->card = card;
- INIT_LIST_HEAD(&jack->pins);
- INIT_LIST_HEAD(&jack->jack_zones);
- BLOCKING_INIT_NOTIFIER_HEAD(&jack->notifier);
- return snd_jack_new(card->snd_card, id, type, &jack->jack, initial_kctl, false);
- }
- /**
- * snd_soc_card_jack_new - Create a new jack without pins
- * @card: ASoC card
- * @id: an identifying string for this jack
- * @type: a bitmask of enum snd_jack_type values that can be detected by
- * this jack
- * @jack: structure to use for the jack
- *
- * Creates a new jack object without pins. If adding pins later,
- * snd_soc_card_jack_new_pins() should be used instead with 0 as num_pins
- * argument.
- *
- * Returns zero if successful, or a negative error code on failure.
- * On success jack will be initialised.
- */
- int snd_soc_card_jack_new(struct snd_soc_card *card, const char *id, int type,
- struct snd_soc_jack *jack)
- {
- return soc_card_ret(card, jack_new(card, id, type, jack, true));
- }
- EXPORT_SYMBOL_GPL(snd_soc_card_jack_new);
- /**
- * snd_soc_card_jack_new_pins - Create a new jack with pins
- * @card: ASoC card
- * @id: an identifying string for this jack
- * @type: a bitmask of enum snd_jack_type values that can be detected by
- * this jack
- * @jack: structure to use for the jack
- * @pins: Array of jack pins to be added to the jack or NULL
- * @num_pins: Number of elements in the @pins array
- *
- * Creates a new jack object with pins. If not adding pins,
- * snd_soc_card_jack_new() should be used instead.
- *
- * Returns zero if successful, or a negative error code on failure.
- * On success jack will be initialised.
- */
- int snd_soc_card_jack_new_pins(struct snd_soc_card *card, const char *id,
- int type, struct snd_soc_jack *jack,
- struct snd_soc_jack_pin *pins,
- unsigned int num_pins)
- {
- int ret;
- ret = jack_new(card, id, type, jack, false);
- if (ret)
- goto end;
- if (num_pins)
- ret = snd_soc_jack_add_pins(jack, num_pins, pins);
- end:
- return soc_card_ret(card, ret);
- }
- EXPORT_SYMBOL_GPL(snd_soc_card_jack_new_pins);
- int snd_soc_card_suspend_pre(struct snd_soc_card *card)
- {
- int ret = 0;
- if (card->suspend_pre)
- ret = card->suspend_pre(card);
- return soc_card_ret(card, ret);
- }
- int snd_soc_card_suspend_post(struct snd_soc_card *card)
- {
- int ret = 0;
- if (card->suspend_post)
- ret = card->suspend_post(card);
- return soc_card_ret(card, ret);
- }
- int snd_soc_card_resume_pre(struct snd_soc_card *card)
- {
- int ret = 0;
- if (card->resume_pre)
- ret = card->resume_pre(card);
- return soc_card_ret(card, ret);
- }
- int snd_soc_card_resume_post(struct snd_soc_card *card)
- {
- int ret = 0;
- if (card->resume_post)
- ret = card->resume_post(card);
- return soc_card_ret(card, ret);
- }
- int snd_soc_card_probe(struct snd_soc_card *card)
- {
- if (card->probe) {
- int ret = card->probe(card);
- if (ret < 0)
- return soc_card_ret(card, ret);
- /*
- * It has "card->probe" and "card->late_probe" callbacks.
- * So, set "probed" flag here, because it needs to care
- * about "late_probe".
- *
- * see
- * snd_soc_bind_card()
- * snd_soc_card_late_probe()
- */
- card->probed = 1;
- }
- return 0;
- }
- int snd_soc_card_late_probe(struct snd_soc_card *card)
- {
- if (card->late_probe) {
- int ret = card->late_probe(card);
- if (ret < 0)
- return soc_card_ret(card, ret);
- }
- /*
- * It has "card->probe" and "card->late_probe" callbacks,
- * and "late_probe" callback is called after "probe".
- * This means, we can set "card->probed" flag afer "late_probe"
- * for all cases.
- *
- * see
- * snd_soc_bind_card()
- * snd_soc_card_probe()
- */
- card->probed = 1;
- return 0;
- }
- void snd_soc_card_fixup_controls(struct snd_soc_card *card)
- {
- if (card->fixup_controls)
- card->fixup_controls(card);
- }
- int snd_soc_card_remove(struct snd_soc_card *card)
- {
- int ret = 0;
- if (card->probed &&
- card->remove)
- ret = card->remove(card);
- card->probed = 0;
- return soc_card_ret(card, ret);
- }
- int snd_soc_card_set_bias_level(struct snd_soc_card *card,
- struct snd_soc_dapm_context *dapm,
- enum snd_soc_bias_level level)
- {
- int ret = 0;
- if (card && card->set_bias_level)
- ret = card->set_bias_level(card, dapm, level);
- return soc_card_ret(card, ret);
- }
- int snd_soc_card_set_bias_level_post(struct snd_soc_card *card,
- struct snd_soc_dapm_context *dapm,
- enum snd_soc_bias_level level)
- {
- int ret = 0;
- if (card && card->set_bias_level_post)
- ret = card->set_bias_level_post(card, dapm, level);
- return soc_card_ret(card, ret);
- }
- int snd_soc_card_add_dai_link(struct snd_soc_card *card,
- struct snd_soc_dai_link *dai_link)
- {
- int ret = 0;
- if (card->add_dai_link)
- ret = card->add_dai_link(card, dai_link);
- return soc_card_ret(card, ret);
- }
- EXPORT_SYMBOL_GPL(snd_soc_card_add_dai_link);
- void snd_soc_card_remove_dai_link(struct snd_soc_card *card,
- struct snd_soc_dai_link *dai_link)
- {
- if (card->remove_dai_link)
- card->remove_dai_link(card, dai_link);
- }
- EXPORT_SYMBOL_GPL(snd_soc_card_remove_dai_link);
|