brintos

brintos / linux-shallow public Read only

0
0
Text · 32.4 KiB · d914dba Raw
1044 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2//3// tegra186_asrc.c - Tegra186 ASRC driver4//5// Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.6 7#include <linux/clk.h>8#include <linux/delay.h>9#include <linux/device.h>10#include <linux/io.h>11#include <linux/mod_devicetable.h>12#include <linux/module.h>13#include <linux/platform_device.h>14#include <linux/pm_runtime.h>15#include <linux/regmap.h>16#include <sound/core.h>17#include <sound/pcm.h>18#include <sound/pcm_params.h>19#include <sound/soc.h>20 21#include "tegra186_asrc.h"22#include "tegra_cif.h"23 24#define ASRC_STREAM_SOURCE_SELECT(id)					       \25	(TEGRA186_ASRC_CFG + ((id) * TEGRA186_ASRC_STREAM_STRIDE))26 27#define ASRC_STREAM_REG(reg, id) ((reg) + ((id) * TEGRA186_ASRC_STREAM_STRIDE))28 29#define ASRC_STREAM_REG_DEFAULTS(id)					       \30	{ ASRC_STREAM_REG(TEGRA186_ASRC_CFG, id),			       \31	  (((id) + 1) << 4) },						       \32	{ ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_INT_PART, id),		       \33	  0x1 },							       \34	{ ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_FRAC_PART, id),		       \35	  0x0 },							       \36	{ ASRC_STREAM_REG(TEGRA186_ASRC_MUTE_UNMUTE_DURATION, id),	       \37	  0x400 },							       \38	{ ASRC_STREAM_REG(TEGRA186_ASRC_RX_CIF_CTRL, id),		       \39	  0x7500 },							       \40	{ ASRC_STREAM_REG(TEGRA186_ASRC_TX_CIF_CTRL, id),		       \41	  0x7500 }42 43static const struct reg_default tegra186_asrc_reg_defaults[] = {44	ASRC_STREAM_REG_DEFAULTS(0),45	ASRC_STREAM_REG_DEFAULTS(1),46	ASRC_STREAM_REG_DEFAULTS(2),47	ASRC_STREAM_REG_DEFAULTS(3),48	ASRC_STREAM_REG_DEFAULTS(4),49	ASRC_STREAM_REG_DEFAULTS(5),50 51	{ TEGRA186_ASRC_GLOBAL_ENB, 0},52	{ TEGRA186_ASRC_GLOBAL_SOFT_RESET, 0},53	{ TEGRA186_ASRC_GLOBAL_CG, 0x1 },54	{ TEGRA186_ASRC_GLOBAL_CFG, 0x0 },55	{ TEGRA186_ASRC_GLOBAL_SCRATCH_ADDR, 0},56	{ TEGRA186_ASRC_GLOBAL_SCRATCH_CFG, 0x0c207980 },57	{ TEGRA186_ASRC_RATIO_UPD_RX_CIF_CTRL, 0x00115500 },58	{ TEGRA186_ASRC_GLOBAL_INT_MASK, 0x0},59	{ TEGRA186_ASRC_GLOBAL_INT_SET, 0x0},60	{ TEGRA186_ASRC_GLOBAL_INT_CLEAR, 0x0},61	{ TEGRA186_ASRC_GLOBAL_APR_CTRL, 0x0},62	{ TEGRA186_ASRC_GLOBAL_APR_CTRL_ACCESS_CTRL, 0x0},63	{ TEGRA186_ASRC_GLOBAL_DISARM_APR, 0x0},64	{ TEGRA186_ASRC_GLOBAL_DISARM_APR_ACCESS_CTRL, 0x0},65	{ TEGRA186_ASRC_GLOBAL_RATIO_WR_ACCESS, 0x0},66	{ TEGRA186_ASRC_GLOBAL_RATIO_WR_ACCESS_CTRL, 0x0},67	{ TEGRA186_ASRC_CYA, 0x0},68};69 70static void tegra186_asrc_lock_stream(struct tegra186_asrc *asrc,71				      unsigned int id)72{73	regmap_write(asrc->regmap,74		     ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_LOCK_STATUS,75				     id),76		     1);77}78 79static int __maybe_unused tegra186_asrc_runtime_suspend(struct device *dev)80{81	struct tegra186_asrc *asrc = dev_get_drvdata(dev);82 83	regcache_cache_only(asrc->regmap, true);84	regcache_mark_dirty(asrc->regmap);85 86	return 0;87}88 89static int __maybe_unused tegra186_asrc_runtime_resume(struct device *dev)90{91	struct tegra186_asrc *asrc = dev_get_drvdata(dev);92	int id;93 94	regcache_cache_only(asrc->regmap, false);95 96	/*97	 * Below sequence is recommended after a runtime PM cycle.98	 * This otherwise leads to transfer failures. The cache99	 * sync is done after this to restore other settings.100	 */101	regmap_write(asrc->regmap, TEGRA186_ASRC_GLOBAL_SCRATCH_ADDR,102		     TEGRA186_ASRC_ARAM_START_ADDR);103	regmap_write(asrc->regmap, TEGRA186_ASRC_GLOBAL_ENB,104		     TEGRA186_ASRC_GLOBAL_EN);105 106	regcache_sync(asrc->regmap);107 108	for (id = 0; id < TEGRA186_ASRC_STREAM_MAX; id++) {109		if (asrc->lane[id].ratio_source !=110		    TEGRA186_ASRC_RATIO_SOURCE_SW)111			continue;112 113		regmap_write(asrc->regmap,114			ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_INT_PART,115					id),116			asrc->lane[id].int_part);117 118		regmap_write(asrc->regmap,119			ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_FRAC_PART,120					id),121			asrc->lane[id].frac_part);122 123		tegra186_asrc_lock_stream(asrc, id);124	}125 126	return 0;127}128 129static int tegra186_asrc_set_audio_cif(struct tegra186_asrc *asrc,130				       struct snd_pcm_hw_params *params,131				       unsigned int reg)132{133	int channels, audio_bits;134	struct tegra_cif_conf cif_conf;135 136	memset(&cif_conf, 0, sizeof(struct tegra_cif_conf));137 138	channels = params_channels(params);139 140	switch (params_format(params)) {141	case SNDRV_PCM_FORMAT_S16_LE:142		audio_bits = TEGRA_ACIF_BITS_16;143		break;144	case SNDRV_PCM_FORMAT_S24_LE:145	case SNDRV_PCM_FORMAT_S32_LE:146		audio_bits = TEGRA_ACIF_BITS_32;147		break;148	default:149		return -EINVAL;150	}151 152	cif_conf.audio_ch = channels;153	cif_conf.client_ch = channels;154	cif_conf.audio_bits = audio_bits;155	cif_conf.client_bits = TEGRA_ACIF_BITS_24;156 157	tegra_set_cif(asrc->regmap, reg, &cif_conf);158 159	return 0;160}161 162static int tegra186_asrc_in_hw_params(struct snd_pcm_substream *substream,163				      struct snd_pcm_hw_params *params,164				      struct snd_soc_dai *dai)165{166	struct device *dev = dai->dev;167	struct tegra186_asrc *asrc = snd_soc_dai_get_drvdata(dai);168	int ret, id = dai->id;169 170	/* Set input threshold */171	regmap_write(asrc->regmap,172		     ASRC_STREAM_REG(TEGRA186_ASRC_RX_THRESHOLD, dai->id),173		     asrc->lane[id].input_thresh);174 175	ret = tegra186_asrc_set_audio_cif(asrc, params,176		ASRC_STREAM_REG(TEGRA186_ASRC_RX_CIF_CTRL, dai->id));177	if (ret) {178		dev_err(dev, "Can't set ASRC RX%d CIF: %d\n", dai->id, ret);179		return ret;180	}181 182	return ret;183}184 185static int tegra186_asrc_out_hw_params(struct snd_pcm_substream *substream,186				       struct snd_pcm_hw_params *params,187				       struct snd_soc_dai *dai)188{189	struct device *dev = dai->dev;190	struct tegra186_asrc *asrc = snd_soc_dai_get_drvdata(dai);191	int ret, id = dai->id - 7;192 193	 /* Set output threshold */194	regmap_write(asrc->regmap,195		     ASRC_STREAM_REG(TEGRA186_ASRC_TX_THRESHOLD, id),196		     asrc->lane[id].output_thresh);197 198	ret = tegra186_asrc_set_audio_cif(asrc, params,199		ASRC_STREAM_REG(TEGRA186_ASRC_TX_CIF_CTRL, id));200	if (ret) {201		dev_err(dev, "Can't set ASRC TX%d CIF: %d\n", id, ret);202		return ret;203	}204 205	/* Set ENABLE_HW_RATIO_COMP */206	if (asrc->lane[id].hwcomp_disable) {207		regmap_update_bits(asrc->regmap,208			ASRC_STREAM_REG(TEGRA186_ASRC_CFG, id),209			TEGRA186_ASRC_STREAM_ENABLE_HW_RATIO_COMP_MASK,210			TEGRA186_ASRC_STREAM_ENABLE_HW_RATIO_COMP_DISABLE);211	} else {212		regmap_update_bits(asrc->regmap,213			ASRC_STREAM_REG(TEGRA186_ASRC_CFG, id),214			TEGRA186_ASRC_STREAM_ENABLE_HW_RATIO_COMP_MASK,215			TEGRA186_ASRC_STREAM_ENABLE_HW_RATIO_COMP_ENABLE);216 217		regmap_write(asrc->regmap,218			ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_COMP, id),219			TEGRA186_ASRC_STREAM_DEFAULT_HW_COMP_BIAS_VALUE);220	}221 222	/* Set lock */223	regmap_update_bits(asrc->regmap,224			   ASRC_STREAM_REG(TEGRA186_ASRC_CFG, id),225			   1, asrc->lane[id].ratio_source);226 227	if (asrc->lane[id].ratio_source == TEGRA186_ASRC_RATIO_SOURCE_SW) {228		regmap_write(asrc->regmap,229			ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_INT_PART, id),230			asrc->lane[id].int_part);231		regmap_write(asrc->regmap,232			ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_FRAC_PART, id),233			asrc->lane[id].frac_part);234		tegra186_asrc_lock_stream(asrc, id);235	}236 237	return ret;238}239 240static int tegra186_asrc_get_ratio_source(struct snd_kcontrol *kcontrol,241					  struct snd_ctl_elem_value *ucontrol)242{243	struct soc_enum *asrc_private =244		(struct soc_enum  *)kcontrol->private_value;245	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);246	struct tegra186_asrc *asrc = snd_soc_component_get_drvdata(cmpnt);247	unsigned int id = asrc_private->reg / TEGRA186_ASRC_STREAM_STRIDE;248 249	ucontrol->value.enumerated.item[0] = asrc->lane[id].ratio_source;250 251	return 0;252}253 254static int tegra186_asrc_put_ratio_source(struct snd_kcontrol *kcontrol,255					  struct snd_ctl_elem_value *ucontrol)256{257	struct soc_enum *asrc_private =258		(struct soc_enum  *)kcontrol->private_value;259	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);260	struct tegra186_asrc *asrc = snd_soc_component_get_drvdata(cmpnt);261	unsigned int id = asrc_private->reg / TEGRA186_ASRC_STREAM_STRIDE;262	bool change = false;263 264	asrc->lane[id].ratio_source = ucontrol->value.enumerated.item[0];265 266	regmap_update_bits_check(asrc->regmap, asrc_private->reg,267				 TEGRA186_ASRC_STREAM_RATIO_TYPE_MASK,268				 asrc->lane[id].ratio_source,269				 &change);270 271	return change ? 1 : 0;272}273 274static int tegra186_asrc_get_ratio_int(struct snd_kcontrol *kcontrol,275				       struct snd_ctl_elem_value *ucontrol)276{277	struct soc_mixer_control *asrc_private =278		(struct soc_mixer_control *)kcontrol->private_value;279	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);280	struct tegra186_asrc *asrc = snd_soc_component_get_drvdata(cmpnt);281	unsigned int id = asrc_private->reg / TEGRA186_ASRC_STREAM_STRIDE;282 283	regmap_read(asrc->regmap,284		    ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_INT_PART, id),285		    &asrc->lane[id].int_part);286 287	ucontrol->value.integer.value[0] = asrc->lane[id].int_part;288 289	return 0;290}291 292static int tegra186_asrc_put_ratio_int(struct snd_kcontrol *kcontrol,293				       struct snd_ctl_elem_value *ucontrol)294{295	struct soc_mixer_control *asrc_private =296		(struct soc_mixer_control *)kcontrol->private_value;297	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);298	struct tegra186_asrc *asrc = snd_soc_component_get_drvdata(cmpnt);299	unsigned int id = asrc_private->reg / TEGRA186_ASRC_STREAM_STRIDE;300	bool change = false;301 302	if (asrc->lane[id].ratio_source == TEGRA186_ASRC_RATIO_SOURCE_ARAD) {303		dev_err(cmpnt->dev,304			"Lane %d ratio source is ARAD, invalid SW update\n",305			id);306		return -EINVAL;307	}308 309	asrc->lane[id].int_part = ucontrol->value.integer.value[0];310 311	regmap_update_bits_check(asrc->regmap,312				 ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_INT_PART,313						 id),314				 TEGRA186_ASRC_STREAM_RATIO_INT_PART_MASK,315				 asrc->lane[id].int_part, &change);316 317	tegra186_asrc_lock_stream(asrc, id);318 319	return change ? 1 : 0;320}321 322static int tegra186_asrc_get_ratio_frac(struct snd_kcontrol *kcontrol,323					struct snd_ctl_elem_value *ucontrol)324{325	struct soc_mreg_control *asrc_private =326		(struct soc_mreg_control *)kcontrol->private_value;327	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);328	struct tegra186_asrc *asrc = snd_soc_component_get_drvdata(cmpnt);329	unsigned int id = asrc_private->regbase / TEGRA186_ASRC_STREAM_STRIDE;330 331	regmap_read(asrc->regmap,332		    ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_FRAC_PART, id),333		    &asrc->lane[id].frac_part);334 335	ucontrol->value.integer.value[0] = asrc->lane[id].frac_part;336 337	return 0;338}339 340static int tegra186_asrc_put_ratio_frac(struct snd_kcontrol *kcontrol,341					struct snd_ctl_elem_value *ucontrol)342{343	struct soc_mreg_control *asrc_private =344		(struct soc_mreg_control *)kcontrol->private_value;345	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);346	struct tegra186_asrc *asrc = snd_soc_component_get_drvdata(cmpnt);347	unsigned int id = asrc_private->regbase / TEGRA186_ASRC_STREAM_STRIDE;348	bool change = false;349 350	if (asrc->lane[id].ratio_source == TEGRA186_ASRC_RATIO_SOURCE_ARAD) {351		dev_err(cmpnt->dev,352			"Lane %d ratio source is ARAD, invalid SW update\n",353			id);354		return -EINVAL;355	}356 357	asrc->lane[id].frac_part = ucontrol->value.integer.value[0];358 359	regmap_update_bits_check(asrc->regmap,360				 ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_FRAC_PART,361						 id),362				 TEGRA186_ASRC_STREAM_RATIO_FRAC_PART_MASK,363				 asrc->lane[id].frac_part, &change);364 365	tegra186_asrc_lock_stream(asrc, id);366 367	return change ? 1 : 0;368}369 370static int tegra186_asrc_get_hwcomp_disable(struct snd_kcontrol *kcontrol,371					    struct snd_ctl_elem_value *ucontrol)372{373	struct soc_mixer_control *asrc_private =374		(struct soc_mixer_control *)kcontrol->private_value;375	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);376	struct tegra186_asrc *asrc = snd_soc_component_get_drvdata(cmpnt);377	unsigned int id = asrc_private->reg / TEGRA186_ASRC_STREAM_STRIDE;378 379	ucontrol->value.integer.value[0] = asrc->lane[id].hwcomp_disable;380 381	return 0;382}383 384static int tegra186_asrc_put_hwcomp_disable(struct snd_kcontrol *kcontrol,385					    struct snd_ctl_elem_value *ucontrol)386{387	struct soc_mixer_control *asrc_private =388		(struct soc_mixer_control *)kcontrol->private_value;389	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);390	struct tegra186_asrc *asrc = snd_soc_component_get_drvdata(cmpnt);391	unsigned int id = asrc_private->reg / TEGRA186_ASRC_STREAM_STRIDE;392	int value = ucontrol->value.integer.value[0];393 394	if (value == asrc->lane[id].hwcomp_disable)395		return 0;396 397	asrc->lane[id].hwcomp_disable = value;398 399	return 1;400}401 402static int tegra186_asrc_get_input_threshold(struct snd_kcontrol *kcontrol,403					     struct snd_ctl_elem_value *ucontrol)404{405	struct soc_mixer_control *asrc_private =406		(struct soc_mixer_control *)kcontrol->private_value;407	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);408	struct tegra186_asrc *asrc = snd_soc_component_get_drvdata(cmpnt);409	unsigned int id = asrc_private->reg / TEGRA186_ASRC_STREAM_STRIDE;410 411	ucontrol->value.integer.value[0] = (asrc->lane[id].input_thresh & 0x3);412 413	return 0;414}415 416static int tegra186_asrc_put_input_threshold(struct snd_kcontrol *kcontrol,417					     struct snd_ctl_elem_value *ucontrol)418{419	struct soc_mixer_control *asrc_private =420		(struct soc_mixer_control *)kcontrol->private_value;421	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);422	struct tegra186_asrc *asrc = snd_soc_component_get_drvdata(cmpnt);423	unsigned int id = asrc_private->reg / TEGRA186_ASRC_STREAM_STRIDE;424	int value = (asrc->lane[id].input_thresh & ~(0x3)) |425		    ucontrol->value.integer.value[0];426 427	if (value == asrc->lane[id].input_thresh)428		return 0;429 430	asrc->lane[id].input_thresh = value;431 432	return 1;433}434 435static int tegra186_asrc_get_output_threshold(struct snd_kcontrol *kcontrol,436					      struct snd_ctl_elem_value *ucontrol)437{438	struct soc_mixer_control *asrc_private =439		(struct soc_mixer_control *)kcontrol->private_value;440	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);441	struct tegra186_asrc *asrc = snd_soc_component_get_drvdata(cmpnt);442	unsigned int id = asrc_private->reg / TEGRA186_ASRC_STREAM_STRIDE;443 444	ucontrol->value.integer.value[0] = (asrc->lane[id].output_thresh & 0x3);445 446	return 0;447}448 449static int tegra186_asrc_put_output_threshold(struct snd_kcontrol *kcontrol,450					      struct snd_ctl_elem_value *ucontrol)451{452	struct soc_mixer_control *asrc_private =453		(struct soc_mixer_control *)kcontrol->private_value;454	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);455	struct tegra186_asrc *asrc = snd_soc_component_get_drvdata(cmpnt);456	unsigned int id = asrc_private->reg / TEGRA186_ASRC_STREAM_STRIDE;457	int value = (asrc->lane[id].output_thresh & ~(0x3)) |458		    ucontrol->value.integer.value[0];459 460	if (value == asrc->lane[id].output_thresh)461		return 0;462 463	asrc->lane[id].output_thresh = value;464 465	return 1;466}467 468static int tegra186_asrc_widget_event(struct snd_soc_dapm_widget *w,469					struct snd_kcontrol *kcontrol, int event)470{471	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);472	struct tegra186_asrc *asrc = dev_get_drvdata(cmpnt->dev);473	unsigned int id =474		(w->reg - TEGRA186_ASRC_ENABLE) / TEGRA186_ASRC_STREAM_STRIDE;475 476	regmap_write(asrc->regmap,477		     ASRC_STREAM_REG(TEGRA186_ASRC_SOFT_RESET, id),478		     0x1);479 480	return 0;481}482 483static const struct snd_soc_dai_ops tegra186_asrc_in_dai_ops = {484	.hw_params	= tegra186_asrc_in_hw_params,485};486 487static const struct snd_soc_dai_ops tegra186_asrc_out_dai_ops = {488	.hw_params	= tegra186_asrc_out_hw_params,489};490 491#define IN_DAI(id)						\492	{							\493		.name = "ASRC-RX-CIF"#id,			\494		.playback = {					\495			.stream_name = "RX" #id "-CIF-Playback",\496			.channels_min = 1,			\497			.channels_max = 12,			\498			.rates = SNDRV_PCM_RATE_8000_192000,	\499			.formats = SNDRV_PCM_FMTBIT_S8 |	\500				SNDRV_PCM_FMTBIT_S16_LE |	\501				SNDRV_PCM_FMTBIT_S24_LE |	\502				SNDRV_PCM_FMTBIT_S32_LE,	\503		},						\504		.capture = {					\505			.stream_name = "RX" #id "-CIF-Capture", \506			.channels_min = 1,			\507			.channels_max = 12,			\508			.rates = SNDRV_PCM_RATE_8000_192000,	\509			.formats = SNDRV_PCM_FMTBIT_S8 |	\510				SNDRV_PCM_FMTBIT_S16_LE |	\511				SNDRV_PCM_FMTBIT_S24_LE |	\512				SNDRV_PCM_FMTBIT_S32_LE,	\513		},						\514		.ops = &tegra186_asrc_in_dai_ops,		\515	}516 517#define OUT_DAI(id)						\518	{							\519		.name = "ASRC-TX-CIF"#id,			\520		.playback = {					\521			.stream_name = "TX" #id "-CIF-Playback",\522			.channels_min = 1,			\523			.channels_max = 12,			\524			.rates = SNDRV_PCM_RATE_8000_192000,	\525			.formats = SNDRV_PCM_FMTBIT_S8 |	\526				SNDRV_PCM_FMTBIT_S16_LE |	\527				SNDRV_PCM_FMTBIT_S24_LE |	\528				SNDRV_PCM_FMTBIT_S32_LE,	\529		},						\530		.capture = {					\531			.stream_name = "TX" #id "-CIF-Capture",	\532			.channels_min = 1,			\533			.channels_max = 12,			\534			.rates = SNDRV_PCM_RATE_8000_192000,	\535			.formats = SNDRV_PCM_FMTBIT_S8 |	\536				SNDRV_PCM_FMTBIT_S16_LE |	\537				SNDRV_PCM_FMTBIT_S24_LE |	\538				SNDRV_PCM_FMTBIT_S32_LE,	\539		},						\540		.ops = &tegra186_asrc_out_dai_ops,		\541	}542 543static struct snd_soc_dai_driver tegra186_asrc_dais[] = {544	/* ASRC Input */545	IN_DAI(1),546	IN_DAI(2),547	IN_DAI(3),548	IN_DAI(4),549	IN_DAI(5),550	IN_DAI(6),551	IN_DAI(7),552	/* ASRC Output */553	OUT_DAI(1),554	OUT_DAI(2),555	OUT_DAI(3),556	OUT_DAI(4),557	OUT_DAI(5),558	OUT_DAI(6),559};560 561static const struct snd_soc_dapm_widget tegra186_asrc_widgets[] = {562	SND_SOC_DAPM_AIF_IN("RX1", NULL, 0, SND_SOC_NOPM, 0, 0),563	SND_SOC_DAPM_AIF_IN("RX2", NULL, 0, SND_SOC_NOPM, 0, 0),564	SND_SOC_DAPM_AIF_IN("RX3", NULL, 0, SND_SOC_NOPM, 0, 0),565	SND_SOC_DAPM_AIF_IN("RX4", NULL, 0, SND_SOC_NOPM, 0, 0),566	SND_SOC_DAPM_AIF_IN("RX5", NULL, 0, SND_SOC_NOPM, 0, 0),567	SND_SOC_DAPM_AIF_IN("RX6", NULL, 0, SND_SOC_NOPM, 0, 0),568	SND_SOC_DAPM_AIF_IN("RX7", NULL, 0, SND_SOC_NOPM, 0, 0),569 570	SND_SOC_DAPM_AIF_OUT_E("TX1", NULL, 0,571			       ASRC_STREAM_REG(TEGRA186_ASRC_ENABLE, 0),572			       TEGRA186_ASRC_STREAM_EN_SHIFT, 0,573			       tegra186_asrc_widget_event,574			       SND_SOC_DAPM_POST_PMD),575 576	SND_SOC_DAPM_AIF_OUT_E("TX2", NULL, 0,577			       ASRC_STREAM_REG(TEGRA186_ASRC_ENABLE, 1),578			       TEGRA186_ASRC_STREAM_EN_SHIFT, 0,579			       tegra186_asrc_widget_event,580			       SND_SOC_DAPM_POST_PMD),581 582	SND_SOC_DAPM_AIF_OUT_E("TX3", NULL, 0,583			       ASRC_STREAM_REG(TEGRA186_ASRC_ENABLE, 2),584			       TEGRA186_ASRC_STREAM_EN_SHIFT, 0,585			       tegra186_asrc_widget_event,586			       SND_SOC_DAPM_POST_PMD),587 588	SND_SOC_DAPM_AIF_OUT_E("TX4", NULL, 0,589			       ASRC_STREAM_REG(TEGRA186_ASRC_ENABLE, 3),590			       TEGRA186_ASRC_STREAM_EN_SHIFT, 0,591			       tegra186_asrc_widget_event,592			       SND_SOC_DAPM_POST_PMD),593 594	SND_SOC_DAPM_AIF_OUT_E("TX5", NULL, 0,595			       ASRC_STREAM_REG(TEGRA186_ASRC_ENABLE, 4),596			       TEGRA186_ASRC_STREAM_EN_SHIFT, 0,597			       tegra186_asrc_widget_event,598			       SND_SOC_DAPM_POST_PMD),599 600	SND_SOC_DAPM_AIF_OUT_E("TX6", NULL, 0,601			       ASRC_STREAM_REG(TEGRA186_ASRC_ENABLE, 5),602			       TEGRA186_ASRC_STREAM_EN_SHIFT, 0,603			       tegra186_asrc_widget_event,604			       SND_SOC_DAPM_POST_PMD),605 606	SND_SOC_DAPM_SPK("Depacketizer", NULL),607};608 609#define ASRC_STREAM_ROUTE(id, sname)					   \610	{ "RX" #id " XBAR-" sname,      NULL,   "RX" #id " XBAR-TX" },	   \611	{ "RX" #id "-CIF-" sname,       NULL,   "RX" #id " XBAR-" sname }, \612	{ "RX" #id,                     NULL,   "RX" #id "-CIF-" sname },  \613	{ "TX" #id,			NULL,   "RX" #id },		   \614	{ "TX" #id "-CIF-" sname,       NULL,   "TX" #id },		   \615	{ "TX" #id " XBAR-" sname,      NULL,   "TX" #id "-CIF-" sname },  \616	{ "TX" #id " XBAR-RX",          NULL,   "TX" #id " XBAR-" sname },617 618#define ASRC_ROUTE(id)							   \619	ASRC_STREAM_ROUTE(id, "Playback")				   \620	ASRC_STREAM_ROUTE(id, "Capture")621 622#define ASRC_RATIO_ROUTE(sname)						   \623	{ "RX7 XBAR-" sname,		NULL,	"RX7 XBAR-TX" },	   \624	{ "RX7-CIF-" sname,		NULL,	"RX7 XBAR-" sname },	   \625	{ "RX7",			NULL,	"RX7-CIF-" sname },	   \626	{ "Depacketizer",		NULL,	"RX7" },627 628static const struct snd_soc_dapm_route tegra186_asrc_routes[] = {629	ASRC_ROUTE(1)630	ASRC_ROUTE(2)631	ASRC_ROUTE(3)632	ASRC_ROUTE(4)633	ASRC_ROUTE(5)634	ASRC_ROUTE(6)635	ASRC_RATIO_ROUTE("Playback")636	ASRC_RATIO_ROUTE("Capture")637};638 639static const char * const tegra186_asrc_ratio_source_text[] = {640	"ARAD",641	"SW",642};643 644#define ASRC_SOURCE_DECL(name, id)					\645	static const struct soc_enum name =				\646		SOC_ENUM_SINGLE(ASRC_STREAM_SOURCE_SELECT(id),		\647				0, 2, tegra186_asrc_ratio_source_text)648 649ASRC_SOURCE_DECL(src_select1, 0);650ASRC_SOURCE_DECL(src_select2, 1);651ASRC_SOURCE_DECL(src_select3, 2);652ASRC_SOURCE_DECL(src_select4, 3);653ASRC_SOURCE_DECL(src_select5, 4);654ASRC_SOURCE_DECL(src_select6, 5);655 656#define SOC_SINGLE_EXT_FRAC(xname, xregbase, xmax, xget, xput)		\657{									\658	.iface	= SNDRV_CTL_ELEM_IFACE_MIXER,				\659	.name	= (xname),						\660	.info	= snd_soc_info_xr_sx,					\661	.get	= xget,							\662	.put	= xput,							\663									\664	.private_value = (unsigned long)&(struct soc_mreg_control)	\665	{								\666		.regbase	= xregbase,				\667		.regcount	= 1,					\668		.nbits		= 32,					\669		.invert		= 0,					\670		.min		= 0,					\671		.max		= xmax					\672	}								\673}674 675static const struct snd_kcontrol_new tegra186_asrc_controls[] = {676	/* Controls for integer part of ratio */677	SOC_SINGLE_EXT("Ratio1 Integer Part",678		       ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_INT_PART, 0),679		       0, TEGRA186_ASRC_STREAM_RATIO_INT_PART_MASK, 0,680		       tegra186_asrc_get_ratio_int,681		       tegra186_asrc_put_ratio_int),682 683	SOC_SINGLE_EXT("Ratio2 Integer Part",684		       ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_INT_PART, 1),685		       0, TEGRA186_ASRC_STREAM_RATIO_INT_PART_MASK, 0,686		       tegra186_asrc_get_ratio_int,687		       tegra186_asrc_put_ratio_int),688 689	SOC_SINGLE_EXT("Ratio3 Integer Part",690		       ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_INT_PART, 2),691		       0, TEGRA186_ASRC_STREAM_RATIO_INT_PART_MASK, 0,692		       tegra186_asrc_get_ratio_int,693		       tegra186_asrc_put_ratio_int),694 695	SOC_SINGLE_EXT("Ratio4 Integer Part",696		       ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_INT_PART, 3),697		       0, TEGRA186_ASRC_STREAM_RATIO_INT_PART_MASK, 0,698		       tegra186_asrc_get_ratio_int,699		       tegra186_asrc_put_ratio_int),700 701	SOC_SINGLE_EXT("Ratio5 Integer Part",702		       ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_INT_PART, 4),703		       0, TEGRA186_ASRC_STREAM_RATIO_INT_PART_MASK, 0,704		       tegra186_asrc_get_ratio_int,705		       tegra186_asrc_put_ratio_int),706 707	SOC_SINGLE_EXT("Ratio6 Integer Part",708		       ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_INT_PART, 5),709		       0, TEGRA186_ASRC_STREAM_RATIO_INT_PART_MASK, 0,710		       tegra186_asrc_get_ratio_int,711		       tegra186_asrc_put_ratio_int),712 713	/* Controls for fractional part of ratio */714	SOC_SINGLE_EXT_FRAC("Ratio1 Fractional Part",715			    ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_FRAC_PART, 0),716			    TEGRA186_ASRC_STREAM_RATIO_FRAC_PART_MASK,717			    tegra186_asrc_get_ratio_frac,718			    tegra186_asrc_put_ratio_frac),719 720	SOC_SINGLE_EXT_FRAC("Ratio2 Fractional Part",721			    ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_FRAC_PART, 1),722			    TEGRA186_ASRC_STREAM_RATIO_FRAC_PART_MASK,723			    tegra186_asrc_get_ratio_frac,724			    tegra186_asrc_put_ratio_frac),725 726	SOC_SINGLE_EXT_FRAC("Ratio3 Fractional Part",727			    ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_FRAC_PART, 2),728			    TEGRA186_ASRC_STREAM_RATIO_FRAC_PART_MASK,729			    tegra186_asrc_get_ratio_frac,730			    tegra186_asrc_put_ratio_frac),731 732	SOC_SINGLE_EXT_FRAC("Ratio4 Fractional Part",733			    ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_FRAC_PART, 3),734			    TEGRA186_ASRC_STREAM_RATIO_FRAC_PART_MASK,735			    tegra186_asrc_get_ratio_frac,736			    tegra186_asrc_put_ratio_frac),737 738	SOC_SINGLE_EXT_FRAC("Ratio5 Fractional Part",739			    ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_FRAC_PART, 4),740			    TEGRA186_ASRC_STREAM_RATIO_FRAC_PART_MASK,741			    tegra186_asrc_get_ratio_frac,742			    tegra186_asrc_put_ratio_frac),743 744	SOC_SINGLE_EXT_FRAC("Ratio6 Fractional Part",745			    ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_FRAC_PART, 5),746			    TEGRA186_ASRC_STREAM_RATIO_FRAC_PART_MASK,747			    tegra186_asrc_get_ratio_frac,748			    tegra186_asrc_put_ratio_frac),749 750	/* Source of ratio provider */751	SOC_ENUM_EXT("Ratio1 Source", src_select1,752		     tegra186_asrc_get_ratio_source,753		     tegra186_asrc_put_ratio_source),754 755	SOC_ENUM_EXT("Ratio2 Source", src_select2,756		     tegra186_asrc_get_ratio_source,757		     tegra186_asrc_put_ratio_source),758 759	SOC_ENUM_EXT("Ratio3 Source", src_select3,760		     tegra186_asrc_get_ratio_source,761		     tegra186_asrc_put_ratio_source),762 763	SOC_ENUM_EXT("Ratio4 Source", src_select4,764		     tegra186_asrc_get_ratio_source,765		     tegra186_asrc_put_ratio_source),766 767	SOC_ENUM_EXT("Ratio5 Source", src_select5,768		     tegra186_asrc_get_ratio_source,769		     tegra186_asrc_put_ratio_source),770 771	SOC_ENUM_EXT("Ratio6 Source", src_select6,772		     tegra186_asrc_get_ratio_source,773		     tegra186_asrc_put_ratio_source),774 775	/* Disable HW managed overflow/underflow issue at input and output */776	SOC_SINGLE_EXT("Stream1 HW Component Disable",777		       ASRC_STREAM_REG(TEGRA186_ASRC_CFG, 0), 0, 1, 0,778		       tegra186_asrc_get_hwcomp_disable,779		       tegra186_asrc_put_hwcomp_disable),780 781	SOC_SINGLE_EXT("Stream2 HW Component Disable",782		       ASRC_STREAM_REG(TEGRA186_ASRC_CFG, 1), 0, 1, 0,783		       tegra186_asrc_get_hwcomp_disable,784		       tegra186_asrc_put_hwcomp_disable),785 786	SOC_SINGLE_EXT("Stream3 HW Component Disable",787		       ASRC_STREAM_REG(TEGRA186_ASRC_CFG, 2), 0, 1, 0,788		       tegra186_asrc_get_hwcomp_disable,789		       tegra186_asrc_put_hwcomp_disable),790 791	SOC_SINGLE_EXT("Stream4 HW Component Disable",792		       ASRC_STREAM_REG(TEGRA186_ASRC_CFG, 3), 0, 1, 0,793		       tegra186_asrc_get_hwcomp_disable,794		       tegra186_asrc_put_hwcomp_disable),795 796	SOC_SINGLE_EXT("Stream5 HW Component Disable",797		       ASRC_STREAM_REG(TEGRA186_ASRC_CFG, 4), 0, 1, 0,798		       tegra186_asrc_get_hwcomp_disable,799		       tegra186_asrc_put_hwcomp_disable),800 801	SOC_SINGLE_EXT("Stream6 HW Component Disable",802		       ASRC_STREAM_REG(TEGRA186_ASRC_CFG, 5), 0, 1, 0,803		       tegra186_asrc_get_hwcomp_disable,804		       tegra186_asrc_put_hwcomp_disable),805 806	/* Input threshold for watermark fields */807	SOC_SINGLE_EXT("Stream1 Input Threshold",808		       ASRC_STREAM_REG(TEGRA186_ASRC_RX_THRESHOLD, 0), 0, 3, 0,809		       tegra186_asrc_get_input_threshold,810		       tegra186_asrc_put_input_threshold),811 812	SOC_SINGLE_EXT("Stream2 Input Threshold",813		       ASRC_STREAM_REG(TEGRA186_ASRC_RX_THRESHOLD, 1), 0, 3, 0,814		       tegra186_asrc_get_input_threshold,815		       tegra186_asrc_put_input_threshold),816 817	SOC_SINGLE_EXT("Stream3 Input Threshold",818		       ASRC_STREAM_REG(TEGRA186_ASRC_RX_THRESHOLD, 2), 0, 3, 0,819		       tegra186_asrc_get_input_threshold,820		       tegra186_asrc_put_input_threshold),821 822	SOC_SINGLE_EXT("Stream4 Input Threshold",823		       ASRC_STREAM_REG(TEGRA186_ASRC_RX_THRESHOLD, 3), 0, 3, 0,824		       tegra186_asrc_get_input_threshold,825		       tegra186_asrc_put_input_threshold),826 827	SOC_SINGLE_EXT("Stream5 Input Threshold",828		       ASRC_STREAM_REG(TEGRA186_ASRC_RX_THRESHOLD, 4), 0, 3, 0,829		       tegra186_asrc_get_input_threshold,830		       tegra186_asrc_put_input_threshold),831 832	SOC_SINGLE_EXT("Stream6 Input Threshold",833		       ASRC_STREAM_REG(TEGRA186_ASRC_RX_THRESHOLD, 4), 0, 3, 0,834		       tegra186_asrc_get_input_threshold,835		       tegra186_asrc_put_input_threshold),836 837	/* Output threshold for watermark fields */838	SOC_SINGLE_EXT("Stream1 Output Threshold",839		       ASRC_STREAM_REG(TEGRA186_ASRC_TX_THRESHOLD, 0), 0, 3, 0,840		       tegra186_asrc_get_output_threshold,841		       tegra186_asrc_put_output_threshold),842 843	SOC_SINGLE_EXT("Stream2 Output Threshold",844		       ASRC_STREAM_REG(TEGRA186_ASRC_TX_THRESHOLD, 1), 0, 3, 0,845		       tegra186_asrc_get_output_threshold,846		       tegra186_asrc_put_output_threshold),847 848	SOC_SINGLE_EXT("Stream3 Output Threshold",849		       ASRC_STREAM_REG(TEGRA186_ASRC_TX_THRESHOLD, 2), 0, 3, 0,850		       tegra186_asrc_get_output_threshold,851		       tegra186_asrc_put_output_threshold),852 853	SOC_SINGLE_EXT("Stream4 Output Threshold",854		       ASRC_STREAM_REG(TEGRA186_ASRC_TX_THRESHOLD, 3), 0, 3, 0,855		       tegra186_asrc_get_output_threshold,856		       tegra186_asrc_put_output_threshold),857 858	SOC_SINGLE_EXT("Stream5 Output Threshold",859		       ASRC_STREAM_REG(TEGRA186_ASRC_TX_THRESHOLD, 4), 0, 3, 0,860		       tegra186_asrc_get_output_threshold,861		       tegra186_asrc_put_output_threshold),862 863	SOC_SINGLE_EXT("Stream6 Output Threshold",864		       ASRC_STREAM_REG(TEGRA186_ASRC_TX_THRESHOLD, 5), 0, 3, 0,865		       tegra186_asrc_get_output_threshold,866		       tegra186_asrc_put_output_threshold),867};868 869static const struct snd_soc_component_driver tegra186_asrc_cmpnt = {870	.dapm_widgets		= tegra186_asrc_widgets,871	.num_dapm_widgets	= ARRAY_SIZE(tegra186_asrc_widgets),872	.dapm_routes		= tegra186_asrc_routes,873	.num_dapm_routes	= ARRAY_SIZE(tegra186_asrc_routes),874	.controls		= tegra186_asrc_controls,875	.num_controls		= ARRAY_SIZE(tegra186_asrc_controls),876};877 878static bool tegra186_asrc_wr_reg(struct device *dev, unsigned int reg)879{880	if (reg < TEGRA186_ASRC_STREAM_LIMIT)881		reg %= TEGRA186_ASRC_STREAM_STRIDE;882 883	switch (reg) {884	case TEGRA186_ASRC_CFG ... TEGRA186_ASRC_RATIO_COMP:885	case TEGRA186_ASRC_RX_CIF_CTRL:886	case TEGRA186_ASRC_TX_CIF_CTRL:887	case TEGRA186_ASRC_ENABLE:888	case TEGRA186_ASRC_SOFT_RESET:889	case TEGRA186_ASRC_GLOBAL_ENB ... TEGRA186_ASRC_RATIO_UPD_RX_CIF_CTRL:890	case TEGRA186_ASRC_GLOBAL_INT_MASK ... TEGRA186_ASRC_GLOBAL_INT_CLEAR:891	case TEGRA186_ASRC_GLOBAL_APR_CTRL ... TEGRA186_ASRC_CYA:892		return true;893	default:894		return false;895	}896}897 898static bool tegra186_asrc_rd_reg(struct device *dev, unsigned int reg)899{900	if (reg < TEGRA186_ASRC_STREAM_LIMIT)901		reg %= TEGRA186_ASRC_STREAM_STRIDE;902 903	if (tegra186_asrc_wr_reg(dev, reg))904		return true;905 906	switch (reg) {907	case TEGRA186_ASRC_RX_STATUS:908	case TEGRA186_ASRC_TX_STATUS:909	case TEGRA186_ASRC_STATUS ... TEGRA186_ASRC_OUTSAMPLEBUF_CFG:910	case TEGRA186_ASRC_RATIO_UPD_RX_STATUS:911	case TEGRA186_ASRC_GLOBAL_STATUS ... TEGRA186_ASRC_GLOBAL_INT_STATUS:912	case TEGRA186_ASRC_GLOBAL_TRANSFER_ERROR_LOG:913		return true;914	default:915		return false;916	}917}918 919static bool tegra186_asrc_volatile_reg(struct device *dev, unsigned int reg)920{921	if (reg < TEGRA186_ASRC_STREAM_LIMIT)922		reg %= TEGRA186_ASRC_STREAM_STRIDE;923 924	switch (reg) {925	case TEGRA186_ASRC_RX_STATUS:926	case TEGRA186_ASRC_TX_STATUS:927	case TEGRA186_ASRC_SOFT_RESET:928	case TEGRA186_ASRC_RATIO_INT_PART:929	case TEGRA186_ASRC_RATIO_FRAC_PART:930	case TEGRA186_ASRC_STATUS:931	case TEGRA186_ASRC_RATIO_LOCK_STATUS:932	case TEGRA186_ASRC_RATIO_UPD_RX_STATUS:933	case TEGRA186_ASRC_GLOBAL_SOFT_RESET:934	case TEGRA186_ASRC_GLOBAL_STATUS:935	case TEGRA186_ASRC_GLOBAL_STREAM_ENABLE_STATUS:936	case TEGRA186_ASRC_GLOBAL_INT_STATUS:937	case TEGRA186_ASRC_GLOBAL_TRANSFER_ERROR_LOG:938		return true;939	default:940		return false;941	}942}943 944static const struct regmap_config tegra186_asrc_regmap_config = {945	.reg_bits		= 32,946	.reg_stride		= 4,947	.val_bits		= 32,948	.max_register		= TEGRA186_ASRC_CYA,949	.writeable_reg		= tegra186_asrc_wr_reg,950	.readable_reg		= tegra186_asrc_rd_reg,951	.volatile_reg		= tegra186_asrc_volatile_reg,952	.reg_defaults		= tegra186_asrc_reg_defaults,953	.num_reg_defaults	= ARRAY_SIZE(tegra186_asrc_reg_defaults),954	.cache_type		= REGCACHE_FLAT,955};956 957static const struct of_device_id tegra186_asrc_of_match[] = {958	{ .compatible = "nvidia,tegra186-asrc" },959	{},960};961MODULE_DEVICE_TABLE(of, tegra186_asrc_of_match);962 963static int tegra186_asrc_platform_probe(struct platform_device *pdev)964{965	struct device *dev = &pdev->dev;966	struct tegra186_asrc *asrc;967	void __iomem *regs;968	unsigned int i;969	int err;970 971	asrc = devm_kzalloc(dev, sizeof(*asrc), GFP_KERNEL);972	if (!asrc)973		return -ENOMEM;974 975	dev_set_drvdata(dev, asrc);976 977	regs = devm_platform_ioremap_resource(pdev, 0);978	if (IS_ERR(regs))979		return PTR_ERR(regs);980 981	asrc->regmap = devm_regmap_init_mmio(dev, regs,982					     &tegra186_asrc_regmap_config);983	if (IS_ERR(asrc->regmap)) {984		dev_err(dev, "regmap init failed\n");985		return PTR_ERR(asrc->regmap);986	}987 988	regcache_cache_only(asrc->regmap, true);989 990	regmap_write(asrc->regmap, TEGRA186_ASRC_GLOBAL_CFG,991		     TEGRA186_ASRC_GLOBAL_CFG_FRAC_32BIT_PRECISION);992 993	/* Initialize default output srate */994	for (i = 0; i < TEGRA186_ASRC_STREAM_MAX; i++) {995		asrc->lane[i].ratio_source = TEGRA186_ASRC_RATIO_SOURCE_SW;996		asrc->lane[i].int_part = 1;997		asrc->lane[i].frac_part = 0;998		asrc->lane[i].hwcomp_disable = 0;999		asrc->lane[i].input_thresh =1000			TEGRA186_ASRC_STREAM_DEFAULT_INPUT_HW_COMP_THRESH_CFG;1001		asrc->lane[i].output_thresh =1002			TEGRA186_ASRC_STREAM_DEFAULT_OUTPUT_HW_COMP_THRESH_CFG;1003	}1004 1005	err = devm_snd_soc_register_component(dev, &tegra186_asrc_cmpnt,1006					      tegra186_asrc_dais,1007					      ARRAY_SIZE(tegra186_asrc_dais));1008	if (err) {1009		dev_err(dev, "can't register ASRC component, err: %d\n", err);1010		return err;1011	}1012 1013	pm_runtime_enable(dev);1014 1015	return 0;1016}1017 1018static void tegra186_asrc_platform_remove(struct platform_device *pdev)1019{1020	pm_runtime_disable(&pdev->dev);1021}1022 1023static const struct dev_pm_ops tegra186_asrc_pm_ops = {1024	SET_RUNTIME_PM_OPS(tegra186_asrc_runtime_suspend,1025			   tegra186_asrc_runtime_resume, NULL)1026	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,1027				pm_runtime_force_resume)1028};1029 1030static struct platform_driver tegra186_asrc_driver = {1031	.driver = {1032		.name = "tegra186-asrc",1033		.of_match_table = tegra186_asrc_of_match,1034		.pm = &tegra186_asrc_pm_ops,1035	},1036	.probe = tegra186_asrc_platform_probe,1037	.remove = tegra186_asrc_platform_remove,1038};1039module_platform_driver(tegra186_asrc_driver)1040 1041MODULE_AUTHOR("Junghyun Kim <juskim@nvidia.com>");1042MODULE_DESCRIPTION("Tegra186 ASRC ASoC driver");1043MODULE_LICENSE("GPL");1044