aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/sound/soc.h17
-rw-r--r--sound/soc/soc-core.c155
2 files changed, 166 insertions, 6 deletions
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 9e593cf1440b..4a9195c5ef2d 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -583,6 +583,14 @@ struct snd_soc_prefix_map {
583 const char *name_prefix; 583 const char *name_prefix;
584}; 584};
585 585
586struct snd_soc_aux_dev {
587 const char *name; /* Codec name */
588 const char *codec_name; /* for multi-codec */
589
590 /* codec/machine specific init - e.g. add machine controls */
591 int (*init)(struct snd_soc_dapm_context *dapm);
592};
593
586/* SoC card */ 594/* SoC card */
587struct snd_soc_card { 595struct snd_soc_card {
588 const char *name; 596 const char *name;
@@ -624,6 +632,15 @@ struct snd_soc_card {
624 struct snd_soc_prefix_map *prefix_map; 632 struct snd_soc_prefix_map *prefix_map;
625 int num_prefixes; 633 int num_prefixes;
626 634
635 /*
636 * optional auxiliary devices such as amplifiers or codecs with DAI
637 * link unused
638 */
639 struct snd_soc_aux_dev *aux_dev;
640 int num_aux_devs;
641 struct snd_soc_pcm_runtime *rtd_aux;
642 int num_aux_rtd;
643
627 struct work_struct deferred_resume_work; 644 struct work_struct deferred_resume_work;
628 645
629 /* lists of probed devices belonging to this card */ 646 /* lists of probed devices belonging to this card */
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index c8d8dde7f4dd..a7670d5ac13d 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -986,6 +986,7 @@ static int soc_suspend(struct device *dev)
986{ 986{
987 struct platform_device *pdev = to_platform_device(dev); 987 struct platform_device *pdev = to_platform_device(dev);
988 struct snd_soc_card *card = platform_get_drvdata(pdev); 988 struct snd_soc_card *card = platform_get_drvdata(pdev);
989 struct snd_soc_codec *codec;
989 int i; 990 int i;
990 991
991 /* If the initialization of this soc device failed, there is no codec 992 /* If the initialization of this soc device failed, there is no codec
@@ -1064,8 +1065,7 @@ static int soc_suspend(struct device *dev)
1064 } 1065 }
1065 1066
1066 /* suspend all CODECs */ 1067 /* suspend all CODECs */
1067 for (i = 0; i < card->num_rtd; i++) { 1068 list_for_each_entry(codec, &card->codec_dev_list, card_list) {
1068 struct snd_soc_codec *codec = card->rtd[i].codec;
1069 /* If there are paths active then the CODEC will be held with 1069 /* If there are paths active then the CODEC will be held with
1070 * bias _ON and should not be suspended. */ 1070 * bias _ON and should not be suspended. */
1071 if (!codec->suspended && codec->driver->suspend) { 1071 if (!codec->suspended && codec->driver->suspend) {
@@ -1106,6 +1106,7 @@ static void soc_resume_deferred(struct work_struct *work)
1106 struct snd_soc_card *card = 1106 struct snd_soc_card *card =
1107 container_of(work, struct snd_soc_card, deferred_resume_work); 1107 container_of(work, struct snd_soc_card, deferred_resume_work);
1108 struct platform_device *pdev = to_platform_device(card->dev); 1108 struct platform_device *pdev = to_platform_device(card->dev);
1109 struct snd_soc_codec *codec;
1109 int i; 1110 int i;
1110 1111
1111 /* our power state is still SNDRV_CTL_POWER_D3hot from suspend time, 1112 /* our power state is still SNDRV_CTL_POWER_D3hot from suspend time,
@@ -1131,8 +1132,7 @@ static void soc_resume_deferred(struct work_struct *work)
1131 cpu_dai->driver->resume(cpu_dai); 1132 cpu_dai->driver->resume(cpu_dai);
1132 } 1133 }
1133 1134
1134 for (i = 0; i < card->num_rtd; i++) { 1135 list_for_each_entry(codec, &card->codec_dev_list, card_list) {
1135 struct snd_soc_codec *codec = card->rtd[i].codec;
1136 /* If the CODEC was idle over suspend then it will have been 1136 /* If the CODEC was idle over suspend then it will have been
1137 * left with bias OFF or STANDBY and suspended so we must now 1137 * left with bias OFF or STANDBY and suspended so we must now
1138 * resume. Otherwise the suspend was suppressed. 1138 * resume. Otherwise the suspend was suppressed.
@@ -1603,6 +1603,130 @@ static void soc_unregister_ac97_dai_link(struct snd_soc_codec *codec)
1603} 1603}
1604#endif 1604#endif
1605 1605
1606static int soc_probe_aux_dev(struct snd_soc_card *card, int num)
1607{
1608 struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num];
1609 struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num];
1610 struct snd_soc_codec *codec;
1611 const char *temp;
1612 int ret = 0;
1613
1614 /* find CODEC from registered CODECs*/
1615 list_for_each_entry(codec, &codec_list, list) {
1616 if (!strcmp(codec->name, aux_dev->codec_name)) {
1617 if (codec->probed) {
1618 dev_err(codec->dev,
1619 "asoc: codec already probed");
1620 ret = -EBUSY;
1621 goto out;
1622 }
1623 break;
1624 }
1625 }
1626
1627 if (!try_module_get(codec->dev->driver->owner))
1628 return -ENODEV;
1629
1630 codec->card = card;
1631 codec->dapm.card = card;
1632
1633 soc_set_name_prefix(card, codec);
1634 if (codec->driver->probe) {
1635 ret = codec->driver->probe(codec);
1636 if (ret < 0) {
1637 dev_err(codec->dev, "asoc: failed to probe CODEC");
1638 return ret;
1639 }
1640 }
1641
1642 soc_init_codec_debugfs(codec);
1643
1644 /* mark codec as probed and add to card codec list */
1645 codec->probed = 1;
1646 list_add(&codec->card_list, &card->codec_dev_list);
1647 list_add(&codec->dapm.list, &card->dapm_list);
1648
1649 /* now that all clients have probed, initialise the DAI link */
1650 if (aux_dev->init) {
1651 /* machine controls, routes and widgets are not prefixed */
1652 temp = codec->name_prefix;
1653 codec->name_prefix = NULL;
1654 ret = aux_dev->init(&codec->dapm);
1655 if (ret < 0) {
1656 dev_err(codec->dev,
1657 "asoc: failed to init %s\n", aux_dev->name);
1658 return ret;
1659 }
1660 codec->name_prefix = temp;
1661 }
1662
1663 /* Make sure all DAPM widgets are instantiated */
1664 snd_soc_dapm_new_widgets(&codec->dapm);
1665 snd_soc_dapm_sync(&codec->dapm);
1666
1667 /* register the rtd device */
1668 rtd->codec = codec;
1669 rtd->card = card;
1670 rtd->dev.parent = card->dev;
1671 rtd->dev.release = rtd_release;
1672 rtd->dev.init_name = aux_dev->name;
1673 ret = device_register(&rtd->dev);
1674 if (ret < 0) {
1675 dev_err(codec->dev,
1676 "asoc: failed to register aux runtime device %d\n",
1677 ret);
1678 return ret;
1679 }
1680 rtd->dev_registered = 1;
1681
1682 /* add DAPM sysfs entries for this codec */
1683 ret = snd_soc_dapm_sys_add(&rtd->dev);
1684 if (ret < 0)
1685 dev_err(codec->dev,
1686 "asoc: failed to add codec dapm sysfs entries\n");
1687
1688 /* add codec sysfs entries */
1689 ret = device_create_file(&rtd->dev, &dev_attr_codec_reg);
1690 if (ret < 0)
1691 dev_err(codec->dev, "asoc: failed to add codec sysfs files\n");
1692
1693out:
1694 return ret;
1695}
1696
1697static void soc_remove_aux_dev(struct snd_soc_card *card, int num)
1698{
1699 struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num];
1700 struct snd_soc_codec *codec = rtd->codec;
1701 int err;
1702
1703 /* unregister the rtd device */
1704 if (rtd->dev_registered) {
1705 device_unregister(&rtd->dev);
1706 rtd->dev_registered = 0;
1707 }
1708
1709 /* remove the CODEC */
1710 if (codec && codec->probed) {
1711 if (codec->driver->remove) {
1712 err = codec->driver->remove(codec);
1713 if (err < 0)
1714 dev_err(codec->dev,
1715 "asoc: failed to remove %s\n",
1716 codec->name);
1717 }
1718
1719 /* Make sure all DAPM widgets are freed */
1720 snd_soc_dapm_free(&codec->dapm);
1721
1722 soc_cleanup_codec_debugfs(codec);
1723 device_remove_file(&rtd->dev, &dev_attr_codec_reg);
1724 codec->probed = 0;
1725 list_del(&codec->card_list);
1726 module_put(codec->dev->driver->owner);
1727 }
1728}
1729
1606static void snd_soc_instantiate_card(struct snd_soc_card *card) 1730static void snd_soc_instantiate_card(struct snd_soc_card *card)
1607{ 1731{
1608 struct platform_device *pdev = to_platform_device(card->dev); 1732 struct platform_device *pdev = to_platform_device(card->dev);
@@ -1657,6 +1781,15 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
1657 } 1781 }
1658 } 1782 }
1659 1783
1784 for (i = 0; i < card->num_aux_devs; i++) {
1785 ret = soc_probe_aux_dev(card, i);
1786 if (ret < 0) {
1787 pr_err("asoc: failed to add auxiliary devices %s: %d\n",
1788 card->name, ret);
1789 goto probe_aux_dev_err;
1790 }
1791 }
1792
1660 snprintf(card->snd_card->shortname, sizeof(card->snd_card->shortname), 1793 snprintf(card->snd_card->shortname, sizeof(card->snd_card->shortname),
1661 "%s", card->name); 1794 "%s", card->name);
1662 snprintf(card->snd_card->longname, sizeof(card->snd_card->longname), 1795 snprintf(card->snd_card->longname, sizeof(card->snd_card->longname),
@@ -1683,6 +1816,10 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
1683 mutex_unlock(&card->mutex); 1816 mutex_unlock(&card->mutex);
1684 return; 1817 return;
1685 1818
1819probe_aux_dev_err:
1820 for (i = 0; i < card->num_aux_devs; i++)
1821 soc_remove_aux_dev(card, i);
1822
1686probe_dai_err: 1823probe_dai_err:
1687 for (i = 0; i < card->num_links; i++) 1824 for (i = 0; i < card->num_links; i++)
1688 soc_remove_dai_link(card, i); 1825 soc_remove_dai_link(card, i);
@@ -1744,6 +1881,10 @@ static int soc_remove(struct platform_device *pdev)
1744 run_delayed_work(&rtd->delayed_work); 1881 run_delayed_work(&rtd->delayed_work);
1745 } 1882 }
1746 1883
1884 /* remove auxiliary devices */
1885 for (i = 0; i < card->num_aux_devs; i++)
1886 soc_remove_aux_dev(card, i);
1887
1747 /* remove and free each DAI */ 1888 /* remove and free each DAI */
1748 for (i = 0; i < card->num_rtd; i++) 1889 for (i = 0; i < card->num_rtd; i++)
1749 soc_remove_dai_link(card, i); 1890 soc_remove_dai_link(card, i);
@@ -2946,10 +3087,12 @@ static int snd_soc_register_card(struct snd_soc_card *card)
2946 if (!card->name || !card->dev) 3087 if (!card->name || !card->dev)
2947 return -EINVAL; 3088 return -EINVAL;
2948 3089
2949 card->rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime) * card->num_links, 3090 card->rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime) *
2950 GFP_KERNEL); 3091 (card->num_links + card->num_aux_devs),
3092 GFP_KERNEL);
2951 if (card->rtd == NULL) 3093 if (card->rtd == NULL)
2952 return -ENOMEM; 3094 return -ENOMEM;
3095 card->rtd_aux = &card->rtd[card->num_links];
2953 3096
2954 for (i = 0; i < card->num_links; i++) 3097 for (i = 0; i < card->num_links; i++)
2955 card->rtd[i].dai_link = &card->dai_link[i]; 3098 card->rtd[i].dai_link = &card->dai_link[i];