1f1b3b320SCezary Rojewski // SPDX-License-Identifier: GPL-2.0-only 2f1b3b320SCezary Rojewski // 3f1b3b320SCezary Rojewski // Copyright(c) 2021-2022 Intel Corporation. All rights reserved. 4f1b3b320SCezary Rojewski // 5f1b3b320SCezary Rojewski // Authors: Cezary Rojewski <cezary.rojewski@intel.com> 6f1b3b320SCezary Rojewski // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> 7f1b3b320SCezary Rojewski // 8f1b3b320SCezary Rojewski 9f1b3b320SCezary Rojewski #include <linux/debugfs.h> 10f1b3b320SCezary Rojewski #include <linux/device.h> 11f1b3b320SCezary Rojewski #include <sound/hda_register.h> 12f1b3b320SCezary Rojewski #include <sound/hdaudio_ext.h> 139114700bSCezary Rojewski #include <sound/pcm_params.h> 14f1b3b320SCezary Rojewski #include <sound/soc-acpi.h> 15f1b3b320SCezary Rojewski #include <sound/soc-acpi-intel-match.h> 16f1b3b320SCezary Rojewski #include <sound/soc-component.h> 17f1b3b320SCezary Rojewski #include "avs.h" 18f1b3b320SCezary Rojewski #include "path.h" 19f1b3b320SCezary Rojewski #include "topology.h" 20f1b3b320SCezary Rojewski 21f1b3b320SCezary Rojewski struct avs_dma_data { 22f1b3b320SCezary Rojewski struct avs_tplg_path_template *template; 23f1b3b320SCezary Rojewski struct avs_path *path; 24f1b3b320SCezary Rojewski /* 25f1b3b320SCezary Rojewski * link stream is stored within substream's runtime 26f1b3b320SCezary Rojewski * private_data to fulfill the needs of codec BE path 27f1b3b320SCezary Rojewski * 28f1b3b320SCezary Rojewski * host stream assigned 29f1b3b320SCezary Rojewski */ 30f1b3b320SCezary Rojewski struct hdac_ext_stream *host_stream; 31f1b3b320SCezary Rojewski }; 32f1b3b320SCezary Rojewski 339114700bSCezary Rojewski static struct avs_tplg_path_template * 349114700bSCezary Rojewski avs_dai_find_path_template(struct snd_soc_dai *dai, bool is_fe, int direction) 359114700bSCezary Rojewski { 369114700bSCezary Rojewski struct snd_soc_dapm_widget *dw; 379114700bSCezary Rojewski struct snd_soc_dapm_path *dp; 389114700bSCezary Rojewski enum snd_soc_dapm_direction dir; 399114700bSCezary Rojewski 409114700bSCezary Rojewski if (direction == SNDRV_PCM_STREAM_CAPTURE) { 419114700bSCezary Rojewski dw = dai->capture_widget; 429114700bSCezary Rojewski dir = is_fe ? SND_SOC_DAPM_DIR_OUT : SND_SOC_DAPM_DIR_IN; 439114700bSCezary Rojewski } else { 449114700bSCezary Rojewski dw = dai->playback_widget; 459114700bSCezary Rojewski dir = is_fe ? SND_SOC_DAPM_DIR_IN : SND_SOC_DAPM_DIR_OUT; 469114700bSCezary Rojewski } 479114700bSCezary Rojewski 489114700bSCezary Rojewski dp = list_first_entry_or_null(&dw->edges[dir], typeof(*dp), list_node[dir]); 499114700bSCezary Rojewski if (!dp) 509114700bSCezary Rojewski return NULL; 519114700bSCezary Rojewski 529114700bSCezary Rojewski /* Get the other widget, with actual path template data */ 539114700bSCezary Rojewski dw = (dp->source == dw) ? dp->sink : dp->source; 549114700bSCezary Rojewski 559114700bSCezary Rojewski return dw->priv; 569114700bSCezary Rojewski } 579114700bSCezary Rojewski 589114700bSCezary Rojewski static int avs_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai, bool is_fe) 599114700bSCezary Rojewski { 609114700bSCezary Rojewski struct avs_tplg_path_template *template; 619114700bSCezary Rojewski struct avs_dma_data *data; 629114700bSCezary Rojewski 639114700bSCezary Rojewski template = avs_dai_find_path_template(dai, is_fe, substream->stream); 649114700bSCezary Rojewski if (!template) { 659114700bSCezary Rojewski dev_err(dai->dev, "no %s path for dai %s, invalid tplg?\n", 669114700bSCezary Rojewski snd_pcm_stream_str(substream), dai->name); 679114700bSCezary Rojewski return -EINVAL; 689114700bSCezary Rojewski } 699114700bSCezary Rojewski 709114700bSCezary Rojewski data = kzalloc(sizeof(*data), GFP_KERNEL); 719114700bSCezary Rojewski if (!data) 729114700bSCezary Rojewski return -ENOMEM; 739114700bSCezary Rojewski 749114700bSCezary Rojewski data->template = template; 759114700bSCezary Rojewski snd_soc_dai_set_dma_data(dai, substream, data); 769114700bSCezary Rojewski 779114700bSCezary Rojewski return 0; 789114700bSCezary Rojewski } 799114700bSCezary Rojewski 809114700bSCezary Rojewski static int avs_dai_hw_params(struct snd_pcm_substream *substream, 819114700bSCezary Rojewski struct snd_pcm_hw_params *fe_hw_params, 829114700bSCezary Rojewski struct snd_pcm_hw_params *be_hw_params, struct snd_soc_dai *dai, 839114700bSCezary Rojewski int dma_id) 849114700bSCezary Rojewski { 859114700bSCezary Rojewski struct avs_dma_data *data; 869114700bSCezary Rojewski struct avs_path *path; 879114700bSCezary Rojewski struct avs_dev *adev = to_avs_dev(dai->dev); 889114700bSCezary Rojewski int ret; 899114700bSCezary Rojewski 909114700bSCezary Rojewski data = snd_soc_dai_get_dma_data(dai, substream); 919114700bSCezary Rojewski 929114700bSCezary Rojewski dev_dbg(dai->dev, "%s FE hw_params str %p rtd %p", 939114700bSCezary Rojewski __func__, substream, substream->runtime); 949114700bSCezary Rojewski dev_dbg(dai->dev, "rate %d chn %d vbd %d bd %d\n", 959114700bSCezary Rojewski params_rate(fe_hw_params), params_channels(fe_hw_params), 969114700bSCezary Rojewski params_width(fe_hw_params), params_physical_width(fe_hw_params)); 979114700bSCezary Rojewski 989114700bSCezary Rojewski dev_dbg(dai->dev, "%s BE hw_params str %p rtd %p", 999114700bSCezary Rojewski __func__, substream, substream->runtime); 1009114700bSCezary Rojewski dev_dbg(dai->dev, "rate %d chn %d vbd %d bd %d\n", 1019114700bSCezary Rojewski params_rate(be_hw_params), params_channels(be_hw_params), 1029114700bSCezary Rojewski params_width(be_hw_params), params_physical_width(be_hw_params)); 1039114700bSCezary Rojewski 1049114700bSCezary Rojewski path = avs_path_create(adev, dma_id, data->template, fe_hw_params, be_hw_params); 1059114700bSCezary Rojewski if (IS_ERR(path)) { 1069114700bSCezary Rojewski ret = PTR_ERR(path); 1079114700bSCezary Rojewski dev_err(dai->dev, "create path failed: %d\n", ret); 1089114700bSCezary Rojewski return ret; 1099114700bSCezary Rojewski } 1109114700bSCezary Rojewski 1119114700bSCezary Rojewski data->path = path; 1129114700bSCezary Rojewski return 0; 1139114700bSCezary Rojewski } 1149114700bSCezary Rojewski 115b9062f98SCezary Rojewski static int avs_dai_be_hw_params(struct snd_pcm_substream *substream, 116b9062f98SCezary Rojewski struct snd_pcm_hw_params *be_hw_params, struct snd_soc_dai *dai, 117b9062f98SCezary Rojewski int dma_id) 118b9062f98SCezary Rojewski { 119b9062f98SCezary Rojewski struct snd_pcm_hw_params *fe_hw_params = NULL; 120b9062f98SCezary Rojewski struct snd_soc_pcm_runtime *fe, *be; 121b9062f98SCezary Rojewski struct snd_soc_dpcm *dpcm; 122b9062f98SCezary Rojewski 123b9062f98SCezary Rojewski be = asoc_substream_to_rtd(substream); 124b9062f98SCezary Rojewski for_each_dpcm_fe(be, substream->stream, dpcm) { 125b9062f98SCezary Rojewski fe = dpcm->fe; 126b9062f98SCezary Rojewski fe_hw_params = &fe->dpcm[substream->stream].hw_params; 127b9062f98SCezary Rojewski } 128b9062f98SCezary Rojewski 129b9062f98SCezary Rojewski return avs_dai_hw_params(substream, fe_hw_params, be_hw_params, dai, dma_id); 130b9062f98SCezary Rojewski } 131b9062f98SCezary Rojewski 1329114700bSCezary Rojewski static int avs_dai_prepare(struct avs_dev *adev, struct snd_pcm_substream *substream, 1339114700bSCezary Rojewski struct snd_soc_dai *dai) 1349114700bSCezary Rojewski { 1359114700bSCezary Rojewski struct avs_dma_data *data; 1369114700bSCezary Rojewski int ret; 1379114700bSCezary Rojewski 1389114700bSCezary Rojewski data = snd_soc_dai_get_dma_data(dai, substream); 1399114700bSCezary Rojewski if (!data->path) 1409114700bSCezary Rojewski return 0; 1419114700bSCezary Rojewski 1429114700bSCezary Rojewski ret = avs_path_reset(data->path); 1439114700bSCezary Rojewski if (ret < 0) { 1449114700bSCezary Rojewski dev_err(dai->dev, "reset path failed: %d\n", ret); 1459114700bSCezary Rojewski return ret; 1469114700bSCezary Rojewski } 1479114700bSCezary Rojewski 1489114700bSCezary Rojewski ret = avs_path_pause(data->path); 1499114700bSCezary Rojewski if (ret < 0) 1509114700bSCezary Rojewski dev_err(dai->dev, "pause path failed: %d\n", ret); 1519114700bSCezary Rojewski return ret; 1529114700bSCezary Rojewski } 1539114700bSCezary Rojewski 154b9062f98SCezary Rojewski static int avs_dai_nonhda_be_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) 155b9062f98SCezary Rojewski { 156b9062f98SCezary Rojewski return avs_dai_startup(substream, dai, false); 157b9062f98SCezary Rojewski } 158b9062f98SCezary Rojewski 159b9062f98SCezary Rojewski static void avs_dai_nonhda_be_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) 160b9062f98SCezary Rojewski { 161b9062f98SCezary Rojewski struct avs_dma_data *data; 162b9062f98SCezary Rojewski 163b9062f98SCezary Rojewski data = snd_soc_dai_get_dma_data(dai, substream); 164b9062f98SCezary Rojewski 165b9062f98SCezary Rojewski snd_soc_dai_set_dma_data(dai, substream, NULL); 166b9062f98SCezary Rojewski kfree(data); 167b9062f98SCezary Rojewski } 168b9062f98SCezary Rojewski 169b9062f98SCezary Rojewski static int avs_dai_nonhda_be_hw_params(struct snd_pcm_substream *substream, 170b9062f98SCezary Rojewski struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *dai) 171b9062f98SCezary Rojewski { 172b9062f98SCezary Rojewski struct avs_dma_data *data; 173b9062f98SCezary Rojewski 174b9062f98SCezary Rojewski data = snd_soc_dai_get_dma_data(dai, substream); 175b9062f98SCezary Rojewski if (data->path) 176b9062f98SCezary Rojewski return 0; 177b9062f98SCezary Rojewski 178b9062f98SCezary Rojewski /* Actual port-id comes from topology. */ 179b9062f98SCezary Rojewski return avs_dai_be_hw_params(substream, hw_params, dai, 0); 180b9062f98SCezary Rojewski } 181b9062f98SCezary Rojewski 182b9062f98SCezary Rojewski static int avs_dai_nonhda_be_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) 183b9062f98SCezary Rojewski { 184b9062f98SCezary Rojewski struct avs_dma_data *data; 185b9062f98SCezary Rojewski 186b9062f98SCezary Rojewski dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); 187b9062f98SCezary Rojewski 188b9062f98SCezary Rojewski data = snd_soc_dai_get_dma_data(dai, substream); 189b9062f98SCezary Rojewski if (data->path) { 190b9062f98SCezary Rojewski avs_path_free(data->path); 191b9062f98SCezary Rojewski data->path = NULL; 192b9062f98SCezary Rojewski } 193b9062f98SCezary Rojewski 194b9062f98SCezary Rojewski return 0; 195b9062f98SCezary Rojewski } 196b9062f98SCezary Rojewski 197b9062f98SCezary Rojewski static int avs_dai_nonhda_be_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) 198b9062f98SCezary Rojewski { 199b9062f98SCezary Rojewski return avs_dai_prepare(to_avs_dev(dai->dev), substream, dai); 200b9062f98SCezary Rojewski } 201b9062f98SCezary Rojewski 202b9062f98SCezary Rojewski static int avs_dai_nonhda_be_trigger(struct snd_pcm_substream *substream, int cmd, 203b9062f98SCezary Rojewski struct snd_soc_dai *dai) 204b9062f98SCezary Rojewski { 205b9062f98SCezary Rojewski struct avs_dma_data *data; 206b9062f98SCezary Rojewski int ret = 0; 207b9062f98SCezary Rojewski 208b9062f98SCezary Rojewski data = snd_soc_dai_get_dma_data(dai, substream); 209b9062f98SCezary Rojewski 210b9062f98SCezary Rojewski switch (cmd) { 211b9062f98SCezary Rojewski case SNDRV_PCM_TRIGGER_START: 212b9062f98SCezary Rojewski case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 213b9062f98SCezary Rojewski ret = avs_path_run(data->path, AVS_TPLG_TRIGGER_AUTO); 214b9062f98SCezary Rojewski if (ret < 0) 215b9062f98SCezary Rojewski dev_err(dai->dev, "run BE path failed: %d\n", ret); 216b9062f98SCezary Rojewski break; 217b9062f98SCezary Rojewski 218b9062f98SCezary Rojewski case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 219b9062f98SCezary Rojewski case SNDRV_PCM_TRIGGER_STOP: 220b9062f98SCezary Rojewski ret = avs_path_pause(data->path); 221b9062f98SCezary Rojewski if (ret < 0) 222b9062f98SCezary Rojewski dev_err(dai->dev, "pause BE path failed: %d\n", ret); 223b9062f98SCezary Rojewski 224b9062f98SCezary Rojewski if (cmd == SNDRV_PCM_TRIGGER_STOP) { 225b9062f98SCezary Rojewski ret = avs_path_reset(data->path); 226b9062f98SCezary Rojewski if (ret < 0) 227b9062f98SCezary Rojewski dev_err(dai->dev, "reset BE path failed: %d\n", ret); 228b9062f98SCezary Rojewski } 229b9062f98SCezary Rojewski break; 230b9062f98SCezary Rojewski 231b9062f98SCezary Rojewski default: 232b9062f98SCezary Rojewski ret = -EINVAL; 233b9062f98SCezary Rojewski break; 234b9062f98SCezary Rojewski } 235b9062f98SCezary Rojewski 236b9062f98SCezary Rojewski return ret; 237b9062f98SCezary Rojewski } 238b9062f98SCezary Rojewski 239b9062f98SCezary Rojewski static const struct snd_soc_dai_ops avs_dai_nonhda_be_ops = { 240b9062f98SCezary Rojewski .startup = avs_dai_nonhda_be_startup, 241b9062f98SCezary Rojewski .shutdown = avs_dai_nonhda_be_shutdown, 242b9062f98SCezary Rojewski .hw_params = avs_dai_nonhda_be_hw_params, 243b9062f98SCezary Rojewski .hw_free = avs_dai_nonhda_be_hw_free, 244b9062f98SCezary Rojewski .prepare = avs_dai_nonhda_be_prepare, 245b9062f98SCezary Rojewski .trigger = avs_dai_nonhda_be_trigger, 246b9062f98SCezary Rojewski }; 247b9062f98SCezary Rojewski 248d070002aSCezary Rojewski static int avs_dai_hda_be_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) 249d070002aSCezary Rojewski { 250d070002aSCezary Rojewski return avs_dai_startup(substream, dai, false); 251d070002aSCezary Rojewski } 252d070002aSCezary Rojewski 253d070002aSCezary Rojewski static void avs_dai_hda_be_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) 254d070002aSCezary Rojewski { 255d070002aSCezary Rojewski return avs_dai_nonhda_be_shutdown(substream, dai); 256d070002aSCezary Rojewski } 257d070002aSCezary Rojewski 258d070002aSCezary Rojewski static int avs_dai_hda_be_hw_params(struct snd_pcm_substream *substream, 259d070002aSCezary Rojewski struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *dai) 260d070002aSCezary Rojewski { 261d070002aSCezary Rojewski struct avs_dma_data *data; 262d070002aSCezary Rojewski struct hdac_ext_stream *link_stream; 263d070002aSCezary Rojewski 264d070002aSCezary Rojewski data = snd_soc_dai_get_dma_data(dai, substream); 265d070002aSCezary Rojewski if (data->path) 266d070002aSCezary Rojewski return 0; 267d070002aSCezary Rojewski 268d070002aSCezary Rojewski link_stream = substream->runtime->private_data; 269d070002aSCezary Rojewski 270d070002aSCezary Rojewski return avs_dai_be_hw_params(substream, hw_params, dai, 271d070002aSCezary Rojewski hdac_stream(link_stream)->stream_tag - 1); 272d070002aSCezary Rojewski } 273d070002aSCezary Rojewski 274d070002aSCezary Rojewski static int avs_dai_hda_be_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) 275d070002aSCezary Rojewski { 276d070002aSCezary Rojewski struct avs_dma_data *data; 277d070002aSCezary Rojewski struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); 278d070002aSCezary Rojewski struct hdac_ext_stream *link_stream; 279d070002aSCezary Rojewski struct hdac_ext_link *link; 280d070002aSCezary Rojewski struct hda_codec *codec; 281d070002aSCezary Rojewski 282d070002aSCezary Rojewski dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); 283d070002aSCezary Rojewski 284d070002aSCezary Rojewski data = snd_soc_dai_get_dma_data(dai, substream); 285d070002aSCezary Rojewski if (!data->path) 286d070002aSCezary Rojewski return 0; 287d070002aSCezary Rojewski 288d070002aSCezary Rojewski link_stream = substream->runtime->private_data; 289d070002aSCezary Rojewski link_stream->link_prepared = false; 290d070002aSCezary Rojewski avs_path_free(data->path); 291d070002aSCezary Rojewski data->path = NULL; 292d070002aSCezary Rojewski 293d070002aSCezary Rojewski /* clear link <-> stream mapping */ 294d070002aSCezary Rojewski codec = dev_to_hda_codec(asoc_rtd_to_codec(rtd, 0)->dev); 295d070002aSCezary Rojewski link = snd_hdac_ext_bus_link_at(&codec->bus->core, codec->core.addr); 296d070002aSCezary Rojewski if (!link) 297d070002aSCezary Rojewski return -EINVAL; 298d070002aSCezary Rojewski 299d070002aSCezary Rojewski if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 300d070002aSCezary Rojewski snd_hdac_ext_link_clear_stream_id(link, hdac_stream(link_stream)->stream_tag); 301d070002aSCezary Rojewski 302d070002aSCezary Rojewski return 0; 303d070002aSCezary Rojewski } 304d070002aSCezary Rojewski 305d070002aSCezary Rojewski static int avs_dai_hda_be_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) 306d070002aSCezary Rojewski { 307d070002aSCezary Rojewski struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); 308d070002aSCezary Rojewski struct snd_pcm_runtime *runtime = substream->runtime; 309d070002aSCezary Rojewski struct hdac_ext_stream *link_stream = runtime->private_data; 310d070002aSCezary Rojewski struct hdac_ext_link *link; 311d070002aSCezary Rojewski struct hda_codec *codec; 312d070002aSCezary Rojewski struct hdac_bus *bus; 313d070002aSCezary Rojewski unsigned int format_val; 314d070002aSCezary Rojewski int ret; 315d070002aSCezary Rojewski 316d070002aSCezary Rojewski if (link_stream->link_prepared) 317d070002aSCezary Rojewski return 0; 318d070002aSCezary Rojewski 319d070002aSCezary Rojewski codec = dev_to_hda_codec(asoc_rtd_to_codec(rtd, 0)->dev); 320d070002aSCezary Rojewski bus = &codec->bus->core; 321d070002aSCezary Rojewski format_val = snd_hdac_calc_stream_format(runtime->rate, runtime->channels, runtime->format, 322d070002aSCezary Rojewski runtime->sample_bits, 0); 323d070002aSCezary Rojewski 324d070002aSCezary Rojewski snd_hdac_ext_stream_decouple(bus, link_stream, true); 325d070002aSCezary Rojewski snd_hdac_ext_link_stream_reset(link_stream); 326d070002aSCezary Rojewski snd_hdac_ext_link_stream_setup(link_stream, format_val); 327d070002aSCezary Rojewski 328d070002aSCezary Rojewski link = snd_hdac_ext_bus_link_at(bus, codec->core.addr); 329d070002aSCezary Rojewski if (!link) 330d070002aSCezary Rojewski return -EINVAL; 331d070002aSCezary Rojewski 332d070002aSCezary Rojewski if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 333d070002aSCezary Rojewski snd_hdac_ext_link_set_stream_id(link, hdac_stream(link_stream)->stream_tag); 334d070002aSCezary Rojewski 335d070002aSCezary Rojewski ret = avs_dai_prepare(to_avs_dev(dai->dev), substream, dai); 336d070002aSCezary Rojewski if (ret) 337d070002aSCezary Rojewski return ret; 338d070002aSCezary Rojewski 339d070002aSCezary Rojewski link_stream->link_prepared = true; 340d070002aSCezary Rojewski return 0; 341d070002aSCezary Rojewski } 342d070002aSCezary Rojewski 343d070002aSCezary Rojewski static int avs_dai_hda_be_trigger(struct snd_pcm_substream *substream, int cmd, 344d070002aSCezary Rojewski struct snd_soc_dai *dai) 345d070002aSCezary Rojewski { 346d070002aSCezary Rojewski struct hdac_ext_stream *link_stream; 347d070002aSCezary Rojewski struct avs_dma_data *data; 348d070002aSCezary Rojewski int ret = 0; 349d070002aSCezary Rojewski 350d070002aSCezary Rojewski dev_dbg(dai->dev, "entry %s cmd=%d\n", __func__, cmd); 351d070002aSCezary Rojewski 352d070002aSCezary Rojewski data = snd_soc_dai_get_dma_data(dai, substream); 353d070002aSCezary Rojewski link_stream = substream->runtime->private_data; 354d070002aSCezary Rojewski 355d070002aSCezary Rojewski switch (cmd) { 356d070002aSCezary Rojewski case SNDRV_PCM_TRIGGER_START: 357d070002aSCezary Rojewski case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 358d070002aSCezary Rojewski snd_hdac_ext_link_stream_start(link_stream); 359d070002aSCezary Rojewski 360d070002aSCezary Rojewski ret = avs_path_run(data->path, AVS_TPLG_TRIGGER_AUTO); 361d070002aSCezary Rojewski if (ret < 0) 362d070002aSCezary Rojewski dev_err(dai->dev, "run BE path failed: %d\n", ret); 363d070002aSCezary Rojewski break; 364d070002aSCezary Rojewski 365d070002aSCezary Rojewski case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 366d070002aSCezary Rojewski case SNDRV_PCM_TRIGGER_STOP: 367d070002aSCezary Rojewski ret = avs_path_pause(data->path); 368d070002aSCezary Rojewski if (ret < 0) 369d070002aSCezary Rojewski dev_err(dai->dev, "pause BE path failed: %d\n", ret); 370d070002aSCezary Rojewski 371d070002aSCezary Rojewski snd_hdac_ext_link_stream_clear(link_stream); 372d070002aSCezary Rojewski 373d070002aSCezary Rojewski if (cmd == SNDRV_PCM_TRIGGER_STOP) { 374d070002aSCezary Rojewski ret = avs_path_reset(data->path); 375d070002aSCezary Rojewski if (ret < 0) 376d070002aSCezary Rojewski dev_err(dai->dev, "reset BE path failed: %d\n", ret); 377d070002aSCezary Rojewski } 378d070002aSCezary Rojewski break; 379d070002aSCezary Rojewski 380d070002aSCezary Rojewski default: 381d070002aSCezary Rojewski ret = -EINVAL; 382d070002aSCezary Rojewski break; 383d070002aSCezary Rojewski } 384d070002aSCezary Rojewski 385d070002aSCezary Rojewski return ret; 386d070002aSCezary Rojewski } 387d070002aSCezary Rojewski 388d070002aSCezary Rojewski static const struct snd_soc_dai_ops avs_dai_hda_be_ops = { 389d070002aSCezary Rojewski .startup = avs_dai_hda_be_startup, 390d070002aSCezary Rojewski .shutdown = avs_dai_hda_be_shutdown, 391d070002aSCezary Rojewski .hw_params = avs_dai_hda_be_hw_params, 392d070002aSCezary Rojewski .hw_free = avs_dai_hda_be_hw_free, 393d070002aSCezary Rojewski .prepare = avs_dai_hda_be_prepare, 394d070002aSCezary Rojewski .trigger = avs_dai_hda_be_trigger, 395d070002aSCezary Rojewski }; 396d070002aSCezary Rojewski 3979114700bSCezary Rojewski static const unsigned int rates[] = { 3989114700bSCezary Rojewski 8000, 11025, 12000, 16000, 3999114700bSCezary Rojewski 22050, 24000, 32000, 44100, 4009114700bSCezary Rojewski 48000, 64000, 88200, 96000, 4019114700bSCezary Rojewski 128000, 176400, 192000, 4029114700bSCezary Rojewski }; 4039114700bSCezary Rojewski 4049114700bSCezary Rojewski static const struct snd_pcm_hw_constraint_list hw_rates = { 4059114700bSCezary Rojewski .count = ARRAY_SIZE(rates), 4069114700bSCezary Rojewski .list = rates, 4079114700bSCezary Rojewski .mask = 0, 4089114700bSCezary Rojewski }; 4099114700bSCezary Rojewski 4109114700bSCezary Rojewski static int avs_dai_fe_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) 4119114700bSCezary Rojewski { 4129114700bSCezary Rojewski struct snd_pcm_runtime *runtime = substream->runtime; 4139114700bSCezary Rojewski struct avs_dma_data *data; 4149114700bSCezary Rojewski struct avs_dev *adev = to_avs_dev(dai->dev); 4159114700bSCezary Rojewski struct hdac_bus *bus = &adev->base.core; 4169114700bSCezary Rojewski struct hdac_ext_stream *host_stream; 4179114700bSCezary Rojewski int ret; 4189114700bSCezary Rojewski 4199114700bSCezary Rojewski ret = avs_dai_startup(substream, dai, true); 4209114700bSCezary Rojewski if (ret) 4219114700bSCezary Rojewski return ret; 4229114700bSCezary Rojewski 4239114700bSCezary Rojewski data = snd_soc_dai_get_dma_data(dai, substream); 4249114700bSCezary Rojewski 4259114700bSCezary Rojewski host_stream = snd_hdac_ext_stream_assign(bus, substream, HDAC_EXT_STREAM_TYPE_HOST); 4269114700bSCezary Rojewski if (!host_stream) { 4279114700bSCezary Rojewski kfree(data); 4289114700bSCezary Rojewski return -EBUSY; 4299114700bSCezary Rojewski } 4309114700bSCezary Rojewski 4319114700bSCezary Rojewski data->host_stream = host_stream; 4329114700bSCezary Rojewski snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); 4339114700bSCezary Rojewski /* avoid wrap-around with wall-clock */ 4349114700bSCezary Rojewski snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_TIME, 20, 178000000); 4359114700bSCezary Rojewski snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_rates); 4369114700bSCezary Rojewski snd_pcm_set_sync(substream); 4379114700bSCezary Rojewski 4389114700bSCezary Rojewski dev_dbg(dai->dev, "%s fe STARTUP tag %d str %p", 4399114700bSCezary Rojewski __func__, hdac_stream(host_stream)->stream_tag, substream); 4409114700bSCezary Rojewski 4419114700bSCezary Rojewski return 0; 4429114700bSCezary Rojewski } 4439114700bSCezary Rojewski 4449114700bSCezary Rojewski static void avs_dai_fe_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) 4459114700bSCezary Rojewski { 4469114700bSCezary Rojewski struct avs_dma_data *data; 4479114700bSCezary Rojewski 4489114700bSCezary Rojewski data = snd_soc_dai_get_dma_data(dai, substream); 4499114700bSCezary Rojewski 4509114700bSCezary Rojewski snd_soc_dai_set_dma_data(dai, substream, NULL); 4519114700bSCezary Rojewski snd_hdac_ext_stream_release(data->host_stream, HDAC_EXT_STREAM_TYPE_HOST); 4529114700bSCezary Rojewski kfree(data); 4539114700bSCezary Rojewski } 4549114700bSCezary Rojewski 4559114700bSCezary Rojewski static int avs_dai_fe_hw_params(struct snd_pcm_substream *substream, 4569114700bSCezary Rojewski struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *dai) 4579114700bSCezary Rojewski { 4589114700bSCezary Rojewski struct snd_pcm_hw_params *be_hw_params = NULL; 4599114700bSCezary Rojewski struct snd_soc_pcm_runtime *fe, *be; 4609114700bSCezary Rojewski struct snd_soc_dpcm *dpcm; 4619114700bSCezary Rojewski struct avs_dma_data *data; 4629114700bSCezary Rojewski struct hdac_ext_stream *host_stream; 4639114700bSCezary Rojewski int ret; 4649114700bSCezary Rojewski 4659114700bSCezary Rojewski data = snd_soc_dai_get_dma_data(dai, substream); 4669114700bSCezary Rojewski if (data->path) 4679114700bSCezary Rojewski return 0; 4689114700bSCezary Rojewski 4699114700bSCezary Rojewski host_stream = data->host_stream; 4709114700bSCezary Rojewski 4719114700bSCezary Rojewski hdac_stream(host_stream)->bufsize = 0; 4729114700bSCezary Rojewski hdac_stream(host_stream)->period_bytes = 0; 4739114700bSCezary Rojewski hdac_stream(host_stream)->format_val = 0; 4749114700bSCezary Rojewski 4759114700bSCezary Rojewski fe = asoc_substream_to_rtd(substream); 4769114700bSCezary Rojewski for_each_dpcm_be(fe, substream->stream, dpcm) { 4779114700bSCezary Rojewski be = dpcm->be; 4789114700bSCezary Rojewski be_hw_params = &be->dpcm[substream->stream].hw_params; 4799114700bSCezary Rojewski } 4809114700bSCezary Rojewski 4819114700bSCezary Rojewski ret = avs_dai_hw_params(substream, hw_params, be_hw_params, dai, 4829114700bSCezary Rojewski hdac_stream(host_stream)->stream_tag - 1); 4839114700bSCezary Rojewski if (ret) 4849114700bSCezary Rojewski goto create_err; 4859114700bSCezary Rojewski 4869114700bSCezary Rojewski ret = avs_path_bind(data->path); 4879114700bSCezary Rojewski if (ret < 0) { 4889114700bSCezary Rojewski dev_err(dai->dev, "bind FE <-> BE failed: %d\n", ret); 4899114700bSCezary Rojewski goto bind_err; 4909114700bSCezary Rojewski } 4919114700bSCezary Rojewski 4929114700bSCezary Rojewski return 0; 4939114700bSCezary Rojewski 4949114700bSCezary Rojewski bind_err: 4959114700bSCezary Rojewski avs_path_free(data->path); 4969114700bSCezary Rojewski data->path = NULL; 4979114700bSCezary Rojewski create_err: 4989114700bSCezary Rojewski snd_pcm_lib_free_pages(substream); 4999114700bSCezary Rojewski return ret; 5009114700bSCezary Rojewski } 5019114700bSCezary Rojewski 5029114700bSCezary Rojewski static int avs_dai_fe_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) 5039114700bSCezary Rojewski { 5049114700bSCezary Rojewski struct avs_dma_data *data; 5059114700bSCezary Rojewski struct hdac_ext_stream *host_stream; 5069114700bSCezary Rojewski int ret; 5079114700bSCezary Rojewski 5089114700bSCezary Rojewski dev_dbg(dai->dev, "%s fe HW_FREE str %p rtd %p", 5099114700bSCezary Rojewski __func__, substream, substream->runtime); 5109114700bSCezary Rojewski 5119114700bSCezary Rojewski data = snd_soc_dai_get_dma_data(dai, substream); 5129114700bSCezary Rojewski if (!data->path) 5139114700bSCezary Rojewski return 0; 5149114700bSCezary Rojewski 5159114700bSCezary Rojewski host_stream = data->host_stream; 5169114700bSCezary Rojewski 5179114700bSCezary Rojewski ret = avs_path_unbind(data->path); 5189114700bSCezary Rojewski if (ret < 0) 5199114700bSCezary Rojewski dev_err(dai->dev, "unbind FE <-> BE failed: %d\n", ret); 5209114700bSCezary Rojewski 5219114700bSCezary Rojewski avs_path_free(data->path); 5229114700bSCezary Rojewski data->path = NULL; 5239114700bSCezary Rojewski snd_hdac_stream_cleanup(hdac_stream(host_stream)); 5249114700bSCezary Rojewski hdac_stream(host_stream)->prepared = false; 5259114700bSCezary Rojewski 5269114700bSCezary Rojewski ret = snd_pcm_lib_free_pages(substream); 5279114700bSCezary Rojewski if (ret < 0) 5289114700bSCezary Rojewski dev_dbg(dai->dev, "Failed to free pages!\n"); 5299114700bSCezary Rojewski 5309114700bSCezary Rojewski return ret; 5319114700bSCezary Rojewski } 5329114700bSCezary Rojewski 5339114700bSCezary Rojewski static int avs_dai_fe_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) 5349114700bSCezary Rojewski { 5359114700bSCezary Rojewski struct snd_pcm_runtime *runtime = substream->runtime; 5369114700bSCezary Rojewski struct avs_dma_data *data; 5379114700bSCezary Rojewski struct avs_dev *adev = to_avs_dev(dai->dev); 5389114700bSCezary Rojewski struct hdac_ext_stream *host_stream; 5399114700bSCezary Rojewski struct hdac_bus *bus; 5409114700bSCezary Rojewski unsigned int format_val; 5419114700bSCezary Rojewski int ret; 5429114700bSCezary Rojewski 5439114700bSCezary Rojewski data = snd_soc_dai_get_dma_data(dai, substream); 5449114700bSCezary Rojewski host_stream = data->host_stream; 5459114700bSCezary Rojewski 5469114700bSCezary Rojewski if (hdac_stream(host_stream)->prepared) 5479114700bSCezary Rojewski return 0; 5489114700bSCezary Rojewski 5499114700bSCezary Rojewski bus = hdac_stream(host_stream)->bus; 5509114700bSCezary Rojewski snd_hdac_ext_stream_decouple(bus, data->host_stream, true); 5519114700bSCezary Rojewski snd_hdac_stream_reset(hdac_stream(host_stream)); 5529114700bSCezary Rojewski 5539114700bSCezary Rojewski format_val = snd_hdac_calc_stream_format(runtime->rate, runtime->channels, runtime->format, 5549114700bSCezary Rojewski runtime->sample_bits, 0); 5559114700bSCezary Rojewski 5569114700bSCezary Rojewski ret = snd_hdac_stream_set_params(hdac_stream(host_stream), format_val); 5579114700bSCezary Rojewski if (ret < 0) 5589114700bSCezary Rojewski return ret; 5599114700bSCezary Rojewski 5609114700bSCezary Rojewski ret = snd_hdac_stream_setup(hdac_stream(host_stream)); 5619114700bSCezary Rojewski if (ret < 0) 5629114700bSCezary Rojewski return ret; 5639114700bSCezary Rojewski 5649114700bSCezary Rojewski ret = avs_dai_prepare(adev, substream, dai); 5659114700bSCezary Rojewski if (ret) 5669114700bSCezary Rojewski return ret; 5679114700bSCezary Rojewski 5689114700bSCezary Rojewski hdac_stream(host_stream)->prepared = true; 5699114700bSCezary Rojewski return 0; 5709114700bSCezary Rojewski } 5719114700bSCezary Rojewski 5729114700bSCezary Rojewski static int avs_dai_fe_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) 5739114700bSCezary Rojewski { 5749114700bSCezary Rojewski struct avs_dma_data *data; 5759114700bSCezary Rojewski struct hdac_ext_stream *host_stream; 5769114700bSCezary Rojewski struct hdac_bus *bus; 5779114700bSCezary Rojewski unsigned long flags; 5789114700bSCezary Rojewski int ret = 0; 5799114700bSCezary Rojewski 5809114700bSCezary Rojewski data = snd_soc_dai_get_dma_data(dai, substream); 5819114700bSCezary Rojewski host_stream = data->host_stream; 5829114700bSCezary Rojewski bus = hdac_stream(host_stream)->bus; 5839114700bSCezary Rojewski 5849114700bSCezary Rojewski switch (cmd) { 5859114700bSCezary Rojewski case SNDRV_PCM_TRIGGER_START: 5869114700bSCezary Rojewski case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 5879114700bSCezary Rojewski spin_lock_irqsave(&bus->reg_lock, flags); 5889114700bSCezary Rojewski snd_hdac_stream_start(hdac_stream(host_stream), true); 5899114700bSCezary Rojewski spin_unlock_irqrestore(&bus->reg_lock, flags); 5909114700bSCezary Rojewski 5919114700bSCezary Rojewski ret = avs_path_run(data->path, AVS_TPLG_TRIGGER_AUTO); 5929114700bSCezary Rojewski if (ret < 0) 5939114700bSCezary Rojewski dev_err(dai->dev, "run FE path failed: %d\n", ret); 5949114700bSCezary Rojewski break; 5959114700bSCezary Rojewski 5969114700bSCezary Rojewski case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 5979114700bSCezary Rojewski case SNDRV_PCM_TRIGGER_STOP: 5989114700bSCezary Rojewski ret = avs_path_pause(data->path); 5999114700bSCezary Rojewski if (ret < 0) 6009114700bSCezary Rojewski dev_err(dai->dev, "pause FE path failed: %d\n", ret); 6019114700bSCezary Rojewski 6029114700bSCezary Rojewski spin_lock_irqsave(&bus->reg_lock, flags); 6039114700bSCezary Rojewski snd_hdac_stream_stop(hdac_stream(host_stream)); 6049114700bSCezary Rojewski spin_unlock_irqrestore(&bus->reg_lock, flags); 6059114700bSCezary Rojewski 6069114700bSCezary Rojewski if (cmd == SNDRV_PCM_TRIGGER_STOP) { 6079114700bSCezary Rojewski ret = avs_path_reset(data->path); 6089114700bSCezary Rojewski if (ret < 0) 6099114700bSCezary Rojewski dev_err(dai->dev, "reset FE path failed: %d\n", ret); 6109114700bSCezary Rojewski } 6119114700bSCezary Rojewski break; 6129114700bSCezary Rojewski 6139114700bSCezary Rojewski default: 6149114700bSCezary Rojewski ret = -EINVAL; 6159114700bSCezary Rojewski break; 6169114700bSCezary Rojewski } 6179114700bSCezary Rojewski 6189114700bSCezary Rojewski return ret; 6199114700bSCezary Rojewski } 6209114700bSCezary Rojewski 6219114700bSCezary Rojewski const struct snd_soc_dai_ops avs_dai_fe_ops = { 6229114700bSCezary Rojewski .startup = avs_dai_fe_startup, 6239114700bSCezary Rojewski .shutdown = avs_dai_fe_shutdown, 6249114700bSCezary Rojewski .hw_params = avs_dai_fe_hw_params, 6259114700bSCezary Rojewski .hw_free = avs_dai_fe_hw_free, 6269114700bSCezary Rojewski .prepare = avs_dai_fe_prepare, 6279114700bSCezary Rojewski .trigger = avs_dai_fe_trigger, 6289114700bSCezary Rojewski }; 6299114700bSCezary Rojewski 630f1b3b320SCezary Rojewski static ssize_t topology_name_read(struct file *file, char __user *user_buf, size_t count, 631f1b3b320SCezary Rojewski loff_t *ppos) 632f1b3b320SCezary Rojewski { 633f1b3b320SCezary Rojewski struct snd_soc_component *component = file->private_data; 634f1b3b320SCezary Rojewski struct snd_soc_card *card = component->card; 635f1b3b320SCezary Rojewski struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev); 636f1b3b320SCezary Rojewski char buf[64]; 637f1b3b320SCezary Rojewski size_t len; 638f1b3b320SCezary Rojewski 639*ca3b7b9dSTakashi Iwai len = scnprintf(buf, sizeof(buf), "%s/%s\n", component->driver->topology_name_prefix, 640f1b3b320SCezary Rojewski mach->tplg_filename); 641f1b3b320SCezary Rojewski 642f1b3b320SCezary Rojewski return simple_read_from_buffer(user_buf, count, ppos, buf, len); 643f1b3b320SCezary Rojewski } 644f1b3b320SCezary Rojewski 645f1b3b320SCezary Rojewski static const struct file_operations topology_name_fops = { 646f1b3b320SCezary Rojewski .open = simple_open, 647f1b3b320SCezary Rojewski .read = topology_name_read, 648f1b3b320SCezary Rojewski .llseek = default_llseek, 649f1b3b320SCezary Rojewski }; 650f1b3b320SCezary Rojewski 651f1b3b320SCezary Rojewski static int avs_component_load_libraries(struct avs_soc_component *acomp) 652f1b3b320SCezary Rojewski { 653f1b3b320SCezary Rojewski struct avs_tplg *tplg = acomp->tplg; 654f1b3b320SCezary Rojewski struct avs_dev *adev = to_avs_dev(acomp->base.dev); 655f1b3b320SCezary Rojewski int ret; 656f1b3b320SCezary Rojewski 657f1b3b320SCezary Rojewski if (!tplg->num_libs) 658f1b3b320SCezary Rojewski return 0; 659f1b3b320SCezary Rojewski 660f1b3b320SCezary Rojewski /* Parent device may be asleep and library loading involves IPCs. */ 661f1b3b320SCezary Rojewski ret = pm_runtime_resume_and_get(adev->dev); 662f1b3b320SCezary Rojewski if (ret < 0) 663f1b3b320SCezary Rojewski return ret; 664f1b3b320SCezary Rojewski 665f1b3b320SCezary Rojewski avs_hda_clock_gating_enable(adev, false); 666f1b3b320SCezary Rojewski avs_hda_l1sen_enable(adev, false); 667f1b3b320SCezary Rojewski 668f1b3b320SCezary Rojewski ret = avs_dsp_load_libraries(adev, tplg->libs, tplg->num_libs); 669f1b3b320SCezary Rojewski 670f1b3b320SCezary Rojewski avs_hda_l1sen_enable(adev, true); 671f1b3b320SCezary Rojewski avs_hda_clock_gating_enable(adev, true); 672f1b3b320SCezary Rojewski 673f1b3b320SCezary Rojewski if (!ret) 674f1b3b320SCezary Rojewski ret = avs_module_info_init(adev, false); 675f1b3b320SCezary Rojewski 676f1b3b320SCezary Rojewski pm_runtime_mark_last_busy(adev->dev); 677f1b3b320SCezary Rojewski pm_runtime_put_autosuspend(adev->dev); 678f1b3b320SCezary Rojewski 679f1b3b320SCezary Rojewski return ret; 680f1b3b320SCezary Rojewski } 681f1b3b320SCezary Rojewski 682f1b3b320SCezary Rojewski static int avs_component_probe(struct snd_soc_component *component) 683f1b3b320SCezary Rojewski { 684f1b3b320SCezary Rojewski struct snd_soc_card *card = component->card; 685f1b3b320SCezary Rojewski struct snd_soc_acpi_mach *mach; 686f1b3b320SCezary Rojewski struct avs_soc_component *acomp; 687f1b3b320SCezary Rojewski struct avs_dev *adev; 688f1b3b320SCezary Rojewski char *filename; 689f1b3b320SCezary Rojewski int ret; 690f1b3b320SCezary Rojewski 691f1b3b320SCezary Rojewski dev_dbg(card->dev, "probing %s card %s\n", component->name, card->name); 692f1b3b320SCezary Rojewski mach = dev_get_platdata(card->dev); 693f1b3b320SCezary Rojewski acomp = to_avs_soc_component(component); 694f1b3b320SCezary Rojewski adev = to_avs_dev(component->dev); 695f1b3b320SCezary Rojewski 696f1b3b320SCezary Rojewski acomp->tplg = avs_tplg_new(component); 697f1b3b320SCezary Rojewski if (!acomp->tplg) 698f1b3b320SCezary Rojewski return -ENOMEM; 699f1b3b320SCezary Rojewski 700f1b3b320SCezary Rojewski if (!mach->tplg_filename) 701f1b3b320SCezary Rojewski goto finalize; 702f1b3b320SCezary Rojewski 703f1b3b320SCezary Rojewski /* Load specified topology and create debugfs for it. */ 704f1b3b320SCezary Rojewski filename = kasprintf(GFP_KERNEL, "%s/%s", component->driver->topology_name_prefix, 705f1b3b320SCezary Rojewski mach->tplg_filename); 706f1b3b320SCezary Rojewski if (!filename) 707f1b3b320SCezary Rojewski return -ENOMEM; 708f1b3b320SCezary Rojewski 709f1b3b320SCezary Rojewski ret = avs_load_topology(component, filename); 710f1b3b320SCezary Rojewski kfree(filename); 711f1b3b320SCezary Rojewski if (ret < 0) 712f1b3b320SCezary Rojewski return ret; 713f1b3b320SCezary Rojewski 714f1b3b320SCezary Rojewski ret = avs_component_load_libraries(acomp); 715f1b3b320SCezary Rojewski if (ret < 0) { 716f1b3b320SCezary Rojewski dev_err(card->dev, "libraries loading failed: %d\n", ret); 717f1b3b320SCezary Rojewski goto err_load_libs; 718f1b3b320SCezary Rojewski } 719f1b3b320SCezary Rojewski 720f1b3b320SCezary Rojewski finalize: 721f1b3b320SCezary Rojewski debugfs_create_file("topology_name", 0444, component->debugfs_root, component, 722f1b3b320SCezary Rojewski &topology_name_fops); 723f1b3b320SCezary Rojewski 724f1b3b320SCezary Rojewski mutex_lock(&adev->comp_list_mutex); 725f1b3b320SCezary Rojewski list_add_tail(&acomp->node, &adev->comp_list); 726f1b3b320SCezary Rojewski mutex_unlock(&adev->comp_list_mutex); 727f1b3b320SCezary Rojewski 728f1b3b320SCezary Rojewski return 0; 729f1b3b320SCezary Rojewski 730f1b3b320SCezary Rojewski err_load_libs: 731f1b3b320SCezary Rojewski avs_remove_topology(component); 732f1b3b320SCezary Rojewski return ret; 733f1b3b320SCezary Rojewski } 734f1b3b320SCezary Rojewski 735f1b3b320SCezary Rojewski static void avs_component_remove(struct snd_soc_component *component) 736f1b3b320SCezary Rojewski { 737f1b3b320SCezary Rojewski struct avs_soc_component *acomp = to_avs_soc_component(component); 738f1b3b320SCezary Rojewski struct snd_soc_acpi_mach *mach; 739f1b3b320SCezary Rojewski struct avs_dev *adev = to_avs_dev(component->dev); 740f1b3b320SCezary Rojewski int ret; 741f1b3b320SCezary Rojewski 742f1b3b320SCezary Rojewski mach = dev_get_platdata(component->card->dev); 743f1b3b320SCezary Rojewski 744f1b3b320SCezary Rojewski mutex_lock(&adev->comp_list_mutex); 745f1b3b320SCezary Rojewski list_del(&acomp->node); 746f1b3b320SCezary Rojewski mutex_unlock(&adev->comp_list_mutex); 747f1b3b320SCezary Rojewski 748f1b3b320SCezary Rojewski if (mach->tplg_filename) { 749f1b3b320SCezary Rojewski ret = avs_remove_topology(component); 750f1b3b320SCezary Rojewski if (ret < 0) 751f1b3b320SCezary Rojewski dev_err(component->dev, "unload topology failed: %d\n", ret); 752f1b3b320SCezary Rojewski } 753f1b3b320SCezary Rojewski } 754f1b3b320SCezary Rojewski 755f1b3b320SCezary Rojewski static int avs_component_open(struct snd_soc_component *component, 756f1b3b320SCezary Rojewski struct snd_pcm_substream *substream) 757f1b3b320SCezary Rojewski { 758f1b3b320SCezary Rojewski struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); 759f1b3b320SCezary Rojewski struct snd_pcm_hardware hwparams; 760f1b3b320SCezary Rojewski 761f1b3b320SCezary Rojewski /* only FE DAI links are handled here */ 762f1b3b320SCezary Rojewski if (rtd->dai_link->no_pcm) 763f1b3b320SCezary Rojewski return 0; 764f1b3b320SCezary Rojewski 765f1b3b320SCezary Rojewski hwparams.info = SNDRV_PCM_INFO_MMAP | 766f1b3b320SCezary Rojewski SNDRV_PCM_INFO_MMAP_VALID | 767f1b3b320SCezary Rojewski SNDRV_PCM_INFO_INTERLEAVED | 768f1b3b320SCezary Rojewski SNDRV_PCM_INFO_PAUSE | 769f1b3b320SCezary Rojewski SNDRV_PCM_INFO_NO_PERIOD_WAKEUP; 770f1b3b320SCezary Rojewski 771f1b3b320SCezary Rojewski hwparams.formats = SNDRV_PCM_FMTBIT_S16_LE | 772f1b3b320SCezary Rojewski SNDRV_PCM_FMTBIT_S24_LE | 773f1b3b320SCezary Rojewski SNDRV_PCM_FMTBIT_S32_LE; 774f1b3b320SCezary Rojewski hwparams.period_bytes_min = 128; 775f1b3b320SCezary Rojewski hwparams.period_bytes_max = AZX_MAX_BUF_SIZE / 2; 776f1b3b320SCezary Rojewski hwparams.periods_min = 2; 777f1b3b320SCezary Rojewski hwparams.periods_max = AZX_MAX_FRAG; 778f1b3b320SCezary Rojewski hwparams.buffer_bytes_max = AZX_MAX_BUF_SIZE; 779f1b3b320SCezary Rojewski hwparams.fifo_size = 0; 780f1b3b320SCezary Rojewski 781f1b3b320SCezary Rojewski return snd_soc_set_runtime_hwparams(substream, &hwparams); 782f1b3b320SCezary Rojewski } 783f1b3b320SCezary Rojewski 784f1b3b320SCezary Rojewski static unsigned int avs_hda_stream_dpib_read(struct hdac_ext_stream *stream) 785f1b3b320SCezary Rojewski { 786f1b3b320SCezary Rojewski return readl(hdac_stream(stream)->bus->remap_addr + AZX_REG_VS_SDXDPIB_XBASE + 787f1b3b320SCezary Rojewski (AZX_REG_VS_SDXDPIB_XINTERVAL * hdac_stream(stream)->index)); 788f1b3b320SCezary Rojewski } 789f1b3b320SCezary Rojewski 790f1b3b320SCezary Rojewski static snd_pcm_uframes_t 791f1b3b320SCezary Rojewski avs_component_pointer(struct snd_soc_component *component, struct snd_pcm_substream *substream) 792f1b3b320SCezary Rojewski { 793f1b3b320SCezary Rojewski struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); 794f1b3b320SCezary Rojewski struct avs_dma_data *data; 795f1b3b320SCezary Rojewski struct hdac_ext_stream *host_stream; 796f1b3b320SCezary Rojewski unsigned int pos; 797f1b3b320SCezary Rojewski 798f1b3b320SCezary Rojewski data = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream); 799f1b3b320SCezary Rojewski if (!data->host_stream) 800f1b3b320SCezary Rojewski return 0; 801f1b3b320SCezary Rojewski 802f1b3b320SCezary Rojewski host_stream = data->host_stream; 803f1b3b320SCezary Rojewski pos = avs_hda_stream_dpib_read(host_stream); 804f1b3b320SCezary Rojewski 805f1b3b320SCezary Rojewski if (pos >= hdac_stream(host_stream)->bufsize) 806f1b3b320SCezary Rojewski pos = 0; 807f1b3b320SCezary Rojewski 808f1b3b320SCezary Rojewski return bytes_to_frames(substream->runtime, pos); 809f1b3b320SCezary Rojewski } 810f1b3b320SCezary Rojewski 811f1b3b320SCezary Rojewski static int avs_component_mmap(struct snd_soc_component *component, 812f1b3b320SCezary Rojewski struct snd_pcm_substream *substream, 813f1b3b320SCezary Rojewski struct vm_area_struct *vma) 814f1b3b320SCezary Rojewski { 815f1b3b320SCezary Rojewski return snd_pcm_lib_default_mmap(substream, vma); 816f1b3b320SCezary Rojewski } 817f1b3b320SCezary Rojewski 818f1b3b320SCezary Rojewski #define MAX_PREALLOC_SIZE (32 * 1024 * 1024) 819f1b3b320SCezary Rojewski 820f1b3b320SCezary Rojewski static int avs_component_construct(struct snd_soc_component *component, 821f1b3b320SCezary Rojewski struct snd_soc_pcm_runtime *rtd) 822f1b3b320SCezary Rojewski { 823f1b3b320SCezary Rojewski struct snd_soc_dai *dai = asoc_rtd_to_cpu(rtd, 0); 824f1b3b320SCezary Rojewski struct snd_pcm *pcm = rtd->pcm; 825f1b3b320SCezary Rojewski 826f1b3b320SCezary Rojewski if (dai->driver->playback.channels_min) 827f1b3b320SCezary Rojewski snd_pcm_set_managed_buffer(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream, 828f1b3b320SCezary Rojewski SNDRV_DMA_TYPE_DEV_SG, component->dev, 0, 829f1b3b320SCezary Rojewski MAX_PREALLOC_SIZE); 830f1b3b320SCezary Rojewski 831f1b3b320SCezary Rojewski if (dai->driver->capture.channels_min) 832f1b3b320SCezary Rojewski snd_pcm_set_managed_buffer(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream, 833f1b3b320SCezary Rojewski SNDRV_DMA_TYPE_DEV_SG, component->dev, 0, 834f1b3b320SCezary Rojewski MAX_PREALLOC_SIZE); 835f1b3b320SCezary Rojewski 836f1b3b320SCezary Rojewski return 0; 837f1b3b320SCezary Rojewski } 838f1b3b320SCezary Rojewski 839f1b3b320SCezary Rojewski static const struct snd_soc_component_driver avs_component_driver = { 840f1b3b320SCezary Rojewski .name = "avs-pcm", 841f1b3b320SCezary Rojewski .probe = avs_component_probe, 842f1b3b320SCezary Rojewski .remove = avs_component_remove, 843f1b3b320SCezary Rojewski .open = avs_component_open, 844f1b3b320SCezary Rojewski .pointer = avs_component_pointer, 845f1b3b320SCezary Rojewski .mmap = avs_component_mmap, 846f1b3b320SCezary Rojewski .pcm_construct = avs_component_construct, 847f1b3b320SCezary Rojewski .module_get_upon_open = 1, /* increment refcount when a pcm is opened */ 848f1b3b320SCezary Rojewski .topology_name_prefix = "intel/avs", 849f1b3b320SCezary Rojewski }; 850f1b3b320SCezary Rojewski 851f1b3b320SCezary Rojewski static int avs_soc_component_register(struct device *dev, const char *name, 852f1b3b320SCezary Rojewski const struct snd_soc_component_driver *drv, 853f1b3b320SCezary Rojewski struct snd_soc_dai_driver *cpu_dais, int num_cpu_dais) 854f1b3b320SCezary Rojewski { 855f1b3b320SCezary Rojewski struct avs_soc_component *acomp; 856f1b3b320SCezary Rojewski int ret; 857f1b3b320SCezary Rojewski 858f1b3b320SCezary Rojewski acomp = devm_kzalloc(dev, sizeof(*acomp), GFP_KERNEL); 859f1b3b320SCezary Rojewski if (!acomp) 860f1b3b320SCezary Rojewski return -ENOMEM; 861f1b3b320SCezary Rojewski 862f1b3b320SCezary Rojewski ret = snd_soc_component_initialize(&acomp->base, drv, dev); 863f1b3b320SCezary Rojewski if (ret < 0) 864f1b3b320SCezary Rojewski return ret; 865f1b3b320SCezary Rojewski 866f1b3b320SCezary Rojewski /* force name change after ASoC is done with its init */ 867f1b3b320SCezary Rojewski acomp->base.name = name; 868f1b3b320SCezary Rojewski INIT_LIST_HEAD(&acomp->node); 869f1b3b320SCezary Rojewski 870f1b3b320SCezary Rojewski return snd_soc_add_component(&acomp->base, cpu_dais, num_cpu_dais); 871f1b3b320SCezary Rojewski } 872b9062f98SCezary Rojewski 873b9062f98SCezary Rojewski static struct snd_soc_dai_driver dmic_cpu_dais[] = { 874b9062f98SCezary Rojewski { 875b9062f98SCezary Rojewski .name = "DMIC Pin", 876b9062f98SCezary Rojewski .ops = &avs_dai_nonhda_be_ops, 877b9062f98SCezary Rojewski .capture = { 878b9062f98SCezary Rojewski .stream_name = "DMIC Rx", 879b9062f98SCezary Rojewski .channels_min = 1, 880b9062f98SCezary Rojewski .channels_max = 4, 881b9062f98SCezary Rojewski .rates = SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_48000, 882b9062f98SCezary Rojewski .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, 883b9062f98SCezary Rojewski }, 884b9062f98SCezary Rojewski }, 885b9062f98SCezary Rojewski { 886b9062f98SCezary Rojewski .name = "DMIC WoV Pin", 887b9062f98SCezary Rojewski .ops = &avs_dai_nonhda_be_ops, 888b9062f98SCezary Rojewski .capture = { 889b9062f98SCezary Rojewski .stream_name = "DMIC WoV Rx", 890b9062f98SCezary Rojewski .channels_min = 1, 891b9062f98SCezary Rojewski .channels_max = 4, 892b9062f98SCezary Rojewski .rates = SNDRV_PCM_RATE_16000, 893b9062f98SCezary Rojewski .formats = SNDRV_PCM_FMTBIT_S16_LE, 894b9062f98SCezary Rojewski }, 895b9062f98SCezary Rojewski }, 896b9062f98SCezary Rojewski }; 897b9062f98SCezary Rojewski 898b9062f98SCezary Rojewski int avs_dmic_platform_register(struct avs_dev *adev, const char *name) 899b9062f98SCezary Rojewski { 900b9062f98SCezary Rojewski return avs_soc_component_register(adev->dev, name, &avs_component_driver, dmic_cpu_dais, 901b9062f98SCezary Rojewski ARRAY_SIZE(dmic_cpu_dais)); 902b9062f98SCezary Rojewski } 903b9062f98SCezary Rojewski 904b9062f98SCezary Rojewski static const struct snd_soc_dai_driver i2s_dai_template = { 905b9062f98SCezary Rojewski .ops = &avs_dai_nonhda_be_ops, 906b9062f98SCezary Rojewski .playback = { 907b9062f98SCezary Rojewski .channels_min = 1, 908b9062f98SCezary Rojewski .channels_max = 8, 909b9062f98SCezary Rojewski .rates = SNDRV_PCM_RATE_8000_192000 | 910b9062f98SCezary Rojewski SNDRV_PCM_RATE_KNOT, 911b9062f98SCezary Rojewski .formats = SNDRV_PCM_FMTBIT_S16_LE | 912b9062f98SCezary Rojewski SNDRV_PCM_FMTBIT_S24_LE | 913b9062f98SCezary Rojewski SNDRV_PCM_FMTBIT_S32_LE, 914b9062f98SCezary Rojewski }, 915b9062f98SCezary Rojewski .capture = { 916b9062f98SCezary Rojewski .channels_min = 1, 917b9062f98SCezary Rojewski .channels_max = 8, 918b9062f98SCezary Rojewski .rates = SNDRV_PCM_RATE_8000_192000 | 919b9062f98SCezary Rojewski SNDRV_PCM_RATE_KNOT, 920b9062f98SCezary Rojewski .formats = SNDRV_PCM_FMTBIT_S16_LE | 921b9062f98SCezary Rojewski SNDRV_PCM_FMTBIT_S24_LE | 922b9062f98SCezary Rojewski SNDRV_PCM_FMTBIT_S32_LE, 923b9062f98SCezary Rojewski }, 924b9062f98SCezary Rojewski }; 925b9062f98SCezary Rojewski 926b9062f98SCezary Rojewski int avs_i2s_platform_register(struct avs_dev *adev, const char *name, unsigned long port_mask, 927b9062f98SCezary Rojewski unsigned long *tdms) 928b9062f98SCezary Rojewski { 929b9062f98SCezary Rojewski struct snd_soc_dai_driver *cpus, *dai; 930b9062f98SCezary Rojewski size_t ssp_count, cpu_count; 931b9062f98SCezary Rojewski int i, j; 932b9062f98SCezary Rojewski 933b9062f98SCezary Rojewski ssp_count = adev->hw_cfg.i2s_caps.ctrl_count; 934b9062f98SCezary Rojewski cpu_count = hweight_long(port_mask); 935b9062f98SCezary Rojewski if (tdms) 936b9062f98SCezary Rojewski for_each_set_bit(i, &port_mask, ssp_count) 937b9062f98SCezary Rojewski cpu_count += hweight_long(tdms[i]); 938b9062f98SCezary Rojewski 939b9062f98SCezary Rojewski cpus = devm_kzalloc(adev->dev, sizeof(*cpus) * cpu_count, GFP_KERNEL); 940b9062f98SCezary Rojewski if (!cpus) 941b9062f98SCezary Rojewski return -ENOMEM; 942b9062f98SCezary Rojewski 943b9062f98SCezary Rojewski dai = cpus; 944b9062f98SCezary Rojewski for_each_set_bit(i, &port_mask, ssp_count) { 945b9062f98SCezary Rojewski memcpy(dai, &i2s_dai_template, sizeof(*dai)); 946b9062f98SCezary Rojewski 947b9062f98SCezary Rojewski dai->name = 948b9062f98SCezary Rojewski devm_kasprintf(adev->dev, GFP_KERNEL, "SSP%d Pin", i); 949b9062f98SCezary Rojewski dai->playback.stream_name = 950b9062f98SCezary Rojewski devm_kasprintf(adev->dev, GFP_KERNEL, "ssp%d Tx", i); 951b9062f98SCezary Rojewski dai->capture.stream_name = 952b9062f98SCezary Rojewski devm_kasprintf(adev->dev, GFP_KERNEL, "ssp%d Rx", i); 953b9062f98SCezary Rojewski 954b9062f98SCezary Rojewski if (!dai->name || !dai->playback.stream_name || !dai->capture.stream_name) 955b9062f98SCezary Rojewski return -ENOMEM; 956b9062f98SCezary Rojewski dai++; 957b9062f98SCezary Rojewski } 958b9062f98SCezary Rojewski 959b9062f98SCezary Rojewski if (!tdms) 960b9062f98SCezary Rojewski goto plat_register; 961b9062f98SCezary Rojewski 962b9062f98SCezary Rojewski for_each_set_bit(i, &port_mask, ssp_count) { 963b9062f98SCezary Rojewski for_each_set_bit(j, &tdms[i], ssp_count) { 964b9062f98SCezary Rojewski memcpy(dai, &i2s_dai_template, sizeof(*dai)); 965b9062f98SCezary Rojewski 966b9062f98SCezary Rojewski dai->name = 967b9062f98SCezary Rojewski devm_kasprintf(adev->dev, GFP_KERNEL, "SSP%d:%d Pin", i, j); 968b9062f98SCezary Rojewski dai->playback.stream_name = 969b9062f98SCezary Rojewski devm_kasprintf(adev->dev, GFP_KERNEL, "ssp%d:%d Tx", i, j); 970b9062f98SCezary Rojewski dai->capture.stream_name = 971b9062f98SCezary Rojewski devm_kasprintf(adev->dev, GFP_KERNEL, "ssp%d:%d Rx", i, j); 972b9062f98SCezary Rojewski 973b9062f98SCezary Rojewski if (!dai->name || !dai->playback.stream_name || !dai->capture.stream_name) 974b9062f98SCezary Rojewski return -ENOMEM; 975b9062f98SCezary Rojewski dai++; 976b9062f98SCezary Rojewski } 977b9062f98SCezary Rojewski } 978b9062f98SCezary Rojewski 979b9062f98SCezary Rojewski plat_register: 980b9062f98SCezary Rojewski return avs_soc_component_register(adev->dev, name, &avs_component_driver, cpus, cpu_count); 981b9062f98SCezary Rojewski } 982d070002aSCezary Rojewski 983d070002aSCezary Rojewski /* HD-Audio CPU DAI template */ 984d070002aSCezary Rojewski static const struct snd_soc_dai_driver hda_cpu_dai = { 985d070002aSCezary Rojewski .ops = &avs_dai_hda_be_ops, 986d070002aSCezary Rojewski .playback = { 987d070002aSCezary Rojewski .channels_min = 1, 988d070002aSCezary Rojewski .channels_max = 8, 989d070002aSCezary Rojewski .rates = SNDRV_PCM_RATE_8000_192000, 990d070002aSCezary Rojewski .formats = SNDRV_PCM_FMTBIT_S16_LE | 991d070002aSCezary Rojewski SNDRV_PCM_FMTBIT_S24_LE | 992d070002aSCezary Rojewski SNDRV_PCM_FMTBIT_S32_LE, 993d070002aSCezary Rojewski }, 994d070002aSCezary Rojewski .capture = { 995d070002aSCezary Rojewski .channels_min = 1, 996d070002aSCezary Rojewski .channels_max = 8, 997d070002aSCezary Rojewski .rates = SNDRV_PCM_RATE_8000_192000, 998d070002aSCezary Rojewski .formats = SNDRV_PCM_FMTBIT_S16_LE | 999d070002aSCezary Rojewski SNDRV_PCM_FMTBIT_S24_LE | 1000d070002aSCezary Rojewski SNDRV_PCM_FMTBIT_S32_LE, 1001d070002aSCezary Rojewski }, 1002d070002aSCezary Rojewski }; 1003d070002aSCezary Rojewski 1004d070002aSCezary Rojewski static void avs_component_hda_unregister_dais(struct snd_soc_component *component) 1005d070002aSCezary Rojewski { 1006d070002aSCezary Rojewski struct snd_soc_acpi_mach *mach; 1007d070002aSCezary Rojewski struct snd_soc_dai *dai, *save; 1008d070002aSCezary Rojewski struct hda_codec *codec; 1009d070002aSCezary Rojewski char name[32]; 1010d070002aSCezary Rojewski 1011d070002aSCezary Rojewski mach = dev_get_platdata(component->card->dev); 1012d070002aSCezary Rojewski codec = mach->pdata; 1013d070002aSCezary Rojewski sprintf(name, "%s-cpu", dev_name(&codec->core.dev)); 1014d070002aSCezary Rojewski 1015d070002aSCezary Rojewski for_each_component_dais_safe(component, dai, save) { 1016d070002aSCezary Rojewski if (!strstr(dai->driver->name, name)) 1017d070002aSCezary Rojewski continue; 1018d070002aSCezary Rojewski 1019d070002aSCezary Rojewski if (dai->playback_widget) 1020d070002aSCezary Rojewski snd_soc_dapm_free_widget(dai->playback_widget); 1021d070002aSCezary Rojewski if (dai->capture_widget) 1022d070002aSCezary Rojewski snd_soc_dapm_free_widget(dai->capture_widget); 1023d070002aSCezary Rojewski snd_soc_unregister_dai(dai); 1024d070002aSCezary Rojewski } 1025d070002aSCezary Rojewski } 1026d070002aSCezary Rojewski 1027d070002aSCezary Rojewski static int avs_component_hda_probe(struct snd_soc_component *component) 1028d070002aSCezary Rojewski { 1029d070002aSCezary Rojewski struct snd_soc_dapm_context *dapm; 1030d070002aSCezary Rojewski struct snd_soc_dai_driver *dais; 1031d070002aSCezary Rojewski struct snd_soc_acpi_mach *mach; 1032d070002aSCezary Rojewski struct hda_codec *codec; 1033d070002aSCezary Rojewski struct hda_pcm *pcm; 1034d070002aSCezary Rojewski const char *cname; 1035d070002aSCezary Rojewski int pcm_count = 0, ret, i; 1036d070002aSCezary Rojewski 1037d070002aSCezary Rojewski mach = dev_get_platdata(component->card->dev); 1038d070002aSCezary Rojewski if (!mach) 1039d070002aSCezary Rojewski return -EINVAL; 1040d070002aSCezary Rojewski 1041d070002aSCezary Rojewski codec = mach->pdata; 1042d070002aSCezary Rojewski if (list_empty(&codec->pcm_list_head)) 1043d070002aSCezary Rojewski return -EINVAL; 1044d070002aSCezary Rojewski list_for_each_entry(pcm, &codec->pcm_list_head, list) 1045d070002aSCezary Rojewski pcm_count++; 1046d070002aSCezary Rojewski 1047d070002aSCezary Rojewski dais = devm_kcalloc(component->dev, pcm_count, sizeof(*dais), 1048d070002aSCezary Rojewski GFP_KERNEL); 1049d070002aSCezary Rojewski if (!dais) 1050d070002aSCezary Rojewski return -ENOMEM; 1051d070002aSCezary Rojewski 1052d070002aSCezary Rojewski cname = dev_name(&codec->core.dev); 1053d070002aSCezary Rojewski dapm = snd_soc_component_get_dapm(component); 1054d070002aSCezary Rojewski pcm = list_first_entry(&codec->pcm_list_head, struct hda_pcm, list); 1055d070002aSCezary Rojewski 1056d070002aSCezary Rojewski for (i = 0; i < pcm_count; i++, pcm = list_next_entry(pcm, list)) { 1057d070002aSCezary Rojewski struct snd_soc_dai *dai; 1058d070002aSCezary Rojewski 1059d070002aSCezary Rojewski memcpy(&dais[i], &hda_cpu_dai, sizeof(*dais)); 1060d070002aSCezary Rojewski dais[i].id = i; 1061d070002aSCezary Rojewski dais[i].name = devm_kasprintf(component->dev, GFP_KERNEL, 1062d070002aSCezary Rojewski "%s-cpu%d", cname, i); 1063d070002aSCezary Rojewski if (!dais[i].name) { 1064d070002aSCezary Rojewski ret = -ENOMEM; 1065d070002aSCezary Rojewski goto exit; 1066d070002aSCezary Rojewski } 1067d070002aSCezary Rojewski 1068d070002aSCezary Rojewski if (pcm->stream[0].substreams) { 1069d070002aSCezary Rojewski dais[i].playback.stream_name = 1070d070002aSCezary Rojewski devm_kasprintf(component->dev, GFP_KERNEL, 1071d070002aSCezary Rojewski "%s-cpu%d Tx", cname, i); 1072d070002aSCezary Rojewski if (!dais[i].playback.stream_name) { 1073d070002aSCezary Rojewski ret = -ENOMEM; 1074d070002aSCezary Rojewski goto exit; 1075d070002aSCezary Rojewski } 1076d070002aSCezary Rojewski } 1077d070002aSCezary Rojewski 1078d070002aSCezary Rojewski if (pcm->stream[1].substreams) { 1079d070002aSCezary Rojewski dais[i].capture.stream_name = 1080d070002aSCezary Rojewski devm_kasprintf(component->dev, GFP_KERNEL, 1081d070002aSCezary Rojewski "%s-cpu%d Rx", cname, i); 1082d070002aSCezary Rojewski if (!dais[i].capture.stream_name) { 1083d070002aSCezary Rojewski ret = -ENOMEM; 1084d070002aSCezary Rojewski goto exit; 1085d070002aSCezary Rojewski } 1086d070002aSCezary Rojewski } 1087d070002aSCezary Rojewski 1088d070002aSCezary Rojewski dai = snd_soc_register_dai(component, &dais[i], false); 1089d070002aSCezary Rojewski if (!dai) { 1090d070002aSCezary Rojewski dev_err(component->dev, "register dai for %s failed\n", 1091d070002aSCezary Rojewski pcm->name); 1092d070002aSCezary Rojewski ret = -EINVAL; 1093d070002aSCezary Rojewski goto exit; 1094d070002aSCezary Rojewski } 1095d070002aSCezary Rojewski 1096d070002aSCezary Rojewski ret = snd_soc_dapm_new_dai_widgets(dapm, dai); 1097d070002aSCezary Rojewski if (ret < 0) { 1098d070002aSCezary Rojewski dev_err(component->dev, "create widgets failed: %d\n", 1099d070002aSCezary Rojewski ret); 1100d070002aSCezary Rojewski goto exit; 1101d070002aSCezary Rojewski } 1102d070002aSCezary Rojewski } 1103d070002aSCezary Rojewski 1104d070002aSCezary Rojewski ret = avs_component_probe(component); 1105d070002aSCezary Rojewski exit: 1106d070002aSCezary Rojewski if (ret) 1107d070002aSCezary Rojewski avs_component_hda_unregister_dais(component); 1108d070002aSCezary Rojewski 1109d070002aSCezary Rojewski return ret; 1110d070002aSCezary Rojewski } 1111d070002aSCezary Rojewski 1112d070002aSCezary Rojewski static void avs_component_hda_remove(struct snd_soc_component *component) 1113d070002aSCezary Rojewski { 1114d070002aSCezary Rojewski avs_component_hda_unregister_dais(component); 1115d070002aSCezary Rojewski avs_component_remove(component); 1116d070002aSCezary Rojewski } 1117d070002aSCezary Rojewski 1118d070002aSCezary Rojewski static int avs_component_hda_open(struct snd_soc_component *component, 1119d070002aSCezary Rojewski struct snd_pcm_substream *substream) 1120d070002aSCezary Rojewski { 1121d070002aSCezary Rojewski struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); 1122d070002aSCezary Rojewski struct hdac_ext_stream *link_stream; 1123d070002aSCezary Rojewski struct hda_codec *codec; 1124d070002aSCezary Rojewski 1125d070002aSCezary Rojewski /* only BE DAI links are handled here */ 1126d070002aSCezary Rojewski if (!rtd->dai_link->no_pcm) 1127d070002aSCezary Rojewski return avs_component_open(component, substream); 1128d070002aSCezary Rojewski 1129d070002aSCezary Rojewski codec = dev_to_hda_codec(asoc_rtd_to_codec(rtd, 0)->dev); 1130d070002aSCezary Rojewski link_stream = snd_hdac_ext_stream_assign(&codec->bus->core, substream, 1131d070002aSCezary Rojewski HDAC_EXT_STREAM_TYPE_LINK); 1132d070002aSCezary Rojewski if (!link_stream) 1133d070002aSCezary Rojewski return -EBUSY; 1134d070002aSCezary Rojewski 1135d070002aSCezary Rojewski substream->runtime->private_data = link_stream; 1136d070002aSCezary Rojewski return 0; 1137d070002aSCezary Rojewski } 1138d070002aSCezary Rojewski 1139d070002aSCezary Rojewski static int avs_component_hda_close(struct snd_soc_component *component, 1140d070002aSCezary Rojewski struct snd_pcm_substream *substream) 1141d070002aSCezary Rojewski { 1142d070002aSCezary Rojewski struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); 1143d070002aSCezary Rojewski struct hdac_ext_stream *link_stream; 1144d070002aSCezary Rojewski 1145d070002aSCezary Rojewski /* only BE DAI links are handled here */ 1146d070002aSCezary Rojewski if (!rtd->dai_link->no_pcm) 1147d070002aSCezary Rojewski return 0; 1148d070002aSCezary Rojewski 1149d070002aSCezary Rojewski link_stream = substream->runtime->private_data; 1150d070002aSCezary Rojewski snd_hdac_ext_stream_release(link_stream, HDAC_EXT_STREAM_TYPE_LINK); 1151d070002aSCezary Rojewski substream->runtime->private_data = NULL; 1152d070002aSCezary Rojewski 1153d070002aSCezary Rojewski return 0; 1154d070002aSCezary Rojewski } 1155d070002aSCezary Rojewski 1156d070002aSCezary Rojewski static const struct snd_soc_component_driver avs_hda_component_driver = { 1157d070002aSCezary Rojewski .name = "avs-hda-pcm", 1158d070002aSCezary Rojewski .probe = avs_component_hda_probe, 1159d070002aSCezary Rojewski .remove = avs_component_hda_remove, 1160d070002aSCezary Rojewski .open = avs_component_hda_open, 1161d070002aSCezary Rojewski .close = avs_component_hda_close, 1162d070002aSCezary Rojewski .pointer = avs_component_pointer, 1163d070002aSCezary Rojewski .mmap = avs_component_mmap, 1164d070002aSCezary Rojewski .pcm_construct = avs_component_construct, 1165d070002aSCezary Rojewski /* 1166d070002aSCezary Rojewski * hda platform component's probe() is dependent on 1167d070002aSCezary Rojewski * codec->pcm_list_head, it needs to be initialized after codec 1168d070002aSCezary Rojewski * component. remove_order is here for completeness sake 1169d070002aSCezary Rojewski */ 1170d070002aSCezary Rojewski .probe_order = SND_SOC_COMP_ORDER_LATE, 1171d070002aSCezary Rojewski .remove_order = SND_SOC_COMP_ORDER_EARLY, 1172d070002aSCezary Rojewski .module_get_upon_open = 1, 1173d070002aSCezary Rojewski .topology_name_prefix = "intel/avs", 1174d070002aSCezary Rojewski }; 1175d070002aSCezary Rojewski 1176d070002aSCezary Rojewski int avs_hda_platform_register(struct avs_dev *adev, const char *name) 1177d070002aSCezary Rojewski { 1178d070002aSCezary Rojewski return avs_soc_component_register(adev->dev, name, 1179d070002aSCezary Rojewski &avs_hda_component_driver, NULL, 0); 1180d070002aSCezary Rojewski } 1181