1649 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2//3// Copyright(c) 2021-2022 Intel Corporation4//5// Authors: Cezary Rojewski <cezary.rojewski@intel.com>6// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>7//8 9#include <linux/debugfs.h>10#include <linux/device.h>11#include <sound/hda_register.h>12#include <sound/hdaudio_ext.h>13#include <sound/pcm_params.h>14#include <sound/soc-acpi.h>15#include <sound/soc-acpi-intel-match.h>16#include <sound/soc-component.h>17#include "avs.h"18#include "path.h"19#include "pcm.h"20#include "topology.h"21#include "../../codecs/hda.h"22 23struct avs_dma_data {24 struct avs_tplg_path_template *template;25 struct avs_path *path;26 struct avs_dev *adev;27 28 /* LINK-stream utilized in BE operations while HOST in FE ones. */29 union {30 struct hdac_ext_stream *link_stream;31 struct hdac_ext_stream *host_stream;32 };33 34 struct work_struct period_elapsed_work;35 struct snd_pcm_substream *substream;36};37 38static struct avs_tplg_path_template *39avs_dai_find_path_template(struct snd_soc_dai *dai, bool is_fe, int direction)40{41 struct snd_soc_dapm_widget *dw = snd_soc_dai_get_widget(dai, direction);42 struct snd_soc_dapm_path *dp;43 enum snd_soc_dapm_direction dir;44 45 if (direction == SNDRV_PCM_STREAM_CAPTURE) {46 dir = is_fe ? SND_SOC_DAPM_DIR_OUT : SND_SOC_DAPM_DIR_IN;47 } else {48 dir = is_fe ? SND_SOC_DAPM_DIR_IN : SND_SOC_DAPM_DIR_OUT;49 }50 51 dp = list_first_entry_or_null(&dw->edges[dir], typeof(*dp), list_node[dir]);52 if (!dp)53 return NULL;54 55 /* Get the other widget, with actual path template data */56 dw = (dp->source == dw) ? dp->sink : dp->source;57 58 return dw->priv;59}60 61static void avs_period_elapsed_work(struct work_struct *work)62{63 struct avs_dma_data *data = container_of(work, struct avs_dma_data, period_elapsed_work);64 65 snd_pcm_period_elapsed(data->substream);66}67 68void avs_period_elapsed(struct snd_pcm_substream *substream)69{70 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);71 struct snd_soc_dai *dai = snd_soc_rtd_to_cpu(rtd, 0);72 struct avs_dma_data *data = snd_soc_dai_get_dma_data(dai, substream);73 74 schedule_work(&data->period_elapsed_work);75}76 77static int avs_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)78{79 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);80 struct avs_dev *adev = to_avs_dev(dai->component->dev);81 struct avs_tplg_path_template *template;82 struct avs_dma_data *data;83 84 template = avs_dai_find_path_template(dai, !rtd->dai_link->no_pcm, substream->stream);85 if (!template) {86 dev_err(dai->dev, "no %s path for dai %s, invalid tplg?\n",87 snd_pcm_stream_str(substream), dai->name);88 return -EINVAL;89 }90 91 data = kzalloc(sizeof(*data), GFP_KERNEL);92 if (!data)93 return -ENOMEM;94 95 data->substream = substream;96 data->template = template;97 data->adev = adev;98 INIT_WORK(&data->period_elapsed_work, avs_period_elapsed_work);99 snd_soc_dai_set_dma_data(dai, substream, data);100 101 if (rtd->dai_link->ignore_suspend)102 adev->num_lp_paths++;103 104 return 0;105}106 107static void avs_dai_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)108{109 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);110 struct avs_dma_data *data;111 112 data = snd_soc_dai_get_dma_data(dai, substream);113 114 if (rtd->dai_link->ignore_suspend)115 data->adev->num_lp_paths--;116 117 snd_soc_dai_set_dma_data(dai, substream, NULL);118 kfree(data);119}120 121static int avs_dai_hw_params(struct snd_pcm_substream *substream,122 struct snd_pcm_hw_params *fe_hw_params,123 struct snd_pcm_hw_params *be_hw_params, struct snd_soc_dai *dai,124 int dma_id)125{126 struct avs_dma_data *data;127 struct avs_path *path;128 int ret;129 130 data = snd_soc_dai_get_dma_data(dai, substream);131 132 dev_dbg(dai->dev, "%s FE hw_params str %p rtd %p",133 __func__, substream, substream->runtime);134 dev_dbg(dai->dev, "rate %d chn %d vbd %d bd %d\n",135 params_rate(fe_hw_params), params_channels(fe_hw_params),136 params_width(fe_hw_params), params_physical_width(fe_hw_params));137 138 dev_dbg(dai->dev, "%s BE hw_params str %p rtd %p",139 __func__, substream, substream->runtime);140 dev_dbg(dai->dev, "rate %d chn %d vbd %d bd %d\n",141 params_rate(be_hw_params), params_channels(be_hw_params),142 params_width(be_hw_params), params_physical_width(be_hw_params));143 144 path = avs_path_create(data->adev, dma_id, data->template, fe_hw_params, be_hw_params);145 if (IS_ERR(path)) {146 ret = PTR_ERR(path);147 dev_err(dai->dev, "create path failed: %d\n", ret);148 return ret;149 }150 151 data->path = path;152 return 0;153}154 155static int avs_dai_be_hw_params(struct snd_pcm_substream *substream,156 struct snd_pcm_hw_params *be_hw_params, struct snd_soc_dai *dai,157 int dma_id)158{159 struct snd_pcm_hw_params *fe_hw_params = NULL;160 struct snd_soc_pcm_runtime *fe, *be;161 struct snd_soc_dpcm *dpcm;162 163 be = snd_soc_substream_to_rtd(substream);164 for_each_dpcm_fe(be, substream->stream, dpcm) {165 fe = dpcm->fe;166 fe_hw_params = &fe->dpcm[substream->stream].hw_params;167 }168 169 return avs_dai_hw_params(substream, fe_hw_params, be_hw_params, dai, dma_id);170}171 172static int avs_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)173{174 struct avs_dma_data *data;175 int ret;176 177 data = snd_soc_dai_get_dma_data(dai, substream);178 if (!data->path)179 return 0;180 181 ret = avs_path_reset(data->path);182 if (ret < 0) {183 dev_err(dai->dev, "reset path failed: %d\n", ret);184 return ret;185 }186 187 ret = avs_path_pause(data->path);188 if (ret < 0)189 dev_err(dai->dev, "pause path failed: %d\n", ret);190 return ret;191}192 193static int avs_dai_nonhda_be_hw_params(struct snd_pcm_substream *substream,194 struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *dai)195{196 struct avs_dma_data *data;197 198 data = snd_soc_dai_get_dma_data(dai, substream);199 if (data->path)200 return 0;201 202 /* Actual port-id comes from topology. */203 return avs_dai_be_hw_params(substream, hw_params, dai, 0);204}205 206static int avs_dai_nonhda_be_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)207{208 struct avs_dma_data *data;209 210 dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);211 212 data = snd_soc_dai_get_dma_data(dai, substream);213 if (data->path) {214 avs_path_free(data->path);215 data->path = NULL;216 }217 218 return 0;219}220 221static int avs_dai_nonhda_be_trigger(struct snd_pcm_substream *substream, int cmd,222 struct snd_soc_dai *dai)223{224 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);225 struct avs_dma_data *data;226 int ret = 0;227 228 data = snd_soc_dai_get_dma_data(dai, substream);229 230 switch (cmd) {231 case SNDRV_PCM_TRIGGER_RESUME:232 if (rtd->dai_link->ignore_suspend)233 break;234 fallthrough;235 case SNDRV_PCM_TRIGGER_START:236 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:237 ret = avs_path_pause(data->path);238 if (ret < 0) {239 dev_err(dai->dev, "pause BE path failed: %d\n", ret);240 break;241 }242 243 ret = avs_path_run(data->path, AVS_TPLG_TRIGGER_AUTO);244 if (ret < 0)245 dev_err(dai->dev, "run BE path failed: %d\n", ret);246 break;247 248 case SNDRV_PCM_TRIGGER_SUSPEND:249 if (rtd->dai_link->ignore_suspend)250 break;251 fallthrough;252 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:253 case SNDRV_PCM_TRIGGER_STOP:254 ret = avs_path_pause(data->path);255 if (ret < 0)256 dev_err(dai->dev, "pause BE path failed: %d\n", ret);257 258 ret = avs_path_reset(data->path);259 if (ret < 0)260 dev_err(dai->dev, "reset BE path failed: %d\n", ret);261 break;262 263 default:264 ret = -EINVAL;265 break;266 }267 268 return ret;269}270 271static const struct snd_soc_dai_ops avs_dai_nonhda_be_ops = {272 .startup = avs_dai_startup,273 .shutdown = avs_dai_shutdown,274 .hw_params = avs_dai_nonhda_be_hw_params,275 .hw_free = avs_dai_nonhda_be_hw_free,276 .prepare = avs_dai_prepare,277 .trigger = avs_dai_nonhda_be_trigger,278};279 280static int avs_dai_hda_be_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)281{282 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);283 struct hdac_ext_stream *link_stream;284 struct avs_dma_data *data;285 struct hda_codec *codec;286 int ret;287 288 ret = avs_dai_startup(substream, dai);289 if (ret)290 return ret;291 292 codec = dev_to_hda_codec(snd_soc_rtd_to_codec(rtd, 0)->dev);293 link_stream = snd_hdac_ext_stream_assign(&codec->bus->core, substream,294 HDAC_EXT_STREAM_TYPE_LINK);295 if (!link_stream) {296 avs_dai_shutdown(substream, dai);297 return -EBUSY;298 }299 300 data = snd_soc_dai_get_dma_data(dai, substream);301 data->link_stream = link_stream;302 substream->runtime->private_data = link_stream;303 return 0;304}305 306static void avs_dai_hda_be_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)307{308 struct avs_dma_data *data = snd_soc_dai_get_dma_data(dai, substream);309 310 snd_hdac_ext_stream_release(data->link_stream, HDAC_EXT_STREAM_TYPE_LINK);311 substream->runtime->private_data = NULL;312 avs_dai_shutdown(substream, dai);313}314 315static int avs_dai_hda_be_hw_params(struct snd_pcm_substream *substream,316 struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *dai)317{318 struct avs_dma_data *data;319 320 data = snd_soc_dai_get_dma_data(dai, substream);321 if (data->path)322 return 0;323 324 return avs_dai_be_hw_params(substream, hw_params, dai,325 hdac_stream(data->link_stream)->stream_tag - 1);326}327 328static int avs_dai_hda_be_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)329{330 struct avs_dma_data *data;331 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);332 struct hdac_ext_stream *link_stream;333 struct hdac_ext_link *link;334 struct hda_codec *codec;335 336 dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);337 338 data = snd_soc_dai_get_dma_data(dai, substream);339 if (!data->path)340 return 0;341 342 link_stream = data->link_stream;343 link_stream->link_prepared = false;344 avs_path_free(data->path);345 data->path = NULL;346 347 /* clear link <-> stream mapping */348 codec = dev_to_hda_codec(snd_soc_rtd_to_codec(rtd, 0)->dev);349 link = snd_hdac_ext_bus_get_hlink_by_addr(&codec->bus->core, codec->core.addr);350 if (!link)351 return -EINVAL;352 353 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)354 snd_hdac_ext_bus_link_clear_stream_id(link, hdac_stream(link_stream)->stream_tag);355 356 return 0;357}358 359static int avs_dai_hda_be_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)360{361 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);362 struct snd_pcm_runtime *runtime = substream->runtime;363 const struct snd_soc_pcm_stream *stream_info;364 struct hdac_ext_stream *link_stream;365 struct hdac_ext_link *link;366 struct avs_dma_data *data;367 struct hda_codec *codec;368 struct hdac_bus *bus;369 unsigned int format_val;370 unsigned int bits;371 int ret;372 373 data = snd_soc_dai_get_dma_data(dai, substream);374 link_stream = data->link_stream;375 376 if (link_stream->link_prepared)377 return 0;378 379 codec = dev_to_hda_codec(snd_soc_rtd_to_codec(rtd, 0)->dev);380 bus = &codec->bus->core;381 stream_info = snd_soc_dai_get_pcm_stream(dai, substream->stream);382 bits = snd_hdac_stream_format_bits(runtime->format, runtime->subformat,383 stream_info->sig_bits);384 format_val = snd_hdac_stream_format(runtime->channels, bits, runtime->rate);385 386 snd_hdac_ext_stream_decouple(bus, link_stream, true);387 snd_hdac_ext_stream_reset(link_stream);388 snd_hdac_ext_stream_setup(link_stream, format_val);389 390 link = snd_hdac_ext_bus_get_hlink_by_addr(bus, codec->core.addr);391 if (!link)392 return -EINVAL;393 394 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)395 snd_hdac_ext_bus_link_set_stream_id(link, hdac_stream(link_stream)->stream_tag);396 397 ret = avs_dai_prepare(substream, dai);398 if (ret)399 return ret;400 401 link_stream->link_prepared = true;402 return 0;403}404 405static int avs_dai_hda_be_trigger(struct snd_pcm_substream *substream, int cmd,406 struct snd_soc_dai *dai)407{408 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);409 struct avs_dma_data *data;410 int ret = 0;411 412 dev_dbg(dai->dev, "entry %s cmd=%d\n", __func__, cmd);413 414 data = snd_soc_dai_get_dma_data(dai, substream);415 416 switch (cmd) {417 case SNDRV_PCM_TRIGGER_RESUME:418 if (rtd->dai_link->ignore_suspend)419 break;420 fallthrough;421 case SNDRV_PCM_TRIGGER_START:422 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:423 snd_hdac_ext_stream_start(data->link_stream);424 425 ret = avs_path_pause(data->path);426 if (ret < 0) {427 dev_err(dai->dev, "pause BE path failed: %d\n", ret);428 break;429 }430 431 ret = avs_path_run(data->path, AVS_TPLG_TRIGGER_AUTO);432 if (ret < 0)433 dev_err(dai->dev, "run BE path failed: %d\n", ret);434 break;435 436 case SNDRV_PCM_TRIGGER_SUSPEND:437 if (rtd->dai_link->ignore_suspend)438 break;439 fallthrough;440 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:441 case SNDRV_PCM_TRIGGER_STOP:442 ret = avs_path_pause(data->path);443 if (ret < 0)444 dev_err(dai->dev, "pause BE path failed: %d\n", ret);445 446 snd_hdac_ext_stream_clear(data->link_stream);447 448 ret = avs_path_reset(data->path);449 if (ret < 0)450 dev_err(dai->dev, "reset BE path failed: %d\n", ret);451 break;452 453 default:454 ret = -EINVAL;455 break;456 }457 458 return ret;459}460 461static const struct snd_soc_dai_ops avs_dai_hda_be_ops = {462 .startup = avs_dai_hda_be_startup,463 .shutdown = avs_dai_hda_be_shutdown,464 .hw_params = avs_dai_hda_be_hw_params,465 .hw_free = avs_dai_hda_be_hw_free,466 .prepare = avs_dai_hda_be_prepare,467 .trigger = avs_dai_hda_be_trigger,468};469 470static int hw_rule_param_size(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule)471{472 struct snd_interval *interval = hw_param_interval(params, rule->var);473 struct snd_interval to;474 475 snd_interval_any(&to);476 to.integer = interval->integer;477 to.max = interval->max;478 /*479 * Commonly 2ms buffer size is used in HDA scenarios whereas 4ms is used480 * when streaming through GPDMA. Align to the latter to account for both.481 */482 to.min = params_rate(params) / 1000 * 4;483 484 if (rule->var == SNDRV_PCM_HW_PARAM_PERIOD_SIZE)485 to.min /= params_periods(params);486 487 return snd_interval_refine(interval, &to);488}489 490static int avs_pcm_hw_constraints_init(struct snd_pcm_substream *substream)491{492 struct snd_pcm_runtime *runtime = substream->runtime;493 int ret;494 495 ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);496 if (ret < 0)497 return ret;498 499 /* Avoid wrap-around with wall-clock. */500 ret = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_TIME, 20, 178000000);501 if (ret < 0)502 return ret;503 504 /* Adjust buffer and period size based on the audio format. */505 snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, hw_rule_param_size, NULL,506 SNDRV_PCM_HW_PARAM_FORMAT, SNDRV_PCM_HW_PARAM_CHANNELS,507 SNDRV_PCM_HW_PARAM_RATE, -1);508 snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, hw_rule_param_size, NULL,509 SNDRV_PCM_HW_PARAM_FORMAT, SNDRV_PCM_HW_PARAM_CHANNELS,510 SNDRV_PCM_HW_PARAM_RATE, -1);511 512 return ret;513}514 515static int avs_dai_fe_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)516{517 struct hdac_ext_stream *host_stream;518 struct avs_dma_data *data;519 struct hdac_bus *bus;520 int ret;521 522 ret = avs_pcm_hw_constraints_init(substream);523 if (ret)524 return ret;525 526 ret = avs_dai_startup(substream, dai);527 if (ret)528 return ret;529 530 data = snd_soc_dai_get_dma_data(dai, substream);531 bus = &data->adev->base.core;532 533 host_stream = snd_hdac_ext_stream_assign(bus, substream, HDAC_EXT_STREAM_TYPE_HOST);534 if (!host_stream) {535 avs_dai_shutdown(substream, dai);536 return -EBUSY;537 }538 539 data->host_stream = host_stream;540 snd_pcm_set_sync(substream);541 542 dev_dbg(dai->dev, "%s fe STARTUP tag %d str %p",543 __func__, hdac_stream(host_stream)->stream_tag, substream);544 545 return 0;546}547 548static void avs_dai_fe_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)549{550 struct avs_dma_data *data;551 552 data = snd_soc_dai_get_dma_data(dai, substream);553 554 snd_hdac_ext_stream_release(data->host_stream, HDAC_EXT_STREAM_TYPE_HOST);555 avs_dai_shutdown(substream, dai);556}557 558static int avs_dai_fe_hw_params(struct snd_pcm_substream *substream,559 struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *dai)560{561 struct snd_pcm_hw_params *be_hw_params = NULL;562 struct snd_soc_pcm_runtime *fe, *be;563 struct snd_soc_dpcm *dpcm;564 struct avs_dma_data *data;565 struct hdac_ext_stream *host_stream;566 int ret;567 568 data = snd_soc_dai_get_dma_data(dai, substream);569 if (data->path)570 return 0;571 572 host_stream = data->host_stream;573 574 hdac_stream(host_stream)->bufsize = 0;575 hdac_stream(host_stream)->period_bytes = 0;576 hdac_stream(host_stream)->format_val = 0;577 578 fe = snd_soc_substream_to_rtd(substream);579 for_each_dpcm_be(fe, substream->stream, dpcm) {580 be = dpcm->be;581 be_hw_params = &be->dpcm[substream->stream].hw_params;582 }583 584 ret = avs_dai_hw_params(substream, hw_params, be_hw_params, dai,585 hdac_stream(host_stream)->stream_tag - 1);586 if (ret)587 goto create_err;588 589 ret = avs_path_bind(data->path);590 if (ret < 0) {591 dev_err(dai->dev, "bind FE <-> BE failed: %d\n", ret);592 goto bind_err;593 }594 595 return 0;596 597bind_err:598 avs_path_free(data->path);599 data->path = NULL;600create_err:601 snd_pcm_lib_free_pages(substream);602 return ret;603}604 605static int __avs_dai_fe_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)606{607 struct avs_dma_data *data;608 struct hdac_ext_stream *host_stream;609 int ret;610 611 dev_dbg(dai->dev, "%s fe HW_FREE str %p rtd %p",612 __func__, substream, substream->runtime);613 614 data = snd_soc_dai_get_dma_data(dai, substream);615 if (!data->path)616 return 0;617 618 host_stream = data->host_stream;619 620 ret = avs_path_unbind(data->path);621 if (ret < 0)622 dev_err(dai->dev, "unbind FE <-> BE failed: %d\n", ret);623 624 avs_path_free(data->path);625 data->path = NULL;626 snd_hdac_stream_cleanup(hdac_stream(host_stream));627 hdac_stream(host_stream)->prepared = false;628 629 return ret;630}631 632static int avs_dai_fe_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)633{634 int ret;635 636 ret = __avs_dai_fe_hw_free(substream, dai);637 snd_pcm_lib_free_pages(substream);638 639 return ret;640}641 642static int avs_dai_fe_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)643{644 struct snd_pcm_runtime *runtime = substream->runtime;645 const struct snd_soc_pcm_stream *stream_info;646 struct avs_dma_data *data;647 struct hdac_ext_stream *host_stream;648 unsigned int format_val;649 struct hdac_bus *bus;650 unsigned int bits;651 int ret;652 653 data = snd_soc_dai_get_dma_data(dai, substream);654 host_stream = data->host_stream;655 656 if (hdac_stream(host_stream)->prepared)657 return 0;658 659 bus = hdac_stream(host_stream)->bus;660 snd_hdac_ext_stream_decouple(bus, data->host_stream, true);661 snd_hdac_stream_reset(hdac_stream(host_stream));662 663 stream_info = snd_soc_dai_get_pcm_stream(dai, substream->stream);664 bits = snd_hdac_stream_format_bits(runtime->format, runtime->subformat,665 stream_info->sig_bits);666 format_val = snd_hdac_stream_format(runtime->channels, bits, runtime->rate);667 668 ret = snd_hdac_stream_set_params(hdac_stream(host_stream), format_val);669 if (ret < 0)670 return ret;671 672 ret = snd_hdac_ext_host_stream_setup(host_stream, false);673 if (ret < 0)674 return ret;675 676 ret = avs_dai_prepare(substream, dai);677 if (ret)678 return ret;679 680 hdac_stream(host_stream)->prepared = true;681 return 0;682}683 684static void avs_hda_stream_start(struct hdac_bus *bus, struct hdac_ext_stream *host_stream)685{686 struct hdac_stream *first_running = NULL;687 struct hdac_stream *pos;688 struct avs_dev *adev = hdac_to_avs(bus);689 690 list_for_each_entry(pos, &bus->stream_list, list) {691 if (pos->running) {692 if (first_running)693 break; /* more than one running */694 first_running = pos;695 }696 }697 698 /*699 * If host_stream is a CAPTURE stream and will be the only one running,700 * disable L1SEN to avoid sound clipping.701 */702 if (!first_running) {703 if (hdac_stream(host_stream)->direction == SNDRV_PCM_STREAM_CAPTURE)704 avs_hda_l1sen_enable(adev, false);705 snd_hdac_stream_start(hdac_stream(host_stream));706 return;707 }708 709 snd_hdac_stream_start(hdac_stream(host_stream));710 /*711 * If host_stream is the first stream to break the rule above,712 * re-enable L1SEN.713 */714 if (list_entry_is_head(pos, &bus->stream_list, list) &&715 first_running->direction == SNDRV_PCM_STREAM_CAPTURE)716 avs_hda_l1sen_enable(adev, true);717}718 719static void avs_hda_stream_stop(struct hdac_bus *bus, struct hdac_ext_stream *host_stream)720{721 struct hdac_stream *first_running = NULL;722 struct hdac_stream *pos;723 struct avs_dev *adev = hdac_to_avs(bus);724 725 list_for_each_entry(pos, &bus->stream_list, list) {726 if (pos == hdac_stream(host_stream))727 continue; /* ignore stream that is about to be stopped */728 if (pos->running) {729 if (first_running)730 break; /* more than one running */731 first_running = pos;732 }733 }734 735 /*736 * If host_stream is a CAPTURE stream and is the only one running,737 * re-enable L1SEN.738 */739 if (!first_running) {740 snd_hdac_stream_stop(hdac_stream(host_stream));741 if (hdac_stream(host_stream)->direction == SNDRV_PCM_STREAM_CAPTURE)742 avs_hda_l1sen_enable(adev, true);743 return;744 }745 746 /*747 * If by stopping host_stream there is only a single, CAPTURE stream running748 * left, disable L1SEN to avoid sound clipping.749 */750 if (list_entry_is_head(pos, &bus->stream_list, list) &&751 first_running->direction == SNDRV_PCM_STREAM_CAPTURE)752 avs_hda_l1sen_enable(adev, false);753 754 snd_hdac_stream_stop(hdac_stream(host_stream));755}756 757static int avs_dai_fe_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)758{759 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);760 struct avs_dma_data *data;761 struct hdac_ext_stream *host_stream;762 struct hdac_bus *bus;763 unsigned long flags;764 int ret = 0;765 766 data = snd_soc_dai_get_dma_data(dai, substream);767 host_stream = data->host_stream;768 bus = hdac_stream(host_stream)->bus;769 770 switch (cmd) {771 case SNDRV_PCM_TRIGGER_RESUME:772 if (rtd->dai_link->ignore_suspend)773 break;774 fallthrough;775 case SNDRV_PCM_TRIGGER_START:776 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:777 spin_lock_irqsave(&bus->reg_lock, flags);778 avs_hda_stream_start(bus, host_stream);779 spin_unlock_irqrestore(&bus->reg_lock, flags);780 781 /* Timeout on DRSM poll shall not stop the resume so ignore the result. */782 if (cmd == SNDRV_PCM_TRIGGER_RESUME)783 snd_hdac_stream_wait_drsm(hdac_stream(host_stream));784 785 ret = avs_path_pause(data->path);786 if (ret < 0) {787 dev_err(dai->dev, "pause FE path failed: %d\n", ret);788 break;789 }790 791 ret = avs_path_run(data->path, AVS_TPLG_TRIGGER_AUTO);792 if (ret < 0)793 dev_err(dai->dev, "run FE path failed: %d\n", ret);794 795 break;796 797 case SNDRV_PCM_TRIGGER_SUSPEND:798 if (rtd->dai_link->ignore_suspend)799 break;800 fallthrough;801 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:802 case SNDRV_PCM_TRIGGER_STOP:803 ret = avs_path_pause(data->path);804 if (ret < 0)805 dev_err(dai->dev, "pause FE path failed: %d\n", ret);806 807 spin_lock_irqsave(&bus->reg_lock, flags);808 avs_hda_stream_stop(bus, host_stream);809 spin_unlock_irqrestore(&bus->reg_lock, flags);810 811 ret = avs_path_reset(data->path);812 if (ret < 0)813 dev_err(dai->dev, "reset FE path failed: %d\n", ret);814 break;815 816 default:817 ret = -EINVAL;818 break;819 }820 821 return ret;822}823 824const struct snd_soc_dai_ops avs_dai_fe_ops = {825 .startup = avs_dai_fe_startup,826 .shutdown = avs_dai_fe_shutdown,827 .hw_params = avs_dai_fe_hw_params,828 .hw_free = avs_dai_fe_hw_free,829 .prepare = avs_dai_fe_prepare,830 .trigger = avs_dai_fe_trigger,831};832 833static ssize_t topology_name_read(struct file *file, char __user *user_buf, size_t count,834 loff_t *ppos)835{836 struct snd_soc_component *component = file->private_data;837 struct snd_soc_card *card = component->card;838 struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev);839 char buf[64];840 size_t len;841 842 len = scnprintf(buf, sizeof(buf), "%s/%s\n", component->driver->topology_name_prefix,843 mach->tplg_filename);844 845 return simple_read_from_buffer(user_buf, count, ppos, buf, len);846}847 848static const struct file_operations topology_name_fops = {849 .open = simple_open,850 .read = topology_name_read,851 .llseek = default_llseek,852};853 854static int avs_component_load_libraries(struct avs_soc_component *acomp)855{856 struct avs_tplg *tplg = acomp->tplg;857 struct avs_dev *adev = to_avs_dev(acomp->base.dev);858 int ret;859 860 if (!tplg->num_libs)861 return 0;862 863 /* Parent device may be asleep and library loading involves IPCs. */864 ret = pm_runtime_resume_and_get(adev->dev);865 if (ret < 0)866 return ret;867 868 avs_hda_power_gating_enable(adev, false);869 avs_hda_clock_gating_enable(adev, false);870 avs_hda_l1sen_enable(adev, false);871 872 ret = avs_dsp_load_libraries(adev, tplg->libs, tplg->num_libs);873 874 avs_hda_l1sen_enable(adev, true);875 avs_hda_clock_gating_enable(adev, true);876 avs_hda_power_gating_enable(adev, true);877 878 if (!ret)879 ret = avs_module_info_init(adev, false);880 881 pm_runtime_mark_last_busy(adev->dev);882 pm_runtime_put_autosuspend(adev->dev);883 884 return ret;885}886 887static int avs_component_probe(struct snd_soc_component *component)888{889 struct snd_soc_card *card = component->card;890 struct snd_soc_acpi_mach *mach;891 struct avs_soc_component *acomp;892 struct avs_dev *adev;893 char *filename;894 int ret;895 896 dev_dbg(card->dev, "probing %s card %s\n", component->name, card->name);897 mach = dev_get_platdata(card->dev);898 acomp = to_avs_soc_component(component);899 adev = to_avs_dev(component->dev);900 901 acomp->tplg = avs_tplg_new(component);902 if (!acomp->tplg)903 return -ENOMEM;904 905 if (!mach->tplg_filename)906 goto finalize;907 908 /* Load specified topology and create debugfs for it. */909 filename = kasprintf(GFP_KERNEL, "%s/%s", component->driver->topology_name_prefix,910 mach->tplg_filename);911 if (!filename)912 return -ENOMEM;913 914 ret = avs_load_topology(component, filename);915 kfree(filename);916 if (ret == -ENOENT && !strncmp(mach->tplg_filename, "hda-", 4)) {917 unsigned int vendor_id;918 919 if (sscanf(mach->tplg_filename, "hda-%08x-tplg.bin", &vendor_id) != 1)920 return ret;921 922 if (((vendor_id >> 16) & 0xFFFF) == 0x8086)923 mach->tplg_filename = devm_kasprintf(adev->dev, GFP_KERNEL,924 "hda-8086-generic-tplg.bin");925 else926 mach->tplg_filename = devm_kasprintf(adev->dev, GFP_KERNEL,927 "hda-generic-tplg.bin");928 929 filename = kasprintf(GFP_KERNEL, "%s/%s", component->driver->topology_name_prefix,930 mach->tplg_filename);931 if (!filename)932 return -ENOMEM;933 934 dev_info(card->dev, "trying to load fallback topology %s\n", mach->tplg_filename);935 ret = avs_load_topology(component, filename);936 kfree(filename);937 }938 if (ret < 0)939 return ret;940 941 ret = avs_component_load_libraries(acomp);942 if (ret < 0) {943 dev_err(card->dev, "libraries loading failed: %d\n", ret);944 goto err_load_libs;945 }946 947finalize:948 debugfs_create_file("topology_name", 0444, component->debugfs_root, component,949 &topology_name_fops);950 951 mutex_lock(&adev->comp_list_mutex);952 list_add_tail(&acomp->node, &adev->comp_list);953 mutex_unlock(&adev->comp_list_mutex);954 955 return 0;956 957err_load_libs:958 avs_remove_topology(component);959 return ret;960}961 962static void avs_component_remove(struct snd_soc_component *component)963{964 struct avs_soc_component *acomp = to_avs_soc_component(component);965 struct snd_soc_acpi_mach *mach;966 struct avs_dev *adev = to_avs_dev(component->dev);967 int ret;968 969 mach = dev_get_platdata(component->card->dev);970 971 mutex_lock(&adev->comp_list_mutex);972 list_del(&acomp->node);973 mutex_unlock(&adev->comp_list_mutex);974 975 if (mach->tplg_filename) {976 ret = avs_remove_topology(component);977 if (ret < 0)978 dev_err(component->dev, "unload topology failed: %d\n", ret);979 }980}981 982static int avs_dai_resume_hw_params(struct snd_soc_dai *dai, struct avs_dma_data *data)983{984 struct snd_pcm_substream *substream;985 struct snd_soc_pcm_runtime *rtd;986 int ret;987 988 substream = data->substream;989 rtd = snd_soc_substream_to_rtd(substream);990 991 ret = dai->driver->ops->hw_params(substream, &rtd->dpcm[substream->stream].hw_params, dai);992 if (ret)993 dev_err(dai->dev, "hw_params on resume failed: %d\n", ret);994 995 return ret;996}997 998static int avs_dai_resume_fe_prepare(struct snd_soc_dai *dai, struct avs_dma_data *data)999{1000 struct hdac_ext_stream *host_stream;1001 struct hdac_stream *hstream;1002 struct hdac_bus *bus;1003 int ret;1004 1005 host_stream = data->host_stream;1006 hstream = hdac_stream(host_stream);1007 bus = hdac_stream(host_stream)->bus;1008 1009 /* Set DRSM before programming stream and position registers. */1010 snd_hdac_stream_drsm_enable(bus, true, hstream->index);1011 1012 ret = dai->driver->ops->prepare(data->substream, dai);1013 if (ret) {1014 dev_err(dai->dev, "prepare FE on resume failed: %d\n", ret);1015 return ret;1016 }1017 1018 writel(host_stream->pphcllpl, host_stream->pphc_addr + AZX_REG_PPHCLLPL);1019 writel(host_stream->pphcllpu, host_stream->pphc_addr + AZX_REG_PPHCLLPU);1020 writel(host_stream->pphcldpl, host_stream->pphc_addr + AZX_REG_PPHCLDPL);1021 writel(host_stream->pphcldpu, host_stream->pphc_addr + AZX_REG_PPHCLDPU);1022 1023 /* As per HW spec recommendation, program LPIB and DPIB to the same value. */1024 snd_hdac_stream_set_lpib(hstream, hstream->lpib);1025 snd_hdac_stream_set_dpibr(bus, hstream, hstream->lpib);1026 1027 return 0;1028}1029 1030static int avs_dai_resume_be_prepare(struct snd_soc_dai *dai, struct avs_dma_data *data)1031{1032 int ret;1033 1034 ret = dai->driver->ops->prepare(data->substream, dai);1035 if (ret)1036 dev_err(dai->dev, "prepare BE on resume failed: %d\n", ret);1037 1038 return ret;1039}1040 1041static int avs_dai_suspend_fe_hw_free(struct snd_soc_dai *dai, struct avs_dma_data *data)1042{1043 struct hdac_ext_stream *host_stream;1044 int ret;1045 1046 host_stream = data->host_stream;1047 1048 /* Store position addresses so we can resume from them later on. */1049 hdac_stream(host_stream)->lpib = snd_hdac_stream_get_pos_lpib(hdac_stream(host_stream));1050 host_stream->pphcllpl = readl(host_stream->pphc_addr + AZX_REG_PPHCLLPL);1051 host_stream->pphcllpu = readl(host_stream->pphc_addr + AZX_REG_PPHCLLPU);1052 host_stream->pphcldpl = readl(host_stream->pphc_addr + AZX_REG_PPHCLDPL);1053 host_stream->pphcldpu = readl(host_stream->pphc_addr + AZX_REG_PPHCLDPU);1054 1055 ret = __avs_dai_fe_hw_free(data->substream, dai);1056 if (ret < 0)1057 dev_err(dai->dev, "hw_free FE on suspend failed: %d\n", ret);1058 1059 return ret;1060}1061 1062static int avs_dai_suspend_be_hw_free(struct snd_soc_dai *dai, struct avs_dma_data *data)1063{1064 int ret;1065 1066 ret = dai->driver->ops->hw_free(data->substream, dai);1067 if (ret < 0)1068 dev_err(dai->dev, "hw_free BE on suspend failed: %d\n", ret);1069 1070 return ret;1071}1072 1073static int avs_component_pm_op(struct snd_soc_component *component, bool be,1074 int (*op)(struct snd_soc_dai *, struct avs_dma_data *))1075{1076 struct snd_soc_pcm_runtime *rtd;1077 struct avs_dma_data *data;1078 struct snd_soc_dai *dai;1079 int ret;1080 1081 for_each_component_dais(component, dai) {1082 data = snd_soc_dai_dma_data_get_playback(dai);1083 if (data) {1084 rtd = snd_soc_substream_to_rtd(data->substream);1085 if (rtd->dai_link->no_pcm == be && !rtd->dai_link->ignore_suspend) {1086 ret = op(dai, data);1087 if (ret < 0) {1088 __snd_pcm_set_state(data->substream->runtime,1089 SNDRV_PCM_STATE_DISCONNECTED);1090 return ret;1091 }1092 }1093 }1094 1095 data = snd_soc_dai_dma_data_get_capture(dai);1096 if (data) {1097 rtd = snd_soc_substream_to_rtd(data->substream);1098 if (rtd->dai_link->no_pcm == be && !rtd->dai_link->ignore_suspend) {1099 ret = op(dai, data);1100 if (ret < 0) {1101 __snd_pcm_set_state(data->substream->runtime,1102 SNDRV_PCM_STATE_DISCONNECTED);1103 return ret;1104 }1105 }1106 }1107 }1108 1109 return 0;1110}1111 1112static int avs_component_resume_hw_params(struct snd_soc_component *component, bool be)1113{1114 return avs_component_pm_op(component, be, &avs_dai_resume_hw_params);1115}1116 1117static int avs_component_resume_prepare(struct snd_soc_component *component, bool be)1118{1119 int (*prepare_cb)(struct snd_soc_dai *dai, struct avs_dma_data *data);1120 1121 if (be)1122 prepare_cb = &avs_dai_resume_be_prepare;1123 else1124 prepare_cb = &avs_dai_resume_fe_prepare;1125 1126 return avs_component_pm_op(component, be, prepare_cb);1127}1128 1129static int avs_component_suspend_hw_free(struct snd_soc_component *component, bool be)1130{1131 int (*hw_free_cb)(struct snd_soc_dai *dai, struct avs_dma_data *data);1132 1133 if (be)1134 hw_free_cb = &avs_dai_suspend_be_hw_free;1135 else1136 hw_free_cb = &avs_dai_suspend_fe_hw_free;1137 1138 return avs_component_pm_op(component, be, hw_free_cb);1139}1140 1141static int avs_component_suspend(struct snd_soc_component *component)1142{1143 int ret;1144 1145 /*1146 * When freeing paths, FEs need to be first as they perform1147 * path unbinding.1148 */1149 ret = avs_component_suspend_hw_free(component, false);1150 if (ret)1151 return ret;1152 1153 return avs_component_suspend_hw_free(component, true);1154}1155 1156static int avs_component_resume(struct snd_soc_component *component)1157{1158 int ret;1159 1160 /*1161 * When creating paths, FEs need to be last as they perform1162 * path binding.1163 */1164 ret = avs_component_resume_hw_params(component, true);1165 if (ret)1166 return ret;1167 1168 ret = avs_component_resume_hw_params(component, false);1169 if (ret)1170 return ret;1171 1172 /* It is expected that the LINK stream is prepared first. */1173 ret = avs_component_resume_prepare(component, true);1174 if (ret)1175 return ret;1176 1177 return avs_component_resume_prepare(component, false);1178}1179 1180static const struct snd_pcm_hardware avs_pcm_hardware = {1181 .info = SNDRV_PCM_INFO_MMAP |1182 SNDRV_PCM_INFO_MMAP_VALID |1183 SNDRV_PCM_INFO_INTERLEAVED |1184 SNDRV_PCM_INFO_PAUSE |1185 SNDRV_PCM_INFO_RESUME |1186 SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,1187 .formats = SNDRV_PCM_FMTBIT_S16_LE |1188 SNDRV_PCM_FMTBIT_S32_LE,1189 .subformats = SNDRV_PCM_SUBFMTBIT_MSBITS_20 |1190 SNDRV_PCM_SUBFMTBIT_MSBITS_24 |1191 SNDRV_PCM_SUBFMTBIT_MSBITS_MAX,1192 .buffer_bytes_max = AZX_MAX_BUF_SIZE,1193 .period_bytes_min = 128,1194 .period_bytes_max = AZX_MAX_BUF_SIZE / 2,1195 .periods_min = 2,1196 .periods_max = AZX_MAX_FRAG,1197 .fifo_size = 0,1198};1199 1200static int avs_component_open(struct snd_soc_component *component,1201 struct snd_pcm_substream *substream)1202{1203 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);1204 1205 /* only FE DAI links are handled here */1206 if (rtd->dai_link->no_pcm)1207 return 0;1208 1209 return snd_soc_set_runtime_hwparams(substream, &avs_pcm_hardware);1210}1211 1212static unsigned int avs_hda_stream_dpib_read(struct hdac_ext_stream *stream)1213{1214 return readl(hdac_stream(stream)->bus->remap_addr + AZX_REG_VS_SDXDPIB_XBASE +1215 (AZX_REG_VS_SDXDPIB_XINTERVAL * hdac_stream(stream)->index));1216}1217 1218static snd_pcm_uframes_t1219avs_component_pointer(struct snd_soc_component *component, struct snd_pcm_substream *substream)1220{1221 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);1222 struct avs_dma_data *data;1223 struct hdac_ext_stream *host_stream;1224 unsigned int pos;1225 1226 data = snd_soc_dai_get_dma_data(snd_soc_rtd_to_cpu(rtd, 0), substream);1227 if (!data->host_stream)1228 return 0;1229 1230 host_stream = data->host_stream;1231 pos = avs_hda_stream_dpib_read(host_stream);1232 1233 if (pos >= hdac_stream(host_stream)->bufsize)1234 pos = 0;1235 1236 return bytes_to_frames(substream->runtime, pos);1237}1238 1239static int avs_component_mmap(struct snd_soc_component *component,1240 struct snd_pcm_substream *substream,1241 struct vm_area_struct *vma)1242{1243 return snd_pcm_lib_default_mmap(substream, vma);1244}1245 1246#define MAX_PREALLOC_SIZE (32 * 1024 * 1024)1247 1248static int avs_component_construct(struct snd_soc_component *component,1249 struct snd_soc_pcm_runtime *rtd)1250{1251 struct snd_soc_dai *dai = snd_soc_rtd_to_cpu(rtd, 0);1252 struct snd_pcm *pcm = rtd->pcm;1253 1254 if (dai->driver->playback.channels_min)1255 snd_pcm_set_managed_buffer(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream,1256 SNDRV_DMA_TYPE_DEV_SG, component->dev, 0,1257 MAX_PREALLOC_SIZE);1258 1259 if (dai->driver->capture.channels_min)1260 snd_pcm_set_managed_buffer(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream,1261 SNDRV_DMA_TYPE_DEV_SG, component->dev, 0,1262 MAX_PREALLOC_SIZE);1263 1264 return 0;1265}1266 1267static const struct snd_soc_component_driver avs_component_driver = {1268 .name = "avs-pcm",1269 .probe = avs_component_probe,1270 .remove = avs_component_remove,1271 .suspend = avs_component_suspend,1272 .resume = avs_component_resume,1273 .open = avs_component_open,1274 .pointer = avs_component_pointer,1275 .mmap = avs_component_mmap,1276 .pcm_construct = avs_component_construct,1277 .module_get_upon_open = 1, /* increment refcount when a pcm is opened */1278 .topology_name_prefix = "intel/avs",1279};1280 1281int avs_soc_component_register(struct device *dev, const char *name,1282 const struct snd_soc_component_driver *drv,1283 struct snd_soc_dai_driver *cpu_dais, int num_cpu_dais)1284{1285 struct avs_soc_component *acomp;1286 int ret;1287 1288 acomp = devm_kzalloc(dev, sizeof(*acomp), GFP_KERNEL);1289 if (!acomp)1290 return -ENOMEM;1291 1292 ret = snd_soc_component_initialize(&acomp->base, drv, dev);1293 if (ret < 0)1294 return ret;1295 1296 /* force name change after ASoC is done with its init */1297 acomp->base.name = name;1298 INIT_LIST_HEAD(&acomp->node);1299 1300 return snd_soc_add_component(&acomp->base, cpu_dais, num_cpu_dais);1301}1302 1303static struct snd_soc_dai_driver dmic_cpu_dais[] = {1304{1305 .name = "DMIC Pin",1306 .ops = &avs_dai_nonhda_be_ops,1307 .capture = {1308 .stream_name = "DMIC Rx",1309 .channels_min = 1,1310 .channels_max = 4,1311 .rates = SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_48000,1312 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,1313 },1314},1315{1316 .name = "DMIC WoV Pin",1317 .ops = &avs_dai_nonhda_be_ops,1318 .capture = {1319 .stream_name = "DMIC WoV Rx",1320 .channels_min = 1,1321 .channels_max = 4,1322 .rates = SNDRV_PCM_RATE_16000,1323 .formats = SNDRV_PCM_FMTBIT_S16_LE,1324 },1325},1326};1327 1328int avs_dmic_platform_register(struct avs_dev *adev, const char *name)1329{1330 return avs_soc_component_register(adev->dev, name, &avs_component_driver, dmic_cpu_dais,1331 ARRAY_SIZE(dmic_cpu_dais));1332}1333 1334static const struct snd_soc_dai_driver i2s_dai_template = {1335 .ops = &avs_dai_nonhda_be_ops,1336 .playback = {1337 .channels_min = 1,1338 .channels_max = 8,1339 .rates = SNDRV_PCM_RATE_8000_192000 |1340 SNDRV_PCM_RATE_12000 |1341 SNDRV_PCM_RATE_24000 |1342 SNDRV_PCM_RATE_128000,1343 .formats = SNDRV_PCM_FMTBIT_S16_LE |1344 SNDRV_PCM_FMTBIT_S32_LE,1345 .subformats = SNDRV_PCM_SUBFMTBIT_MSBITS_20 |1346 SNDRV_PCM_SUBFMTBIT_MSBITS_24 |1347 SNDRV_PCM_SUBFMTBIT_MSBITS_MAX,1348 },1349 .capture = {1350 .channels_min = 1,1351 .channels_max = 8,1352 .rates = SNDRV_PCM_RATE_8000_192000 |1353 SNDRV_PCM_RATE_12000 |1354 SNDRV_PCM_RATE_24000 |1355 SNDRV_PCM_RATE_128000,1356 .formats = SNDRV_PCM_FMTBIT_S16_LE |1357 SNDRV_PCM_FMTBIT_S32_LE,1358 .subformats = SNDRV_PCM_SUBFMTBIT_MSBITS_20 |1359 SNDRV_PCM_SUBFMTBIT_MSBITS_24 |1360 SNDRV_PCM_SUBFMTBIT_MSBITS_MAX,1361 },1362};1363 1364int avs_i2s_platform_register(struct avs_dev *adev, const char *name, unsigned long port_mask,1365 unsigned long *tdms)1366{1367 struct snd_soc_dai_driver *cpus, *dai;1368 size_t ssp_count, cpu_count;1369 int i, j;1370 1371 ssp_count = adev->hw_cfg.i2s_caps.ctrl_count;1372 1373 cpu_count = 0;1374 for_each_set_bit(i, &port_mask, ssp_count)1375 if (!tdms || test_bit(0, &tdms[i]))1376 cpu_count++;1377 if (tdms)1378 for_each_set_bit(i, &port_mask, ssp_count)1379 cpu_count += hweight_long(tdms[i]);1380 1381 cpus = devm_kzalloc(adev->dev, sizeof(*cpus) * cpu_count, GFP_KERNEL);1382 if (!cpus)1383 return -ENOMEM;1384 1385 dai = cpus;1386 for_each_set_bit(i, &port_mask, ssp_count) {1387 if (!tdms || test_bit(0, &tdms[i])) {1388 memcpy(dai, &i2s_dai_template, sizeof(*dai));1389 1390 dai->name =1391 devm_kasprintf(adev->dev, GFP_KERNEL, "SSP%d Pin", i);1392 dai->playback.stream_name =1393 devm_kasprintf(adev->dev, GFP_KERNEL, "ssp%d Tx", i);1394 dai->capture.stream_name =1395 devm_kasprintf(adev->dev, GFP_KERNEL, "ssp%d Rx", i);1396 1397 if (!dai->name || !dai->playback.stream_name || !dai->capture.stream_name)1398 return -ENOMEM;1399 dai++;1400 }1401 }1402 1403 if (!tdms)1404 goto plat_register;1405 1406 for_each_set_bit(i, &port_mask, ssp_count) {1407 for_each_set_bit(j, &tdms[i], ssp_count) {1408 memcpy(dai, &i2s_dai_template, sizeof(*dai));1409 1410 dai->name =1411 devm_kasprintf(adev->dev, GFP_KERNEL, "SSP%d:%d Pin", i, j);1412 dai->playback.stream_name =1413 devm_kasprintf(adev->dev, GFP_KERNEL, "ssp%d:%d Tx", i, j);1414 dai->capture.stream_name =1415 devm_kasprintf(adev->dev, GFP_KERNEL, "ssp%d:%d Rx", i, j);1416 1417 if (!dai->name || !dai->playback.stream_name || !dai->capture.stream_name)1418 return -ENOMEM;1419 dai++;1420 }1421 }1422 1423plat_register:1424 return avs_soc_component_register(adev->dev, name, &avs_component_driver, cpus, cpu_count);1425}1426 1427/* HD-Audio CPU DAI template */1428static const struct snd_soc_dai_driver hda_cpu_dai = {1429 .ops = &avs_dai_hda_be_ops,1430 .playback = {1431 .channels_min = 1,1432 .channels_max = 8,1433 .rates = SNDRV_PCM_RATE_8000_192000,1434 .formats = SNDRV_PCM_FMTBIT_S16_LE |1435 SNDRV_PCM_FMTBIT_S32_LE,1436 .subformats = SNDRV_PCM_SUBFMTBIT_MSBITS_20 |1437 SNDRV_PCM_SUBFMTBIT_MSBITS_24 |1438 SNDRV_PCM_SUBFMTBIT_MSBITS_MAX,1439 },1440 .capture = {1441 .channels_min = 1,1442 .channels_max = 8,1443 .rates = SNDRV_PCM_RATE_8000_192000,1444 .formats = SNDRV_PCM_FMTBIT_S16_LE |1445 SNDRV_PCM_FMTBIT_S32_LE,1446 .subformats = SNDRV_PCM_SUBFMTBIT_MSBITS_20 |1447 SNDRV_PCM_SUBFMTBIT_MSBITS_24 |1448 SNDRV_PCM_SUBFMTBIT_MSBITS_MAX,1449 },1450};1451 1452static void avs_component_hda_unregister_dais(struct snd_soc_component *component)1453{1454 struct snd_soc_acpi_mach *mach;1455 struct snd_soc_dai *dai, *save;1456 struct hda_codec *codec;1457 char name[32];1458 1459 mach = dev_get_platdata(component->card->dev);1460 codec = mach->pdata;1461 snprintf(name, sizeof(name), "%s-cpu", dev_name(&codec->core.dev));1462 1463 for_each_component_dais_safe(component, dai, save) {1464 int stream;1465 1466 if (!strstr(dai->driver->name, name))1467 continue;1468 1469 for_each_pcm_streams(stream)1470 snd_soc_dapm_free_widget(snd_soc_dai_get_widget(dai, stream));1471 1472 snd_soc_unregister_dai(dai);1473 }1474}1475 1476static int avs_component_hda_probe(struct snd_soc_component *component)1477{1478 struct snd_soc_dapm_context *dapm;1479 struct snd_soc_dai_driver *dais;1480 struct snd_soc_acpi_mach *mach;1481 struct hda_codec *codec;1482 struct hda_pcm *pcm;1483 const char *cname;1484 int pcm_count = 0, ret, i;1485 1486 mach = dev_get_platdata(component->card->dev);1487 if (!mach)1488 return -EINVAL;1489 1490 codec = mach->pdata;1491 if (list_empty(&codec->pcm_list_head))1492 return -EINVAL;1493 list_for_each_entry(pcm, &codec->pcm_list_head, list)1494 pcm_count++;1495 1496 dais = devm_kcalloc(component->dev, pcm_count, sizeof(*dais),1497 GFP_KERNEL);1498 if (!dais)1499 return -ENOMEM;1500 1501 cname = dev_name(&codec->core.dev);1502 dapm = snd_soc_component_get_dapm(component);1503 pcm = list_first_entry(&codec->pcm_list_head, struct hda_pcm, list);1504 1505 for (i = 0; i < pcm_count; i++, pcm = list_next_entry(pcm, list)) {1506 struct snd_soc_dai *dai;1507 1508 memcpy(&dais[i], &hda_cpu_dai, sizeof(*dais));1509 dais[i].id = i;1510 dais[i].name = devm_kasprintf(component->dev, GFP_KERNEL,1511 "%s-cpu%d", cname, i);1512 if (!dais[i].name) {1513 ret = -ENOMEM;1514 goto exit;1515 }1516 1517 if (pcm->stream[0].substreams) {1518 dais[i].playback.stream_name =1519 devm_kasprintf(component->dev, GFP_KERNEL,1520 "%s-cpu%d Tx", cname, i);1521 if (!dais[i].playback.stream_name) {1522 ret = -ENOMEM;1523 goto exit;1524 }1525 1526 if (!hda_codec_is_display(codec)) {1527 dais[i].playback.formats = pcm->stream[0].formats;1528 dais[i].playback.subformats = pcm->stream[0].subformats;1529 dais[i].playback.rates = pcm->stream[0].rates;1530 dais[i].playback.channels_min = pcm->stream[0].channels_min;1531 dais[i].playback.channels_max = pcm->stream[0].channels_max;1532 dais[i].playback.sig_bits = pcm->stream[0].maxbps;1533 }1534 }1535 1536 if (pcm->stream[1].substreams) {1537 dais[i].capture.stream_name =1538 devm_kasprintf(component->dev, GFP_KERNEL,1539 "%s-cpu%d Rx", cname, i);1540 if (!dais[i].capture.stream_name) {1541 ret = -ENOMEM;1542 goto exit;1543 }1544 1545 if (!hda_codec_is_display(codec)) {1546 dais[i].capture.formats = pcm->stream[1].formats;1547 dais[i].capture.subformats = pcm->stream[1].subformats;1548 dais[i].capture.rates = pcm->stream[1].rates;1549 dais[i].capture.channels_min = pcm->stream[1].channels_min;1550 dais[i].capture.channels_max = pcm->stream[1].channels_max;1551 dais[i].capture.sig_bits = pcm->stream[1].maxbps;1552 }1553 }1554 1555 dai = snd_soc_register_dai(component, &dais[i], false);1556 if (!dai) {1557 dev_err(component->dev, "register dai for %s failed\n",1558 pcm->name);1559 ret = -EINVAL;1560 goto exit;1561 }1562 1563 ret = snd_soc_dapm_new_dai_widgets(dapm, dai);1564 if (ret < 0) {1565 dev_err(component->dev, "create widgets failed: %d\n",1566 ret);1567 goto exit;1568 }1569 }1570 1571 ret = avs_component_probe(component);1572exit:1573 if (ret)1574 avs_component_hda_unregister_dais(component);1575 1576 return ret;1577}1578 1579static void avs_component_hda_remove(struct snd_soc_component *component)1580{1581 avs_component_hda_unregister_dais(component);1582 avs_component_remove(component);1583}1584 1585static int avs_component_hda_open(struct snd_soc_component *component,1586 struct snd_pcm_substream *substream)1587{1588 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);1589 1590 if (!rtd->dai_link->no_pcm) {1591 struct snd_pcm_hardware hwparams = avs_pcm_hardware;1592 struct snd_soc_pcm_runtime *be;1593 struct snd_soc_dpcm *dpcm;1594 int dir = substream->stream;1595 1596 /*1597 * Support the DPCM reparenting while still fulfilling expectations of HDAudio1598 * common code - a valid stream pointer at substream->runtime->private_data -1599 * by having all FEs point to the same private data.1600 */1601 for_each_dpcm_be(rtd, dir, dpcm) {1602 struct snd_pcm_substream *be_substream;1603 1604 be = dpcm->be;1605 if (be->dpcm[dir].users == 1)1606 break;1607 1608 be_substream = snd_soc_dpcm_get_substream(be, dir);1609 substream->runtime->private_data = be_substream->runtime->private_data;1610 break;1611 }1612 1613 /* RESUME unsupported for de-coupled HD-Audio capture. */1614 if (dir == SNDRV_PCM_STREAM_CAPTURE)1615 hwparams.info &= ~SNDRV_PCM_INFO_RESUME;1616 1617 return snd_soc_set_runtime_hwparams(substream, &hwparams);1618 }1619 1620 return 0;1621}1622 1623static const struct snd_soc_component_driver avs_hda_component_driver = {1624 .name = "avs-hda-pcm",1625 .probe = avs_component_hda_probe,1626 .remove = avs_component_hda_remove,1627 .suspend = avs_component_suspend,1628 .resume = avs_component_resume,1629 .open = avs_component_hda_open,1630 .pointer = avs_component_pointer,1631 .mmap = avs_component_mmap,1632 .pcm_construct = avs_component_construct,1633 /*1634 * hda platform component's probe() is dependent on1635 * codec->pcm_list_head, it needs to be initialized after codec1636 * component. remove_order is here for completeness sake1637 */1638 .probe_order = SND_SOC_COMP_ORDER_LATE,1639 .remove_order = SND_SOC_COMP_ORDER_EARLY,1640 .module_get_upon_open = 1,1641 .topology_name_prefix = "intel/avs",1642};1643 1644int avs_hda_platform_register(struct avs_dev *adev, const char *name)1645{1646 return avs_soc_component_register(adev->dev, name,1647 &avs_hda_component_driver, NULL, 0);1648}1649