@@ -1012,6 +1012,13 @@ struct snd_soc_platform_driver {
/* platform stream compress ops */
const struct snd_compr_ops *compr_ops;
+
+ /* this platform uses topology and ignore machine driver FEs */
+ const char *ignore_machine;
+ int (*be_hw_params_fixup)(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params);
+ bool use_dai_pcm_id; /* use the DAI link PCM ID as PCM device number */
+ int be_pcm_base; /* base device ID for all BE PCMs */
};
struct snd_soc_dai_link_component {
@@ -1118,6 +1125,9 @@ struct snd_soc_dai_link {
/* pmdown_time is ignored at stop */
unsigned int ignore_pmdown_time:1;
+ /* Do not create a PCM for this DAI link (Backend link) */
+ unsigned int ignore:1;
+
struct list_head list; /* DAI link list of the soc card */
struct snd_soc_dobj dobj; /* For topology */
};
@@ -1050,6 +1050,9 @@ static int soc_bind_dai_link(struct snd_soc_card *card,
const char *platform_name;
int i;
+ if (dai_link->ignore)
+ return 0;
+
dev_dbg(card->dev, "ASoC: binding %s\n", dai_link->name);
if (soc_is_dai_link_bound(card, dai_link)) {
@@ -1672,7 +1675,7 @@ static int soc_probe_link_dais(struct snd_soc_card *card,
{
struct snd_soc_dai_link *dai_link = rtd->dai_link;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- int i, ret;
+ int i, ret, num;
dev_dbg(card->dev, "ASoC: probe %s dai link %d late %d\n",
card->name, rtd->num, order);
@@ -1718,9 +1721,23 @@ static int soc_probe_link_dais(struct snd_soc_card *card,
soc_dpcm_debugfs_add(rtd);
#endif
+ /*
+ * most drivers will register their PCMs using DAI link ordering but
+ * topology based drivers can use the DAI link id field to set PCM
+ * device number and then use rtd + a base offset of the BEs.
+ */
+ if (rtd->platform->driver->use_dai_pcm_id) {
+ if (rtd->dai_link->no_pcm)
+ num = rtd->platform->driver->be_pcm_base + rtd->num;
+ else
+ num = rtd->dai_link->id;
+ } else {
+ num = rtd->num;
+ }
+
if (cpu_dai->driver->compress_new) {
/*create compress_device"*/
- ret = cpu_dai->driver->compress_new(rtd, rtd->num);
+ ret = cpu_dai->driver->compress_new(rtd, num);
if (ret < 0) {
dev_err(card->dev, "ASoC: can't create compress %s\n",
dai_link->stream_name);
@@ -1730,7 +1747,7 @@ static int soc_probe_link_dais(struct snd_soc_card *card,
if (!dai_link->params) {
/* create the pcm */
- ret = soc_new_pcm(rtd, rtd->num);
+ ret = soc_new_pcm(rtd, num);
if (ret < 0) {
dev_err(card->dev, "ASoC: can't create pcm %s :%d\n",
dai_link->stream_name, ret);
@@ -2076,6 +2093,59 @@ int snd_soc_set_dmi_name(struct snd_soc_card *card, const char *flavour)
EXPORT_SYMBOL_GPL(snd_soc_set_dmi_name);
#endif /* CONFIG_DMI */
+static void soc_check_tplg_fes(struct snd_soc_card *card)
+{
+ struct snd_soc_platform *platform;
+ struct snd_soc_dai_link *dai_link;
+ int i;
+
+ list_for_each_entry(platform, &platform_list, list) {
+
+ /* does this platform override FEs ? */
+ if (!platform->driver->ignore_machine)
+ continue;
+
+ /* for this machine ? */
+ if (strcmp(platform->driver->ignore_machine,
+ card->dev->driver->name))
+ continue;
+
+ /* machine matches, so override the rtd data */
+ for (i = 0; i < card->num_links; i++) {
+
+ dai_link = &card->dai_link[i];
+
+ /* ignore this FE */
+ if (dai_link->dynamic) {
+ dai_link->ignore = true;
+ continue;
+ }
+
+ dev_info(card->dev, "info: override FE DAI link %s\n",
+ card->dai_link[i].name);
+
+ /* override platform */
+ dai_link->platform_name = platform->component.name;
+ dai_link->cpu_dai_name = platform->component.name;
+
+ /* convert non BE into BE */
+ dai_link->no_pcm = 1;
+ dai_link->dpcm_playback = 1;
+ dai_link->dpcm_capture = 1;
+
+ /* override any BE fixups */
+ dai_link->be_hw_params_fixup =
+ platform->driver->be_hw_params_fixup;
+
+ /* most BE links dont set stream name, so set it to
+ * dai link name if it's NULL to help bind widgets.
+ */
+ if (!dai_link->stream_name)
+ dai_link->stream_name = dai_link->name;
+ }
+ }
+}
+
static int snd_soc_instantiate_card(struct snd_soc_card *card)
{
struct snd_soc_codec *codec;
@@ -2086,6 +2156,9 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
mutex_lock(&client_mutex);
mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_INIT);
+ /* check whether any platform is ignore machine FE and using topology */
+ soc_check_tplg_fes(card);
+
/* bind DAIs */
for (i = 0; i < card->num_links; i++) {
ret = soc_bind_dai_link(card, &card->dai_link[i]);
@@ -909,8 +909,20 @@ int soc_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
int ret;
+ /* perform any topology hw_params fixups before DAI */
+ if (rtd->dai_link->be_hw_params_fixup) {
+ ret = rtd->dai_link->be_hw_params_fixup(rtd, params);
+ if (ret < 0) {
+ dev_err(rtd->dev,
+ "ASoC: hw_params topology fixup failed %d\n",
+ ret);
+ return ret;
+ }
+ }
+
if (dai->driver->ops->hw_params) {
ret = dai->driver->ops->hw_params(substream, params, dai);
if (ret < 0) {