brintos

brintos / linux-shallow public Read only

0
0
Text · 44.7 KiB · 4af8115 Raw
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