|
8 | 8 | // |
9 | 9 |
|
10 | 10 | #include <uapi/sound/sof/tokens.h> |
| 11 | +#include <sound/pcm_params.h> |
11 | 12 | #include "sof-priv.h" |
12 | 13 | #include "sof-audio.h" |
13 | 14 | #include "ops.h" |
@@ -1698,6 +1699,194 @@ static int sof_ipc3_control_free(struct snd_sof_dev *sdev, struct snd_sof_contro |
1698 | 1699 | return sof_ipc_tx_message(sdev->ipc, fcomp.hdr.cmd, &fcomp, sizeof(fcomp), NULL, 0); |
1699 | 1700 | } |
1700 | 1701 |
|
| 1702 | +/* send pcm params ipc */ |
| 1703 | +static int sof_ipc3_keyword_detect_pcm_params(struct snd_sof_widget *swidget, int dir) |
| 1704 | +{ |
| 1705 | + struct snd_soc_component *scomp = swidget->scomp; |
| 1706 | + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); |
| 1707 | + struct sof_ipc_pcm_params_reply ipc_params_reply; |
| 1708 | + struct snd_pcm_hw_params *params; |
| 1709 | + struct sof_ipc_pcm_params pcm; |
| 1710 | + struct snd_sof_pcm *spcm; |
| 1711 | + int ret; |
| 1712 | + |
| 1713 | + /* get runtime PCM params using widget's stream name */ |
| 1714 | + spcm = snd_sof_find_spcm_name(scomp, swidget->widget->sname); |
| 1715 | + if (!spcm) { |
| 1716 | + dev_err(scomp->dev, "Cannot find PCM for %s\n", swidget->widget->name); |
| 1717 | + return -EINVAL; |
| 1718 | + } |
| 1719 | + |
| 1720 | + params = &spcm->params[dir]; |
| 1721 | + |
| 1722 | + /* set IPC PCM params */ |
| 1723 | + memset(&pcm, 0, sizeof(pcm)); |
| 1724 | + pcm.hdr.size = sizeof(pcm); |
| 1725 | + pcm.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_PARAMS; |
| 1726 | + pcm.comp_id = swidget->comp_id; |
| 1727 | + pcm.params.hdr.size = sizeof(pcm.params); |
| 1728 | + pcm.params.direction = dir; |
| 1729 | + pcm.params.sample_valid_bytes = params_width(params) >> 3; |
| 1730 | + pcm.params.buffer_fmt = SOF_IPC_BUFFER_INTERLEAVED; |
| 1731 | + pcm.params.rate = params_rate(params); |
| 1732 | + pcm.params.channels = params_channels(params); |
| 1733 | + pcm.params.host_period_bytes = params_period_bytes(params); |
| 1734 | + |
| 1735 | + /* set format */ |
| 1736 | + switch (params_format(params)) { |
| 1737 | + case SNDRV_PCM_FORMAT_S16: |
| 1738 | + pcm.params.frame_fmt = SOF_IPC_FRAME_S16_LE; |
| 1739 | + break; |
| 1740 | + case SNDRV_PCM_FORMAT_S24: |
| 1741 | + pcm.params.frame_fmt = SOF_IPC_FRAME_S24_4LE; |
| 1742 | + break; |
| 1743 | + case SNDRV_PCM_FORMAT_S32: |
| 1744 | + pcm.params.frame_fmt = SOF_IPC_FRAME_S32_LE; |
| 1745 | + break; |
| 1746 | + default: |
| 1747 | + return -EINVAL; |
| 1748 | + } |
| 1749 | + |
| 1750 | + /* send IPC to the DSP */ |
| 1751 | + ret = sof_ipc_tx_message(sdev->ipc, pcm.hdr.cmd, &pcm, sizeof(pcm), |
| 1752 | + &ipc_params_reply, sizeof(ipc_params_reply)); |
| 1753 | + if (ret < 0) |
| 1754 | + dev_err(scomp->dev, "%s: PCM params failed for %s\n", __func__, |
| 1755 | + swidget->widget->name); |
| 1756 | + |
| 1757 | + return ret; |
| 1758 | +} |
| 1759 | + |
| 1760 | + /* send stream trigger ipc */ |
| 1761 | +static int sof_ipc3_keyword_detect_trigger(struct snd_sof_widget *swidget, int cmd) |
| 1762 | +{ |
| 1763 | + struct snd_soc_component *scomp = swidget->scomp; |
| 1764 | + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); |
| 1765 | + struct sof_ipc_stream stream; |
| 1766 | + struct sof_ipc_reply reply; |
| 1767 | + int ret; |
| 1768 | + |
| 1769 | + /* set IPC stream params */ |
| 1770 | + stream.hdr.size = sizeof(stream); |
| 1771 | + stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | cmd; |
| 1772 | + stream.comp_id = swidget->comp_id; |
| 1773 | + |
| 1774 | + /* send IPC to the DSP */ |
| 1775 | + ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream, |
| 1776 | + sizeof(stream), &reply, sizeof(reply)); |
| 1777 | + if (ret < 0) |
| 1778 | + dev_err(scomp->dev, "%s: Failed to trigger %s\n", __func__, swidget->widget->name); |
| 1779 | + |
| 1780 | + return ret; |
| 1781 | +} |
| 1782 | + |
| 1783 | +static int sof_ipc3_keyword_dapm_event(struct snd_soc_dapm_widget *w, |
| 1784 | + struct snd_kcontrol *k, int event) |
| 1785 | +{ |
| 1786 | + struct snd_sof_widget *swidget = w->dobj.private; |
| 1787 | + struct snd_soc_component *scomp; |
| 1788 | + int stream = SNDRV_PCM_STREAM_CAPTURE; |
| 1789 | + struct snd_sof_pcm *spcm; |
| 1790 | + int ret = 0; |
| 1791 | + |
| 1792 | + if (!swidget) |
| 1793 | + return 0; |
| 1794 | + |
| 1795 | + scomp = swidget->scomp; |
| 1796 | + |
| 1797 | + dev_dbg(scomp->dev, "received event %d for widget %s\n", |
| 1798 | + event, w->name); |
| 1799 | + |
| 1800 | + /* get runtime PCM params using widget's stream name */ |
| 1801 | + spcm = snd_sof_find_spcm_name(scomp, swidget->widget->sname); |
| 1802 | + if (!spcm) { |
| 1803 | + dev_err(scomp->dev, "%s: Cannot find PCM for %s\n", __func__, |
| 1804 | + swidget->widget->name); |
| 1805 | + return -EINVAL; |
| 1806 | + } |
| 1807 | + |
| 1808 | + /* process events */ |
| 1809 | + switch (event) { |
| 1810 | + case SND_SOC_DAPM_PRE_PMU: |
| 1811 | + if (spcm->stream[stream].suspend_ignored) { |
| 1812 | + dev_dbg(scomp->dev, "PRE_PMU event ignored, KWD pipeline is already RUNNING\n"); |
| 1813 | + return 0; |
| 1814 | + } |
| 1815 | + |
| 1816 | + /* set pcm params */ |
| 1817 | + ret = sof_ipc3_keyword_detect_pcm_params(swidget, stream); |
| 1818 | + if (ret < 0) { |
| 1819 | + dev_err(scomp->dev, "%s: Failed to set pcm params for widget %s\n", |
| 1820 | + __func__, swidget->widget->name); |
| 1821 | + break; |
| 1822 | + } |
| 1823 | + |
| 1824 | + /* start trigger */ |
| 1825 | + ret = sof_ipc3_keyword_detect_trigger(swidget, SOF_IPC_STREAM_TRIG_START); |
| 1826 | + if (ret < 0) |
| 1827 | + dev_err(scomp->dev, "%s: Failed to trigger widget %s\n", __func__, |
| 1828 | + swidget->widget->name); |
| 1829 | + break; |
| 1830 | + case SND_SOC_DAPM_POST_PMD: |
| 1831 | + if (spcm->stream[stream].suspend_ignored) { |
| 1832 | + dev_dbg(scomp->dev, |
| 1833 | + "POST_PMD event ignored, KWD pipeline will remain RUNNING\n"); |
| 1834 | + return 0; |
| 1835 | + } |
| 1836 | + |
| 1837 | + /* stop trigger */ |
| 1838 | + ret = sof_ipc3_keyword_detect_trigger(swidget, SOF_IPC_STREAM_TRIG_STOP); |
| 1839 | + if (ret < 0) |
| 1840 | + dev_err(scomp->dev, "%s: Failed to trigger widget %s\n", __func__, |
| 1841 | + swidget->widget->name); |
| 1842 | + |
| 1843 | + /* pcm free */ |
| 1844 | + ret = sof_ipc3_keyword_detect_trigger(swidget, SOF_IPC_STREAM_PCM_FREE); |
| 1845 | + if (ret < 0) |
| 1846 | + dev_err(scomp->dev, "%s: Failed to free PCM for widget %s\n", __func__, |
| 1847 | + swidget->widget->name); |
| 1848 | + break; |
| 1849 | + default: |
| 1850 | + break; |
| 1851 | + } |
| 1852 | + |
| 1853 | + return ret; |
| 1854 | +} |
| 1855 | + |
| 1856 | +/* event handlers for keyword detect component */ |
| 1857 | +static const struct snd_soc_tplg_widget_events sof_kwd_events[] = { |
| 1858 | + {SOF_KEYWORD_DETECT_DAPM_EVENT, sof_ipc3_keyword_dapm_event}, |
| 1859 | +}; |
| 1860 | + |
| 1861 | +static int sof_ipc3_widget_bind_event(struct snd_soc_component *scomp, |
| 1862 | + struct snd_sof_widget *swidget, u16 event_type) |
| 1863 | +{ |
| 1864 | + struct sof_ipc_comp *ipc_comp; |
| 1865 | + |
| 1866 | + /* validate widget event type */ |
| 1867 | + switch (event_type) { |
| 1868 | + case SOF_KEYWORD_DETECT_DAPM_EVENT: |
| 1869 | + /* only KEYWORD_DETECT comps should handle this */ |
| 1870 | + if (swidget->id != snd_soc_dapm_effect) |
| 1871 | + break; |
| 1872 | + |
| 1873 | + ipc_comp = swidget->private; |
| 1874 | + if (ipc_comp && ipc_comp->type != SOF_COMP_KEYWORD_DETECT) |
| 1875 | + break; |
| 1876 | + |
| 1877 | + /* bind event to keyword detect comp */ |
| 1878 | + return snd_soc_tplg_widget_bind_event(swidget->widget, sof_kwd_events, |
| 1879 | + ARRAY_SIZE(sof_kwd_events), event_type); |
| 1880 | + default: |
| 1881 | + break; |
| 1882 | + } |
| 1883 | + |
| 1884 | + dev_err(scomp->dev, "Invalid event type %d for widget %s\n", event_type, |
| 1885 | + swidget->widget->name); |
| 1886 | + |
| 1887 | + return -EINVAL; |
| 1888 | +} |
| 1889 | + |
1701 | 1890 | /* token list for each topology object */ |
1702 | 1891 | static enum sof_tokens host_token_list[] = { |
1703 | 1892 | SOF_CORE_TOKENS, |
@@ -1790,7 +1979,8 @@ static const struct sof_ipc_tplg_widget_ops tplg_ipc3_widget_ops[SND_SOC_DAPM_TY |
1790 | 1979 | comp_generic_token_list, ARRAY_SIZE(comp_generic_token_list), |
1791 | 1980 | NULL}, |
1792 | 1981 | [snd_soc_dapm_effect] = {sof_widget_update_ipc_comp_process, sof_ipc3_widget_free_comp, |
1793 | | - process_token_list, ARRAY_SIZE(process_token_list), NULL}, |
| 1982 | + process_token_list, ARRAY_SIZE(process_token_list), |
| 1983 | + sof_ipc3_widget_bind_event}, |
1794 | 1984 | }; |
1795 | 1985 |
|
1796 | 1986 | static const struct sof_ipc_tplg_ops ipc3_tplg_ops = { |
|
0 commit comments