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(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 } 40 EXPORT_SYMBOL_GPL(snd_soc_card_get_kcontrol); 41 42 static 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 pins 56 * @card: ASoC card 57 * @id: an identifying string for this jack 58 * @type: a bitmask of enum snd_jack_type values that can be detected by 59 * this jack 60 * @jack: structure to use for the jack 61 * 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_pins 64 * argument. 65 * 66 * Returns zero if successful, or a negative error code on failure. 67 * On success jack will be initialised. 68 */ 69 int 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 } 74 EXPORT_SYMBOL_GPL(snd_soc_card_jack_new); 75 76 /** 77 * snd_soc_card_jack_new_pins - Create a new jack with pins 78 * @card: ASoC card 79 * @id: an identifying string for this jack 80 * @type: a bitmask of enum snd_jack_type values that can be detected by 81 * this jack 82 * @jack: structure to use for the jack 83 * @pins: Array of jack pins to be added to the jack or NULL 84 * @num_pins: Number of elements in the @pins array 85 * 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 */ 92 int 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); 105 end: 106 return soc_card_ret(card, ret); 107 } 108 EXPORT_SYMBOL_GPL(snd_soc_card_jack_new_pins); 109 110 int 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 120 int 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 130 int 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 140 int 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 150 int 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 care 161 * about "late_probe". 162 * 163 * see 164 * snd_soc_bind_card() 165 * snd_soc_card_late_probe() 166 */ 167 card->probed = 1; 168 } 169 170 return 0; 171 } 172 173 int 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 * see 189 * snd_soc_bind_card() 190 * snd_soc_card_probe() 191 */ 192 card->probed = 1; 193 194 return 0; 195 } 196 197 void snd_soc_card_fixup_controls(struct snd_soc_card *card) 198 { 199 if (card->fixup_controls) 200 card->fixup_controls(card); 201 } 202 203 int 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 216 int 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 228 int 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 240 int 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 } 250 EXPORT_SYMBOL_GPL(snd_soc_card_add_dai_link); 251 252 void 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 } 258 EXPORT_SYMBOL_GPL(snd_soc_card_remove_dai_link); 259