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