aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMengdong Lin <mengdong.lin@linux.intel.com>2016-01-15 03:13:28 -0500
committerMark Brown <broonie@kernel.org>2016-02-15 14:35:59 -0500
commit64527e8a352968bda529f01df1c9dd5fe581ff04 (patch)
treeb25e10c3b839f8517bd54374ffddc679b4c9ce24
parent92e963f50fc74041b5e9e744c330dca48e04f08d (diff)
ASoC: topology: Add FE DAIs dynamically
Topology will create FE DAIs dynamically from the PCM objects, and register them to the component. A PCM topoplogy object describes a FE DAI and DAI link. Later patch will add FE DAI links as well. Change tplg load ops for DAI: - Only process a DAI. - Pass the DAI driver pointer to the component driver for extra initialization. Signed-off-by: Mengdong Lin <mengdong.lin@linux.intel.com> Acked-by: Liam Girdwood <liam.r.girdwood@linux.intel.com> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--include/sound/soc-topology.h15
-rw-r--r--include/sound/soc.h2
-rw-r--r--sound/soc/soc-topology.c129
3 files changed, 92 insertions, 54 deletions
diff --git a/include/sound/soc-topology.h b/include/sound/soc-topology.h
index 5b68e3f5aa85..78813adca2a1 100644
--- a/include/sound/soc-topology.h
+++ b/include/sound/soc-topology.h
@@ -56,12 +56,6 @@ struct snd_soc_dobj_widget {
56 unsigned int kcontrol_enum:1; /* this widget is an enum kcontrol */ 56 unsigned int kcontrol_enum:1; /* this widget is an enum kcontrol */
57}; 57};
58 58
59/* dynamic PCM DAI object */
60struct snd_soc_dobj_pcm_dai {
61 struct snd_soc_tplg_pcm_dai *pd;
62 unsigned int count;
63};
64
65/* generic dynamic object - all dynamic objects belong to this struct */ 59/* generic dynamic object - all dynamic objects belong to this struct */
66struct snd_soc_dobj { 60struct snd_soc_dobj {
67 enum snd_soc_dobj_type type; 61 enum snd_soc_dobj_type type;
@@ -71,7 +65,6 @@ struct snd_soc_dobj {
71 union { 65 union {
72 struct snd_soc_dobj_control control; 66 struct snd_soc_dobj_control control;
73 struct snd_soc_dobj_widget widget; 67 struct snd_soc_dobj_widget widget;
74 struct snd_soc_dobj_pcm_dai pcm_dai;
75 }; 68 };
76 void *private; /* core does not touch this */ 69 void *private; /* core does not touch this */
77}; 70};
@@ -126,10 +119,10 @@ struct snd_soc_tplg_ops {
126 int (*widget_unload)(struct snd_soc_component *, 119 int (*widget_unload)(struct snd_soc_component *,
127 struct snd_soc_dobj *); 120 struct snd_soc_dobj *);
128 121
129 /* FE - used for any driver specific init */ 122 /* FE DAI - used for any driver specific init */
130 int (*pcm_dai_load)(struct snd_soc_component *, 123 int (*dai_load)(struct snd_soc_component *,
131 struct snd_soc_tplg_pcm_dai *pcm_dai, int num_fe); 124 struct snd_soc_dai_driver *dai_drv);
132 int (*pcm_dai_unload)(struct snd_soc_component *, 125 int (*dai_unload)(struct snd_soc_component *,
133 struct snd_soc_dobj *); 126 struct snd_soc_dobj *);
134 127
135 /* callback to handle vendor bespoke data */ 128 /* callback to handle vendor bespoke data */
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 7afb72ceac56..02b4a215fd75 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -27,7 +27,6 @@
27#include <sound/compress_driver.h> 27#include <sound/compress_driver.h>
28#include <sound/control.h> 28#include <sound/control.h>
29#include <sound/ac97_codec.h> 29#include <sound/ac97_codec.h>
30#include <sound/soc-topology.h>
31 30
32/* 31/*
33 * Convenience kcontrol builders 32 * Convenience kcontrol builders
@@ -404,6 +403,7 @@ struct snd_soc_jack_zone;
404struct snd_soc_jack_pin; 403struct snd_soc_jack_pin;
405#include <sound/soc-dapm.h> 404#include <sound/soc-dapm.h>
406#include <sound/soc-dpcm.h> 405#include <sound/soc-dpcm.h>
406#include <sound/soc-topology.h>
407 407
408struct snd_soc_jack_gpio; 408struct snd_soc_jack_gpio;
409 409
diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c
index 6963ba20991c..446ac9a93aef 100644
--- a/sound/soc/soc-topology.c
+++ b/sound/soc/soc-topology.c
@@ -330,12 +330,12 @@ static int soc_tplg_widget_load(struct soc_tplg *tplg,
330 return 0; 330 return 0;
331} 331}
332 332
333/* pass dynamic FEs configurations to component driver */ 333/* pass DAI configurations to component driver for extra intialization */
334static int soc_tplg_pcm_dai_load(struct soc_tplg *tplg, 334static int soc_tplg_dai_load(struct soc_tplg *tplg,
335 struct snd_soc_tplg_pcm_dai *pcm_dai, int num_pcm_dai) 335 struct snd_soc_dai_driver *dai_drv)
336{ 336{
337 if (tplg->comp && tplg->ops && tplg->ops->pcm_dai_load) 337 if (tplg->comp && tplg->ops && tplg->ops->dai_load)
338 return tplg->ops->pcm_dai_load(tplg->comp, pcm_dai, num_pcm_dai); 338 return tplg->ops->dai_load(tplg->comp, dai_drv);
339 339
340 return 0; 340 return 0;
341} 341}
@@ -495,18 +495,21 @@ static void remove_widget(struct snd_soc_component *comp,
495 /* widget w is freed by soc-dapm.c */ 495 /* widget w is freed by soc-dapm.c */
496} 496}
497 497
498/* remove PCM DAI configurations */ 498/* remove DAI configurations */
499static void remove_pcm_dai(struct snd_soc_component *comp, 499static void remove_dai(struct snd_soc_component *comp,
500 struct snd_soc_dobj *dobj, int pass) 500 struct snd_soc_dobj *dobj, int pass)
501{ 501{
502 struct snd_soc_dai_driver *dai_drv =
503 container_of(dobj, struct snd_soc_dai_driver, dobj);
504
502 if (pass != SOC_TPLG_PASS_PCM_DAI) 505 if (pass != SOC_TPLG_PASS_PCM_DAI)
503 return; 506 return;
504 507
505 if (dobj->ops && dobj->ops->pcm_dai_unload) 508 if (dobj->ops && dobj->ops->dai_unload)
506 dobj->ops->pcm_dai_unload(comp, dobj); 509 dobj->ops->dai_unload(comp, dobj);
507 510
508 list_del(&dobj->list); 511 list_del(&dobj->list);
509 kfree(dobj); 512 kfree(dai_drv);
510} 513}
511 514
512/* bind a kcontrol to it's IO handlers */ 515/* bind a kcontrol to it's IO handlers */
@@ -1544,18 +1547,79 @@ static int soc_tplg_dapm_complete(struct soc_tplg *tplg)
1544 return 0; 1547 return 0;
1545} 1548}
1546 1549
1547static int soc_tplg_pcm_dai_elems_load(struct soc_tplg *tplg, 1550static int soc_tplg_dai_create(struct soc_tplg *tplg,
1551 struct snd_soc_tplg_pcm *pcm)
1552{
1553 struct snd_soc_dai_driver *dai_drv;
1554 struct snd_soc_pcm_stream *stream;
1555 struct snd_soc_tplg_stream_caps *caps;
1556 int ret;
1557
1558 dai_drv = kzalloc(sizeof(struct snd_soc_dai_driver), GFP_KERNEL);
1559 if (dai_drv == NULL)
1560 return -ENOMEM;
1561
1562 dai_drv->name = pcm->dai_name;
1563 dai_drv->id = pcm->dai_id;
1564
1565 if (pcm->playback) {
1566 stream = &dai_drv->playback;
1567 caps = &pcm->caps[SND_SOC_TPLG_STREAM_PLAYBACK];
1568
1569 stream->stream_name = kstrdup(caps->name, GFP_KERNEL);
1570 stream->channels_min = caps->channels_min;
1571 stream->channels_max = caps->channels_max;
1572 stream->rates = snd_pcm_rate_range_to_bits(caps->rate_min,
1573 caps->rate_max);
1574 stream->formats = caps->formats;
1575 }
1576
1577 if (pcm->capture) {
1578 stream = &dai_drv->capture;
1579 caps = &pcm->caps[SND_SOC_TPLG_STREAM_CAPTURE];
1580
1581 stream->stream_name = kstrdup(caps->name, GFP_KERNEL);
1582 stream->channels_min = caps->channels_min;
1583 stream->channels_max = caps->channels_max;
1584 stream->rates = snd_pcm_rate_range_to_bits(caps->rate_min,
1585 caps->rate_max);
1586 stream->formats = caps->formats;
1587 }
1588
1589 /* pass control to component driver for optional further init */
1590 ret = soc_tplg_dai_load(tplg, dai_drv);
1591 if (ret < 0) {
1592 dev_err(tplg->comp->dev, "ASoC: DAI loading failed\n");
1593 kfree(dai_drv);
1594 return ret;
1595 }
1596
1597 dai_drv->dobj.index = tplg->index;
1598 dai_drv->dobj.ops = tplg->ops;
1599 dai_drv->dobj.type = SND_SOC_DOBJ_PCM;
1600 list_add(&dai_drv->dobj.list, &tplg->comp->dobj_list);
1601
1602 /* register the DAI to the component */
1603 return snd_soc_register_dai(tplg->comp, dai_drv);
1604}
1605
1606static int soc_tplg_pcm_create(struct soc_tplg *tplg,
1607 struct snd_soc_tplg_pcm *pcm)
1608{
1609 return soc_tplg_dai_create(tplg, pcm);
1610}
1611
1612static int soc_tplg_pcm_elems_load(struct soc_tplg *tplg,
1548 struct snd_soc_tplg_hdr *hdr) 1613 struct snd_soc_tplg_hdr *hdr)
1549{ 1614{
1550 struct snd_soc_tplg_pcm_dai *pcm_dai; 1615 struct snd_soc_tplg_pcm *pcm;
1551 struct snd_soc_dobj *dobj;
1552 int count = hdr->count; 1616 int count = hdr->count;
1553 int ret; 1617 int i;
1554 1618
1555 if (tplg->pass != SOC_TPLG_PASS_PCM_DAI) 1619 if (tplg->pass != SOC_TPLG_PASS_PCM_DAI)
1556 return 0; 1620 return 0;
1557 1621
1558 pcm_dai = (struct snd_soc_tplg_pcm_dai *)tplg->pos; 1622 pcm = (struct snd_soc_tplg_pcm *)tplg->pos;
1559 1623
1560 if (soc_tplg_check_elem_count(tplg, 1624 if (soc_tplg_check_elem_count(tplg,
1561 sizeof(struct snd_soc_tplg_pcm), count, 1625 sizeof(struct snd_soc_tplg_pcm), count,
@@ -1565,31 +1629,16 @@ static int soc_tplg_pcm_dai_elems_load(struct soc_tplg *tplg,
1565 return -EINVAL; 1629 return -EINVAL;
1566 } 1630 }
1567 1631
1632 /* create the FE DAIs and DAI links */
1633 for (i = 0; i < count; i++) {
1634 soc_tplg_pcm_create(tplg, pcm);
1635 pcm++;
1636 }
1637
1568 dev_dbg(tplg->dev, "ASoC: adding %d PCM DAIs\n", count); 1638 dev_dbg(tplg->dev, "ASoC: adding %d PCM DAIs\n", count);
1569 tplg->pos += sizeof(struct snd_soc_tplg_pcm) * count; 1639 tplg->pos += sizeof(struct snd_soc_tplg_pcm) * count;
1570 1640
1571 dobj = kzalloc(sizeof(struct snd_soc_dobj), GFP_KERNEL);
1572 if (dobj == NULL)
1573 return -ENOMEM;
1574
1575 /* Call the platform driver call back to register the dais */
1576 ret = soc_tplg_pcm_dai_load(tplg, pcm_dai, count);
1577 if (ret < 0) {
1578 dev_err(tplg->comp->dev, "ASoC: PCM DAI loading failed\n");
1579 goto err;
1580 }
1581
1582 dobj->type = get_dobj_type(hdr, NULL);
1583 dobj->pcm_dai.count = count;
1584 dobj->pcm_dai.pd = pcm_dai;
1585 dobj->ops = tplg->ops;
1586 dobj->index = tplg->index;
1587 list_add(&dobj->list, &tplg->comp->dobj_list);
1588 return 0; 1641 return 0;
1589
1590err:
1591 kfree(dobj);
1592 return ret;
1593} 1642}
1594 1643
1595static int soc_tplg_manifest_load(struct soc_tplg *tplg, 1644static int soc_tplg_manifest_load(struct soc_tplg *tplg,
@@ -1681,9 +1730,7 @@ static int soc_tplg_load_header(struct soc_tplg *tplg,
1681 case SND_SOC_TPLG_TYPE_DAPM_WIDGET: 1730 case SND_SOC_TPLG_TYPE_DAPM_WIDGET:
1682 return soc_tplg_dapm_widget_elems_load(tplg, hdr); 1731 return soc_tplg_dapm_widget_elems_load(tplg, hdr);
1683 case SND_SOC_TPLG_TYPE_PCM: 1732 case SND_SOC_TPLG_TYPE_PCM:
1684 case SND_SOC_TPLG_TYPE_DAI_LINK: 1733 return soc_tplg_pcm_elems_load(tplg, hdr);
1685 case SND_SOC_TPLG_TYPE_CODEC_LINK:
1686 return soc_tplg_pcm_dai_elems_load(tplg, hdr);
1687 case SND_SOC_TPLG_TYPE_MANIFEST: 1734 case SND_SOC_TPLG_TYPE_MANIFEST:
1688 return soc_tplg_manifest_load(tplg, hdr); 1735 return soc_tplg_manifest_load(tplg, hdr);
1689 default: 1736 default:
@@ -1841,9 +1888,7 @@ int snd_soc_tplg_component_remove(struct snd_soc_component *comp, u32 index)
1841 remove_widget(comp, dobj, pass); 1888 remove_widget(comp, dobj, pass);
1842 break; 1889 break;
1843 case SND_SOC_DOBJ_PCM: 1890 case SND_SOC_DOBJ_PCM:
1844 case SND_SOC_DOBJ_DAI_LINK: 1891 remove_dai(comp, dobj, pass);
1845 case SND_SOC_DOBJ_CODEC_LINK:
1846 remove_pcm_dai(comp, dobj, pass);
1847 break; 1892 break;
1848 default: 1893 default:
1849 dev_err(comp->dev, "ASoC: invalid component type %d for removal\n", 1894 dev_err(comp->dev, "ASoC: invalid component type %d for removal\n",