1 // SPDX-License-Identifier: GPL-2.0 1 // SPDX-License-Identifier: GPL-2.0 2 // 2 // 3 // soc-card.c 3 // soc-card.c 4 // 4 // 5 // Copyright (C) 2019 Renesas Electronics Corp 5 // Copyright (C) 2019 Renesas Electronics Corp. 6 // Kuninori Morimoto <kuninori.morimoto.gx@ren 6 // Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> 7 // 7 // 8 << 9 #include <linux/lockdep.h> << 10 #include <linux/rwsem.h> << 11 #include <sound/soc.h> 8 #include <sound/soc.h> 12 #include <sound/jack.h> 9 #include <sound/jack.h> 13 10 14 #define soc_card_ret(dai, ret) _soc_card_ret(d 11 #define soc_card_ret(dai, ret) _soc_card_ret(dai, __func__, ret) 15 static inline int _soc_card_ret(struct snd_soc 12 static inline int _soc_card_ret(struct snd_soc_card *card, 16 const char *fu 13 const char *func, int ret) 17 { 14 { 18 switch (ret) { 15 switch (ret) { 19 case -EPROBE_DEFER: 16 case -EPROBE_DEFER: 20 case -ENOTSUPP: 17 case -ENOTSUPP: 21 case 0: 18 case 0: 22 break; 19 break; 23 default: 20 default: 24 dev_err(card->dev, 21 dev_err(card->dev, 25 "ASoC: error at %s on 22 "ASoC: error at %s on %s: %d\n", 26 func, card->name, ret) 23 func, card->name, ret); 27 } 24 } 28 25 29 return ret; 26 return ret; 30 } 27 } 31 28 32 struct snd_kcontrol *snd_soc_card_get_kcontrol 29 struct snd_kcontrol *snd_soc_card_get_kcontrol(struct snd_soc_card *soc_card, 33 30 const char *name) 34 { 31 { >> 32 struct snd_card *card = soc_card->snd_card; >> 33 struct snd_kcontrol *kctl; >> 34 35 if (unlikely(!name)) 35 if (unlikely(!name)) 36 return NULL; 36 return NULL; 37 37 38 return snd_ctl_find_id_mixer(soc_card- !! 38 list_for_each_entry(kctl, &card->controls, list) >> 39 if (!strncmp(kctl->id.name, name, sizeof(kctl->id.name))) >> 40 return kctl; >> 41 return NULL; 39 } 42 } 40 EXPORT_SYMBOL_GPL(snd_soc_card_get_kcontrol); 43 EXPORT_SYMBOL_GPL(snd_soc_card_get_kcontrol); 41 44 42 static int jack_new(struct snd_soc_card *card, 45 static int jack_new(struct snd_soc_card *card, const char *id, int type, 43 struct snd_soc_jack *jack, 46 struct snd_soc_jack *jack, bool initial_kctl) 44 { 47 { 45 mutex_init(&jack->mutex); 48 mutex_init(&jack->mutex); 46 jack->card = card; 49 jack->card = card; 47 INIT_LIST_HEAD(&jack->pins); 50 INIT_LIST_HEAD(&jack->pins); 48 INIT_LIST_HEAD(&jack->jack_zones); 51 INIT_LIST_HEAD(&jack->jack_zones); 49 BLOCKING_INIT_NOTIFIER_HEAD(&jack->not 52 BLOCKING_INIT_NOTIFIER_HEAD(&jack->notifier); 50 53 51 return snd_jack_new(card->snd_card, id 54 return snd_jack_new(card->snd_card, id, type, &jack->jack, initial_kctl, false); 52 } 55 } 53 56 54 /** 57 /** 55 * snd_soc_card_jack_new - Create a new jack w 58 * snd_soc_card_jack_new - Create a new jack without pins 56 * @card: ASoC card 59 * @card: ASoC card 57 * @id: an identifying string for this jack 60 * @id: an identifying string for this jack 58 * @type: a bitmask of enum snd_jack_type val 61 * @type: a bitmask of enum snd_jack_type values that can be detected by 59 * this jack 62 * this jack 60 * @jack: structure to use for the jack 63 * @jack: structure to use for the jack 61 * 64 * 62 * Creates a new jack object without pins. If 65 * Creates a new jack object without pins. If adding pins later, 63 * snd_soc_card_jack_new_pins() should be used 66 * snd_soc_card_jack_new_pins() should be used instead with 0 as num_pins 64 * argument. 67 * argument. 65 * 68 * 66 * Returns zero if successful, or a negative e 69 * Returns zero if successful, or a negative error code on failure. 67 * On success jack will be initialised. 70 * On success jack will be initialised. 68 */ 71 */ 69 int snd_soc_card_jack_new(struct snd_soc_card 72 int snd_soc_card_jack_new(struct snd_soc_card *card, const char *id, int type, 70 struct snd_soc_jack 73 struct snd_soc_jack *jack) 71 { 74 { 72 return soc_card_ret(card, jack_new(car 75 return soc_card_ret(card, jack_new(card, id, type, jack, true)); 73 } 76 } 74 EXPORT_SYMBOL_GPL(snd_soc_card_jack_new); 77 EXPORT_SYMBOL_GPL(snd_soc_card_jack_new); 75 78 76 /** 79 /** 77 * snd_soc_card_jack_new_pins - Create a new j 80 * snd_soc_card_jack_new_pins - Create a new jack with pins 78 * @card: ASoC card 81 * @card: ASoC card 79 * @id: an identifying string for this jack 82 * @id: an identifying string for this jack 80 * @type: a bitmask of enum snd_jack_type val 83 * @type: a bitmask of enum snd_jack_type values that can be detected by 81 * this jack 84 * this jack 82 * @jack: structure to use for the jack 85 * @jack: structure to use for the jack 83 * @pins: Array of jack pins to be added to t 86 * @pins: Array of jack pins to be added to the jack or NULL 84 * @num_pins: Number of elements in the @pins 87 * @num_pins: Number of elements in the @pins array 85 * 88 * 86 * Creates a new jack object with pins. If not 89 * Creates a new jack object with pins. If not adding pins, 87 * snd_soc_card_jack_new() should be used inst 90 * snd_soc_card_jack_new() should be used instead. 88 * 91 * 89 * Returns zero if successful, or a negative e 92 * Returns zero if successful, or a negative error code on failure. 90 * On success jack will be initialised. 93 * On success jack will be initialised. 91 */ 94 */ 92 int snd_soc_card_jack_new_pins(struct snd_soc_ 95 int snd_soc_card_jack_new_pins(struct snd_soc_card *card, const char *id, 93 int type, struc 96 int type, struct snd_soc_jack *jack, 94 struct snd_soc_ 97 struct snd_soc_jack_pin *pins, 95 unsigned int nu 98 unsigned int num_pins) 96 { 99 { 97 int ret; 100 int ret; 98 101 99 ret = jack_new(card, id, type, jack, f 102 ret = jack_new(card, id, type, jack, false); 100 if (ret) 103 if (ret) 101 goto end; 104 goto end; 102 105 103 if (num_pins) 106 if (num_pins) 104 ret = snd_soc_jack_add_pins(ja 107 ret = snd_soc_jack_add_pins(jack, num_pins, pins); 105 end: 108 end: 106 return soc_card_ret(card, ret); 109 return soc_card_ret(card, ret); 107 } 110 } 108 EXPORT_SYMBOL_GPL(snd_soc_card_jack_new_pins); 111 EXPORT_SYMBOL_GPL(snd_soc_card_jack_new_pins); 109 112 110 int snd_soc_card_suspend_pre(struct snd_soc_ca 113 int snd_soc_card_suspend_pre(struct snd_soc_card *card) 111 { 114 { 112 int ret = 0; 115 int ret = 0; 113 116 114 if (card->suspend_pre) 117 if (card->suspend_pre) 115 ret = card->suspend_pre(card); 118 ret = card->suspend_pre(card); 116 119 117 return soc_card_ret(card, ret); 120 return soc_card_ret(card, ret); 118 } 121 } 119 122 120 int snd_soc_card_suspend_post(struct snd_soc_c 123 int snd_soc_card_suspend_post(struct snd_soc_card *card) 121 { 124 { 122 int ret = 0; 125 int ret = 0; 123 126 124 if (card->suspend_post) 127 if (card->suspend_post) 125 ret = card->suspend_post(card) 128 ret = card->suspend_post(card); 126 129 127 return soc_card_ret(card, ret); 130 return soc_card_ret(card, ret); 128 } 131 } 129 132 130 int snd_soc_card_resume_pre(struct snd_soc_car 133 int snd_soc_card_resume_pre(struct snd_soc_card *card) 131 { 134 { 132 int ret = 0; 135 int ret = 0; 133 136 134 if (card->resume_pre) 137 if (card->resume_pre) 135 ret = card->resume_pre(card); 138 ret = card->resume_pre(card); 136 139 137 return soc_card_ret(card, ret); 140 return soc_card_ret(card, ret); 138 } 141 } 139 142 140 int snd_soc_card_resume_post(struct snd_soc_ca 143 int snd_soc_card_resume_post(struct snd_soc_card *card) 141 { 144 { 142 int ret = 0; 145 int ret = 0; 143 146 144 if (card->resume_post) 147 if (card->resume_post) 145 ret = card->resume_post(card); 148 ret = card->resume_post(card); 146 149 147 return soc_card_ret(card, ret); 150 return soc_card_ret(card, ret); 148 } 151 } 149 152 150 int snd_soc_card_probe(struct snd_soc_card *ca 153 int snd_soc_card_probe(struct snd_soc_card *card) 151 { 154 { 152 if (card->probe) { 155 if (card->probe) { 153 int ret = card->probe(card); 156 int ret = card->probe(card); 154 157 155 if (ret < 0) 158 if (ret < 0) 156 return soc_card_ret(ca 159 return soc_card_ret(card, ret); 157 160 158 /* 161 /* 159 * It has "card->probe" and "c 162 * It has "card->probe" and "card->late_probe" callbacks. 160 * So, set "probed" flag here, 163 * So, set "probed" flag here, because it needs to care 161 * about "late_probe". 164 * about "late_probe". 162 * 165 * 163 * see 166 * see 164 * snd_soc_bind_card() 167 * snd_soc_bind_card() 165 * snd_soc_card_late_prob 168 * snd_soc_card_late_probe() 166 */ 169 */ 167 card->probed = 1; 170 card->probed = 1; 168 } 171 } 169 172 170 return 0; 173 return 0; 171 } 174 } 172 175 173 int snd_soc_card_late_probe(struct snd_soc_car 176 int snd_soc_card_late_probe(struct snd_soc_card *card) 174 { 177 { 175 if (card->late_probe) { 178 if (card->late_probe) { 176 int ret = card->late_probe(car 179 int ret = card->late_probe(card); 177 180 178 if (ret < 0) 181 if (ret < 0) 179 return soc_card_ret(ca 182 return soc_card_ret(card, ret); 180 } 183 } 181 184 182 /* 185 /* 183 * It has "card->probe" and "card->lat 186 * It has "card->probe" and "card->late_probe" callbacks, 184 * and "late_probe" callback is called 187 * and "late_probe" callback is called after "probe". 185 * This means, we can set "card->probe 188 * This means, we can set "card->probed" flag afer "late_probe" 186 * for all cases. 189 * for all cases. 187 * 190 * 188 * see 191 * see 189 * snd_soc_bind_card() 192 * snd_soc_bind_card() 190 * snd_soc_card_probe() 193 * snd_soc_card_probe() 191 */ 194 */ 192 card->probed = 1; 195 card->probed = 1; 193 196 194 return 0; 197 return 0; 195 } << 196 << 197 void snd_soc_card_fixup_controls(struct snd_so << 198 { << 199 if (card->fixup_controls) << 200 card->fixup_controls(card); << 201 } 198 } 202 199 203 int snd_soc_card_remove(struct snd_soc_card *c 200 int snd_soc_card_remove(struct snd_soc_card *card) 204 { 201 { 205 int ret = 0; 202 int ret = 0; 206 203 207 if (card->probed && 204 if (card->probed && 208 card->remove) 205 card->remove) 209 ret = card->remove(card); 206 ret = card->remove(card); 210 207 211 card->probed = 0; 208 card->probed = 0; 212 209 213 return soc_card_ret(card, ret); 210 return soc_card_ret(card, ret); 214 } 211 } 215 212 216 int snd_soc_card_set_bias_level(struct snd_soc 213 int snd_soc_card_set_bias_level(struct snd_soc_card *card, 217 struct snd_soc 214 struct snd_soc_dapm_context *dapm, 218 enum snd_soc_b 215 enum snd_soc_bias_level level) 219 { 216 { 220 int ret = 0; 217 int ret = 0; 221 218 222 if (card && card->set_bias_level) 219 if (card && card->set_bias_level) 223 ret = card->set_bias_level(car 220 ret = card->set_bias_level(card, dapm, level); 224 221 225 return soc_card_ret(card, ret); 222 return soc_card_ret(card, ret); 226 } 223 } 227 224 228 int snd_soc_card_set_bias_level_post(struct sn 225 int snd_soc_card_set_bias_level_post(struct snd_soc_card *card, 229 struct sn 226 struct snd_soc_dapm_context *dapm, 230 enum snd_ 227 enum snd_soc_bias_level level) 231 { 228 { 232 int ret = 0; 229 int ret = 0; 233 230 234 if (card && card->set_bias_level_post) 231 if (card && card->set_bias_level_post) 235 ret = card->set_bias_level_pos 232 ret = card->set_bias_level_post(card, dapm, level); 236 233 237 return soc_card_ret(card, ret); 234 return soc_card_ret(card, ret); 238 } 235 } 239 236 240 int snd_soc_card_add_dai_link(struct snd_soc_c 237 int snd_soc_card_add_dai_link(struct snd_soc_card *card, 241 struct snd_soc_d 238 struct snd_soc_dai_link *dai_link) 242 { 239 { 243 int ret = 0; 240 int ret = 0; 244 241 245 if (card->add_dai_link) 242 if (card->add_dai_link) 246 ret = card->add_dai_link(card, 243 ret = card->add_dai_link(card, dai_link); 247 244 248 return soc_card_ret(card, ret); 245 return soc_card_ret(card, ret); 249 } 246 } 250 EXPORT_SYMBOL_GPL(snd_soc_card_add_dai_link); 247 EXPORT_SYMBOL_GPL(snd_soc_card_add_dai_link); 251 248 252 void snd_soc_card_remove_dai_link(struct snd_s 249 void snd_soc_card_remove_dai_link(struct snd_soc_card *card, 253 struct snd_s 250 struct snd_soc_dai_link *dai_link) 254 { 251 { 255 if (card->remove_dai_link) 252 if (card->remove_dai_link) 256 card->remove_dai_link(card, da 253 card->remove_dai_link(card, dai_link); 257 } 254 } 258 EXPORT_SYMBOL_GPL(snd_soc_card_remove_dai_link 255 EXPORT_SYMBOL_GPL(snd_soc_card_remove_dai_link); 259 256
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.