diff options
author | Mengdong Lin <mengdong.lin@linux.intel.com> | 2016-01-15 03:13:28 -0500 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2016-02-15 14:35:59 -0500 |
commit | 64527e8a352968bda529f01df1c9dd5fe581ff04 (patch) | |
tree | b25e10c3b839f8517bd54374ffddc679b4c9ce24 | |
parent | 92e963f50fc74041b5e9e744c330dca48e04f08d (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.h | 15 | ||||
-rw-r--r-- | include/sound/soc.h | 2 | ||||
-rw-r--r-- | sound/soc/soc-topology.c | 129 |
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 */ | ||
60 | struct 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 */ |
66 | struct snd_soc_dobj { | 60 | struct 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; | |||
404 | struct snd_soc_jack_pin; | 403 | struct 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 | ||
408 | struct snd_soc_jack_gpio; | 408 | struct 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 */ |
334 | static int soc_tplg_pcm_dai_load(struct soc_tplg *tplg, | 334 | static 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 */ |
499 | static void remove_pcm_dai(struct snd_soc_component *comp, | 499 | static 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 | ||
1547 | static int soc_tplg_pcm_dai_elems_load(struct soc_tplg *tplg, | 1550 | static 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 | |||
1606 | static 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 | |||
1612 | static 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 | |||
1590 | err: | ||
1591 | kfree(dobj); | ||
1592 | return ret; | ||
1593 | } | 1642 | } |
1594 | 1643 | ||
1595 | static int soc_tplg_manifest_load(struct soc_tplg *tplg, | 1644 | static 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", |