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