Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ASoC: dpcm: Add bespoke trigger()

Some on SoC DSP HW is very tightly coupled with DMA and DAI drivers. It's
necessary to allow some flexability wrt to PCM operations here so that we
can define a bespoke DPCM trigger() PCM operation for such HW.

A bespoke DPCM trigger() allows exact ordering and timing of component
triggering by allowing a component driver to manage the final enable
and disable configurations without adding extra complexity to other
component drivers. e.g. The McPDM DAI and ABE are tightly coupled on
OMAP4 so we have a bespoke trigger to manage the trigger to improve
performance and reduce complexity when triggering new McPDM BEs.

Signed-off-by: Liam Girdwood <lrg@ti.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>

authored by

Liam Girdwood and committed by
Mark Brown
07bf84aa 47c88fff

+96 -10
+2
include/sound/soc-dai.h
··· 173 173 struct snd_soc_dai *); 174 174 int (*trigger)(struct snd_pcm_substream *, int, 175 175 struct snd_soc_dai *); 176 + int (*bespoke_trigger)(struct snd_pcm_substream *, int, 177 + struct snd_soc_dai *); 176 178 /* 177 179 * For hardware based FIFO caused delay reporting. 178 180 * Optional.
+1
include/sound/soc-dpcm.h
··· 60 60 enum snd_soc_dpcm_trigger { 61 61 SND_SOC_DPCM_TRIGGER_PRE = 0, 62 62 SND_SOC_DPCM_TRIGGER_POST, 63 + SND_SOC_DPCM_TRIGGER_BESPOKE, 63 64 }; 64 65 65 66 /*
+4
include/sound/soc.h
··· 377 377 int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream, 378 378 const struct snd_pcm_hardware *hw); 379 379 380 + int snd_soc_platform_trigger(struct snd_pcm_substream *substream, 381 + int cmd, struct snd_soc_platform *platform); 382 + 380 383 /* Jack reporting */ 381 384 int snd_soc_jack_new(struct snd_soc_codec *codec, const char *id, int type, 382 385 struct snd_soc_jack *jack); ··· 756 753 /* platform IO - used for platform DAPM */ 757 754 unsigned int (*read)(struct snd_soc_platform *, unsigned int); 758 755 int (*write)(struct snd_soc_platform *, unsigned int, unsigned int); 756 + int (*bespoke_trigger)(struct snd_pcm_substream *, int); 759 757 }; 760 758 761 759 struct snd_soc_platform {
+89 -10
sound/soc/soc-pcm.c
··· 632 632 return 0; 633 633 } 634 634 635 + int soc_pcm_bespoke_trigger(struct snd_pcm_substream *substream, int cmd) 636 + { 637 + struct snd_soc_pcm_runtime *rtd = substream->private_data; 638 + struct snd_soc_platform *platform = rtd->platform; 639 + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; 640 + struct snd_soc_dai *codec_dai = rtd->codec_dai; 641 + int ret; 642 + 643 + if (codec_dai->driver->ops->bespoke_trigger) { 644 + ret = codec_dai->driver->ops->bespoke_trigger(substream, cmd, codec_dai); 645 + if (ret < 0) 646 + return ret; 647 + } 648 + 649 + if (platform->driver->bespoke_trigger) { 650 + ret = platform->driver->bespoke_trigger(substream, cmd); 651 + if (ret < 0) 652 + return ret; 653 + } 654 + 655 + if (cpu_dai->driver->ops->bespoke_trigger) { 656 + ret = cpu_dai->driver->ops->bespoke_trigger(substream, cmd, cpu_dai); 657 + if (ret < 0) 658 + return ret; 659 + } 660 + return 0; 661 + } 635 662 /* 636 663 * soc level wrapper for pointer callback 637 664 * If cpu_dai, codec_dai, platform driver has the delay callback, than ··· 1534 1507 1535 1508 ret = soc_pcm_trigger(substream, cmd); 1536 1509 break; 1510 + case SND_SOC_DPCM_TRIGGER_BESPOKE: 1511 + /* bespoke trigger() - handles both FE and BEs */ 1512 + 1513 + dev_dbg(fe->dev, "dpcm: bespoke trigger FE %s cmd %d\n", 1514 + fe->dai_link->name, cmd); 1515 + 1516 + ret = soc_pcm_bespoke_trigger(substream, cmd); 1517 + if (ret < 0) { 1518 + dev_err(fe->dev,"dpcm: trigger FE failed %d\n", ret); 1519 + goto out; 1520 + } 1521 + break; 1537 1522 default: 1538 1523 dev_err(fe->dev, "dpcm: invalid trigger cmd %d for %s\n", cmd, 1539 1524 fe->dai_link->name); ··· 1649 1610 1650 1611 static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream) 1651 1612 { 1613 + struct snd_pcm_substream *substream = 1614 + snd_soc_dpcm_get_substream(fe, stream); 1615 + enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream]; 1652 1616 int err; 1653 1617 1654 1618 dev_dbg(fe->dev, "runtime %s close on FE %s\n", 1655 1619 stream ? "capture" : "playback", fe->dai_link->name); 1656 1620 1657 - err = dpcm_be_dai_trigger(fe, stream, SNDRV_PCM_TRIGGER_STOP); 1658 - if (err < 0) 1659 - dev_err(fe->dev,"dpcm: trigger FE failed %d\n", err); 1621 + if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) { 1622 + /* call bespoke trigger - FE takes care of all BE triggers */ 1623 + dev_dbg(fe->dev, "dpcm: bespoke trigger FE %s cmd stop\n", 1624 + fe->dai_link->name); 1625 + 1626 + err = soc_pcm_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_STOP); 1627 + if (err < 0) 1628 + dev_err(fe->dev,"dpcm: trigger FE failed %d\n", err); 1629 + } else { 1630 + dev_dbg(fe->dev, "dpcm: trigger FE %s cmd stop\n", 1631 + fe->dai_link->name); 1632 + 1633 + err = dpcm_be_dai_trigger(fe, stream, SNDRV_PCM_TRIGGER_STOP); 1634 + if (err < 0) 1635 + dev_err(fe->dev,"dpcm: trigger FE failed %d\n", err); 1636 + } 1660 1637 1661 1638 err = dpcm_be_dai_hw_free(fe, stream); 1662 1639 if (err < 0) ··· 1690 1635 1691 1636 static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream) 1692 1637 { 1638 + struct snd_pcm_substream *substream = 1639 + snd_soc_dpcm_get_substream(fe, stream); 1693 1640 struct snd_soc_dpcm *dpcm; 1641 + enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream]; 1694 1642 int ret; 1695 1643 1696 1644 dev_dbg(fe->dev, "runtime %s open on FE %s\n", ··· 1740 1682 fe->dpcm[stream].state == SND_SOC_DPCM_STATE_STOP) 1741 1683 return 0; 1742 1684 1743 - dev_dbg(fe->dev, "dpcm: trigger FE %s cmd start\n", 1744 - fe->dai_link->name); 1685 + if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) { 1686 + /* call trigger on the frontend - FE takes care of all BE triggers */ 1687 + dev_dbg(fe->dev, "dpcm: bespoke trigger FE %s cmd start\n", 1688 + fe->dai_link->name); 1745 1689 1746 - ret = dpcm_be_dai_trigger(fe, stream, 1747 - SNDRV_PCM_TRIGGER_START); 1748 - if (ret < 0) { 1749 - dev_err(fe->dev,"dpcm: trigger FE failed %d\n", ret); 1750 - goto hw_free; 1690 + ret = soc_pcm_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_START); 1691 + if (ret < 0) { 1692 + dev_err(fe->dev,"dpcm: bespoke trigger FE failed %d\n", ret); 1693 + goto hw_free; 1694 + } 1695 + } else { 1696 + dev_dbg(fe->dev, "dpcm: trigger FE %s cmd start\n", 1697 + fe->dai_link->name); 1698 + 1699 + ret = dpcm_be_dai_trigger(fe, stream, 1700 + SNDRV_PCM_TRIGGER_START); 1701 + if (ret < 0) { 1702 + dev_err(fe->dev,"dpcm: trigger FE failed %d\n", ret); 1703 + goto hw_free; 1704 + } 1751 1705 } 1752 1706 1753 1707 return 0; ··· 2189 2119 return 1; 2190 2120 } 2191 2121 EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_params); 2122 + 2123 + int snd_soc_platform_trigger(struct snd_pcm_substream *substream, 2124 + int cmd, struct snd_soc_platform *platform) 2125 + { 2126 + if (platform->driver->ops->trigger) 2127 + return platform->driver->ops->trigger(substream, cmd); 2128 + return 0; 2129 + } 2130 + EXPORT_SYMBOL_GPL(snd_soc_platform_trigger); 2192 2131 2193 2132 #ifdef CONFIG_DEBUG_FS 2194 2133 static char *dpcm_state_string(enum snd_soc_dpcm_state state)