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; 31*2b9a50eaSCezary Rojewski 32*2b9a50eaSCezary Rojewski struct snd_pcm_substream *substream; 33f1b3b320SCezary Rojewski }; 34f1b3b320SCezary Rojewski 359114700bSCezary Rojewski static struct avs_tplg_path_template * 369114700bSCezary Rojewski avs_dai_find_path_template(struct snd_soc_dai *dai, bool is_fe, int direction) 379114700bSCezary Rojewski { 389114700bSCezary Rojewski struct snd_soc_dapm_widget *dw; 399114700bSCezary Rojewski struct snd_soc_dapm_path *dp; 409114700bSCezary Rojewski enum snd_soc_dapm_direction dir; 419114700bSCezary Rojewski 429114700bSCezary Rojewski if (direction == SNDRV_PCM_STREAM_CAPTURE) { 439114700bSCezary Rojewski dw = dai->capture_widget; 449114700bSCezary Rojewski dir = is_fe ? SND_SOC_DAPM_DIR_OUT : SND_SOC_DAPM_DIR_IN; 459114700bSCezary Rojewski } else { 469114700bSCezary Rojewski dw = dai->playback_widget; 479114700bSCezary Rojewski dir = is_fe ? SND_SOC_DAPM_DIR_IN : SND_SOC_DAPM_DIR_OUT; 489114700bSCezary Rojewski } 499114700bSCezary Rojewski 509114700bSCezary Rojewski dp = list_first_entry_or_null(&dw->edges[dir], typeof(*dp), list_node[dir]); 519114700bSCezary Rojewski if (!dp) 529114700bSCezary Rojewski return NULL; 539114700bSCezary Rojewski 549114700bSCezary Rojewski /* Get the other widget, with actual path template data */ 559114700bSCezary Rojewski dw = (dp->source == dw) ? dp->sink : dp->source; 569114700bSCezary Rojewski 579114700bSCezary Rojewski return dw->priv; 589114700bSCezary Rojewski } 599114700bSCezary Rojewski 60*2b9a50eaSCezary Rojewski static int avs_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai, bool is_fe, 61*2b9a50eaSCezary Rojewski const struct snd_soc_dai_ops *ops) 629114700bSCezary Rojewski { 639114700bSCezary Rojewski struct avs_tplg_path_template *template; 649114700bSCezary Rojewski struct avs_dma_data *data; 659114700bSCezary Rojewski 669114700bSCezary Rojewski template = avs_dai_find_path_template(dai, is_fe, substream->stream); 679114700bSCezary Rojewski if (!template) { 689114700bSCezary Rojewski dev_err(dai->dev, "no %s path for dai %s, invalid tplg?\n", 699114700bSCezary Rojewski snd_pcm_stream_str(substream), dai->name); 709114700bSCezary Rojewski return -EINVAL; 719114700bSCezary Rojewski } 729114700bSCezary Rojewski 739114700bSCezary Rojewski data = kzalloc(sizeof(*data), GFP_KERNEL); 749114700bSCezary Rojewski if (!data) 759114700bSCezary Rojewski return -ENOMEM; 769114700bSCezary Rojewski 77*2b9a50eaSCezary Rojewski data->substream = substream; 789114700bSCezary Rojewski data->template = template; 799114700bSCezary Rojewski snd_soc_dai_set_dma_data(dai, substream, data); 809114700bSCezary Rojewski 819114700bSCezary Rojewski return 0; 829114700bSCezary Rojewski } 839114700bSCezary Rojewski 849114700bSCezary Rojewski static int avs_dai_hw_params(struct snd_pcm_substream *substream, 859114700bSCezary Rojewski struct snd_pcm_hw_params *fe_hw_params, 869114700bSCezary Rojewski struct snd_pcm_hw_params *be_hw_params, struct snd_soc_dai *dai, 879114700bSCezary Rojewski int dma_id) 889114700bSCezary Rojewski { 899114700bSCezary Rojewski struct avs_dma_data *data; 909114700bSCezary Rojewski struct avs_path *path; 919114700bSCezary Rojewski struct avs_dev *adev = to_avs_dev(dai->dev); 929114700bSCezary Rojewski int ret; 939114700bSCezary Rojewski 949114700bSCezary Rojewski data = snd_soc_dai_get_dma_data(dai, substream); 959114700bSCezary Rojewski 969114700bSCezary Rojewski dev_dbg(dai->dev, "%s FE hw_params str %p rtd %p", 979114700bSCezary Rojewski __func__, substream, substream->runtime); 989114700bSCezary Rojewski dev_dbg(dai->dev, "rate %d chn %d vbd %d bd %d\n", 999114700bSCezary Rojewski params_rate(fe_hw_params), params_channels(fe_hw_params), 1009114700bSCezary Rojewski params_width(fe_hw_params), params_physical_width(fe_hw_params)); 1019114700bSCezary Rojewski 1029114700bSCezary Rojewski dev_dbg(dai->dev, "%s BE hw_params str %p rtd %p", 1039114700bSCezary Rojewski __func__, substream, substream->runtime); 1049114700bSCezary Rojewski dev_dbg(dai->dev, "rate %d chn %d vbd %d bd %d\n", 1059114700bSCezary Rojewski params_rate(be_hw_params), params_channels(be_hw_params), 1069114700bSCezary Rojewski params_width(be_hw_params), params_physical_width(be_hw_params)); 1079114700bSCezary Rojewski 1089114700bSCezary Rojewski path = avs_path_create(adev, dma_id, data->template, fe_hw_params, be_hw_params); 1099114700bSCezary Rojewski if (IS_ERR(path)) { 1109114700bSCezary Rojewski ret = PTR_ERR(path); 1119114700bSCezary Rojewski dev_err(dai->dev, "create path failed: %d\n", ret); 1129114700bSCezary Rojewski return ret; 1139114700bSCezary Rojewski } 1149114700bSCezary Rojewski 1159114700bSCezary Rojewski data->path = path; 1169114700bSCezary Rojewski return 0; 1179114700bSCezary Rojewski } 1189114700bSCezary Rojewski 119b9062f98SCezary Rojewski static int avs_dai_be_hw_params(struct snd_pcm_substream *substream, 120b9062f98SCezary Rojewski struct snd_pcm_hw_params *be_hw_params, struct snd_soc_dai *dai, 121b9062f98SCezary Rojewski int dma_id) 122b9062f98SCezary Rojewski { 123b9062f98SCezary Rojewski struct snd_pcm_hw_params *fe_hw_params = NULL; 124b9062f98SCezary Rojewski struct snd_soc_pcm_runtime *fe, *be; 125b9062f98SCezary Rojewski struct snd_soc_dpcm *dpcm; 126b9062f98SCezary Rojewski 127b9062f98SCezary Rojewski be = asoc_substream_to_rtd(substream); 128b9062f98SCezary Rojewski for_each_dpcm_fe(be, substream->stream, dpcm) { 129b9062f98SCezary Rojewski fe = dpcm->fe; 130b9062f98SCezary Rojewski fe_hw_params = &fe->dpcm[substream->stream].hw_params; 131b9062f98SCezary Rojewski } 132b9062f98SCezary Rojewski 133b9062f98SCezary Rojewski return avs_dai_hw_params(substream, fe_hw_params, be_hw_params, dai, dma_id); 134b9062f98SCezary Rojewski } 135b9062f98SCezary Rojewski 1369114700bSCezary Rojewski static int avs_dai_prepare(struct avs_dev *adev, struct snd_pcm_substream *substream, 1379114700bSCezary Rojewski struct snd_soc_dai *dai) 1389114700bSCezary Rojewski { 1399114700bSCezary Rojewski struct avs_dma_data *data; 1409114700bSCezary Rojewski int ret; 1419114700bSCezary Rojewski 1429114700bSCezary Rojewski data = snd_soc_dai_get_dma_data(dai, substream); 1439114700bSCezary Rojewski if (!data->path) 1449114700bSCezary Rojewski return 0; 1459114700bSCezary Rojewski 1469114700bSCezary Rojewski ret = avs_path_reset(data->path); 1479114700bSCezary Rojewski if (ret < 0) { 1489114700bSCezary Rojewski dev_err(dai->dev, "reset path failed: %d\n", ret); 1499114700bSCezary Rojewski return ret; 1509114700bSCezary Rojewski } 1519114700bSCezary Rojewski 1529114700bSCezary Rojewski ret = avs_path_pause(data->path); 1539114700bSCezary Rojewski if (ret < 0) 1549114700bSCezary Rojewski dev_err(dai->dev, "pause path failed: %d\n", ret); 1559114700bSCezary Rojewski return ret; 1569114700bSCezary Rojewski } 1579114700bSCezary Rojewski 158*2b9a50eaSCezary Rojewski static const struct snd_soc_dai_ops avs_dai_nonhda_be_ops; 159*2b9a50eaSCezary Rojewski 160b9062f98SCezary Rojewski static int avs_dai_nonhda_be_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) 161b9062f98SCezary Rojewski { 162*2b9a50eaSCezary Rojewski return avs_dai_startup(substream, dai, false, &avs_dai_nonhda_be_ops); 163b9062f98SCezary Rojewski } 164b9062f98SCezary Rojewski 165b9062f98SCezary Rojewski static void avs_dai_nonhda_be_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) 166b9062f98SCezary Rojewski { 167b9062f98SCezary Rojewski struct avs_dma_data *data; 168b9062f98SCezary Rojewski 169b9062f98SCezary Rojewski data = snd_soc_dai_get_dma_data(dai, substream); 170b9062f98SCezary Rojewski 171b9062f98SCezary Rojewski snd_soc_dai_set_dma_data(dai, substream, NULL); 172b9062f98SCezary Rojewski kfree(data); 173b9062f98SCezary Rojewski } 174b9062f98SCezary Rojewski 175b9062f98SCezary Rojewski static int avs_dai_nonhda_be_hw_params(struct snd_pcm_substream *substream, 176b9062f98SCezary Rojewski struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *dai) 177b9062f98SCezary Rojewski { 178b9062f98SCezary Rojewski struct avs_dma_data *data; 179b9062f98SCezary Rojewski 180b9062f98SCezary Rojewski data = snd_soc_dai_get_dma_data(dai, substream); 181b9062f98SCezary Rojewski if (data->path) 182b9062f98SCezary Rojewski return 0; 183b9062f98SCezary Rojewski 184b9062f98SCezary Rojewski /* Actual port-id comes from topology. */ 185b9062f98SCezary Rojewski return avs_dai_be_hw_params(substream, hw_params, dai, 0); 186b9062f98SCezary Rojewski } 187b9062f98SCezary Rojewski 188b9062f98SCezary Rojewski static int avs_dai_nonhda_be_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) 189b9062f98SCezary Rojewski { 190b9062f98SCezary Rojewski struct avs_dma_data *data; 191b9062f98SCezary Rojewski 192b9062f98SCezary Rojewski dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); 193b9062f98SCezary Rojewski 194b9062f98SCezary Rojewski data = snd_soc_dai_get_dma_data(dai, substream); 195b9062f98SCezary Rojewski if (data->path) { 196b9062f98SCezary Rojewski avs_path_free(data->path); 197b9062f98SCezary Rojewski data->path = NULL; 198b9062f98SCezary Rojewski } 199b9062f98SCezary Rojewski 200b9062f98SCezary Rojewski return 0; 201b9062f98SCezary Rojewski } 202b9062f98SCezary Rojewski 203b9062f98SCezary Rojewski static int avs_dai_nonhda_be_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) 204b9062f98SCezary Rojewski { 205b9062f98SCezary Rojewski return avs_dai_prepare(to_avs_dev(dai->dev), substream, dai); 206b9062f98SCezary Rojewski } 207b9062f98SCezary Rojewski 208b9062f98SCezary Rojewski static int avs_dai_nonhda_be_trigger(struct snd_pcm_substream *substream, int cmd, 209b9062f98SCezary Rojewski struct snd_soc_dai *dai) 210b9062f98SCezary Rojewski { 211b9062f98SCezary Rojewski struct avs_dma_data *data; 212b9062f98SCezary Rojewski int ret = 0; 213b9062f98SCezary Rojewski 214b9062f98SCezary Rojewski data = snd_soc_dai_get_dma_data(dai, substream); 215b9062f98SCezary Rojewski 216b9062f98SCezary Rojewski switch (cmd) { 217b9062f98SCezary Rojewski case SNDRV_PCM_TRIGGER_START: 218b9062f98SCezary Rojewski case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 219b9062f98SCezary Rojewski ret = avs_path_run(data->path, AVS_TPLG_TRIGGER_AUTO); 220b9062f98SCezary Rojewski if (ret < 0) 221b9062f98SCezary Rojewski dev_err(dai->dev, "run BE path failed: %d\n", ret); 222b9062f98SCezary Rojewski break; 223b9062f98SCezary Rojewski 224b9062f98SCezary Rojewski case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 225b9062f98SCezary Rojewski case SNDRV_PCM_TRIGGER_STOP: 226b9062f98SCezary Rojewski ret = avs_path_pause(data->path); 227b9062f98SCezary Rojewski if (ret < 0) 228b9062f98SCezary Rojewski dev_err(dai->dev, "pause BE path failed: %d\n", ret); 229b9062f98SCezary Rojewski 230b9062f98SCezary Rojewski if (cmd == SNDRV_PCM_TRIGGER_STOP) { 231b9062f98SCezary Rojewski ret = avs_path_reset(data->path); 232b9062f98SCezary Rojewski if (ret < 0) 233b9062f98SCezary Rojewski dev_err(dai->dev, "reset BE path failed: %d\n", ret); 234b9062f98SCezary Rojewski } 235b9062f98SCezary Rojewski break; 236b9062f98SCezary Rojewski 237b9062f98SCezary Rojewski default: 238b9062f98SCezary Rojewski ret = -EINVAL; 239b9062f98SCezary Rojewski break; 240b9062f98SCezary Rojewski } 241b9062f98SCezary Rojewski 242b9062f98SCezary Rojewski return ret; 243b9062f98SCezary Rojewski } 244b9062f98SCezary Rojewski 245b9062f98SCezary Rojewski static const struct snd_soc_dai_ops avs_dai_nonhda_be_ops = { 246b9062f98SCezary Rojewski .startup = avs_dai_nonhda_be_startup, 247b9062f98SCezary Rojewski .shutdown = avs_dai_nonhda_be_shutdown, 248b9062f98SCezary Rojewski .hw_params = avs_dai_nonhda_be_hw_params, 249b9062f98SCezary Rojewski .hw_free = avs_dai_nonhda_be_hw_free, 250b9062f98SCezary Rojewski .prepare = avs_dai_nonhda_be_prepare, 251b9062f98SCezary Rojewski .trigger = avs_dai_nonhda_be_trigger, 252b9062f98SCezary Rojewski }; 253b9062f98SCezary Rojewski 254*2b9a50eaSCezary Rojewski static const struct snd_soc_dai_ops avs_dai_hda_be_ops; 255*2b9a50eaSCezary Rojewski 256d070002aSCezary Rojewski static int avs_dai_hda_be_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) 257d070002aSCezary Rojewski { 258*2b9a50eaSCezary Rojewski return avs_dai_startup(substream, dai, false, &avs_dai_hda_be_ops); 259d070002aSCezary Rojewski } 260d070002aSCezary Rojewski 261d070002aSCezary Rojewski static void avs_dai_hda_be_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) 262d070002aSCezary Rojewski { 263d070002aSCezary Rojewski return avs_dai_nonhda_be_shutdown(substream, dai); 264d070002aSCezary Rojewski } 265d070002aSCezary Rojewski 266d070002aSCezary Rojewski static int avs_dai_hda_be_hw_params(struct snd_pcm_substream *substream, 267d070002aSCezary Rojewski struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *dai) 268d070002aSCezary Rojewski { 269d070002aSCezary Rojewski struct avs_dma_data *data; 270d070002aSCezary Rojewski struct hdac_ext_stream *link_stream; 271d070002aSCezary Rojewski 272d070002aSCezary Rojewski data = snd_soc_dai_get_dma_data(dai, substream); 273d070002aSCezary Rojewski if (data->path) 274d070002aSCezary Rojewski return 0; 275d070002aSCezary Rojewski 276d070002aSCezary Rojewski link_stream = substream->runtime->private_data; 277d070002aSCezary Rojewski 278d070002aSCezary Rojewski return avs_dai_be_hw_params(substream, hw_params, dai, 279d070002aSCezary Rojewski hdac_stream(link_stream)->stream_tag - 1); 280d070002aSCezary Rojewski } 281d070002aSCezary Rojewski 282d070002aSCezary Rojewski static int avs_dai_hda_be_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) 283d070002aSCezary Rojewski { 284d070002aSCezary Rojewski struct avs_dma_data *data; 285d070002aSCezary Rojewski struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); 286d070002aSCezary Rojewski struct hdac_ext_stream *link_stream; 287d070002aSCezary Rojewski struct hdac_ext_link *link; 288d070002aSCezary Rojewski struct hda_codec *codec; 289d070002aSCezary Rojewski 290d070002aSCezary Rojewski dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); 291d070002aSCezary Rojewski 292d070002aSCezary Rojewski data = snd_soc_dai_get_dma_data(dai, substream); 293d070002aSCezary Rojewski if (!data->path) 294d070002aSCezary Rojewski return 0; 295d070002aSCezary Rojewski 296d070002aSCezary Rojewski link_stream = substream->runtime->private_data; 297d070002aSCezary Rojewski link_stream->link_prepared = false; 298d070002aSCezary Rojewski avs_path_free(data->path); 299d070002aSCezary Rojewski data->path = NULL; 300d070002aSCezary Rojewski 301d070002aSCezary Rojewski /* clear link <-> stream mapping */ 302d070002aSCezary Rojewski codec = dev_to_hda_codec(asoc_rtd_to_codec(rtd, 0)->dev); 303b0cd60f3SPierre-Louis Bossart link = snd_hdac_ext_bus_get_hlink_by_addr(&codec->bus->core, codec->core.addr); 304d070002aSCezary Rojewski if (!link) 305d070002aSCezary Rojewski return -EINVAL; 306d070002aSCezary Rojewski 307d070002aSCezary Rojewski if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 3087fa403f2SPierre-Louis Bossart snd_hdac_ext_bus_link_clear_stream_id(link, hdac_stream(link_stream)->stream_tag); 309d070002aSCezary Rojewski 310d070002aSCezary Rojewski return 0; 311d070002aSCezary Rojewski } 312d070002aSCezary Rojewski 313d070002aSCezary Rojewski static int avs_dai_hda_be_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) 314d070002aSCezary Rojewski { 315d070002aSCezary Rojewski struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); 316d070002aSCezary Rojewski struct snd_pcm_runtime *runtime = substream->runtime; 317d070002aSCezary Rojewski struct hdac_ext_stream *link_stream = runtime->private_data; 318d070002aSCezary Rojewski struct hdac_ext_link *link; 319d070002aSCezary Rojewski struct hda_codec *codec; 320d070002aSCezary Rojewski struct hdac_bus *bus; 321d070002aSCezary Rojewski unsigned int format_val; 322d070002aSCezary Rojewski int ret; 323d070002aSCezary Rojewski 324d070002aSCezary Rojewski if (link_stream->link_prepared) 325d070002aSCezary Rojewski return 0; 326d070002aSCezary Rojewski 327d070002aSCezary Rojewski codec = dev_to_hda_codec(asoc_rtd_to_codec(rtd, 0)->dev); 328d070002aSCezary Rojewski bus = &codec->bus->core; 329d070002aSCezary Rojewski format_val = snd_hdac_calc_stream_format(runtime->rate, runtime->channels, runtime->format, 330d070002aSCezary Rojewski runtime->sample_bits, 0); 331d070002aSCezary Rojewski 332d070002aSCezary Rojewski snd_hdac_ext_stream_decouple(bus, link_stream, true); 33300b6cd95SPierre-Louis Bossart snd_hdac_ext_stream_reset(link_stream); 33400b6cd95SPierre-Louis Bossart snd_hdac_ext_stream_setup(link_stream, format_val); 335d070002aSCezary Rojewski 336b0cd60f3SPierre-Louis Bossart link = snd_hdac_ext_bus_get_hlink_by_addr(bus, codec->core.addr); 337d070002aSCezary Rojewski if (!link) 338d070002aSCezary Rojewski return -EINVAL; 339d070002aSCezary Rojewski 340d070002aSCezary Rojewski if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 3417fa403f2SPierre-Louis Bossart snd_hdac_ext_bus_link_set_stream_id(link, hdac_stream(link_stream)->stream_tag); 342d070002aSCezary Rojewski 343d070002aSCezary Rojewski ret = avs_dai_prepare(to_avs_dev(dai->dev), substream, dai); 344d070002aSCezary Rojewski if (ret) 345d070002aSCezary Rojewski return ret; 346d070002aSCezary Rojewski 347d070002aSCezary Rojewski link_stream->link_prepared = true; 348d070002aSCezary Rojewski return 0; 349d070002aSCezary Rojewski } 350d070002aSCezary Rojewski 351d070002aSCezary Rojewski static int avs_dai_hda_be_trigger(struct snd_pcm_substream *substream, int cmd, 352d070002aSCezary Rojewski struct snd_soc_dai *dai) 353d070002aSCezary Rojewski { 354d070002aSCezary Rojewski struct hdac_ext_stream *link_stream; 355d070002aSCezary Rojewski struct avs_dma_data *data; 356d070002aSCezary Rojewski int ret = 0; 357d070002aSCezary Rojewski 358d070002aSCezary Rojewski dev_dbg(dai->dev, "entry %s cmd=%d\n", __func__, cmd); 359d070002aSCezary Rojewski 360d070002aSCezary Rojewski data = snd_soc_dai_get_dma_data(dai, substream); 361d070002aSCezary Rojewski link_stream = substream->runtime->private_data; 362d070002aSCezary Rojewski 363d070002aSCezary Rojewski switch (cmd) { 364d070002aSCezary Rojewski case SNDRV_PCM_TRIGGER_START: 365d070002aSCezary Rojewski case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 36600b6cd95SPierre-Louis Bossart snd_hdac_ext_stream_start(link_stream); 367d070002aSCezary Rojewski 368d070002aSCezary Rojewski ret = avs_path_run(data->path, AVS_TPLG_TRIGGER_AUTO); 369d070002aSCezary Rojewski if (ret < 0) 370d070002aSCezary Rojewski dev_err(dai->dev, "run BE path failed: %d\n", ret); 371d070002aSCezary Rojewski break; 372d070002aSCezary Rojewski 373d070002aSCezary Rojewski case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 374d070002aSCezary Rojewski case SNDRV_PCM_TRIGGER_STOP: 375d070002aSCezary Rojewski ret = avs_path_pause(data->path); 376d070002aSCezary Rojewski if (ret < 0) 377d070002aSCezary Rojewski dev_err(dai->dev, "pause BE path failed: %d\n", ret); 378d070002aSCezary Rojewski 37900b6cd95SPierre-Louis Bossart snd_hdac_ext_stream_clear(link_stream); 380d070002aSCezary Rojewski 381d070002aSCezary Rojewski if (cmd == SNDRV_PCM_TRIGGER_STOP) { 382d070002aSCezary Rojewski ret = avs_path_reset(data->path); 383d070002aSCezary Rojewski if (ret < 0) 384d070002aSCezary Rojewski dev_err(dai->dev, "reset BE path failed: %d\n", ret); 385d070002aSCezary Rojewski } 386d070002aSCezary Rojewski break; 387d070002aSCezary Rojewski 388d070002aSCezary Rojewski default: 389d070002aSCezary Rojewski ret = -EINVAL; 390d070002aSCezary Rojewski break; 391d070002aSCezary Rojewski } 392d070002aSCezary Rojewski 393d070002aSCezary Rojewski return ret; 394d070002aSCezary Rojewski } 395d070002aSCezary Rojewski 396d070002aSCezary Rojewski static const struct snd_soc_dai_ops avs_dai_hda_be_ops = { 397d070002aSCezary Rojewski .startup = avs_dai_hda_be_startup, 398d070002aSCezary Rojewski .shutdown = avs_dai_hda_be_shutdown, 399d070002aSCezary Rojewski .hw_params = avs_dai_hda_be_hw_params, 400d070002aSCezary Rojewski .hw_free = avs_dai_hda_be_hw_free, 401d070002aSCezary Rojewski .prepare = avs_dai_hda_be_prepare, 402d070002aSCezary Rojewski .trigger = avs_dai_hda_be_trigger, 403d070002aSCezary Rojewski }; 404d070002aSCezary Rojewski 4059114700bSCezary Rojewski static const unsigned int rates[] = { 4069114700bSCezary Rojewski 8000, 11025, 12000, 16000, 4079114700bSCezary Rojewski 22050, 24000, 32000, 44100, 4089114700bSCezary Rojewski 48000, 64000, 88200, 96000, 4099114700bSCezary Rojewski 128000, 176400, 192000, 4109114700bSCezary Rojewski }; 4119114700bSCezary Rojewski 4129114700bSCezary Rojewski static const struct snd_pcm_hw_constraint_list hw_rates = { 4139114700bSCezary Rojewski .count = ARRAY_SIZE(rates), 4149114700bSCezary Rojewski .list = rates, 4159114700bSCezary Rojewski .mask = 0, 4169114700bSCezary Rojewski }; 4179114700bSCezary Rojewski 418*2b9a50eaSCezary Rojewski const struct snd_soc_dai_ops avs_dai_fe_ops; 419*2b9a50eaSCezary Rojewski 4209114700bSCezary Rojewski static int avs_dai_fe_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) 4219114700bSCezary Rojewski { 4229114700bSCezary Rojewski struct snd_pcm_runtime *runtime = substream->runtime; 4239114700bSCezary Rojewski struct avs_dma_data *data; 4249114700bSCezary Rojewski struct avs_dev *adev = to_avs_dev(dai->dev); 4259114700bSCezary Rojewski struct hdac_bus *bus = &adev->base.core; 4269114700bSCezary Rojewski struct hdac_ext_stream *host_stream; 4279114700bSCezary Rojewski int ret; 4289114700bSCezary Rojewski 429*2b9a50eaSCezary Rojewski ret = avs_dai_startup(substream, dai, true, &avs_dai_fe_ops); 4309114700bSCezary Rojewski if (ret) 4319114700bSCezary Rojewski return ret; 4329114700bSCezary Rojewski 4339114700bSCezary Rojewski data = snd_soc_dai_get_dma_data(dai, substream); 4349114700bSCezary Rojewski 4359114700bSCezary Rojewski host_stream = snd_hdac_ext_stream_assign(bus, substream, HDAC_EXT_STREAM_TYPE_HOST); 4369114700bSCezary Rojewski if (!host_stream) { 4379114700bSCezary Rojewski kfree(data); 4389114700bSCezary Rojewski return -EBUSY; 4399114700bSCezary Rojewski } 4409114700bSCezary Rojewski 4419114700bSCezary Rojewski data->host_stream = host_stream; 4429114700bSCezary Rojewski snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); 4439114700bSCezary Rojewski /* avoid wrap-around with wall-clock */ 4449114700bSCezary Rojewski snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_TIME, 20, 178000000); 4459114700bSCezary Rojewski snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_rates); 4469114700bSCezary Rojewski snd_pcm_set_sync(substream); 4479114700bSCezary Rojewski 4489114700bSCezary Rojewski dev_dbg(dai->dev, "%s fe STARTUP tag %d str %p", 4499114700bSCezary Rojewski __func__, hdac_stream(host_stream)->stream_tag, substream); 4509114700bSCezary Rojewski 4519114700bSCezary Rojewski return 0; 4529114700bSCezary Rojewski } 4539114700bSCezary Rojewski 4549114700bSCezary Rojewski static void avs_dai_fe_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) 4559114700bSCezary Rojewski { 4569114700bSCezary Rojewski struct avs_dma_data *data; 4579114700bSCezary Rojewski 4589114700bSCezary Rojewski data = snd_soc_dai_get_dma_data(dai, substream); 4599114700bSCezary Rojewski 4609114700bSCezary Rojewski snd_soc_dai_set_dma_data(dai, substream, NULL); 4619114700bSCezary Rojewski snd_hdac_ext_stream_release(data->host_stream, HDAC_EXT_STREAM_TYPE_HOST); 4629114700bSCezary Rojewski kfree(data); 4639114700bSCezary Rojewski } 4649114700bSCezary Rojewski 4659114700bSCezary Rojewski static int avs_dai_fe_hw_params(struct snd_pcm_substream *substream, 4669114700bSCezary Rojewski struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *dai) 4679114700bSCezary Rojewski { 4689114700bSCezary Rojewski struct snd_pcm_hw_params *be_hw_params = NULL; 4699114700bSCezary Rojewski struct snd_soc_pcm_runtime *fe, *be; 4709114700bSCezary Rojewski struct snd_soc_dpcm *dpcm; 4719114700bSCezary Rojewski struct avs_dma_data *data; 4729114700bSCezary Rojewski struct hdac_ext_stream *host_stream; 4739114700bSCezary Rojewski int ret; 4749114700bSCezary Rojewski 4759114700bSCezary Rojewski data = snd_soc_dai_get_dma_data(dai, substream); 4769114700bSCezary Rojewski if (data->path) 4779114700bSCezary Rojewski return 0; 4789114700bSCezary Rojewski 4799114700bSCezary Rojewski host_stream = data->host_stream; 4809114700bSCezary Rojewski 4819114700bSCezary Rojewski hdac_stream(host_stream)->bufsize = 0; 4829114700bSCezary Rojewski hdac_stream(host_stream)->period_bytes = 0; 4839114700bSCezary Rojewski hdac_stream(host_stream)->format_val = 0; 4849114700bSCezary Rojewski 4859114700bSCezary Rojewski fe = asoc_substream_to_rtd(substream); 4869114700bSCezary Rojewski for_each_dpcm_be(fe, substream->stream, dpcm) { 4879114700bSCezary Rojewski be = dpcm->be; 4889114700bSCezary Rojewski be_hw_params = &be->dpcm[substream->stream].hw_params; 4899114700bSCezary Rojewski } 4909114700bSCezary Rojewski 4919114700bSCezary Rojewski ret = avs_dai_hw_params(substream, hw_params, be_hw_params, dai, 4929114700bSCezary Rojewski hdac_stream(host_stream)->stream_tag - 1); 4939114700bSCezary Rojewski if (ret) 4949114700bSCezary Rojewski goto create_err; 4959114700bSCezary Rojewski 4969114700bSCezary Rojewski ret = avs_path_bind(data->path); 4979114700bSCezary Rojewski if (ret < 0) { 4989114700bSCezary Rojewski dev_err(dai->dev, "bind FE <-> BE failed: %d\n", ret); 4999114700bSCezary Rojewski goto bind_err; 5009114700bSCezary Rojewski } 5019114700bSCezary Rojewski 5029114700bSCezary Rojewski return 0; 5039114700bSCezary Rojewski 5049114700bSCezary Rojewski bind_err: 5059114700bSCezary Rojewski avs_path_free(data->path); 5069114700bSCezary Rojewski data->path = NULL; 5079114700bSCezary Rojewski create_err: 5089114700bSCezary Rojewski snd_pcm_lib_free_pages(substream); 5099114700bSCezary Rojewski return ret; 5109114700bSCezary Rojewski } 5119114700bSCezary Rojewski 5120abfc84bSCezary Rojewski static int __avs_dai_fe_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) 5139114700bSCezary Rojewski { 5149114700bSCezary Rojewski struct avs_dma_data *data; 5159114700bSCezary Rojewski struct hdac_ext_stream *host_stream; 5169114700bSCezary Rojewski int ret; 5179114700bSCezary Rojewski 5189114700bSCezary Rojewski dev_dbg(dai->dev, "%s fe HW_FREE str %p rtd %p", 5199114700bSCezary Rojewski __func__, substream, substream->runtime); 5209114700bSCezary Rojewski 5219114700bSCezary Rojewski data = snd_soc_dai_get_dma_data(dai, substream); 5229114700bSCezary Rojewski if (!data->path) 5239114700bSCezary Rojewski return 0; 5249114700bSCezary Rojewski 5259114700bSCezary Rojewski host_stream = data->host_stream; 5269114700bSCezary Rojewski 5279114700bSCezary Rojewski ret = avs_path_unbind(data->path); 5289114700bSCezary Rojewski if (ret < 0) 5299114700bSCezary Rojewski dev_err(dai->dev, "unbind FE <-> BE failed: %d\n", ret); 5309114700bSCezary Rojewski 5319114700bSCezary Rojewski avs_path_free(data->path); 5329114700bSCezary Rojewski data->path = NULL; 5339114700bSCezary Rojewski snd_hdac_stream_cleanup(hdac_stream(host_stream)); 5349114700bSCezary Rojewski hdac_stream(host_stream)->prepared = false; 5359114700bSCezary Rojewski 5360abfc84bSCezary Rojewski return ret; 5370abfc84bSCezary Rojewski } 5380abfc84bSCezary Rojewski 5390abfc84bSCezary Rojewski static int avs_dai_fe_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) 5400abfc84bSCezary Rojewski { 5410abfc84bSCezary Rojewski int ret; 5420abfc84bSCezary Rojewski 5430abfc84bSCezary Rojewski ret = __avs_dai_fe_hw_free(substream, dai); 5440abfc84bSCezary Rojewski snd_pcm_lib_free_pages(substream); 5459114700bSCezary Rojewski 5469114700bSCezary Rojewski return ret; 5479114700bSCezary Rojewski } 5489114700bSCezary Rojewski 5499114700bSCezary Rojewski static int avs_dai_fe_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) 5509114700bSCezary Rojewski { 5519114700bSCezary Rojewski struct snd_pcm_runtime *runtime = substream->runtime; 5529114700bSCezary Rojewski struct avs_dma_data *data; 5539114700bSCezary Rojewski struct avs_dev *adev = to_avs_dev(dai->dev); 5549114700bSCezary Rojewski struct hdac_ext_stream *host_stream; 5559114700bSCezary Rojewski struct hdac_bus *bus; 5569114700bSCezary Rojewski unsigned int format_val; 5579114700bSCezary Rojewski int ret; 5589114700bSCezary Rojewski 5599114700bSCezary Rojewski data = snd_soc_dai_get_dma_data(dai, substream); 5609114700bSCezary Rojewski host_stream = data->host_stream; 5619114700bSCezary Rojewski 5629114700bSCezary Rojewski if (hdac_stream(host_stream)->prepared) 5639114700bSCezary Rojewski return 0; 5649114700bSCezary Rojewski 5659114700bSCezary Rojewski bus = hdac_stream(host_stream)->bus; 5669114700bSCezary Rojewski snd_hdac_ext_stream_decouple(bus, data->host_stream, true); 5679114700bSCezary Rojewski snd_hdac_stream_reset(hdac_stream(host_stream)); 5689114700bSCezary Rojewski 5699114700bSCezary Rojewski format_val = snd_hdac_calc_stream_format(runtime->rate, runtime->channels, runtime->format, 5709114700bSCezary Rojewski runtime->sample_bits, 0); 5719114700bSCezary Rojewski 5729114700bSCezary Rojewski ret = snd_hdac_stream_set_params(hdac_stream(host_stream), format_val); 5739114700bSCezary Rojewski if (ret < 0) 5749114700bSCezary Rojewski return ret; 5759114700bSCezary Rojewski 5769114700bSCezary Rojewski ret = snd_hdac_stream_setup(hdac_stream(host_stream)); 5779114700bSCezary Rojewski if (ret < 0) 5789114700bSCezary Rojewski return ret; 5799114700bSCezary Rojewski 5809114700bSCezary Rojewski ret = avs_dai_prepare(adev, substream, dai); 5819114700bSCezary Rojewski if (ret) 5829114700bSCezary Rojewski return ret; 5839114700bSCezary Rojewski 5849114700bSCezary Rojewski hdac_stream(host_stream)->prepared = true; 5859114700bSCezary Rojewski return 0; 5869114700bSCezary Rojewski } 5879114700bSCezary Rojewski 5889114700bSCezary Rojewski static int avs_dai_fe_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) 5899114700bSCezary Rojewski { 5909114700bSCezary Rojewski struct avs_dma_data *data; 5919114700bSCezary Rojewski struct hdac_ext_stream *host_stream; 5929114700bSCezary Rojewski struct hdac_bus *bus; 5939114700bSCezary Rojewski unsigned long flags; 5949114700bSCezary Rojewski int ret = 0; 5959114700bSCezary Rojewski 5969114700bSCezary Rojewski data = snd_soc_dai_get_dma_data(dai, substream); 5979114700bSCezary Rojewski host_stream = data->host_stream; 5989114700bSCezary Rojewski bus = hdac_stream(host_stream)->bus; 5999114700bSCezary Rojewski 6009114700bSCezary Rojewski switch (cmd) { 6019114700bSCezary Rojewski case SNDRV_PCM_TRIGGER_START: 6029114700bSCezary Rojewski case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 6039114700bSCezary Rojewski spin_lock_irqsave(&bus->reg_lock, flags); 6049114700bSCezary Rojewski snd_hdac_stream_start(hdac_stream(host_stream), true); 6059114700bSCezary Rojewski spin_unlock_irqrestore(&bus->reg_lock, flags); 6069114700bSCezary Rojewski 6079114700bSCezary Rojewski ret = avs_path_run(data->path, AVS_TPLG_TRIGGER_AUTO); 6089114700bSCezary Rojewski if (ret < 0) 6099114700bSCezary Rojewski dev_err(dai->dev, "run FE path failed: %d\n", ret); 6109114700bSCezary Rojewski break; 6119114700bSCezary Rojewski 6129114700bSCezary Rojewski case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 6139114700bSCezary Rojewski case SNDRV_PCM_TRIGGER_STOP: 6149114700bSCezary Rojewski ret = avs_path_pause(data->path); 6159114700bSCezary Rojewski if (ret < 0) 6169114700bSCezary Rojewski dev_err(dai->dev, "pause FE path failed: %d\n", ret); 6179114700bSCezary Rojewski 6189114700bSCezary Rojewski spin_lock_irqsave(&bus->reg_lock, flags); 6199114700bSCezary Rojewski snd_hdac_stream_stop(hdac_stream(host_stream)); 6209114700bSCezary Rojewski spin_unlock_irqrestore(&bus->reg_lock, flags); 6219114700bSCezary Rojewski 6229114700bSCezary Rojewski if (cmd == SNDRV_PCM_TRIGGER_STOP) { 6239114700bSCezary Rojewski ret = avs_path_reset(data->path); 6249114700bSCezary Rojewski if (ret < 0) 6259114700bSCezary Rojewski dev_err(dai->dev, "reset FE path failed: %d\n", ret); 6269114700bSCezary Rojewski } 6279114700bSCezary Rojewski break; 6289114700bSCezary Rojewski 6299114700bSCezary Rojewski default: 6309114700bSCezary Rojewski ret = -EINVAL; 6319114700bSCezary Rojewski break; 6329114700bSCezary Rojewski } 6339114700bSCezary Rojewski 6349114700bSCezary Rojewski return ret; 6359114700bSCezary Rojewski } 6369114700bSCezary Rojewski 6379114700bSCezary Rojewski const struct snd_soc_dai_ops avs_dai_fe_ops = { 6389114700bSCezary Rojewski .startup = avs_dai_fe_startup, 6399114700bSCezary Rojewski .shutdown = avs_dai_fe_shutdown, 6409114700bSCezary Rojewski .hw_params = avs_dai_fe_hw_params, 6419114700bSCezary Rojewski .hw_free = avs_dai_fe_hw_free, 6429114700bSCezary Rojewski .prepare = avs_dai_fe_prepare, 6439114700bSCezary Rojewski .trigger = avs_dai_fe_trigger, 6449114700bSCezary Rojewski }; 6459114700bSCezary Rojewski 646f1b3b320SCezary Rojewski static ssize_t topology_name_read(struct file *file, char __user *user_buf, size_t count, 647f1b3b320SCezary Rojewski loff_t *ppos) 648f1b3b320SCezary Rojewski { 649f1b3b320SCezary Rojewski struct snd_soc_component *component = file->private_data; 650f1b3b320SCezary Rojewski struct snd_soc_card *card = component->card; 651f1b3b320SCezary Rojewski struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev); 652f1b3b320SCezary Rojewski char buf[64]; 653f1b3b320SCezary Rojewski size_t len; 654f1b3b320SCezary Rojewski 655ca3b7b9dSTakashi Iwai len = scnprintf(buf, sizeof(buf), "%s/%s\n", component->driver->topology_name_prefix, 656f1b3b320SCezary Rojewski mach->tplg_filename); 657f1b3b320SCezary Rojewski 658f1b3b320SCezary Rojewski return simple_read_from_buffer(user_buf, count, ppos, buf, len); 659f1b3b320SCezary Rojewski } 660f1b3b320SCezary Rojewski 661f1b3b320SCezary Rojewski static const struct file_operations topology_name_fops = { 662f1b3b320SCezary Rojewski .open = simple_open, 663f1b3b320SCezary Rojewski .read = topology_name_read, 664f1b3b320SCezary Rojewski .llseek = default_llseek, 665f1b3b320SCezary Rojewski }; 666f1b3b320SCezary Rojewski 667f1b3b320SCezary Rojewski static int avs_component_load_libraries(struct avs_soc_component *acomp) 668f1b3b320SCezary Rojewski { 669f1b3b320SCezary Rojewski struct avs_tplg *tplg = acomp->tplg; 670f1b3b320SCezary Rojewski struct avs_dev *adev = to_avs_dev(acomp->base.dev); 671f1b3b320SCezary Rojewski int ret; 672f1b3b320SCezary Rojewski 673f1b3b320SCezary Rojewski if (!tplg->num_libs) 674f1b3b320SCezary Rojewski return 0; 675f1b3b320SCezary Rojewski 676f1b3b320SCezary Rojewski /* Parent device may be asleep and library loading involves IPCs. */ 677f1b3b320SCezary Rojewski ret = pm_runtime_resume_and_get(adev->dev); 678f1b3b320SCezary Rojewski if (ret < 0) 679f1b3b320SCezary Rojewski return ret; 680f1b3b320SCezary Rojewski 681f1b3b320SCezary Rojewski avs_hda_clock_gating_enable(adev, false); 682f1b3b320SCezary Rojewski avs_hda_l1sen_enable(adev, false); 683f1b3b320SCezary Rojewski 684f1b3b320SCezary Rojewski ret = avs_dsp_load_libraries(adev, tplg->libs, tplg->num_libs); 685f1b3b320SCezary Rojewski 686f1b3b320SCezary Rojewski avs_hda_l1sen_enable(adev, true); 687f1b3b320SCezary Rojewski avs_hda_clock_gating_enable(adev, true); 688f1b3b320SCezary Rojewski 689f1b3b320SCezary Rojewski if (!ret) 690f1b3b320SCezary Rojewski ret = avs_module_info_init(adev, false); 691f1b3b320SCezary Rojewski 692f1b3b320SCezary Rojewski pm_runtime_mark_last_busy(adev->dev); 693f1b3b320SCezary Rojewski pm_runtime_put_autosuspend(adev->dev); 694f1b3b320SCezary Rojewski 695f1b3b320SCezary Rojewski return ret; 696f1b3b320SCezary Rojewski } 697f1b3b320SCezary Rojewski 698f1b3b320SCezary Rojewski static int avs_component_probe(struct snd_soc_component *component) 699f1b3b320SCezary Rojewski { 700f1b3b320SCezary Rojewski struct snd_soc_card *card = component->card; 701f1b3b320SCezary Rojewski struct snd_soc_acpi_mach *mach; 702f1b3b320SCezary Rojewski struct avs_soc_component *acomp; 703f1b3b320SCezary Rojewski struct avs_dev *adev; 704f1b3b320SCezary Rojewski char *filename; 705f1b3b320SCezary Rojewski int ret; 706f1b3b320SCezary Rojewski 707f1b3b320SCezary Rojewski dev_dbg(card->dev, "probing %s card %s\n", component->name, card->name); 708f1b3b320SCezary Rojewski mach = dev_get_platdata(card->dev); 709f1b3b320SCezary Rojewski acomp = to_avs_soc_component(component); 710f1b3b320SCezary Rojewski adev = to_avs_dev(component->dev); 711f1b3b320SCezary Rojewski 712f1b3b320SCezary Rojewski acomp->tplg = avs_tplg_new(component); 713f1b3b320SCezary Rojewski if (!acomp->tplg) 714f1b3b320SCezary Rojewski return -ENOMEM; 715f1b3b320SCezary Rojewski 716f1b3b320SCezary Rojewski if (!mach->tplg_filename) 717f1b3b320SCezary Rojewski goto finalize; 718f1b3b320SCezary Rojewski 719f1b3b320SCezary Rojewski /* Load specified topology and create debugfs for it. */ 720f1b3b320SCezary Rojewski filename = kasprintf(GFP_KERNEL, "%s/%s", component->driver->topology_name_prefix, 721f1b3b320SCezary Rojewski mach->tplg_filename); 722f1b3b320SCezary Rojewski if (!filename) 723f1b3b320SCezary Rojewski return -ENOMEM; 724f1b3b320SCezary Rojewski 725f1b3b320SCezary Rojewski ret = avs_load_topology(component, filename); 726f1b3b320SCezary Rojewski kfree(filename); 727f1b3b320SCezary Rojewski if (ret < 0) 728f1b3b320SCezary Rojewski return ret; 729f1b3b320SCezary Rojewski 730f1b3b320SCezary Rojewski ret = avs_component_load_libraries(acomp); 731f1b3b320SCezary Rojewski if (ret < 0) { 732f1b3b320SCezary Rojewski dev_err(card->dev, "libraries loading failed: %d\n", ret); 733f1b3b320SCezary Rojewski goto err_load_libs; 734f1b3b320SCezary Rojewski } 735f1b3b320SCezary Rojewski 736f1b3b320SCezary Rojewski finalize: 737f1b3b320SCezary Rojewski debugfs_create_file("topology_name", 0444, component->debugfs_root, component, 738f1b3b320SCezary Rojewski &topology_name_fops); 739f1b3b320SCezary Rojewski 740f1b3b320SCezary Rojewski mutex_lock(&adev->comp_list_mutex); 741f1b3b320SCezary Rojewski list_add_tail(&acomp->node, &adev->comp_list); 742f1b3b320SCezary Rojewski mutex_unlock(&adev->comp_list_mutex); 743f1b3b320SCezary Rojewski 744f1b3b320SCezary Rojewski return 0; 745f1b3b320SCezary Rojewski 746f1b3b320SCezary Rojewski err_load_libs: 747f1b3b320SCezary Rojewski avs_remove_topology(component); 748f1b3b320SCezary Rojewski return ret; 749f1b3b320SCezary Rojewski } 750f1b3b320SCezary Rojewski 751f1b3b320SCezary Rojewski static void avs_component_remove(struct snd_soc_component *component) 752f1b3b320SCezary Rojewski { 753f1b3b320SCezary Rojewski struct avs_soc_component *acomp = to_avs_soc_component(component); 754f1b3b320SCezary Rojewski struct snd_soc_acpi_mach *mach; 755f1b3b320SCezary Rojewski struct avs_dev *adev = to_avs_dev(component->dev); 756f1b3b320SCezary Rojewski int ret; 757f1b3b320SCezary Rojewski 758f1b3b320SCezary Rojewski mach = dev_get_platdata(component->card->dev); 759f1b3b320SCezary Rojewski 760f1b3b320SCezary Rojewski mutex_lock(&adev->comp_list_mutex); 761f1b3b320SCezary Rojewski list_del(&acomp->node); 762f1b3b320SCezary Rojewski mutex_unlock(&adev->comp_list_mutex); 763f1b3b320SCezary Rojewski 764f1b3b320SCezary Rojewski if (mach->tplg_filename) { 765f1b3b320SCezary Rojewski ret = avs_remove_topology(component); 766f1b3b320SCezary Rojewski if (ret < 0) 767f1b3b320SCezary Rojewski dev_err(component->dev, "unload topology failed: %d\n", ret); 768f1b3b320SCezary Rojewski } 769f1b3b320SCezary Rojewski } 770f1b3b320SCezary Rojewski 771*2b9a50eaSCezary Rojewski static int avs_dai_resume_hw_params(struct snd_soc_dai *dai, struct avs_dma_data *data) 772*2b9a50eaSCezary Rojewski { 773*2b9a50eaSCezary Rojewski struct snd_pcm_substream *substream; 774*2b9a50eaSCezary Rojewski struct snd_soc_pcm_runtime *rtd; 775*2b9a50eaSCezary Rojewski int ret; 776*2b9a50eaSCezary Rojewski 777*2b9a50eaSCezary Rojewski substream = data->substream; 778*2b9a50eaSCezary Rojewski rtd = snd_pcm_substream_chip(substream); 779*2b9a50eaSCezary Rojewski 780*2b9a50eaSCezary Rojewski ret = dai->driver->ops->hw_params(substream, &rtd->dpcm[substream->stream].hw_params, dai); 781*2b9a50eaSCezary Rojewski if (ret) 782*2b9a50eaSCezary Rojewski dev_err(dai->dev, "hw_params on resume failed: %d\n", ret); 783*2b9a50eaSCezary Rojewski 784*2b9a50eaSCezary Rojewski return ret; 785*2b9a50eaSCezary Rojewski } 786*2b9a50eaSCezary Rojewski 787*2b9a50eaSCezary Rojewski static int avs_dai_resume_fe_prepare(struct snd_soc_dai *dai, struct avs_dma_data *data) 788*2b9a50eaSCezary Rojewski { 789*2b9a50eaSCezary Rojewski struct hdac_ext_stream *host_stream; 790*2b9a50eaSCezary Rojewski struct hdac_stream *hstream; 791*2b9a50eaSCezary Rojewski struct hdac_bus *bus; 792*2b9a50eaSCezary Rojewski int ret; 793*2b9a50eaSCezary Rojewski 794*2b9a50eaSCezary Rojewski host_stream = data->host_stream; 795*2b9a50eaSCezary Rojewski hstream = hdac_stream(host_stream); 796*2b9a50eaSCezary Rojewski bus = hdac_stream(host_stream)->bus; 797*2b9a50eaSCezary Rojewski 798*2b9a50eaSCezary Rojewski /* Set DRSM before programming stream and position registers. */ 799*2b9a50eaSCezary Rojewski snd_hdac_stream_drsm_enable(bus, true, hstream->index); 800*2b9a50eaSCezary Rojewski 801*2b9a50eaSCezary Rojewski ret = dai->driver->ops->prepare(data->substream, dai); 802*2b9a50eaSCezary Rojewski if (ret) { 803*2b9a50eaSCezary Rojewski dev_err(dai->dev, "prepare FE on resume failed: %d\n", ret); 804*2b9a50eaSCezary Rojewski return ret; 805*2b9a50eaSCezary Rojewski } 806*2b9a50eaSCezary Rojewski 807*2b9a50eaSCezary Rojewski writel(host_stream->pphcllpl, host_stream->pphc_addr + AZX_REG_PPHCLLPL); 808*2b9a50eaSCezary Rojewski writel(host_stream->pphcllpu, host_stream->pphc_addr + AZX_REG_PPHCLLPU); 809*2b9a50eaSCezary Rojewski writel(host_stream->pphcldpl, host_stream->pphc_addr + AZX_REG_PPHCLDPL); 810*2b9a50eaSCezary Rojewski writel(host_stream->pphcldpu, host_stream->pphc_addr + AZX_REG_PPHCLDPU); 811*2b9a50eaSCezary Rojewski 812*2b9a50eaSCezary Rojewski /* As per HW spec recommendation, program LPIB and DPIB to the same value. */ 813*2b9a50eaSCezary Rojewski snd_hdac_stream_set_lpib(hstream, hstream->lpib); 814*2b9a50eaSCezary Rojewski snd_hdac_stream_set_dpibr(bus, hstream, hstream->lpib); 815*2b9a50eaSCezary Rojewski 816*2b9a50eaSCezary Rojewski return 0; 817*2b9a50eaSCezary Rojewski } 818*2b9a50eaSCezary Rojewski 819*2b9a50eaSCezary Rojewski static int avs_dai_resume_be_prepare(struct snd_soc_dai *dai, struct avs_dma_data *data) 820*2b9a50eaSCezary Rojewski { 821*2b9a50eaSCezary Rojewski int ret; 822*2b9a50eaSCezary Rojewski 823*2b9a50eaSCezary Rojewski ret = dai->driver->ops->prepare(data->substream, dai); 824*2b9a50eaSCezary Rojewski if (ret) 825*2b9a50eaSCezary Rojewski dev_err(dai->dev, "prepare BE on resume failed: %d\n", ret); 826*2b9a50eaSCezary Rojewski 827*2b9a50eaSCezary Rojewski return ret; 828*2b9a50eaSCezary Rojewski } 829*2b9a50eaSCezary Rojewski 830*2b9a50eaSCezary Rojewski static int avs_dai_suspend_fe_hw_free(struct snd_soc_dai *dai, struct avs_dma_data *data) 831*2b9a50eaSCezary Rojewski { 832*2b9a50eaSCezary Rojewski struct hdac_ext_stream *host_stream; 833*2b9a50eaSCezary Rojewski int ret; 834*2b9a50eaSCezary Rojewski 835*2b9a50eaSCezary Rojewski host_stream = data->host_stream; 836*2b9a50eaSCezary Rojewski 837*2b9a50eaSCezary Rojewski /* Store position addresses so we can resume from them later on. */ 838*2b9a50eaSCezary Rojewski hdac_stream(host_stream)->lpib = snd_hdac_stream_get_pos_lpib(hdac_stream(host_stream)); 839*2b9a50eaSCezary Rojewski host_stream->pphcllpl = readl(host_stream->pphc_addr + AZX_REG_PPHCLLPL); 840*2b9a50eaSCezary Rojewski host_stream->pphcllpu = readl(host_stream->pphc_addr + AZX_REG_PPHCLLPU); 841*2b9a50eaSCezary Rojewski host_stream->pphcldpl = readl(host_stream->pphc_addr + AZX_REG_PPHCLDPL); 842*2b9a50eaSCezary Rojewski host_stream->pphcldpu = readl(host_stream->pphc_addr + AZX_REG_PPHCLDPU); 843*2b9a50eaSCezary Rojewski 844*2b9a50eaSCezary Rojewski ret = __avs_dai_fe_hw_free(data->substream, dai); 845*2b9a50eaSCezary Rojewski if (ret < 0) 846*2b9a50eaSCezary Rojewski dev_err(dai->dev, "hw_free FE on suspend failed: %d\n", ret); 847*2b9a50eaSCezary Rojewski 848*2b9a50eaSCezary Rojewski return ret; 849*2b9a50eaSCezary Rojewski } 850*2b9a50eaSCezary Rojewski 851*2b9a50eaSCezary Rojewski static int avs_dai_suspend_be_hw_free(struct snd_soc_dai *dai, struct avs_dma_data *data) 852*2b9a50eaSCezary Rojewski { 853*2b9a50eaSCezary Rojewski int ret; 854*2b9a50eaSCezary Rojewski 855*2b9a50eaSCezary Rojewski ret = dai->driver->ops->hw_free(data->substream, dai); 856*2b9a50eaSCezary Rojewski if (ret < 0) 857*2b9a50eaSCezary Rojewski dev_err(dai->dev, "hw_free BE on suspend failed: %d\n", ret); 858*2b9a50eaSCezary Rojewski 859*2b9a50eaSCezary Rojewski return ret; 860*2b9a50eaSCezary Rojewski } 861*2b9a50eaSCezary Rojewski 862*2b9a50eaSCezary Rojewski static int avs_component_pm_op(struct snd_soc_component *component, bool be, 863*2b9a50eaSCezary Rojewski int (*op)(struct snd_soc_dai *, struct avs_dma_data *)) 864*2b9a50eaSCezary Rojewski { 865*2b9a50eaSCezary Rojewski struct snd_soc_pcm_runtime *rtd; 866*2b9a50eaSCezary Rojewski struct avs_dma_data *data; 867*2b9a50eaSCezary Rojewski struct snd_soc_dai *dai; 868*2b9a50eaSCezary Rojewski int ret; 869*2b9a50eaSCezary Rojewski 870*2b9a50eaSCezary Rojewski for_each_component_dais(component, dai) { 871*2b9a50eaSCezary Rojewski data = dai->playback_dma_data; 872*2b9a50eaSCezary Rojewski if (data) { 873*2b9a50eaSCezary Rojewski rtd = snd_pcm_substream_chip(data->substream); 874*2b9a50eaSCezary Rojewski if (rtd->dai_link->no_pcm == be && !rtd->dai_link->ignore_suspend) { 875*2b9a50eaSCezary Rojewski ret = op(dai, data); 876*2b9a50eaSCezary Rojewski if (ret < 0) 877*2b9a50eaSCezary Rojewski return ret; 878*2b9a50eaSCezary Rojewski } 879*2b9a50eaSCezary Rojewski } 880*2b9a50eaSCezary Rojewski 881*2b9a50eaSCezary Rojewski data = dai->capture_dma_data; 882*2b9a50eaSCezary Rojewski if (data) { 883*2b9a50eaSCezary Rojewski rtd = snd_pcm_substream_chip(data->substream); 884*2b9a50eaSCezary Rojewski if (rtd->dai_link->no_pcm == be && !rtd->dai_link->ignore_suspend) { 885*2b9a50eaSCezary Rojewski ret = op(dai, data); 886*2b9a50eaSCezary Rojewski if (ret < 0) 887*2b9a50eaSCezary Rojewski return ret; 888*2b9a50eaSCezary Rojewski } 889*2b9a50eaSCezary Rojewski } 890*2b9a50eaSCezary Rojewski } 891*2b9a50eaSCezary Rojewski 892*2b9a50eaSCezary Rojewski return 0; 893*2b9a50eaSCezary Rojewski } 894*2b9a50eaSCezary Rojewski 895*2b9a50eaSCezary Rojewski static int avs_component_resume_hw_params(struct snd_soc_component *component, bool be) 896*2b9a50eaSCezary Rojewski { 897*2b9a50eaSCezary Rojewski return avs_component_pm_op(component, be, &avs_dai_resume_hw_params); 898*2b9a50eaSCezary Rojewski } 899*2b9a50eaSCezary Rojewski 900*2b9a50eaSCezary Rojewski static int avs_component_resume_prepare(struct snd_soc_component *component, bool be) 901*2b9a50eaSCezary Rojewski { 902*2b9a50eaSCezary Rojewski int (*prepare_cb)(struct snd_soc_dai *dai, struct avs_dma_data *data); 903*2b9a50eaSCezary Rojewski 904*2b9a50eaSCezary Rojewski if (be) 905*2b9a50eaSCezary Rojewski prepare_cb = &avs_dai_resume_be_prepare; 906*2b9a50eaSCezary Rojewski else 907*2b9a50eaSCezary Rojewski prepare_cb = &avs_dai_resume_fe_prepare; 908*2b9a50eaSCezary Rojewski 909*2b9a50eaSCezary Rojewski return avs_component_pm_op(component, be, prepare_cb); 910*2b9a50eaSCezary Rojewski } 911*2b9a50eaSCezary Rojewski 912*2b9a50eaSCezary Rojewski static int avs_component_suspend_hw_free(struct snd_soc_component *component, bool be) 913*2b9a50eaSCezary Rojewski { 914*2b9a50eaSCezary Rojewski int (*hw_free_cb)(struct snd_soc_dai *dai, struct avs_dma_data *data); 915*2b9a50eaSCezary Rojewski 916*2b9a50eaSCezary Rojewski if (be) 917*2b9a50eaSCezary Rojewski hw_free_cb = &avs_dai_suspend_be_hw_free; 918*2b9a50eaSCezary Rojewski else 919*2b9a50eaSCezary Rojewski hw_free_cb = &avs_dai_suspend_fe_hw_free; 920*2b9a50eaSCezary Rojewski 921*2b9a50eaSCezary Rojewski return avs_component_pm_op(component, be, hw_free_cb); 922*2b9a50eaSCezary Rojewski } 923*2b9a50eaSCezary Rojewski 924*2b9a50eaSCezary Rojewski static int avs_component_suspend(struct snd_soc_component *component) 925*2b9a50eaSCezary Rojewski { 926*2b9a50eaSCezary Rojewski int ret; 927*2b9a50eaSCezary Rojewski 928*2b9a50eaSCezary Rojewski /* 929*2b9a50eaSCezary Rojewski * When freeing paths, FEs need to be first as they perform 930*2b9a50eaSCezary Rojewski * path unbinding. 931*2b9a50eaSCezary Rojewski */ 932*2b9a50eaSCezary Rojewski ret = avs_component_suspend_hw_free(component, false); 933*2b9a50eaSCezary Rojewski if (ret) 934*2b9a50eaSCezary Rojewski return ret; 935*2b9a50eaSCezary Rojewski 936*2b9a50eaSCezary Rojewski return avs_component_suspend_hw_free(component, true); 937*2b9a50eaSCezary Rojewski } 938*2b9a50eaSCezary Rojewski 939*2b9a50eaSCezary Rojewski static int avs_component_resume(struct snd_soc_component *component) 940*2b9a50eaSCezary Rojewski { 941*2b9a50eaSCezary Rojewski int ret; 942*2b9a50eaSCezary Rojewski 943*2b9a50eaSCezary Rojewski /* 944*2b9a50eaSCezary Rojewski * When creating paths, FEs need to be last as they perform 945*2b9a50eaSCezary Rojewski * path binding. 946*2b9a50eaSCezary Rojewski */ 947*2b9a50eaSCezary Rojewski ret = avs_component_resume_hw_params(component, true); 948*2b9a50eaSCezary Rojewski if (ret) 949*2b9a50eaSCezary Rojewski return ret; 950*2b9a50eaSCezary Rojewski 951*2b9a50eaSCezary Rojewski ret = avs_component_resume_hw_params(component, false); 952*2b9a50eaSCezary Rojewski if (ret) 953*2b9a50eaSCezary Rojewski return ret; 954*2b9a50eaSCezary Rojewski 955*2b9a50eaSCezary Rojewski /* It is expected that the LINK stream is prepared first. */ 956*2b9a50eaSCezary Rojewski ret = avs_component_resume_prepare(component, true); 957*2b9a50eaSCezary Rojewski if (ret) 958*2b9a50eaSCezary Rojewski return ret; 959*2b9a50eaSCezary Rojewski 960*2b9a50eaSCezary Rojewski return avs_component_resume_prepare(component, false); 961*2b9a50eaSCezary Rojewski } 962*2b9a50eaSCezary Rojewski 963f1b3b320SCezary Rojewski static int avs_component_open(struct snd_soc_component *component, 964f1b3b320SCezary Rojewski struct snd_pcm_substream *substream) 965f1b3b320SCezary Rojewski { 966f1b3b320SCezary Rojewski struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); 967f1b3b320SCezary Rojewski struct snd_pcm_hardware hwparams; 968f1b3b320SCezary Rojewski 969f1b3b320SCezary Rojewski /* only FE DAI links are handled here */ 970f1b3b320SCezary Rojewski if (rtd->dai_link->no_pcm) 971f1b3b320SCezary Rojewski return 0; 972f1b3b320SCezary Rojewski 973f1b3b320SCezary Rojewski hwparams.info = SNDRV_PCM_INFO_MMAP | 974f1b3b320SCezary Rojewski SNDRV_PCM_INFO_MMAP_VALID | 975f1b3b320SCezary Rojewski SNDRV_PCM_INFO_INTERLEAVED | 976f1b3b320SCezary Rojewski SNDRV_PCM_INFO_PAUSE | 977f1b3b320SCezary Rojewski SNDRV_PCM_INFO_NO_PERIOD_WAKEUP; 978f1b3b320SCezary Rojewski 979f1b3b320SCezary Rojewski hwparams.formats = SNDRV_PCM_FMTBIT_S16_LE | 980f1b3b320SCezary Rojewski SNDRV_PCM_FMTBIT_S24_LE | 981f1b3b320SCezary Rojewski SNDRV_PCM_FMTBIT_S32_LE; 982f1b3b320SCezary Rojewski hwparams.period_bytes_min = 128; 983f1b3b320SCezary Rojewski hwparams.period_bytes_max = AZX_MAX_BUF_SIZE / 2; 984f1b3b320SCezary Rojewski hwparams.periods_min = 2; 985f1b3b320SCezary Rojewski hwparams.periods_max = AZX_MAX_FRAG; 986f1b3b320SCezary Rojewski hwparams.buffer_bytes_max = AZX_MAX_BUF_SIZE; 987f1b3b320SCezary Rojewski hwparams.fifo_size = 0; 988f1b3b320SCezary Rojewski 989f1b3b320SCezary Rojewski return snd_soc_set_runtime_hwparams(substream, &hwparams); 990f1b3b320SCezary Rojewski } 991f1b3b320SCezary Rojewski 992f1b3b320SCezary Rojewski static unsigned int avs_hda_stream_dpib_read(struct hdac_ext_stream *stream) 993f1b3b320SCezary Rojewski { 994f1b3b320SCezary Rojewski return readl(hdac_stream(stream)->bus->remap_addr + AZX_REG_VS_SDXDPIB_XBASE + 995f1b3b320SCezary Rojewski (AZX_REG_VS_SDXDPIB_XINTERVAL * hdac_stream(stream)->index)); 996f1b3b320SCezary Rojewski } 997f1b3b320SCezary Rojewski 998f1b3b320SCezary Rojewski static snd_pcm_uframes_t 999f1b3b320SCezary Rojewski avs_component_pointer(struct snd_soc_component *component, struct snd_pcm_substream *substream) 1000f1b3b320SCezary Rojewski { 1001f1b3b320SCezary Rojewski struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); 1002f1b3b320SCezary Rojewski struct avs_dma_data *data; 1003f1b3b320SCezary Rojewski struct hdac_ext_stream *host_stream; 1004f1b3b320SCezary Rojewski unsigned int pos; 1005f1b3b320SCezary Rojewski 1006f1b3b320SCezary Rojewski data = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream); 1007f1b3b320SCezary Rojewski if (!data->host_stream) 1008f1b3b320SCezary Rojewski return 0; 1009f1b3b320SCezary Rojewski 1010f1b3b320SCezary Rojewski host_stream = data->host_stream; 1011f1b3b320SCezary Rojewski pos = avs_hda_stream_dpib_read(host_stream); 1012f1b3b320SCezary Rojewski 1013f1b3b320SCezary Rojewski if (pos >= hdac_stream(host_stream)->bufsize) 1014f1b3b320SCezary Rojewski pos = 0; 1015f1b3b320SCezary Rojewski 1016f1b3b320SCezary Rojewski return bytes_to_frames(substream->runtime, pos); 1017f1b3b320SCezary Rojewski } 1018f1b3b320SCezary Rojewski 1019f1b3b320SCezary Rojewski static int avs_component_mmap(struct snd_soc_component *component, 1020f1b3b320SCezary Rojewski struct snd_pcm_substream *substream, 1021f1b3b320SCezary Rojewski struct vm_area_struct *vma) 1022f1b3b320SCezary Rojewski { 1023f1b3b320SCezary Rojewski return snd_pcm_lib_default_mmap(substream, vma); 1024f1b3b320SCezary Rojewski } 1025f1b3b320SCezary Rojewski 1026f1b3b320SCezary Rojewski #define MAX_PREALLOC_SIZE (32 * 1024 * 1024) 1027f1b3b320SCezary Rojewski 1028f1b3b320SCezary Rojewski static int avs_component_construct(struct snd_soc_component *component, 1029f1b3b320SCezary Rojewski struct snd_soc_pcm_runtime *rtd) 1030f1b3b320SCezary Rojewski { 1031f1b3b320SCezary Rojewski struct snd_soc_dai *dai = asoc_rtd_to_cpu(rtd, 0); 1032f1b3b320SCezary Rojewski struct snd_pcm *pcm = rtd->pcm; 1033f1b3b320SCezary Rojewski 1034f1b3b320SCezary Rojewski if (dai->driver->playback.channels_min) 1035f1b3b320SCezary Rojewski snd_pcm_set_managed_buffer(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream, 1036f1b3b320SCezary Rojewski SNDRV_DMA_TYPE_DEV_SG, component->dev, 0, 1037f1b3b320SCezary Rojewski MAX_PREALLOC_SIZE); 1038f1b3b320SCezary Rojewski 1039f1b3b320SCezary Rojewski if (dai->driver->capture.channels_min) 1040f1b3b320SCezary Rojewski snd_pcm_set_managed_buffer(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream, 1041f1b3b320SCezary Rojewski SNDRV_DMA_TYPE_DEV_SG, component->dev, 0, 1042f1b3b320SCezary Rojewski MAX_PREALLOC_SIZE); 1043f1b3b320SCezary Rojewski 1044f1b3b320SCezary Rojewski return 0; 1045f1b3b320SCezary Rojewski } 1046f1b3b320SCezary Rojewski 1047f1b3b320SCezary Rojewski static const struct snd_soc_component_driver avs_component_driver = { 1048f1b3b320SCezary Rojewski .name = "avs-pcm", 1049f1b3b320SCezary Rojewski .probe = avs_component_probe, 1050f1b3b320SCezary Rojewski .remove = avs_component_remove, 1051*2b9a50eaSCezary Rojewski .suspend = avs_component_suspend, 1052*2b9a50eaSCezary Rojewski .resume = avs_component_resume, 1053f1b3b320SCezary Rojewski .open = avs_component_open, 1054f1b3b320SCezary Rojewski .pointer = avs_component_pointer, 1055f1b3b320SCezary Rojewski .mmap = avs_component_mmap, 1056f1b3b320SCezary Rojewski .pcm_construct = avs_component_construct, 1057f1b3b320SCezary Rojewski .module_get_upon_open = 1, /* increment refcount when a pcm is opened */ 1058f1b3b320SCezary Rojewski .topology_name_prefix = "intel/avs", 1059f1b3b320SCezary Rojewski }; 1060f1b3b320SCezary Rojewski 1061f1b3b320SCezary Rojewski static int avs_soc_component_register(struct device *dev, const char *name, 1062f1b3b320SCezary Rojewski const struct snd_soc_component_driver *drv, 1063f1b3b320SCezary Rojewski struct snd_soc_dai_driver *cpu_dais, int num_cpu_dais) 1064f1b3b320SCezary Rojewski { 1065f1b3b320SCezary Rojewski struct avs_soc_component *acomp; 1066f1b3b320SCezary Rojewski int ret; 1067f1b3b320SCezary Rojewski 1068f1b3b320SCezary Rojewski acomp = devm_kzalloc(dev, sizeof(*acomp), GFP_KERNEL); 1069f1b3b320SCezary Rojewski if (!acomp) 1070f1b3b320SCezary Rojewski return -ENOMEM; 1071f1b3b320SCezary Rojewski 1072f1b3b320SCezary Rojewski ret = snd_soc_component_initialize(&acomp->base, drv, dev); 1073f1b3b320SCezary Rojewski if (ret < 0) 1074f1b3b320SCezary Rojewski return ret; 1075f1b3b320SCezary Rojewski 1076f1b3b320SCezary Rojewski /* force name change after ASoC is done with its init */ 1077f1b3b320SCezary Rojewski acomp->base.name = name; 1078f1b3b320SCezary Rojewski INIT_LIST_HEAD(&acomp->node); 1079f1b3b320SCezary Rojewski 1080f1b3b320SCezary Rojewski return snd_soc_add_component(&acomp->base, cpu_dais, num_cpu_dais); 1081f1b3b320SCezary Rojewski } 1082b9062f98SCezary Rojewski 1083b9062f98SCezary Rojewski static struct snd_soc_dai_driver dmic_cpu_dais[] = { 1084b9062f98SCezary Rojewski { 1085b9062f98SCezary Rojewski .name = "DMIC Pin", 1086b9062f98SCezary Rojewski .ops = &avs_dai_nonhda_be_ops, 1087b9062f98SCezary Rojewski .capture = { 1088b9062f98SCezary Rojewski .stream_name = "DMIC Rx", 1089b9062f98SCezary Rojewski .channels_min = 1, 1090b9062f98SCezary Rojewski .channels_max = 4, 1091b9062f98SCezary Rojewski .rates = SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_48000, 1092b9062f98SCezary Rojewski .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, 1093b9062f98SCezary Rojewski }, 1094b9062f98SCezary Rojewski }, 1095b9062f98SCezary Rojewski { 1096b9062f98SCezary Rojewski .name = "DMIC WoV Pin", 1097b9062f98SCezary Rojewski .ops = &avs_dai_nonhda_be_ops, 1098b9062f98SCezary Rojewski .capture = { 1099b9062f98SCezary Rojewski .stream_name = "DMIC WoV Rx", 1100b9062f98SCezary Rojewski .channels_min = 1, 1101b9062f98SCezary Rojewski .channels_max = 4, 1102b9062f98SCezary Rojewski .rates = SNDRV_PCM_RATE_16000, 1103b9062f98SCezary Rojewski .formats = SNDRV_PCM_FMTBIT_S16_LE, 1104b9062f98SCezary Rojewski }, 1105b9062f98SCezary Rojewski }, 1106b9062f98SCezary Rojewski }; 1107b9062f98SCezary Rojewski 1108b9062f98SCezary Rojewski int avs_dmic_platform_register(struct avs_dev *adev, const char *name) 1109b9062f98SCezary Rojewski { 1110b9062f98SCezary Rojewski return avs_soc_component_register(adev->dev, name, &avs_component_driver, dmic_cpu_dais, 1111b9062f98SCezary Rojewski ARRAY_SIZE(dmic_cpu_dais)); 1112b9062f98SCezary Rojewski } 1113b9062f98SCezary Rojewski 1114b9062f98SCezary Rojewski static const struct snd_soc_dai_driver i2s_dai_template = { 1115b9062f98SCezary Rojewski .ops = &avs_dai_nonhda_be_ops, 1116b9062f98SCezary Rojewski .playback = { 1117b9062f98SCezary Rojewski .channels_min = 1, 1118b9062f98SCezary Rojewski .channels_max = 8, 1119b9062f98SCezary Rojewski .rates = SNDRV_PCM_RATE_8000_192000 | 1120b9062f98SCezary Rojewski SNDRV_PCM_RATE_KNOT, 1121b9062f98SCezary Rojewski .formats = SNDRV_PCM_FMTBIT_S16_LE | 1122b9062f98SCezary Rojewski SNDRV_PCM_FMTBIT_S24_LE | 1123b9062f98SCezary Rojewski SNDRV_PCM_FMTBIT_S32_LE, 1124b9062f98SCezary Rojewski }, 1125b9062f98SCezary Rojewski .capture = { 1126b9062f98SCezary Rojewski .channels_min = 1, 1127b9062f98SCezary Rojewski .channels_max = 8, 1128b9062f98SCezary Rojewski .rates = SNDRV_PCM_RATE_8000_192000 | 1129b9062f98SCezary Rojewski SNDRV_PCM_RATE_KNOT, 1130b9062f98SCezary Rojewski .formats = SNDRV_PCM_FMTBIT_S16_LE | 1131b9062f98SCezary Rojewski SNDRV_PCM_FMTBIT_S24_LE | 1132b9062f98SCezary Rojewski SNDRV_PCM_FMTBIT_S32_LE, 1133b9062f98SCezary Rojewski }, 1134b9062f98SCezary Rojewski }; 1135b9062f98SCezary Rojewski 1136b9062f98SCezary Rojewski int avs_i2s_platform_register(struct avs_dev *adev, const char *name, unsigned long port_mask, 1137b9062f98SCezary Rojewski unsigned long *tdms) 1138b9062f98SCezary Rojewski { 1139b9062f98SCezary Rojewski struct snd_soc_dai_driver *cpus, *dai; 1140b9062f98SCezary Rojewski size_t ssp_count, cpu_count; 1141b9062f98SCezary Rojewski int i, j; 1142b9062f98SCezary Rojewski 1143b9062f98SCezary Rojewski ssp_count = adev->hw_cfg.i2s_caps.ctrl_count; 1144b9062f98SCezary Rojewski cpu_count = hweight_long(port_mask); 1145b9062f98SCezary Rojewski if (tdms) 1146b9062f98SCezary Rojewski for_each_set_bit(i, &port_mask, ssp_count) 1147b9062f98SCezary Rojewski cpu_count += hweight_long(tdms[i]); 1148b9062f98SCezary Rojewski 1149b9062f98SCezary Rojewski cpus = devm_kzalloc(adev->dev, sizeof(*cpus) * cpu_count, GFP_KERNEL); 1150b9062f98SCezary Rojewski if (!cpus) 1151b9062f98SCezary Rojewski return -ENOMEM; 1152b9062f98SCezary Rojewski 1153b9062f98SCezary Rojewski dai = cpus; 1154b9062f98SCezary Rojewski for_each_set_bit(i, &port_mask, ssp_count) { 1155b9062f98SCezary Rojewski memcpy(dai, &i2s_dai_template, sizeof(*dai)); 1156b9062f98SCezary Rojewski 1157b9062f98SCezary Rojewski dai->name = 1158b9062f98SCezary Rojewski devm_kasprintf(adev->dev, GFP_KERNEL, "SSP%d Pin", i); 1159b9062f98SCezary Rojewski dai->playback.stream_name = 1160b9062f98SCezary Rojewski devm_kasprintf(adev->dev, GFP_KERNEL, "ssp%d Tx", i); 1161b9062f98SCezary Rojewski dai->capture.stream_name = 1162b9062f98SCezary Rojewski devm_kasprintf(adev->dev, GFP_KERNEL, "ssp%d Rx", i); 1163b9062f98SCezary Rojewski 1164b9062f98SCezary Rojewski if (!dai->name || !dai->playback.stream_name || !dai->capture.stream_name) 1165b9062f98SCezary Rojewski return -ENOMEM; 1166b9062f98SCezary Rojewski dai++; 1167b9062f98SCezary Rojewski } 1168b9062f98SCezary Rojewski 1169b9062f98SCezary Rojewski if (!tdms) 1170b9062f98SCezary Rojewski goto plat_register; 1171b9062f98SCezary Rojewski 1172b9062f98SCezary Rojewski for_each_set_bit(i, &port_mask, ssp_count) { 1173b9062f98SCezary Rojewski for_each_set_bit(j, &tdms[i], ssp_count) { 1174b9062f98SCezary Rojewski memcpy(dai, &i2s_dai_template, sizeof(*dai)); 1175b9062f98SCezary Rojewski 1176b9062f98SCezary Rojewski dai->name = 1177b9062f98SCezary Rojewski devm_kasprintf(adev->dev, GFP_KERNEL, "SSP%d:%d Pin", i, j); 1178b9062f98SCezary Rojewski dai->playback.stream_name = 1179b9062f98SCezary Rojewski devm_kasprintf(adev->dev, GFP_KERNEL, "ssp%d:%d Tx", i, j); 1180b9062f98SCezary Rojewski dai->capture.stream_name = 1181b9062f98SCezary Rojewski devm_kasprintf(adev->dev, GFP_KERNEL, "ssp%d:%d Rx", i, j); 1182b9062f98SCezary Rojewski 1183b9062f98SCezary Rojewski if (!dai->name || !dai->playback.stream_name || !dai->capture.stream_name) 1184b9062f98SCezary Rojewski return -ENOMEM; 1185b9062f98SCezary Rojewski dai++; 1186b9062f98SCezary Rojewski } 1187b9062f98SCezary Rojewski } 1188b9062f98SCezary Rojewski 1189b9062f98SCezary Rojewski plat_register: 1190b9062f98SCezary Rojewski return avs_soc_component_register(adev->dev, name, &avs_component_driver, cpus, cpu_count); 1191b9062f98SCezary Rojewski } 1192d070002aSCezary Rojewski 1193d070002aSCezary Rojewski /* HD-Audio CPU DAI template */ 1194d070002aSCezary Rojewski static const struct snd_soc_dai_driver hda_cpu_dai = { 1195d070002aSCezary Rojewski .ops = &avs_dai_hda_be_ops, 1196d070002aSCezary Rojewski .playback = { 1197d070002aSCezary Rojewski .channels_min = 1, 1198d070002aSCezary Rojewski .channels_max = 8, 1199d070002aSCezary Rojewski .rates = SNDRV_PCM_RATE_8000_192000, 1200d070002aSCezary Rojewski .formats = SNDRV_PCM_FMTBIT_S16_LE | 1201d070002aSCezary Rojewski SNDRV_PCM_FMTBIT_S24_LE | 1202d070002aSCezary Rojewski SNDRV_PCM_FMTBIT_S32_LE, 1203d070002aSCezary Rojewski }, 1204d070002aSCezary Rojewski .capture = { 1205d070002aSCezary Rojewski .channels_min = 1, 1206d070002aSCezary Rojewski .channels_max = 8, 1207d070002aSCezary Rojewski .rates = SNDRV_PCM_RATE_8000_192000, 1208d070002aSCezary Rojewski .formats = SNDRV_PCM_FMTBIT_S16_LE | 1209d070002aSCezary Rojewski SNDRV_PCM_FMTBIT_S24_LE | 1210d070002aSCezary Rojewski SNDRV_PCM_FMTBIT_S32_LE, 1211d070002aSCezary Rojewski }, 1212d070002aSCezary Rojewski }; 1213d070002aSCezary Rojewski 1214d070002aSCezary Rojewski static void avs_component_hda_unregister_dais(struct snd_soc_component *component) 1215d070002aSCezary Rojewski { 1216d070002aSCezary Rojewski struct snd_soc_acpi_mach *mach; 1217d070002aSCezary Rojewski struct snd_soc_dai *dai, *save; 1218d070002aSCezary Rojewski struct hda_codec *codec; 1219d070002aSCezary Rojewski char name[32]; 1220d070002aSCezary Rojewski 1221d070002aSCezary Rojewski mach = dev_get_platdata(component->card->dev); 1222d070002aSCezary Rojewski codec = mach->pdata; 1223d070002aSCezary Rojewski sprintf(name, "%s-cpu", dev_name(&codec->core.dev)); 1224d070002aSCezary Rojewski 1225d070002aSCezary Rojewski for_each_component_dais_safe(component, dai, save) { 1226d070002aSCezary Rojewski if (!strstr(dai->driver->name, name)) 1227d070002aSCezary Rojewski continue; 1228d070002aSCezary Rojewski 1229d070002aSCezary Rojewski snd_soc_dapm_free_widget(dai->playback_widget); 1230d070002aSCezary Rojewski snd_soc_dapm_free_widget(dai->capture_widget); 1231d070002aSCezary Rojewski snd_soc_unregister_dai(dai); 1232d070002aSCezary Rojewski } 1233d070002aSCezary Rojewski } 1234d070002aSCezary Rojewski 1235d070002aSCezary Rojewski static int avs_component_hda_probe(struct snd_soc_component *component) 1236d070002aSCezary Rojewski { 1237d070002aSCezary Rojewski struct snd_soc_dapm_context *dapm; 1238d070002aSCezary Rojewski struct snd_soc_dai_driver *dais; 1239d070002aSCezary Rojewski struct snd_soc_acpi_mach *mach; 1240d070002aSCezary Rojewski struct hda_codec *codec; 1241d070002aSCezary Rojewski struct hda_pcm *pcm; 1242d070002aSCezary Rojewski const char *cname; 1243d070002aSCezary Rojewski int pcm_count = 0, ret, i; 1244d070002aSCezary Rojewski 1245d070002aSCezary Rojewski mach = dev_get_platdata(component->card->dev); 1246d070002aSCezary Rojewski if (!mach) 1247d070002aSCezary Rojewski return -EINVAL; 1248d070002aSCezary Rojewski 1249d070002aSCezary Rojewski codec = mach->pdata; 1250d070002aSCezary Rojewski if (list_empty(&codec->pcm_list_head)) 1251d070002aSCezary Rojewski return -EINVAL; 1252d070002aSCezary Rojewski list_for_each_entry(pcm, &codec->pcm_list_head, list) 1253d070002aSCezary Rojewski pcm_count++; 1254d070002aSCezary Rojewski 1255d070002aSCezary Rojewski dais = devm_kcalloc(component->dev, pcm_count, sizeof(*dais), 1256d070002aSCezary Rojewski GFP_KERNEL); 1257d070002aSCezary Rojewski if (!dais) 1258d070002aSCezary Rojewski return -ENOMEM; 1259d070002aSCezary Rojewski 1260d070002aSCezary Rojewski cname = dev_name(&codec->core.dev); 1261d070002aSCezary Rojewski dapm = snd_soc_component_get_dapm(component); 1262d070002aSCezary Rojewski pcm = list_first_entry(&codec->pcm_list_head, struct hda_pcm, list); 1263d070002aSCezary Rojewski 1264d070002aSCezary Rojewski for (i = 0; i < pcm_count; i++, pcm = list_next_entry(pcm, list)) { 1265d070002aSCezary Rojewski struct snd_soc_dai *dai; 1266d070002aSCezary Rojewski 1267d070002aSCezary Rojewski memcpy(&dais[i], &hda_cpu_dai, sizeof(*dais)); 1268d070002aSCezary Rojewski dais[i].id = i; 1269d070002aSCezary Rojewski dais[i].name = devm_kasprintf(component->dev, GFP_KERNEL, 1270d070002aSCezary Rojewski "%s-cpu%d", cname, i); 1271d070002aSCezary Rojewski if (!dais[i].name) { 1272d070002aSCezary Rojewski ret = -ENOMEM; 1273d070002aSCezary Rojewski goto exit; 1274d070002aSCezary Rojewski } 1275d070002aSCezary Rojewski 1276d070002aSCezary Rojewski if (pcm->stream[0].substreams) { 1277d070002aSCezary Rojewski dais[i].playback.stream_name = 1278d070002aSCezary Rojewski devm_kasprintf(component->dev, GFP_KERNEL, 1279d070002aSCezary Rojewski "%s-cpu%d Tx", cname, i); 1280d070002aSCezary Rojewski if (!dais[i].playback.stream_name) { 1281d070002aSCezary Rojewski ret = -ENOMEM; 1282d070002aSCezary Rojewski goto exit; 1283d070002aSCezary Rojewski } 1284d070002aSCezary Rojewski } 1285d070002aSCezary Rojewski 1286d070002aSCezary Rojewski if (pcm->stream[1].substreams) { 1287d070002aSCezary Rojewski dais[i].capture.stream_name = 1288d070002aSCezary Rojewski devm_kasprintf(component->dev, GFP_KERNEL, 1289d070002aSCezary Rojewski "%s-cpu%d Rx", cname, i); 1290d070002aSCezary Rojewski if (!dais[i].capture.stream_name) { 1291d070002aSCezary Rojewski ret = -ENOMEM; 1292d070002aSCezary Rojewski goto exit; 1293d070002aSCezary Rojewski } 1294d070002aSCezary Rojewski } 1295d070002aSCezary Rojewski 1296d070002aSCezary Rojewski dai = snd_soc_register_dai(component, &dais[i], false); 1297d070002aSCezary Rojewski if (!dai) { 1298d070002aSCezary Rojewski dev_err(component->dev, "register dai for %s failed\n", 1299d070002aSCezary Rojewski pcm->name); 1300d070002aSCezary Rojewski ret = -EINVAL; 1301d070002aSCezary Rojewski goto exit; 1302d070002aSCezary Rojewski } 1303d070002aSCezary Rojewski 1304d070002aSCezary Rojewski ret = snd_soc_dapm_new_dai_widgets(dapm, dai); 1305d070002aSCezary Rojewski if (ret < 0) { 1306d070002aSCezary Rojewski dev_err(component->dev, "create widgets failed: %d\n", 1307d070002aSCezary Rojewski ret); 1308d070002aSCezary Rojewski goto exit; 1309d070002aSCezary Rojewski } 1310d070002aSCezary Rojewski } 1311d070002aSCezary Rojewski 1312d070002aSCezary Rojewski ret = avs_component_probe(component); 1313d070002aSCezary Rojewski exit: 1314d070002aSCezary Rojewski if (ret) 1315d070002aSCezary Rojewski avs_component_hda_unregister_dais(component); 1316d070002aSCezary Rojewski 1317d070002aSCezary Rojewski return ret; 1318d070002aSCezary Rojewski } 1319d070002aSCezary Rojewski 1320d070002aSCezary Rojewski static void avs_component_hda_remove(struct snd_soc_component *component) 1321d070002aSCezary Rojewski { 1322d070002aSCezary Rojewski avs_component_hda_unregister_dais(component); 1323d070002aSCezary Rojewski avs_component_remove(component); 1324d070002aSCezary Rojewski } 1325d070002aSCezary Rojewski 1326d070002aSCezary Rojewski static int avs_component_hda_open(struct snd_soc_component *component, 1327d070002aSCezary Rojewski struct snd_pcm_substream *substream) 1328d070002aSCezary Rojewski { 1329d070002aSCezary Rojewski struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); 1330d070002aSCezary Rojewski struct hdac_ext_stream *link_stream; 1331d070002aSCezary Rojewski struct hda_codec *codec; 1332d070002aSCezary Rojewski 1333d070002aSCezary Rojewski /* only BE DAI links are handled here */ 1334d070002aSCezary Rojewski if (!rtd->dai_link->no_pcm) 1335d070002aSCezary Rojewski return avs_component_open(component, substream); 1336d070002aSCezary Rojewski 1337d070002aSCezary Rojewski codec = dev_to_hda_codec(asoc_rtd_to_codec(rtd, 0)->dev); 1338d070002aSCezary Rojewski link_stream = snd_hdac_ext_stream_assign(&codec->bus->core, substream, 1339d070002aSCezary Rojewski HDAC_EXT_STREAM_TYPE_LINK); 1340d070002aSCezary Rojewski if (!link_stream) 1341d070002aSCezary Rojewski return -EBUSY; 1342d070002aSCezary Rojewski 1343d070002aSCezary Rojewski substream->runtime->private_data = link_stream; 1344d070002aSCezary Rojewski return 0; 1345d070002aSCezary Rojewski } 1346d070002aSCezary Rojewski 1347d070002aSCezary Rojewski static int avs_component_hda_close(struct snd_soc_component *component, 1348d070002aSCezary Rojewski struct snd_pcm_substream *substream) 1349d070002aSCezary Rojewski { 1350d070002aSCezary Rojewski struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); 1351d070002aSCezary Rojewski struct hdac_ext_stream *link_stream; 1352d070002aSCezary Rojewski 1353d070002aSCezary Rojewski /* only BE DAI links are handled here */ 1354d070002aSCezary Rojewski if (!rtd->dai_link->no_pcm) 1355d070002aSCezary Rojewski return 0; 1356d070002aSCezary Rojewski 1357d070002aSCezary Rojewski link_stream = substream->runtime->private_data; 1358d070002aSCezary Rojewski snd_hdac_ext_stream_release(link_stream, HDAC_EXT_STREAM_TYPE_LINK); 1359d070002aSCezary Rojewski substream->runtime->private_data = NULL; 1360d070002aSCezary Rojewski 1361d070002aSCezary Rojewski return 0; 1362d070002aSCezary Rojewski } 1363d070002aSCezary Rojewski 1364d070002aSCezary Rojewski static const struct snd_soc_component_driver avs_hda_component_driver = { 1365d070002aSCezary Rojewski .name = "avs-hda-pcm", 1366d070002aSCezary Rojewski .probe = avs_component_hda_probe, 1367d070002aSCezary Rojewski .remove = avs_component_hda_remove, 1368*2b9a50eaSCezary Rojewski .suspend = avs_component_suspend, 1369*2b9a50eaSCezary Rojewski .resume = avs_component_resume, 1370d070002aSCezary Rojewski .open = avs_component_hda_open, 1371d070002aSCezary Rojewski .close = avs_component_hda_close, 1372d070002aSCezary Rojewski .pointer = avs_component_pointer, 1373d070002aSCezary Rojewski .mmap = avs_component_mmap, 1374d070002aSCezary Rojewski .pcm_construct = avs_component_construct, 1375d070002aSCezary Rojewski /* 1376d070002aSCezary Rojewski * hda platform component's probe() is dependent on 1377d070002aSCezary Rojewski * codec->pcm_list_head, it needs to be initialized after codec 1378d070002aSCezary Rojewski * component. remove_order is here for completeness sake 1379d070002aSCezary Rojewski */ 1380d070002aSCezary Rojewski .probe_order = SND_SOC_COMP_ORDER_LATE, 1381d070002aSCezary Rojewski .remove_order = SND_SOC_COMP_ORDER_EARLY, 1382d070002aSCezary Rojewski .module_get_upon_open = 1, 1383d070002aSCezary Rojewski .topology_name_prefix = "intel/avs", 1384d070002aSCezary Rojewski }; 1385d070002aSCezary Rojewski 1386d070002aSCezary Rojewski int avs_hda_platform_register(struct avs_dev *adev, const char *name) 1387d070002aSCezary Rojewski { 1388d070002aSCezary Rojewski return avs_soc_component_register(adev->dev, name, 1389d070002aSCezary Rojewski &avs_hda_component_driver, NULL, 0); 1390d070002aSCezary Rojewski } 1391