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