aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorMark Brown <broonie@linaro.org>2014-03-25 17:22:15 -0400
committerMark Brown <broonie@linaro.org>2014-03-25 17:22:15 -0400
commitbad318cd02e7cacb8e93608f050fa001830ad224 (patch)
tree8b47692f96016d7df76da4adb15645e5e1e03ad3 /sound
parentc61e9e8c47dd6ed82535e2145954ab3770e3c767 (diff)
parent6a91a17bd7b92b2d2aa9ece85457f52a62fd7708 (diff)
Merge remote-tracking branch 'asoc/topic/simple' into asoc-next
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/generic/simple-card.c220
1 files changed, 142 insertions, 78 deletions
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index 2ee8ed56bcf1..21f1ccbdf582 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -20,9 +20,11 @@
20 20
21struct simple_card_data { 21struct simple_card_data {
22 struct snd_soc_card snd_card; 22 struct snd_soc_card snd_card;
23 struct asoc_simple_dai cpu_dai; 23 struct simple_dai_props {
24 struct asoc_simple_dai codec_dai; 24 struct asoc_simple_dai cpu_dai;
25 struct snd_soc_dai_link snd_link; 25 struct asoc_simple_dai codec_dai;
26 } *dai_props;
27 struct snd_soc_dai_link dai_link[]; /* dynamically allocated */
26}; 28};
27 29
28static int __asoc_simple_card_dai_init(struct snd_soc_dai *dai, 30static int __asoc_simple_card_dai_init(struct snd_soc_dai *dai,
@@ -68,13 +70,16 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
68 snd_soc_card_get_drvdata(rtd->card); 70 snd_soc_card_get_drvdata(rtd->card);
69 struct snd_soc_dai *codec = rtd->codec_dai; 71 struct snd_soc_dai *codec = rtd->codec_dai;
70 struct snd_soc_dai *cpu = rtd->cpu_dai; 72 struct snd_soc_dai *cpu = rtd->cpu_dai;
71 int ret; 73 struct simple_dai_props *dai_props;
74 int num, ret;
72 75
73 ret = __asoc_simple_card_dai_init(codec, &priv->codec_dai); 76 num = rtd - rtd->card->rtd;
77 dai_props = &priv->dai_props[num];
78 ret = __asoc_simple_card_dai_init(codec, &dai_props->codec_dai);
74 if (ret < 0) 79 if (ret < 0)
75 return ret; 80 return ret;
76 81
77 ret = __asoc_simple_card_dai_init(cpu, &priv->cpu_dai); 82 ret = __asoc_simple_card_dai_init(cpu, &dai_props->cpu_dai);
78 if (ret < 0) 83 if (ret < 0)
79 return ret; 84 return ret;
80 85
@@ -146,13 +151,47 @@ asoc_simple_card_sub_parse_of(struct device_node *np,
146 return 0; 151 return 0;
147} 152}
148 153
154static int simple_card_cpu_codec_of(struct device_node *node,
155 int daifmt,
156 struct snd_soc_dai_link *dai_link,
157 struct simple_dai_props *dai_props)
158{
159 struct device_node *np;
160 int ret;
161
162 /* CPU sub-node */
163 ret = -EINVAL;
164 np = of_get_child_by_name(node, "simple-audio-card,cpu");
165 if (np) {
166 ret = asoc_simple_card_sub_parse_of(np, daifmt,
167 &dai_props->cpu_dai,
168 &dai_link->cpu_of_node,
169 &dai_link->cpu_dai_name);
170 of_node_put(np);
171 }
172 if (ret < 0)
173 return ret;
174
175 /* CODEC sub-node */
176 ret = -EINVAL;
177 np = of_get_child_by_name(node, "simple-audio-card,codec");
178 if (np) {
179 ret = asoc_simple_card_sub_parse_of(np, daifmt,
180 &dai_props->codec_dai,
181 &dai_link->codec_of_node,
182 &dai_link->codec_dai_name);
183 of_node_put(np);
184 }
185 return ret;
186}
187
149static int asoc_simple_card_parse_of(struct device_node *node, 188static int asoc_simple_card_parse_of(struct device_node *node,
150 struct simple_card_data *priv, 189 struct simple_card_data *priv,
151 struct device *dev) 190 struct device *dev,
191 int multi)
152{ 192{
153 struct snd_soc_dai_link *dai_link = priv->snd_card.dai_link; 193 struct snd_soc_dai_link *dai_link = priv->snd_card.dai_link;
154 struct asoc_simple_dai *codec_dai = &priv->codec_dai; 194 struct simple_dai_props *dai_props = priv->dai_props;
155 struct asoc_simple_dai *cpu_dai = &priv->cpu_dai;
156 struct device_node *np; 195 struct device_node *np;
157 char *name; 196 char *name;
158 unsigned int daifmt; 197 unsigned int daifmt;
@@ -181,78 +220,71 @@ static int asoc_simple_card_parse_of(struct device_node *node,
181 return ret; 220 return ret;
182 } 221 }
183 222
184 /* CPU sub-node */ 223 /* loop on the DAI links */
185 ret = -EINVAL; 224 np = NULL;
186 np = of_get_child_by_name(node, "simple-audio-card,cpu"); 225 for (;;) {
187 if (np) { 226 if (multi) {
188 ret = asoc_simple_card_sub_parse_of(np, daifmt, 227 np = of_get_next_child(node, np);
189 cpu_dai, 228 if (!np)
190 &dai_link->cpu_of_node, 229 break;
191 &dai_link->cpu_dai_name); 230 }
192 of_node_put(np);
193 }
194 if (ret < 0)
195 return ret;
196 231
197 /* CODEC sub-node */ 232 ret = simple_card_cpu_codec_of(multi ? np : node,
198 ret = -EINVAL; 233 daifmt, dai_link, dai_props);
199 np = of_get_child_by_name(node, "simple-audio-card,codec"); 234 if (ret < 0)
200 if (np) { 235 goto err;
201 ret = asoc_simple_card_sub_parse_of(np, daifmt,
202 codec_dai,
203 &dai_link->codec_of_node,
204 &dai_link->codec_dai_name);
205 of_node_put(np);
206 }
207 if (ret < 0)
208 return ret;
209 236
210 /* 237 /*
211 * overwrite cpu_dai->fmt as its DAIFMT_MASTER bit is based on CODEC 238 * overwrite cpu_dai->fmt as its DAIFMT_MASTER bit is based on CODEC
212 * while the other bits should be identical unless buggy SW/HW design. 239 * while the other bits should be identical unless buggy SW/HW design.
213 */ 240 */
214 cpu_dai->fmt = codec_dai->fmt; 241 dai_props->cpu_dai.fmt = dai_props->codec_dai.fmt;
242
243 if (!dai_link->cpu_dai_name || !dai_link->codec_dai_name) {
244 ret = -EINVAL;
245 goto err;
246 }
247
248 /* simple-card assumes platform == cpu */
249 dai_link->platform_of_node = dai_link->cpu_of_node;
250
251 name = devm_kzalloc(dev,
252 strlen(dai_link->cpu_dai_name) +
253 strlen(dai_link->codec_dai_name) + 2,
254 GFP_KERNEL);
255 sprintf(name, "%s-%s", dai_link->cpu_dai_name,
256 dai_link->codec_dai_name);
257 dai_link->name = dai_link->stream_name = name;
215 258
216 if (!dai_link->cpu_dai_name || !dai_link->codec_dai_name) 259 if (!multi)
217 return -EINVAL; 260 break;
261
262 dai_link++;
263 dai_props++;
264 }
218 265
219 /* card name is created from CPU/CODEC dai name */ 266 /* card name is created from CPU/CODEC dai name */
220 name = devm_kzalloc(dev, 267 dai_link = priv->snd_card.dai_link;
221 strlen(dai_link->cpu_dai_name) +
222 strlen(dai_link->codec_dai_name) + 2,
223 GFP_KERNEL);
224 sprintf(name, "%s-%s", dai_link->cpu_dai_name,
225 dai_link->codec_dai_name);
226 if (!priv->snd_card.name) 268 if (!priv->snd_card.name)
227 priv->snd_card.name = name; 269 priv->snd_card.name = dai_link->name;
228 dai_link->name = dai_link->stream_name = name;
229
230 /* simple-card assumes platform == cpu */
231 dai_link->platform_of_node = dai_link->cpu_of_node;
232 270
233 dev_dbg(dev, "card-name : %s\n", name); 271 dev_dbg(dev, "card-name : %s\n", priv->snd_card.name);
234 dev_dbg(dev, "platform : %04x\n", daifmt); 272 dev_dbg(dev, "platform : %04x\n", daifmt);
273 dai_props = priv->dai_props;
235 dev_dbg(dev, "cpu : %s / %04x / %d\n", 274 dev_dbg(dev, "cpu : %s / %04x / %d\n",
236 dai_link->cpu_dai_name, 275 dai_link->cpu_dai_name,
237 cpu_dai->fmt, 276 dai_props->cpu_dai.fmt,
238 cpu_dai->sysclk); 277 dai_props->cpu_dai.sysclk);
239 dev_dbg(dev, "codec : %s / %04x / %d\n", 278 dev_dbg(dev, "codec : %s / %04x / %d\n",
240 dai_link->codec_dai_name, 279 dai_link->codec_dai_name,
241 codec_dai->fmt, 280 dai_props->codec_dai.fmt,
242 codec_dai->sysclk); 281 dai_props->codec_dai.sysclk);
243
244 /*
245 * soc_bind_dai_link() will check cpu name
246 * after of_node matching if dai_link has cpu_dai_name.
247 * but, it will never match if name was created by fmt_single_name()
248 * remove cpu_dai_name to escape name matching.
249 * see
250 * fmt_single_name()
251 * fmt_multiple_name()
252 */
253 dai_link->cpu_dai_name = NULL;
254 282
255 return 0; 283 return 0;
284
285err:
286 of_node_put(np);
287 return ret;
256} 288}
257 289
258/* update the reference count of the devices nodes at end of probe */ 290/* update the reference count of the devices nodes at end of probe */
@@ -282,9 +314,21 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
282 struct snd_soc_dai_link *dai_link; 314 struct snd_soc_dai_link *dai_link;
283 struct device_node *np = pdev->dev.of_node; 315 struct device_node *np = pdev->dev.of_node;
284 struct device *dev = &pdev->dev; 316 struct device *dev = &pdev->dev;
285 int ret; 317 int num_links, multi, ret;
318
319 /* get the number of DAI links */
320 if (np && of_get_child_by_name(np, "simple-audio-card,dai-link")) {
321 num_links = of_get_child_count(np);
322 multi = 1;
323 } else {
324 num_links = 1;
325 multi = 0;
326 }
286 327
287 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 328 /* allocate the private data and the DAI link array */
329 priv = devm_kzalloc(dev,
330 sizeof(*priv) + sizeof(*dai_link) * num_links,
331 GFP_KERNEL);
288 if (!priv) 332 if (!priv)
289 return -ENOMEM; 333 return -ENOMEM;
290 334
@@ -293,18 +337,38 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
293 */ 337 */
294 priv->snd_card.owner = THIS_MODULE; 338 priv->snd_card.owner = THIS_MODULE;
295 priv->snd_card.dev = dev; 339 priv->snd_card.dev = dev;
296 dai_link = &priv->snd_link; 340 dai_link = priv->dai_link;
297 priv->snd_card.dai_link = dai_link; 341 priv->snd_card.dai_link = dai_link;
298 priv->snd_card.num_links = 1; 342 priv->snd_card.num_links = num_links;
343
344 /* get room for the other properties */
345 priv->dai_props = devm_kzalloc(dev,
346 sizeof(*priv->dai_props) * num_links,
347 GFP_KERNEL);
348 if (!priv->dai_props)
349 return -ENOMEM;
299 350
300 if (np && of_device_is_available(np)) { 351 if (np && of_device_is_available(np)) {
301 352
302 ret = asoc_simple_card_parse_of(np, priv, dev); 353 ret = asoc_simple_card_parse_of(np, priv, dev, multi);
303 if (ret < 0) { 354 if (ret < 0) {
304 if (ret != -EPROBE_DEFER) 355 if (ret != -EPROBE_DEFER)
305 dev_err(dev, "parse error %d\n", ret); 356 dev_err(dev, "parse error %d\n", ret);
306 goto err; 357 goto err;
307 } 358 }
359
360 /*
361 * soc_bind_dai_link() will check cpu name
362 * after of_node matching if dai_link has cpu_dai_name.
363 * but, it will never match if name was created by fmt_single_name()
364 * remove cpu_dai_name to escape name matching.
365 * see
366 * fmt_single_name()
367 * fmt_multiple_name()
368 */
369 if (num_links == 1)
370 dai_link->cpu_dai_name = NULL;
371
308 } else { 372 } else {
309 struct asoc_simple_card_info *cinfo; 373 struct asoc_simple_card_info *cinfo;
310 374
@@ -330,13 +394,13 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
330 dai_link->codec_name = cinfo->codec; 394 dai_link->codec_name = cinfo->codec;
331 dai_link->cpu_dai_name = cinfo->cpu_dai.name; 395 dai_link->cpu_dai_name = cinfo->cpu_dai.name;
332 dai_link->codec_dai_name = cinfo->codec_dai.name; 396 dai_link->codec_dai_name = cinfo->codec_dai.name;
333 memcpy(&priv->cpu_dai, &cinfo->cpu_dai, 397 memcpy(&priv->dai_props->cpu_dai, &cinfo->cpu_dai,
334 sizeof(priv->cpu_dai)); 398 sizeof(priv->dai_props->cpu_dai));
335 memcpy(&priv->codec_dai, &cinfo->codec_dai, 399 memcpy(&priv->dai_props->codec_dai, &cinfo->codec_dai,
336 sizeof(priv->codec_dai)); 400 sizeof(priv->dai_props->codec_dai));
337 401
338 priv->cpu_dai.fmt |= cinfo->daifmt; 402 priv->dai_props->cpu_dai.fmt |= cinfo->daifmt;
339 priv->codec_dai.fmt |= cinfo->daifmt; 403 priv->dai_props->codec_dai.fmt |= cinfo->daifmt;
340 } 404 }
341 405
342 /* 406 /*