aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc
diff options
context:
space:
mode:
authorLiam Girdwood <lrg@ti.com>2012-04-25 07:12:51 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2012-04-26 12:48:19 -0400
commit618dae11f809aaccd05710aa8cee8c46a9cef1a7 (patch)
tree99c882f9657b492bc2b721e36e82831efb1b66ca /sound/soc
parentf86dcef87b771935c223334324a93c1d71f7a84c (diff)
ASoC: dpcm: Add runtime dynamic route update
This patch allows DPCM to dynamically alter the FE to BE PCM links at runtime based on mixer setting updates. DAPM is looked up after every mixer update and we perform a DPCM runtime update if the mixer has a change of value. This patchs adds/changes the following :- o Adds DPCM runtime update core. o Changes soc_dapm_mixer_update_power() and soc_dapm_mux_update_power() to return if a change has occured rather than 0. No other users check atm. Signed-off-by: Liam Girdwood <lrg@ti.com> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc')
-rw-r--r--sound/soc/soc-dapm.c8
-rw-r--r--sound/soc/soc-pcm.c221
2 files changed, 227 insertions, 2 deletions
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 214323f53956..02db2c09076b 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -1846,7 +1846,7 @@ static int soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
1846 dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP); 1846 dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP);
1847 } 1847 }
1848 1848
1849 return 0; 1849 return found;
1850} 1850}
1851 1851
1852int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget, 1852int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
@@ -1858,6 +1858,8 @@ int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
1858 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); 1858 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
1859 ret = soc_dapm_mux_update_power(widget, kcontrol, mux, e); 1859 ret = soc_dapm_mux_update_power(widget, kcontrol, mux, e);
1860 mutex_unlock(&card->dapm_mutex); 1860 mutex_unlock(&card->dapm_mutex);
1861 if (ret > 0)
1862 soc_dpcm_runtime_update(widget);
1861 return ret; 1863 return ret;
1862} 1864}
1863EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power); 1865EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power);
@@ -1890,7 +1892,7 @@ static int soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
1890 dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP); 1892 dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP);
1891 } 1893 }
1892 1894
1893 return 0; 1895 return found;
1894} 1896}
1895 1897
1896int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, 1898int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
@@ -1902,6 +1904,8 @@ int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
1902 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); 1904 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
1903 ret = soc_dapm_mixer_update_power(widget, kcontrol, connect); 1905 ret = soc_dapm_mixer_update_power(widget, kcontrol, connect);
1904 mutex_unlock(&card->dapm_mutex); 1906 mutex_unlock(&card->dapm_mutex);
1907 if (ret > 0)
1908 soc_dpcm_runtime_update(widget);
1905 return ret; 1909 return ret;
1906} 1910}
1907EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power); 1911EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power);
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index a1d4426a99d9..ca36fd6746fc 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -1608,7 +1608,228 @@ out:
1608 return ret; 1608 return ret;
1609} 1609}
1610 1610
1611static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
1612{
1613 int err;
1614
1615 dev_dbg(fe->dev, "runtime %s close on FE %s\n",
1616 stream ? "capture" : "playback", fe->dai_link->name);
1617
1618 err = dpcm_be_dai_trigger(fe, stream, SNDRV_PCM_TRIGGER_STOP);
1619 if (err < 0)
1620 dev_err(fe->dev,"dpcm: trigger FE failed %d\n", err);
1621
1622 err = dpcm_be_dai_hw_free(fe, stream);
1623 if (err < 0)
1624 dev_err(fe->dev,"dpcm: hw_free FE failed %d\n", err);
1625
1626 err = dpcm_be_dai_shutdown(fe, stream);
1627 if (err < 0)
1628 dev_err(fe->dev,"dpcm: shutdown FE failed %d\n", err);
1629
1630 /* run the stream event for each BE */
1631 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP);
1632
1633 return 0;
1634}
1635
1636static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream)
1637{
1638 struct snd_soc_dpcm *dpcm;
1639 int ret;
1640
1641 dev_dbg(fe->dev, "runtime %s open on FE %s\n",
1642 stream ? "capture" : "playback", fe->dai_link->name);
1643
1644 /* Only start the BE if the FE is ready */
1645 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_FREE ||
1646 fe->dpcm[stream].state == SND_SOC_DPCM_STATE_CLOSE)
1647 return -EINVAL;
1648
1649 /* startup must always be called for new BEs */
1650 ret = dpcm_be_dai_startup(fe, stream);
1651 if (ret < 0) {
1652 goto disconnect;
1653 return ret;
1654 }
1655
1656 /* keep going if FE state is > open */
1657 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_OPEN)
1658 return 0;
1611 1659
1660 ret = dpcm_be_dai_hw_params(fe, stream);
1661 if (ret < 0) {
1662 goto close;
1663 return ret;
1664 }
1665
1666 /* keep going if FE state is > hw_params */
1667 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_PARAMS)
1668 return 0;
1669
1670
1671 ret = dpcm_be_dai_prepare(fe, stream);
1672 if (ret < 0) {
1673 goto hw_free;
1674 return ret;
1675 }
1676
1677 /* run the stream event for each BE */
1678 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP);
1679
1680 /* keep going if FE state is > prepare */
1681 if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_PREPARE ||
1682 fe->dpcm[stream].state == SND_SOC_DPCM_STATE_STOP)
1683 return 0;
1684
1685 dev_dbg(fe->dev, "dpcm: trigger FE %s cmd start\n",
1686 fe->dai_link->name);
1687
1688 ret = dpcm_be_dai_trigger(fe, stream,
1689 SNDRV_PCM_TRIGGER_START);
1690 if (ret < 0) {
1691 dev_err(fe->dev,"dpcm: trigger FE failed %d\n", ret);
1692 goto hw_free;
1693 }
1694
1695 return 0;
1696
1697hw_free:
1698 dpcm_be_dai_hw_free(fe, stream);
1699close:
1700 dpcm_be_dai_shutdown(fe, stream);
1701disconnect:
1702 /* disconnect any non started BEs */
1703 list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
1704 struct snd_soc_pcm_runtime *be = dpcm->be;
1705 if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
1706 dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
1707 }
1708
1709 return ret;
1710}
1711
1712static int dpcm_run_new_update(struct snd_soc_pcm_runtime *fe, int stream)
1713{
1714 int ret;
1715
1716 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE;
1717 ret = dpcm_run_update_startup(fe, stream);
1718 if (ret < 0)
1719 dev_err(fe->dev, "failed to startup some BEs\n");
1720 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
1721
1722 return ret;
1723}
1724
1725static int dpcm_run_old_update(struct snd_soc_pcm_runtime *fe, int stream)
1726{
1727 int ret;
1728
1729 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE;
1730 ret = dpcm_run_update_shutdown(fe, stream);
1731 if (ret < 0)
1732 dev_err(fe->dev, "failed to shutdown some BEs\n");
1733 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
1734
1735 return ret;
1736}
1737
1738/* Called by DAPM mixer/mux changes to update audio routing between PCMs and
1739 * any DAI links.
1740 */
1741int soc_dpcm_runtime_update(struct snd_soc_dapm_widget *widget)
1742{
1743 struct snd_soc_card *card;
1744 int i, old, new, paths;
1745
1746 if (widget->codec)
1747 card = widget->codec->card;
1748 else if (widget->platform)
1749 card = widget->platform->card;
1750 else
1751 return -EINVAL;
1752
1753 mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
1754 for (i = 0; i < card->num_rtd; i++) {
1755 struct snd_soc_dapm_widget_list *list;
1756 struct snd_soc_pcm_runtime *fe = &card->rtd[i];
1757
1758 /* make sure link is FE */
1759 if (!fe->dai_link->dynamic)
1760 continue;
1761
1762 /* only check active links */
1763 if (!fe->cpu_dai->active)
1764 continue;
1765
1766 /* DAPM sync will call this to update DSP paths */
1767 dev_dbg(fe->dev, "DPCM runtime update for FE %s\n",
1768 fe->dai_link->name);
1769
1770 /* skip if FE doesn't have playback capability */
1771 if (!fe->cpu_dai->driver->playback.channels_min)
1772 goto capture;
1773
1774 paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_PLAYBACK, &list);
1775 if (paths < 0) {
1776 dev_warn(fe->dev, "%s no valid %s path\n",
1777 fe->dai_link->name, "playback");
1778 mutex_unlock(&card->mutex);
1779 return paths;
1780 }
1781
1782 /* update any new playback paths */
1783 new = dpcm_process_paths(fe, SNDRV_PCM_STREAM_PLAYBACK, &list, 1);
1784 if (new) {
1785 dpcm_run_new_update(fe, SNDRV_PCM_STREAM_PLAYBACK);
1786 dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_PLAYBACK);
1787 dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_PLAYBACK);
1788 }
1789
1790 /* update any old playback paths */
1791 old = dpcm_process_paths(fe, SNDRV_PCM_STREAM_PLAYBACK, &list, 0);
1792 if (old) {
1793 dpcm_run_old_update(fe, SNDRV_PCM_STREAM_PLAYBACK);
1794 dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_PLAYBACK);
1795 dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_PLAYBACK);
1796 }
1797
1798capture:
1799 /* skip if FE doesn't have capture capability */
1800 if (!fe->cpu_dai->driver->capture.channels_min)
1801 continue;
1802
1803 paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_CAPTURE, &list);
1804 if (paths < 0) {
1805 dev_warn(fe->dev, "%s no valid %s path\n",
1806 fe->dai_link->name, "capture");
1807 mutex_unlock(&card->mutex);
1808 return paths;
1809 }
1810
1811 /* update any new capture paths */
1812 new = dpcm_process_paths(fe, SNDRV_PCM_STREAM_CAPTURE, &list, 1);
1813 if (new) {
1814 dpcm_run_new_update(fe, SNDRV_PCM_STREAM_CAPTURE);
1815 dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_CAPTURE);
1816 dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_CAPTURE);
1817 }
1818
1819 /* update any old capture paths */
1820 old = dpcm_process_paths(fe, SNDRV_PCM_STREAM_CAPTURE, &list, 0);
1821 if (old) {
1822 dpcm_run_old_update(fe, SNDRV_PCM_STREAM_CAPTURE);
1823 dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_CAPTURE);
1824 dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_CAPTURE);
1825 }
1826
1827 dpcm_path_put(&list);
1828 }
1829
1830 mutex_unlock(&card->mutex);
1831 return 0;
1832}
1612int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute) 1833int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute)
1613{ 1834{
1614 struct snd_soc_dpcm *dpcm; 1835 struct snd_soc_dpcm *dpcm;