brintos

brintos / linux-shallow public Read only

0
0
Text · 26.2 KiB · a866aeb Raw
871 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2//3// tegra210_admaif.c - Tegra ADMAIF driver4//5// Copyright (c) 2020 NVIDIA CORPORATION.  All rights reserved.6 7#include <linux/clk.h>8#include <linux/device.h>9#include <linux/module.h>10#include <linux/of_platform.h>11#include <linux/platform_device.h>12#include <linux/pm_runtime.h>13#include <linux/regmap.h>14#include <sound/pcm_params.h>15#include <sound/soc.h>16#include "tegra210_admaif.h"17#include "tegra_cif.h"18#include "tegra_pcm.h"19 20#define CH_REG(offset, reg, id)						       \21	((offset) + (reg) + (TEGRA_ADMAIF_CHANNEL_REG_STRIDE * (id)))22 23#define CH_TX_REG(reg, id) CH_REG(admaif->soc_data->tx_base, reg, id)24 25#define CH_RX_REG(reg, id) CH_REG(admaif->soc_data->rx_base, reg, id)26 27#define REG_DEFAULTS(id, rx_ctrl, tx_ctrl, tx_base, rx_base)		       \28	{ CH_REG(rx_base, TEGRA_ADMAIF_RX_INT_MASK, id), 0x00000001 },	       \29	{ CH_REG(rx_base, TEGRA_ADMAIF_CH_ACIF_RX_CTRL, id), 0x00007700 },     \30	{ CH_REG(rx_base, TEGRA_ADMAIF_RX_FIFO_CTRL, id), rx_ctrl },	       \31	{ CH_REG(tx_base, TEGRA_ADMAIF_TX_INT_MASK, id), 0x00000001 },	       \32	{ CH_REG(tx_base, TEGRA_ADMAIF_CH_ACIF_TX_CTRL, id), 0x00007700 },     \33	{ CH_REG(tx_base, TEGRA_ADMAIF_TX_FIFO_CTRL, id), tx_ctrl }34 35#define ADMAIF_REG_DEFAULTS(id, chip)					       \36	REG_DEFAULTS((id) - 1,						       \37		chip ## _ADMAIF_RX ## id ## _FIFO_CTRL_REG_DEFAULT,	       \38		chip ## _ADMAIF_TX ## id ## _FIFO_CTRL_REG_DEFAULT,	       \39		chip ## _ADMAIF_TX_BASE,				       \40		chip ## _ADMAIF_RX_BASE)41 42static const struct reg_default tegra186_admaif_reg_defaults[] = {43	{(TEGRA_ADMAIF_GLOBAL_CG_0 + TEGRA186_ADMAIF_GLOBAL_BASE), 0x00000003},44	ADMAIF_REG_DEFAULTS(1, TEGRA186),45	ADMAIF_REG_DEFAULTS(2, TEGRA186),46	ADMAIF_REG_DEFAULTS(3, TEGRA186),47	ADMAIF_REG_DEFAULTS(4, TEGRA186),48	ADMAIF_REG_DEFAULTS(5, TEGRA186),49	ADMAIF_REG_DEFAULTS(6, TEGRA186),50	ADMAIF_REG_DEFAULTS(7, TEGRA186),51	ADMAIF_REG_DEFAULTS(8, TEGRA186),52	ADMAIF_REG_DEFAULTS(9, TEGRA186),53	ADMAIF_REG_DEFAULTS(10, TEGRA186),54	ADMAIF_REG_DEFAULTS(11, TEGRA186),55	ADMAIF_REG_DEFAULTS(12, TEGRA186),56	ADMAIF_REG_DEFAULTS(13, TEGRA186),57	ADMAIF_REG_DEFAULTS(14, TEGRA186),58	ADMAIF_REG_DEFAULTS(15, TEGRA186),59	ADMAIF_REG_DEFAULTS(16, TEGRA186),60	ADMAIF_REG_DEFAULTS(17, TEGRA186),61	ADMAIF_REG_DEFAULTS(18, TEGRA186),62	ADMAIF_REG_DEFAULTS(19, TEGRA186),63	ADMAIF_REG_DEFAULTS(20, TEGRA186)64};65 66static const struct reg_default tegra210_admaif_reg_defaults[] = {67	{(TEGRA_ADMAIF_GLOBAL_CG_0 + TEGRA210_ADMAIF_GLOBAL_BASE), 0x00000003},68	ADMAIF_REG_DEFAULTS(1, TEGRA210),69	ADMAIF_REG_DEFAULTS(2, TEGRA210),70	ADMAIF_REG_DEFAULTS(3, TEGRA210),71	ADMAIF_REG_DEFAULTS(4, TEGRA210),72	ADMAIF_REG_DEFAULTS(5, TEGRA210),73	ADMAIF_REG_DEFAULTS(6, TEGRA210),74	ADMAIF_REG_DEFAULTS(7, TEGRA210),75	ADMAIF_REG_DEFAULTS(8, TEGRA210),76	ADMAIF_REG_DEFAULTS(9, TEGRA210),77	ADMAIF_REG_DEFAULTS(10, TEGRA210)78};79 80static bool tegra_admaif_wr_reg(struct device *dev, unsigned int reg)81{82	struct tegra_admaif *admaif = dev_get_drvdata(dev);83	unsigned int ch_stride = TEGRA_ADMAIF_CHANNEL_REG_STRIDE;84	unsigned int num_ch = admaif->soc_data->num_ch;85	unsigned int rx_base = admaif->soc_data->rx_base;86	unsigned int tx_base = admaif->soc_data->tx_base;87	unsigned int global_base = admaif->soc_data->global_base;88	unsigned int reg_max = admaif->soc_data->regmap_conf->max_register;89	unsigned int rx_max = rx_base + (num_ch * ch_stride);90	unsigned int tx_max = tx_base + (num_ch * ch_stride);91 92	if ((reg >= rx_base) && (reg < rx_max)) {93		reg = (reg - rx_base) % ch_stride;94		if ((reg == TEGRA_ADMAIF_RX_ENABLE) ||95		    (reg == TEGRA_ADMAIF_RX_FIFO_CTRL) ||96		    (reg == TEGRA_ADMAIF_RX_SOFT_RESET) ||97		    (reg == TEGRA_ADMAIF_CH_ACIF_RX_CTRL))98			return true;99	} else if ((reg >= tx_base) && (reg < tx_max)) {100		reg = (reg - tx_base) % ch_stride;101		if ((reg == TEGRA_ADMAIF_TX_ENABLE) ||102		    (reg == TEGRA_ADMAIF_TX_FIFO_CTRL) ||103		    (reg == TEGRA_ADMAIF_TX_SOFT_RESET) ||104		    (reg == TEGRA_ADMAIF_CH_ACIF_TX_CTRL))105			return true;106	} else if ((reg >= global_base) && (reg < reg_max)) {107		if (reg == (global_base + TEGRA_ADMAIF_GLOBAL_ENABLE))108			return true;109	}110 111	return false;112}113 114static bool tegra_admaif_rd_reg(struct device *dev, unsigned int reg)115{116	struct tegra_admaif *admaif = dev_get_drvdata(dev);117	unsigned int ch_stride = TEGRA_ADMAIF_CHANNEL_REG_STRIDE;118	unsigned int num_ch = admaif->soc_data->num_ch;119	unsigned int rx_base = admaif->soc_data->rx_base;120	unsigned int tx_base = admaif->soc_data->tx_base;121	unsigned int global_base = admaif->soc_data->global_base;122	unsigned int reg_max = admaif->soc_data->regmap_conf->max_register;123	unsigned int rx_max = rx_base + (num_ch * ch_stride);124	unsigned int tx_max = tx_base + (num_ch * ch_stride);125 126	if ((reg >= rx_base) && (reg < rx_max)) {127		reg = (reg - rx_base) % ch_stride;128		if ((reg == TEGRA_ADMAIF_RX_ENABLE) ||129		    (reg == TEGRA_ADMAIF_RX_STATUS) ||130		    (reg == TEGRA_ADMAIF_RX_INT_STATUS) ||131		    (reg == TEGRA_ADMAIF_RX_FIFO_CTRL) ||132		    (reg == TEGRA_ADMAIF_RX_SOFT_RESET) ||133		    (reg == TEGRA_ADMAIF_CH_ACIF_RX_CTRL))134			return true;135	} else if ((reg >= tx_base) && (reg < tx_max)) {136		reg = (reg - tx_base) % ch_stride;137		if ((reg == TEGRA_ADMAIF_TX_ENABLE) ||138		    (reg == TEGRA_ADMAIF_TX_STATUS) ||139		    (reg == TEGRA_ADMAIF_TX_INT_STATUS) ||140		    (reg == TEGRA_ADMAIF_TX_FIFO_CTRL) ||141		    (reg == TEGRA_ADMAIF_TX_SOFT_RESET) ||142		    (reg == TEGRA_ADMAIF_CH_ACIF_TX_CTRL))143			return true;144	} else if ((reg >= global_base) && (reg < reg_max)) {145		if ((reg == (global_base + TEGRA_ADMAIF_GLOBAL_ENABLE)) ||146		    (reg == (global_base + TEGRA_ADMAIF_GLOBAL_CG_0)) ||147		    (reg == (global_base + TEGRA_ADMAIF_GLOBAL_STATUS)) ||148		    (reg == (global_base +149				TEGRA_ADMAIF_GLOBAL_RX_ENABLE_STATUS)) ||150		    (reg == (global_base +151				TEGRA_ADMAIF_GLOBAL_TX_ENABLE_STATUS)))152			return true;153	}154 155	return false;156}157 158static bool tegra_admaif_volatile_reg(struct device *dev, unsigned int reg)159{160	struct tegra_admaif *admaif = dev_get_drvdata(dev);161	unsigned int ch_stride = TEGRA_ADMAIF_CHANNEL_REG_STRIDE;162	unsigned int num_ch = admaif->soc_data->num_ch;163	unsigned int rx_base = admaif->soc_data->rx_base;164	unsigned int tx_base = admaif->soc_data->tx_base;165	unsigned int global_base = admaif->soc_data->global_base;166	unsigned int reg_max = admaif->soc_data->regmap_conf->max_register;167	unsigned int rx_max = rx_base + (num_ch * ch_stride);168	unsigned int tx_max = tx_base + (num_ch * ch_stride);169 170	if ((reg >= rx_base) && (reg < rx_max)) {171		reg = (reg - rx_base) % ch_stride;172		if ((reg == TEGRA_ADMAIF_RX_ENABLE) ||173		    (reg == TEGRA_ADMAIF_RX_STATUS) ||174		    (reg == TEGRA_ADMAIF_RX_INT_STATUS) ||175		    (reg == TEGRA_ADMAIF_RX_SOFT_RESET))176			return true;177	} else if ((reg >= tx_base) && (reg < tx_max)) {178		reg = (reg - tx_base) % ch_stride;179		if ((reg == TEGRA_ADMAIF_TX_ENABLE) ||180		    (reg == TEGRA_ADMAIF_TX_STATUS) ||181		    (reg == TEGRA_ADMAIF_TX_INT_STATUS) ||182		    (reg == TEGRA_ADMAIF_TX_SOFT_RESET))183			return true;184	} else if ((reg >= global_base) && (reg < reg_max)) {185		if ((reg == (global_base + TEGRA_ADMAIF_GLOBAL_STATUS)) ||186		    (reg == (global_base +187				TEGRA_ADMAIF_GLOBAL_RX_ENABLE_STATUS)) ||188		    (reg == (global_base +189				TEGRA_ADMAIF_GLOBAL_TX_ENABLE_STATUS)))190			return true;191	}192 193	return false;194}195 196static const struct regmap_config tegra210_admaif_regmap_config = {197	.reg_bits		= 32,198	.reg_stride		= 4,199	.val_bits		= 32,200	.max_register		= TEGRA210_ADMAIF_LAST_REG,201	.writeable_reg		= tegra_admaif_wr_reg,202	.readable_reg		= tegra_admaif_rd_reg,203	.volatile_reg		= tegra_admaif_volatile_reg,204	.reg_defaults		= tegra210_admaif_reg_defaults,205	.num_reg_defaults	= TEGRA210_ADMAIF_CHANNEL_COUNT * 6 + 1,206	.cache_type		= REGCACHE_FLAT,207};208 209static const struct regmap_config tegra186_admaif_regmap_config = {210	.reg_bits		= 32,211	.reg_stride		= 4,212	.val_bits		= 32,213	.max_register		= TEGRA186_ADMAIF_LAST_REG,214	.writeable_reg		= tegra_admaif_wr_reg,215	.readable_reg		= tegra_admaif_rd_reg,216	.volatile_reg		= tegra_admaif_volatile_reg,217	.reg_defaults		= tegra186_admaif_reg_defaults,218	.num_reg_defaults	= TEGRA186_ADMAIF_CHANNEL_COUNT * 6 + 1,219	.cache_type		= REGCACHE_FLAT,220};221 222static int __maybe_unused tegra_admaif_runtime_suspend(struct device *dev)223{224	struct tegra_admaif *admaif = dev_get_drvdata(dev);225 226	regcache_cache_only(admaif->regmap, true);227	regcache_mark_dirty(admaif->regmap);228 229	return 0;230}231 232static int __maybe_unused tegra_admaif_runtime_resume(struct device *dev)233{234	struct tegra_admaif *admaif = dev_get_drvdata(dev);235 236	regcache_cache_only(admaif->regmap, false);237	regcache_sync(admaif->regmap);238 239	return 0;240}241 242static int tegra_admaif_set_pack_mode(struct regmap *map, unsigned int reg,243				      int valid_bit)244{245	switch (valid_bit) {246	case DATA_8BIT:247		regmap_update_bits(map, reg, PACK8_EN_MASK, PACK8_EN);248		regmap_update_bits(map, reg, PACK16_EN_MASK, 0);249		break;250	case DATA_16BIT:251		regmap_update_bits(map, reg, PACK16_EN_MASK, PACK16_EN);252		regmap_update_bits(map, reg, PACK8_EN_MASK, 0);253		break;254	case DATA_32BIT:255		regmap_update_bits(map, reg, PACK16_EN_MASK, 0);256		regmap_update_bits(map, reg, PACK8_EN_MASK, 0);257		break;258	default:259		return -EINVAL;260	}261 262	return 0;263}264 265static int tegra_admaif_hw_params(struct snd_pcm_substream *substream,266				  struct snd_pcm_hw_params *params,267				  struct snd_soc_dai *dai)268{269	struct device *dev = dai->dev;270	struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai);271	struct tegra_cif_conf cif_conf;272	unsigned int reg, path;273	int valid_bit, channels;274 275	memset(&cif_conf, 0, sizeof(struct tegra_cif_conf));276 277	switch (params_format(params)) {278	case SNDRV_PCM_FORMAT_S8:279		cif_conf.audio_bits = TEGRA_ACIF_BITS_8;280		cif_conf.client_bits = TEGRA_ACIF_BITS_8;281		valid_bit = DATA_8BIT;282		break;283	case SNDRV_PCM_FORMAT_S16_LE:284		cif_conf.audio_bits = TEGRA_ACIF_BITS_16;285		cif_conf.client_bits = TEGRA_ACIF_BITS_16;286		valid_bit = DATA_16BIT;287		break;288	case SNDRV_PCM_FORMAT_S32_LE:289		cif_conf.audio_bits = TEGRA_ACIF_BITS_32;290		cif_conf.client_bits = TEGRA_ACIF_BITS_32;291		valid_bit  = DATA_32BIT;292		break;293	default:294		dev_err(dev, "unsupported format!\n");295		return -EOPNOTSUPP;296	}297 298	channels = params_channels(params);299	cif_conf.client_ch = channels;300	cif_conf.audio_ch = channels;301 302	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {303		path = ADMAIF_TX_PATH;304		reg = CH_TX_REG(TEGRA_ADMAIF_CH_ACIF_TX_CTRL, dai->id);305	} else {306		path = ADMAIF_RX_PATH;307		reg = CH_RX_REG(TEGRA_ADMAIF_CH_ACIF_RX_CTRL, dai->id);308	}309 310	cif_conf.mono_conv = admaif->mono_to_stereo[path][dai->id];311	cif_conf.stereo_conv = admaif->stereo_to_mono[path][dai->id];312 313	tegra_admaif_set_pack_mode(admaif->regmap, reg, valid_bit);314 315	tegra_set_cif(admaif->regmap, reg, &cif_conf);316 317	return 0;318}319 320static int tegra_admaif_start(struct snd_soc_dai *dai, int direction)321{322	struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai);323	unsigned int reg, mask, val;324 325	switch (direction) {326	case SNDRV_PCM_STREAM_PLAYBACK:327		mask = TX_ENABLE_MASK;328		val = TX_ENABLE;329		reg = CH_TX_REG(TEGRA_ADMAIF_TX_ENABLE, dai->id);330		break;331	case SNDRV_PCM_STREAM_CAPTURE:332		mask = RX_ENABLE_MASK;333		val = RX_ENABLE;334		reg = CH_RX_REG(TEGRA_ADMAIF_RX_ENABLE, dai->id);335		break;336	default:337		return -EINVAL;338	}339 340	regmap_update_bits(admaif->regmap, reg, mask, val);341 342	return 0;343}344 345static int tegra_admaif_stop(struct snd_soc_dai *dai, int direction)346{347	struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai);348	unsigned int enable_reg, status_reg, reset_reg, mask, val;349	char *dir_name;350	int err, enable;351 352	switch (direction) {353	case SNDRV_PCM_STREAM_PLAYBACK:354		mask = TX_ENABLE_MASK;355		enable = TX_ENABLE;356		dir_name = "TX";357		enable_reg = CH_TX_REG(TEGRA_ADMAIF_TX_ENABLE, dai->id);358		status_reg = CH_TX_REG(TEGRA_ADMAIF_TX_STATUS, dai->id);359		reset_reg = CH_TX_REG(TEGRA_ADMAIF_TX_SOFT_RESET, dai->id);360		break;361	case SNDRV_PCM_STREAM_CAPTURE:362		mask = RX_ENABLE_MASK;363		enable = RX_ENABLE;364		dir_name = "RX";365		enable_reg = CH_RX_REG(TEGRA_ADMAIF_RX_ENABLE, dai->id);366		status_reg = CH_RX_REG(TEGRA_ADMAIF_RX_STATUS, dai->id);367		reset_reg = CH_RX_REG(TEGRA_ADMAIF_RX_SOFT_RESET, dai->id);368		break;369	default:370		return -EINVAL;371	}372 373	/* Disable TX/RX channel */374	regmap_update_bits(admaif->regmap, enable_reg, mask, ~enable);375 376	/* Wait until ADMAIF TX/RX status is disabled */377	err = regmap_read_poll_timeout_atomic(admaif->regmap, status_reg, val,378					      !(val & enable), 10, 10000);379	if (err < 0)380		dev_warn(dai->dev, "timeout: failed to disable ADMAIF%d_%s\n",381			 dai->id + 1, dir_name);382 383	/* SW reset */384	regmap_update_bits(admaif->regmap, reset_reg, SW_RESET_MASK, SW_RESET);385 386	/* Wait till SW reset is complete */387	err = regmap_read_poll_timeout_atomic(admaif->regmap, reset_reg, val,388					      !(val & SW_RESET_MASK & SW_RESET),389					      10, 10000);390	if (err) {391		dev_err(dai->dev, "timeout: SW reset failed for ADMAIF%d_%s\n",392			dai->id + 1, dir_name);393		return err;394	}395 396	return 0;397}398 399static int tegra_admaif_trigger(struct snd_pcm_substream *substream, int cmd,400				struct snd_soc_dai *dai)401{402	int err;403 404	err = snd_dmaengine_pcm_trigger(substream, cmd);405	if (err)406		return err;407 408	switch (cmd) {409	case SNDRV_PCM_TRIGGER_START:410	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:411	case SNDRV_PCM_TRIGGER_RESUME:412		return tegra_admaif_start(dai, substream->stream);413	case SNDRV_PCM_TRIGGER_STOP:414	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:415	case SNDRV_PCM_TRIGGER_SUSPEND:416		return tegra_admaif_stop(dai, substream->stream);417	default:418		return -EINVAL;419	}420}421 422static int tegra210_admaif_pget_mono_to_stereo(struct snd_kcontrol *kcontrol,423	struct snd_ctl_elem_value *ucontrol)424{425	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);426	struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);427	struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;428 429	ucontrol->value.enumerated.item[0] =430		admaif->mono_to_stereo[ADMAIF_TX_PATH][ec->reg];431 432	return 0;433}434 435static int tegra210_admaif_pput_mono_to_stereo(struct snd_kcontrol *kcontrol,436	struct snd_ctl_elem_value *ucontrol)437{438	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);439	struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);440	struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;441	unsigned int value = ucontrol->value.enumerated.item[0];442 443	if (value == admaif->mono_to_stereo[ADMAIF_TX_PATH][ec->reg])444		return 0;445 446	admaif->mono_to_stereo[ADMAIF_TX_PATH][ec->reg] = value;447 448	return 1;449}450 451static int tegra210_admaif_cget_mono_to_stereo(struct snd_kcontrol *kcontrol,452	struct snd_ctl_elem_value *ucontrol)453{454	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);455	struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);456	struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;457 458	ucontrol->value.enumerated.item[0] =459		admaif->mono_to_stereo[ADMAIF_RX_PATH][ec->reg];460 461	return 0;462}463 464static int tegra210_admaif_cput_mono_to_stereo(struct snd_kcontrol *kcontrol,465	struct snd_ctl_elem_value *ucontrol)466{467	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);468	struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);469	struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;470	unsigned int value = ucontrol->value.enumerated.item[0];471 472	if (value == admaif->mono_to_stereo[ADMAIF_RX_PATH][ec->reg])473		return 0;474 475	admaif->mono_to_stereo[ADMAIF_RX_PATH][ec->reg] = value;476 477	return 1;478}479 480static int tegra210_admaif_pget_stereo_to_mono(struct snd_kcontrol *kcontrol,481	struct snd_ctl_elem_value *ucontrol)482{483	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);484	struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);485	struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;486 487	ucontrol->value.enumerated.item[0] =488		admaif->stereo_to_mono[ADMAIF_TX_PATH][ec->reg];489 490	return 0;491}492 493static int tegra210_admaif_pput_stereo_to_mono(struct snd_kcontrol *kcontrol,494	struct snd_ctl_elem_value *ucontrol)495{496	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);497	struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);498	struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;499	unsigned int value = ucontrol->value.enumerated.item[0];500 501	if (value == admaif->stereo_to_mono[ADMAIF_TX_PATH][ec->reg])502		return 0;503 504	admaif->stereo_to_mono[ADMAIF_TX_PATH][ec->reg] = value;505 506	return 1;507}508 509static int tegra210_admaif_cget_stereo_to_mono(struct snd_kcontrol *kcontrol,510	struct snd_ctl_elem_value *ucontrol)511{512	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);513	struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);514	struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;515 516	ucontrol->value.enumerated.item[0] =517		admaif->stereo_to_mono[ADMAIF_RX_PATH][ec->reg];518 519	return 0;520}521 522static int tegra210_admaif_cput_stereo_to_mono(struct snd_kcontrol *kcontrol,523	struct snd_ctl_elem_value *ucontrol)524{525	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);526	struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);527	struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;528	unsigned int value = ucontrol->value.enumerated.item[0];529 530	if (value == admaif->stereo_to_mono[ADMAIF_RX_PATH][ec->reg])531		return 0;532 533	admaif->stereo_to_mono[ADMAIF_RX_PATH][ec->reg] = value;534 535	return 1;536}537 538static int tegra_admaif_dai_probe(struct snd_soc_dai *dai)539{540	struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai);541 542	snd_soc_dai_init_dma_data(dai,	&admaif->playback_dma_data[dai->id],543					&admaif->capture_dma_data[dai->id]);544 545	return 0;546}547 548static const struct snd_soc_dai_ops tegra_admaif_dai_ops = {549	.probe		= tegra_admaif_dai_probe,550	.hw_params	= tegra_admaif_hw_params,551	.trigger	= tegra_admaif_trigger,552};553 554#define DAI(dai_name)					\555	{							\556		.name = dai_name,				\557		.playback = {					\558			.stream_name = dai_name " Playback",	\559			.channels_min = 1,			\560			.channels_max = 16,			\561			.rates = SNDRV_PCM_RATE_8000_192000,	\562			.formats = SNDRV_PCM_FMTBIT_S8 |	\563				SNDRV_PCM_FMTBIT_S16_LE |	\564				SNDRV_PCM_FMTBIT_S32_LE,	\565		},						\566		.capture = {					\567			.stream_name = dai_name " Capture",	\568			.channels_min = 1,			\569			.channels_max = 16,			\570			.rates = SNDRV_PCM_RATE_8000_192000,	\571			.formats = SNDRV_PCM_FMTBIT_S8 |	\572				SNDRV_PCM_FMTBIT_S16_LE |	\573				SNDRV_PCM_FMTBIT_S32_LE,	\574		},						\575		.ops = &tegra_admaif_dai_ops,			\576	}577 578static struct snd_soc_dai_driver tegra210_admaif_cmpnt_dais[] = {579	DAI("ADMAIF1"),580	DAI("ADMAIF2"),581	DAI("ADMAIF3"),582	DAI("ADMAIF4"),583	DAI("ADMAIF5"),584	DAI("ADMAIF6"),585	DAI("ADMAIF7"),586	DAI("ADMAIF8"),587	DAI("ADMAIF9"),588	DAI("ADMAIF10"),589};590 591static struct snd_soc_dai_driver tegra186_admaif_cmpnt_dais[] = {592	DAI("ADMAIF1"),593	DAI("ADMAIF2"),594	DAI("ADMAIF3"),595	DAI("ADMAIF4"),596	DAI("ADMAIF5"),597	DAI("ADMAIF6"),598	DAI("ADMAIF7"),599	DAI("ADMAIF8"),600	DAI("ADMAIF9"),601	DAI("ADMAIF10"),602	DAI("ADMAIF11"),603	DAI("ADMAIF12"),604	DAI("ADMAIF13"),605	DAI("ADMAIF14"),606	DAI("ADMAIF15"),607	DAI("ADMAIF16"),608	DAI("ADMAIF17"),609	DAI("ADMAIF18"),610	DAI("ADMAIF19"),611	DAI("ADMAIF20"),612};613 614static const char * const tegra_admaif_stereo_conv_text[] = {615	"CH0", "CH1", "AVG",616};617 618static const char * const tegra_admaif_mono_conv_text[] = {619	"Zero", "Copy",620};621 622/*623 * Below macro is added to avoid looping over all ADMAIFx controls related624 * to mono/stereo conversions in get()/put() callbacks.625 */626#define NV_SOC_ENUM_EXT(xname, xreg, xhandler_get, xhandler_put, xenum_text)   \627{									       \628	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,				       \629	.info = snd_soc_info_enum_double,				       \630	.name = xname,							       \631	.get = xhandler_get,						       \632	.put = xhandler_put,						       \633	.private_value = (unsigned long)&(struct soc_enum)		       \634		SOC_ENUM_SINGLE(xreg, 0, ARRAY_SIZE(xenum_text), xenum_text)   \635}636 637#define TEGRA_ADMAIF_CIF_CTRL(reg)					       \638	NV_SOC_ENUM_EXT("ADMAIF" #reg " Playback Mono To Stereo", reg - 1,     \639			tegra210_admaif_pget_mono_to_stereo,		       \640			tegra210_admaif_pput_mono_to_stereo,		       \641			tegra_admaif_mono_conv_text),			       \642	NV_SOC_ENUM_EXT("ADMAIF" #reg " Playback Stereo To Mono", reg - 1,     \643			tegra210_admaif_pget_stereo_to_mono,		       \644			tegra210_admaif_pput_stereo_to_mono,		       \645			tegra_admaif_stereo_conv_text),			       \646	NV_SOC_ENUM_EXT("ADMAIF" #reg " Capture Mono To Stereo", reg - 1,      \647			tegra210_admaif_cget_mono_to_stereo,		       \648			tegra210_admaif_cput_mono_to_stereo,		       \649			tegra_admaif_mono_conv_text),			       \650	NV_SOC_ENUM_EXT("ADMAIF" #reg " Capture Stereo To Mono", reg - 1,      \651			tegra210_admaif_cget_stereo_to_mono,		       \652			tegra210_admaif_cput_stereo_to_mono,		       \653			tegra_admaif_stereo_conv_text)654 655static struct snd_kcontrol_new tegra210_admaif_controls[] = {656	TEGRA_ADMAIF_CIF_CTRL(1),657	TEGRA_ADMAIF_CIF_CTRL(2),658	TEGRA_ADMAIF_CIF_CTRL(3),659	TEGRA_ADMAIF_CIF_CTRL(4),660	TEGRA_ADMAIF_CIF_CTRL(5),661	TEGRA_ADMAIF_CIF_CTRL(6),662	TEGRA_ADMAIF_CIF_CTRL(7),663	TEGRA_ADMAIF_CIF_CTRL(8),664	TEGRA_ADMAIF_CIF_CTRL(9),665	TEGRA_ADMAIF_CIF_CTRL(10),666};667 668static struct snd_kcontrol_new tegra186_admaif_controls[] = {669	TEGRA_ADMAIF_CIF_CTRL(1),670	TEGRA_ADMAIF_CIF_CTRL(2),671	TEGRA_ADMAIF_CIF_CTRL(3),672	TEGRA_ADMAIF_CIF_CTRL(4),673	TEGRA_ADMAIF_CIF_CTRL(5),674	TEGRA_ADMAIF_CIF_CTRL(6),675	TEGRA_ADMAIF_CIF_CTRL(7),676	TEGRA_ADMAIF_CIF_CTRL(8),677	TEGRA_ADMAIF_CIF_CTRL(9),678	TEGRA_ADMAIF_CIF_CTRL(10),679	TEGRA_ADMAIF_CIF_CTRL(11),680	TEGRA_ADMAIF_CIF_CTRL(12),681	TEGRA_ADMAIF_CIF_CTRL(13),682	TEGRA_ADMAIF_CIF_CTRL(14),683	TEGRA_ADMAIF_CIF_CTRL(15),684	TEGRA_ADMAIF_CIF_CTRL(16),685	TEGRA_ADMAIF_CIF_CTRL(17),686	TEGRA_ADMAIF_CIF_CTRL(18),687	TEGRA_ADMAIF_CIF_CTRL(19),688	TEGRA_ADMAIF_CIF_CTRL(20),689};690 691static const struct snd_soc_component_driver tegra210_admaif_cmpnt = {692	.controls		= tegra210_admaif_controls,693	.num_controls		= ARRAY_SIZE(tegra210_admaif_controls),694	.pcm_construct		= tegra_pcm_construct,695	.open			= tegra_pcm_open,696	.close			= tegra_pcm_close,697	.hw_params		= tegra_pcm_hw_params,698	.pointer		= tegra_pcm_pointer,699};700 701static const struct snd_soc_component_driver tegra186_admaif_cmpnt = {702	.controls		= tegra186_admaif_controls,703	.num_controls		= ARRAY_SIZE(tegra186_admaif_controls),704	.pcm_construct		= tegra_pcm_construct,705	.open			= tegra_pcm_open,706	.close			= tegra_pcm_close,707	.hw_params		= tegra_pcm_hw_params,708	.pointer		= tegra_pcm_pointer,709};710 711static const struct tegra_admaif_soc_data soc_data_tegra210 = {712	.num_ch		= TEGRA210_ADMAIF_CHANNEL_COUNT,713	.cmpnt		= &tegra210_admaif_cmpnt,714	.dais		= tegra210_admaif_cmpnt_dais,715	.regmap_conf	= &tegra210_admaif_regmap_config,716	.global_base	= TEGRA210_ADMAIF_GLOBAL_BASE,717	.tx_base	= TEGRA210_ADMAIF_TX_BASE,718	.rx_base	= TEGRA210_ADMAIF_RX_BASE,719};720 721static const struct tegra_admaif_soc_data soc_data_tegra186 = {722	.num_ch		= TEGRA186_ADMAIF_CHANNEL_COUNT,723	.cmpnt		= &tegra186_admaif_cmpnt,724	.dais		= tegra186_admaif_cmpnt_dais,725	.regmap_conf	= &tegra186_admaif_regmap_config,726	.global_base	= TEGRA186_ADMAIF_GLOBAL_BASE,727	.tx_base	= TEGRA186_ADMAIF_TX_BASE,728	.rx_base	= TEGRA186_ADMAIF_RX_BASE,729};730 731static const struct of_device_id tegra_admaif_of_match[] = {732	{ .compatible = "nvidia,tegra210-admaif", .data = &soc_data_tegra210 },733	{ .compatible = "nvidia,tegra186-admaif", .data = &soc_data_tegra186 },734	{},735};736MODULE_DEVICE_TABLE(of, tegra_admaif_of_match);737 738static int tegra_admaif_probe(struct platform_device *pdev)739{740	struct tegra_admaif *admaif;741	void __iomem *regs;742	struct resource *res;743	int err, i;744 745	admaif = devm_kzalloc(&pdev->dev, sizeof(*admaif), GFP_KERNEL);746	if (!admaif)747		return -ENOMEM;748 749	admaif->soc_data = of_device_get_match_data(&pdev->dev);750 751	dev_set_drvdata(&pdev->dev, admaif);752 753	admaif->capture_dma_data =754		devm_kcalloc(&pdev->dev,755			     admaif->soc_data->num_ch,756			     sizeof(struct snd_dmaengine_dai_dma_data),757			     GFP_KERNEL);758	if (!admaif->capture_dma_data)759		return -ENOMEM;760 761	admaif->playback_dma_data =762		devm_kcalloc(&pdev->dev,763			     admaif->soc_data->num_ch,764			     sizeof(struct snd_dmaengine_dai_dma_data),765			     GFP_KERNEL);766	if (!admaif->playback_dma_data)767		return -ENOMEM;768 769	for (i = 0; i < ADMAIF_PATHS; i++) {770		admaif->mono_to_stereo[i] =771			devm_kcalloc(&pdev->dev, admaif->soc_data->num_ch,772				     sizeof(unsigned int), GFP_KERNEL);773		if (!admaif->mono_to_stereo[i])774			return -ENOMEM;775 776		admaif->stereo_to_mono[i] =777			devm_kcalloc(&pdev->dev, admaif->soc_data->num_ch,778				     sizeof(unsigned int), GFP_KERNEL);779		if (!admaif->stereo_to_mono[i])780			return -ENOMEM;781	}782 783	regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);784	if (IS_ERR(regs))785		return PTR_ERR(regs);786 787	admaif->regmap = devm_regmap_init_mmio(&pdev->dev, regs,788					       admaif->soc_data->regmap_conf);789	if (IS_ERR(admaif->regmap)) {790		dev_err(&pdev->dev, "regmap init failed\n");791		return PTR_ERR(admaif->regmap);792	}793 794	regcache_cache_only(admaif->regmap, true);795 796	regmap_update_bits(admaif->regmap, admaif->soc_data->global_base +797			   TEGRA_ADMAIF_GLOBAL_ENABLE, 1, 1);798 799	for (i = 0; i < admaif->soc_data->num_ch; i++) {800		admaif->playback_dma_data[i].addr = res->start +801			CH_TX_REG(TEGRA_ADMAIF_TX_FIFO_WRITE, i);802 803		admaif->capture_dma_data[i].addr = res->start +804			CH_RX_REG(TEGRA_ADMAIF_RX_FIFO_READ, i);805 806		admaif->playback_dma_data[i].addr_width = 32;807 808		if (of_property_read_string_index(pdev->dev.of_node,809				"dma-names", (i * 2) + 1,810				&admaif->playback_dma_data[i].chan_name) < 0) {811			dev_err(&pdev->dev,812				"missing property nvidia,dma-names\n");813 814			return -ENODEV;815		}816 817		admaif->capture_dma_data[i].addr_width = 32;818 819		if (of_property_read_string_index(pdev->dev.of_node,820				"dma-names",821				(i * 2),822				&admaif->capture_dma_data[i].chan_name) < 0) {823			dev_err(&pdev->dev,824				"missing property nvidia,dma-names\n");825 826			return -ENODEV;827		}828	}829 830	err = devm_snd_soc_register_component(&pdev->dev,831					      admaif->soc_data->cmpnt,832					      admaif->soc_data->dais,833					      admaif->soc_data->num_ch);834	if (err) {835		dev_err(&pdev->dev,836			"can't register ADMAIF component, err: %d\n", err);837		return err;838	}839 840	pm_runtime_enable(&pdev->dev);841 842	return 0;843}844 845static void tegra_admaif_remove(struct platform_device *pdev)846{847	pm_runtime_disable(&pdev->dev);848}849 850static const struct dev_pm_ops tegra_admaif_pm_ops = {851	SET_RUNTIME_PM_OPS(tegra_admaif_runtime_suspend,852			   tegra_admaif_runtime_resume, NULL)853	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,854				pm_runtime_force_resume)855};856 857static struct platform_driver tegra_admaif_driver = {858	.probe = tegra_admaif_probe,859	.remove = tegra_admaif_remove,860	.driver = {861		.name = "tegra210-admaif",862		.of_match_table = tegra_admaif_of_match,863		.pm = &tegra_admaif_pm_ops,864	},865};866module_platform_driver(tegra_admaif_driver);867 868MODULE_AUTHOR("Songhee Baek <sbaek@nvidia.com>");869MODULE_DESCRIPTION("Tegra210 ASoC ADMAIF driver");870MODULE_LICENSE("GPL v2");871