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