18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci//
38c2ecf20Sopenharmony_ci// tegra210_admaif.c - Tegra ADMAIF driver
48c2ecf20Sopenharmony_ci//
58c2ecf20Sopenharmony_ci// Copyright (c) 2020 NVIDIA CORPORATION.  All rights reserved.
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <linux/clk.h>
88c2ecf20Sopenharmony_ci#include <linux/device.h>
98c2ecf20Sopenharmony_ci#include <linux/module.h>
108c2ecf20Sopenharmony_ci#include <linux/of_platform.h>
118c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
128c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h>
138c2ecf20Sopenharmony_ci#include <linux/regmap.h>
148c2ecf20Sopenharmony_ci#include <sound/pcm_params.h>
158c2ecf20Sopenharmony_ci#include <sound/soc.h>
168c2ecf20Sopenharmony_ci#include "tegra210_admaif.h"
178c2ecf20Sopenharmony_ci#include "tegra_cif.h"
188c2ecf20Sopenharmony_ci#include "tegra_pcm.h"
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#define CH_REG(offset, reg, id)						       \
218c2ecf20Sopenharmony_ci	((offset) + (reg) + (TEGRA_ADMAIF_CHANNEL_REG_STRIDE * (id)))
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#define CH_TX_REG(reg, id) CH_REG(admaif->soc_data->tx_base, reg, id)
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#define CH_RX_REG(reg, id) CH_REG(admaif->soc_data->rx_base, reg, id)
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#define REG_DEFAULTS(id, rx_ctrl, tx_ctrl, tx_base, rx_base)		       \
288c2ecf20Sopenharmony_ci	{ CH_REG(rx_base, TEGRA_ADMAIF_RX_INT_MASK, id), 0x00000001 },	       \
298c2ecf20Sopenharmony_ci	{ CH_REG(rx_base, TEGRA_ADMAIF_CH_ACIF_RX_CTRL, id), 0x00007700 },     \
308c2ecf20Sopenharmony_ci	{ CH_REG(rx_base, TEGRA_ADMAIF_RX_FIFO_CTRL, id), rx_ctrl },	       \
318c2ecf20Sopenharmony_ci	{ CH_REG(tx_base, TEGRA_ADMAIF_TX_INT_MASK, id), 0x00000001 },	       \
328c2ecf20Sopenharmony_ci	{ CH_REG(tx_base, TEGRA_ADMAIF_CH_ACIF_TX_CTRL, id), 0x00007700 },     \
338c2ecf20Sopenharmony_ci	{ CH_REG(tx_base, TEGRA_ADMAIF_TX_FIFO_CTRL, id), tx_ctrl }
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci#define ADMAIF_REG_DEFAULTS(id, chip)					       \
368c2ecf20Sopenharmony_ci	REG_DEFAULTS((id) - 1,						       \
378c2ecf20Sopenharmony_ci		chip ## _ADMAIF_RX ## id ## _FIFO_CTRL_REG_DEFAULT,	       \
388c2ecf20Sopenharmony_ci		chip ## _ADMAIF_TX ## id ## _FIFO_CTRL_REG_DEFAULT,	       \
398c2ecf20Sopenharmony_ci		chip ## _ADMAIF_TX_BASE,				       \
408c2ecf20Sopenharmony_ci		chip ## _ADMAIF_RX_BASE)
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistatic const struct reg_default tegra186_admaif_reg_defaults[] = {
438c2ecf20Sopenharmony_ci	{(TEGRA_ADMAIF_GLOBAL_CG_0 + TEGRA186_ADMAIF_GLOBAL_BASE), 0x00000003},
448c2ecf20Sopenharmony_ci	ADMAIF_REG_DEFAULTS(1, TEGRA186),
458c2ecf20Sopenharmony_ci	ADMAIF_REG_DEFAULTS(2, TEGRA186),
468c2ecf20Sopenharmony_ci	ADMAIF_REG_DEFAULTS(3, TEGRA186),
478c2ecf20Sopenharmony_ci	ADMAIF_REG_DEFAULTS(4, TEGRA186),
488c2ecf20Sopenharmony_ci	ADMAIF_REG_DEFAULTS(5, TEGRA186),
498c2ecf20Sopenharmony_ci	ADMAIF_REG_DEFAULTS(6, TEGRA186),
508c2ecf20Sopenharmony_ci	ADMAIF_REG_DEFAULTS(7, TEGRA186),
518c2ecf20Sopenharmony_ci	ADMAIF_REG_DEFAULTS(8, TEGRA186),
528c2ecf20Sopenharmony_ci	ADMAIF_REG_DEFAULTS(9, TEGRA186),
538c2ecf20Sopenharmony_ci	ADMAIF_REG_DEFAULTS(10, TEGRA186),
548c2ecf20Sopenharmony_ci	ADMAIF_REG_DEFAULTS(11, TEGRA186),
558c2ecf20Sopenharmony_ci	ADMAIF_REG_DEFAULTS(12, TEGRA186),
568c2ecf20Sopenharmony_ci	ADMAIF_REG_DEFAULTS(13, TEGRA186),
578c2ecf20Sopenharmony_ci	ADMAIF_REG_DEFAULTS(14, TEGRA186),
588c2ecf20Sopenharmony_ci	ADMAIF_REG_DEFAULTS(15, TEGRA186),
598c2ecf20Sopenharmony_ci	ADMAIF_REG_DEFAULTS(16, TEGRA186),
608c2ecf20Sopenharmony_ci	ADMAIF_REG_DEFAULTS(17, TEGRA186),
618c2ecf20Sopenharmony_ci	ADMAIF_REG_DEFAULTS(18, TEGRA186),
628c2ecf20Sopenharmony_ci	ADMAIF_REG_DEFAULTS(19, TEGRA186),
638c2ecf20Sopenharmony_ci	ADMAIF_REG_DEFAULTS(20, TEGRA186)
648c2ecf20Sopenharmony_ci};
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_cistatic const struct reg_default tegra210_admaif_reg_defaults[] = {
678c2ecf20Sopenharmony_ci	{(TEGRA_ADMAIF_GLOBAL_CG_0 + TEGRA210_ADMAIF_GLOBAL_BASE), 0x00000003},
688c2ecf20Sopenharmony_ci	ADMAIF_REG_DEFAULTS(1, TEGRA210),
698c2ecf20Sopenharmony_ci	ADMAIF_REG_DEFAULTS(2, TEGRA210),
708c2ecf20Sopenharmony_ci	ADMAIF_REG_DEFAULTS(3, TEGRA210),
718c2ecf20Sopenharmony_ci	ADMAIF_REG_DEFAULTS(4, TEGRA210),
728c2ecf20Sopenharmony_ci	ADMAIF_REG_DEFAULTS(5, TEGRA210),
738c2ecf20Sopenharmony_ci	ADMAIF_REG_DEFAULTS(6, TEGRA210),
748c2ecf20Sopenharmony_ci	ADMAIF_REG_DEFAULTS(7, TEGRA210),
758c2ecf20Sopenharmony_ci	ADMAIF_REG_DEFAULTS(8, TEGRA210),
768c2ecf20Sopenharmony_ci	ADMAIF_REG_DEFAULTS(9, TEGRA210),
778c2ecf20Sopenharmony_ci	ADMAIF_REG_DEFAULTS(10, TEGRA210)
788c2ecf20Sopenharmony_ci};
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_cistatic bool tegra_admaif_wr_reg(struct device *dev, unsigned int reg)
818c2ecf20Sopenharmony_ci{
828c2ecf20Sopenharmony_ci	struct tegra_admaif *admaif = dev_get_drvdata(dev);
838c2ecf20Sopenharmony_ci	unsigned int ch_stride = TEGRA_ADMAIF_CHANNEL_REG_STRIDE;
848c2ecf20Sopenharmony_ci	unsigned int num_ch = admaif->soc_data->num_ch;
858c2ecf20Sopenharmony_ci	unsigned int rx_base = admaif->soc_data->rx_base;
868c2ecf20Sopenharmony_ci	unsigned int tx_base = admaif->soc_data->tx_base;
878c2ecf20Sopenharmony_ci	unsigned int global_base = admaif->soc_data->global_base;
888c2ecf20Sopenharmony_ci	unsigned int reg_max = admaif->soc_data->regmap_conf->max_register;
898c2ecf20Sopenharmony_ci	unsigned int rx_max = rx_base + (num_ch * ch_stride);
908c2ecf20Sopenharmony_ci	unsigned int tx_max = tx_base + (num_ch * ch_stride);
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	if ((reg >= rx_base) && (reg < rx_max)) {
938c2ecf20Sopenharmony_ci		reg = (reg - rx_base) % ch_stride;
948c2ecf20Sopenharmony_ci		if ((reg == TEGRA_ADMAIF_RX_ENABLE) ||
958c2ecf20Sopenharmony_ci		    (reg == TEGRA_ADMAIF_RX_FIFO_CTRL) ||
968c2ecf20Sopenharmony_ci		    (reg == TEGRA_ADMAIF_RX_SOFT_RESET) ||
978c2ecf20Sopenharmony_ci		    (reg == TEGRA_ADMAIF_CH_ACIF_RX_CTRL))
988c2ecf20Sopenharmony_ci			return true;
998c2ecf20Sopenharmony_ci	} else if ((reg >= tx_base) && (reg < tx_max)) {
1008c2ecf20Sopenharmony_ci		reg = (reg - tx_base) % ch_stride;
1018c2ecf20Sopenharmony_ci		if ((reg == TEGRA_ADMAIF_TX_ENABLE) ||
1028c2ecf20Sopenharmony_ci		    (reg == TEGRA_ADMAIF_TX_FIFO_CTRL) ||
1038c2ecf20Sopenharmony_ci		    (reg == TEGRA_ADMAIF_TX_SOFT_RESET) ||
1048c2ecf20Sopenharmony_ci		    (reg == TEGRA_ADMAIF_CH_ACIF_TX_CTRL))
1058c2ecf20Sopenharmony_ci			return true;
1068c2ecf20Sopenharmony_ci	} else if ((reg >= global_base) && (reg < reg_max)) {
1078c2ecf20Sopenharmony_ci		if (reg == (global_base + TEGRA_ADMAIF_GLOBAL_ENABLE))
1088c2ecf20Sopenharmony_ci			return true;
1098c2ecf20Sopenharmony_ci	}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	return false;
1128c2ecf20Sopenharmony_ci}
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_cistatic bool tegra_admaif_rd_reg(struct device *dev, unsigned int reg)
1158c2ecf20Sopenharmony_ci{
1168c2ecf20Sopenharmony_ci	struct tegra_admaif *admaif = dev_get_drvdata(dev);
1178c2ecf20Sopenharmony_ci	unsigned int ch_stride = TEGRA_ADMAIF_CHANNEL_REG_STRIDE;
1188c2ecf20Sopenharmony_ci	unsigned int num_ch = admaif->soc_data->num_ch;
1198c2ecf20Sopenharmony_ci	unsigned int rx_base = admaif->soc_data->rx_base;
1208c2ecf20Sopenharmony_ci	unsigned int tx_base = admaif->soc_data->tx_base;
1218c2ecf20Sopenharmony_ci	unsigned int global_base = admaif->soc_data->global_base;
1228c2ecf20Sopenharmony_ci	unsigned int reg_max = admaif->soc_data->regmap_conf->max_register;
1238c2ecf20Sopenharmony_ci	unsigned int rx_max = rx_base + (num_ch * ch_stride);
1248c2ecf20Sopenharmony_ci	unsigned int tx_max = tx_base + (num_ch * ch_stride);
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	if ((reg >= rx_base) && (reg < rx_max)) {
1278c2ecf20Sopenharmony_ci		reg = (reg - rx_base) % ch_stride;
1288c2ecf20Sopenharmony_ci		if ((reg == TEGRA_ADMAIF_RX_ENABLE) ||
1298c2ecf20Sopenharmony_ci		    (reg == TEGRA_ADMAIF_RX_STATUS) ||
1308c2ecf20Sopenharmony_ci		    (reg == TEGRA_ADMAIF_RX_INT_STATUS) ||
1318c2ecf20Sopenharmony_ci		    (reg == TEGRA_ADMAIF_RX_FIFO_CTRL) ||
1328c2ecf20Sopenharmony_ci		    (reg == TEGRA_ADMAIF_RX_SOFT_RESET) ||
1338c2ecf20Sopenharmony_ci		    (reg == TEGRA_ADMAIF_CH_ACIF_RX_CTRL))
1348c2ecf20Sopenharmony_ci			return true;
1358c2ecf20Sopenharmony_ci	} else if ((reg >= tx_base) && (reg < tx_max)) {
1368c2ecf20Sopenharmony_ci		reg = (reg - tx_base) % ch_stride;
1378c2ecf20Sopenharmony_ci		if ((reg == TEGRA_ADMAIF_TX_ENABLE) ||
1388c2ecf20Sopenharmony_ci		    (reg == TEGRA_ADMAIF_TX_STATUS) ||
1398c2ecf20Sopenharmony_ci		    (reg == TEGRA_ADMAIF_TX_INT_STATUS) ||
1408c2ecf20Sopenharmony_ci		    (reg == TEGRA_ADMAIF_TX_FIFO_CTRL) ||
1418c2ecf20Sopenharmony_ci		    (reg == TEGRA_ADMAIF_TX_SOFT_RESET) ||
1428c2ecf20Sopenharmony_ci		    (reg == TEGRA_ADMAIF_CH_ACIF_TX_CTRL))
1438c2ecf20Sopenharmony_ci			return true;
1448c2ecf20Sopenharmony_ci	} else if ((reg >= global_base) && (reg < reg_max)) {
1458c2ecf20Sopenharmony_ci		if ((reg == (global_base + TEGRA_ADMAIF_GLOBAL_ENABLE)) ||
1468c2ecf20Sopenharmony_ci		    (reg == (global_base + TEGRA_ADMAIF_GLOBAL_CG_0)) ||
1478c2ecf20Sopenharmony_ci		    (reg == (global_base + TEGRA_ADMAIF_GLOBAL_STATUS)) ||
1488c2ecf20Sopenharmony_ci		    (reg == (global_base +
1498c2ecf20Sopenharmony_ci				TEGRA_ADMAIF_GLOBAL_RX_ENABLE_STATUS)) ||
1508c2ecf20Sopenharmony_ci		    (reg == (global_base +
1518c2ecf20Sopenharmony_ci				TEGRA_ADMAIF_GLOBAL_TX_ENABLE_STATUS)))
1528c2ecf20Sopenharmony_ci			return true;
1538c2ecf20Sopenharmony_ci	}
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	return false;
1568c2ecf20Sopenharmony_ci}
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_cistatic bool tegra_admaif_volatile_reg(struct device *dev, unsigned int reg)
1598c2ecf20Sopenharmony_ci{
1608c2ecf20Sopenharmony_ci	struct tegra_admaif *admaif = dev_get_drvdata(dev);
1618c2ecf20Sopenharmony_ci	unsigned int ch_stride = TEGRA_ADMAIF_CHANNEL_REG_STRIDE;
1628c2ecf20Sopenharmony_ci	unsigned int num_ch = admaif->soc_data->num_ch;
1638c2ecf20Sopenharmony_ci	unsigned int rx_base = admaif->soc_data->rx_base;
1648c2ecf20Sopenharmony_ci	unsigned int tx_base = admaif->soc_data->tx_base;
1658c2ecf20Sopenharmony_ci	unsigned int global_base = admaif->soc_data->global_base;
1668c2ecf20Sopenharmony_ci	unsigned int reg_max = admaif->soc_data->regmap_conf->max_register;
1678c2ecf20Sopenharmony_ci	unsigned int rx_max = rx_base + (num_ch * ch_stride);
1688c2ecf20Sopenharmony_ci	unsigned int tx_max = tx_base + (num_ch * ch_stride);
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	if ((reg >= rx_base) && (reg < rx_max)) {
1718c2ecf20Sopenharmony_ci		reg = (reg - rx_base) % ch_stride;
1728c2ecf20Sopenharmony_ci		if ((reg == TEGRA_ADMAIF_RX_ENABLE) ||
1738c2ecf20Sopenharmony_ci		    (reg == TEGRA_ADMAIF_RX_STATUS) ||
1748c2ecf20Sopenharmony_ci		    (reg == TEGRA_ADMAIF_RX_INT_STATUS) ||
1758c2ecf20Sopenharmony_ci		    (reg == TEGRA_ADMAIF_RX_SOFT_RESET))
1768c2ecf20Sopenharmony_ci			return true;
1778c2ecf20Sopenharmony_ci	} else if ((reg >= tx_base) && (reg < tx_max)) {
1788c2ecf20Sopenharmony_ci		reg = (reg - tx_base) % ch_stride;
1798c2ecf20Sopenharmony_ci		if ((reg == TEGRA_ADMAIF_TX_ENABLE) ||
1808c2ecf20Sopenharmony_ci		    (reg == TEGRA_ADMAIF_TX_STATUS) ||
1818c2ecf20Sopenharmony_ci		    (reg == TEGRA_ADMAIF_TX_INT_STATUS) ||
1828c2ecf20Sopenharmony_ci		    (reg == TEGRA_ADMAIF_TX_SOFT_RESET))
1838c2ecf20Sopenharmony_ci			return true;
1848c2ecf20Sopenharmony_ci	} else if ((reg >= global_base) && (reg < reg_max)) {
1858c2ecf20Sopenharmony_ci		if ((reg == (global_base + TEGRA_ADMAIF_GLOBAL_STATUS)) ||
1868c2ecf20Sopenharmony_ci		    (reg == (global_base +
1878c2ecf20Sopenharmony_ci				TEGRA_ADMAIF_GLOBAL_RX_ENABLE_STATUS)) ||
1888c2ecf20Sopenharmony_ci		    (reg == (global_base +
1898c2ecf20Sopenharmony_ci				TEGRA_ADMAIF_GLOBAL_TX_ENABLE_STATUS)))
1908c2ecf20Sopenharmony_ci			return true;
1918c2ecf20Sopenharmony_ci	}
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	return false;
1948c2ecf20Sopenharmony_ci}
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_cistatic const struct regmap_config tegra210_admaif_regmap_config = {
1978c2ecf20Sopenharmony_ci	.reg_bits		= 32,
1988c2ecf20Sopenharmony_ci	.reg_stride		= 4,
1998c2ecf20Sopenharmony_ci	.val_bits		= 32,
2008c2ecf20Sopenharmony_ci	.max_register		= TEGRA210_ADMAIF_LAST_REG,
2018c2ecf20Sopenharmony_ci	.writeable_reg		= tegra_admaif_wr_reg,
2028c2ecf20Sopenharmony_ci	.readable_reg		= tegra_admaif_rd_reg,
2038c2ecf20Sopenharmony_ci	.volatile_reg		= tegra_admaif_volatile_reg,
2048c2ecf20Sopenharmony_ci	.reg_defaults		= tegra210_admaif_reg_defaults,
2058c2ecf20Sopenharmony_ci	.num_reg_defaults	= TEGRA210_ADMAIF_CHANNEL_COUNT * 6 + 1,
2068c2ecf20Sopenharmony_ci	.cache_type		= REGCACHE_FLAT,
2078c2ecf20Sopenharmony_ci};
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_cistatic const struct regmap_config tegra186_admaif_regmap_config = {
2108c2ecf20Sopenharmony_ci	.reg_bits		= 32,
2118c2ecf20Sopenharmony_ci	.reg_stride		= 4,
2128c2ecf20Sopenharmony_ci	.val_bits		= 32,
2138c2ecf20Sopenharmony_ci	.max_register		= TEGRA186_ADMAIF_LAST_REG,
2148c2ecf20Sopenharmony_ci	.writeable_reg		= tegra_admaif_wr_reg,
2158c2ecf20Sopenharmony_ci	.readable_reg		= tegra_admaif_rd_reg,
2168c2ecf20Sopenharmony_ci	.volatile_reg		= tegra_admaif_volatile_reg,
2178c2ecf20Sopenharmony_ci	.reg_defaults		= tegra186_admaif_reg_defaults,
2188c2ecf20Sopenharmony_ci	.num_reg_defaults	= TEGRA186_ADMAIF_CHANNEL_COUNT * 6 + 1,
2198c2ecf20Sopenharmony_ci	.cache_type		= REGCACHE_FLAT,
2208c2ecf20Sopenharmony_ci};
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_cistatic int __maybe_unused tegra_admaif_runtime_suspend(struct device *dev)
2238c2ecf20Sopenharmony_ci{
2248c2ecf20Sopenharmony_ci	struct tegra_admaif *admaif = dev_get_drvdata(dev);
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	regcache_cache_only(admaif->regmap, true);
2278c2ecf20Sopenharmony_ci	regcache_mark_dirty(admaif->regmap);
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	return 0;
2308c2ecf20Sopenharmony_ci}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_cistatic int __maybe_unused tegra_admaif_runtime_resume(struct device *dev)
2338c2ecf20Sopenharmony_ci{
2348c2ecf20Sopenharmony_ci	struct tegra_admaif *admaif = dev_get_drvdata(dev);
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	regcache_cache_only(admaif->regmap, false);
2378c2ecf20Sopenharmony_ci	regcache_sync(admaif->regmap);
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	return 0;
2408c2ecf20Sopenharmony_ci}
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_cistatic int tegra_admaif_set_pack_mode(struct regmap *map, unsigned int reg,
2438c2ecf20Sopenharmony_ci				      int valid_bit)
2448c2ecf20Sopenharmony_ci{
2458c2ecf20Sopenharmony_ci	switch (valid_bit) {
2468c2ecf20Sopenharmony_ci	case DATA_8BIT:
2478c2ecf20Sopenharmony_ci		regmap_update_bits(map, reg, PACK8_EN_MASK, PACK8_EN);
2488c2ecf20Sopenharmony_ci		regmap_update_bits(map, reg, PACK16_EN_MASK, 0);
2498c2ecf20Sopenharmony_ci		break;
2508c2ecf20Sopenharmony_ci	case DATA_16BIT:
2518c2ecf20Sopenharmony_ci		regmap_update_bits(map, reg, PACK16_EN_MASK, PACK16_EN);
2528c2ecf20Sopenharmony_ci		regmap_update_bits(map, reg, PACK8_EN_MASK, 0);
2538c2ecf20Sopenharmony_ci		break;
2548c2ecf20Sopenharmony_ci	case DATA_32BIT:
2558c2ecf20Sopenharmony_ci		regmap_update_bits(map, reg, PACK16_EN_MASK, 0);
2568c2ecf20Sopenharmony_ci		regmap_update_bits(map, reg, PACK8_EN_MASK, 0);
2578c2ecf20Sopenharmony_ci		break;
2588c2ecf20Sopenharmony_ci	default:
2598c2ecf20Sopenharmony_ci		return -EINVAL;
2608c2ecf20Sopenharmony_ci	}
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	return 0;
2638c2ecf20Sopenharmony_ci}
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_cistatic int tegra_admaif_hw_params(struct snd_pcm_substream *substream,
2668c2ecf20Sopenharmony_ci				  struct snd_pcm_hw_params *params,
2678c2ecf20Sopenharmony_ci				  struct snd_soc_dai *dai)
2688c2ecf20Sopenharmony_ci{
2698c2ecf20Sopenharmony_ci	struct device *dev = dai->dev;
2708c2ecf20Sopenharmony_ci	struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai);
2718c2ecf20Sopenharmony_ci	struct tegra_cif_conf cif_conf;
2728c2ecf20Sopenharmony_ci	unsigned int reg, path;
2738c2ecf20Sopenharmony_ci	int valid_bit, channels;
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	memset(&cif_conf, 0, sizeof(struct tegra_cif_conf));
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	switch (params_format(params)) {
2788c2ecf20Sopenharmony_ci	case SNDRV_PCM_FORMAT_S8:
2798c2ecf20Sopenharmony_ci		cif_conf.audio_bits = TEGRA_ACIF_BITS_8;
2808c2ecf20Sopenharmony_ci		cif_conf.client_bits = TEGRA_ACIF_BITS_8;
2818c2ecf20Sopenharmony_ci		valid_bit = DATA_8BIT;
2828c2ecf20Sopenharmony_ci		break;
2838c2ecf20Sopenharmony_ci	case SNDRV_PCM_FORMAT_S16_LE:
2848c2ecf20Sopenharmony_ci		cif_conf.audio_bits = TEGRA_ACIF_BITS_16;
2858c2ecf20Sopenharmony_ci		cif_conf.client_bits = TEGRA_ACIF_BITS_16;
2868c2ecf20Sopenharmony_ci		valid_bit = DATA_16BIT;
2878c2ecf20Sopenharmony_ci		break;
2888c2ecf20Sopenharmony_ci	case SNDRV_PCM_FORMAT_S32_LE:
2898c2ecf20Sopenharmony_ci		cif_conf.audio_bits = TEGRA_ACIF_BITS_32;
2908c2ecf20Sopenharmony_ci		cif_conf.client_bits = TEGRA_ACIF_BITS_32;
2918c2ecf20Sopenharmony_ci		valid_bit  = DATA_32BIT;
2928c2ecf20Sopenharmony_ci		break;
2938c2ecf20Sopenharmony_ci	default:
2948c2ecf20Sopenharmony_ci		dev_err(dev, "unsupported format!\n");
2958c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
2968c2ecf20Sopenharmony_ci	}
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	channels = params_channels(params);
2998c2ecf20Sopenharmony_ci	cif_conf.client_ch = channels;
3008c2ecf20Sopenharmony_ci	cif_conf.audio_ch = channels;
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
3038c2ecf20Sopenharmony_ci		path = ADMAIF_TX_PATH;
3048c2ecf20Sopenharmony_ci		reg = CH_TX_REG(TEGRA_ADMAIF_CH_ACIF_TX_CTRL, dai->id);
3058c2ecf20Sopenharmony_ci	} else {
3068c2ecf20Sopenharmony_ci		path = ADMAIF_RX_PATH;
3078c2ecf20Sopenharmony_ci		reg = CH_RX_REG(TEGRA_ADMAIF_CH_ACIF_RX_CTRL, dai->id);
3088c2ecf20Sopenharmony_ci	}
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	cif_conf.mono_conv = admaif->mono_to_stereo[path][dai->id];
3118c2ecf20Sopenharmony_ci	cif_conf.stereo_conv = admaif->stereo_to_mono[path][dai->id];
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	tegra_admaif_set_pack_mode(admaif->regmap, reg, valid_bit);
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	tegra_set_cif(admaif->regmap, reg, &cif_conf);
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	return 0;
3188c2ecf20Sopenharmony_ci}
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_cistatic int tegra_admaif_start(struct snd_soc_dai *dai, int direction)
3218c2ecf20Sopenharmony_ci{
3228c2ecf20Sopenharmony_ci	struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai);
3238c2ecf20Sopenharmony_ci	unsigned int reg, mask, val;
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	switch (direction) {
3268c2ecf20Sopenharmony_ci	case SNDRV_PCM_STREAM_PLAYBACK:
3278c2ecf20Sopenharmony_ci		mask = TX_ENABLE_MASK;
3288c2ecf20Sopenharmony_ci		val = TX_ENABLE;
3298c2ecf20Sopenharmony_ci		reg = CH_TX_REG(TEGRA_ADMAIF_TX_ENABLE, dai->id);
3308c2ecf20Sopenharmony_ci		break;
3318c2ecf20Sopenharmony_ci	case SNDRV_PCM_STREAM_CAPTURE:
3328c2ecf20Sopenharmony_ci		mask = RX_ENABLE_MASK;
3338c2ecf20Sopenharmony_ci		val = RX_ENABLE;
3348c2ecf20Sopenharmony_ci		reg = CH_RX_REG(TEGRA_ADMAIF_RX_ENABLE, dai->id);
3358c2ecf20Sopenharmony_ci		break;
3368c2ecf20Sopenharmony_ci	default:
3378c2ecf20Sopenharmony_ci		return -EINVAL;
3388c2ecf20Sopenharmony_ci	}
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	regmap_update_bits(admaif->regmap, reg, mask, val);
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	return 0;
3438c2ecf20Sopenharmony_ci}
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_cistatic int tegra_admaif_stop(struct snd_soc_dai *dai, int direction)
3468c2ecf20Sopenharmony_ci{
3478c2ecf20Sopenharmony_ci	struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai);
3488c2ecf20Sopenharmony_ci	unsigned int enable_reg, status_reg, reset_reg, mask, val;
3498c2ecf20Sopenharmony_ci	char *dir_name;
3508c2ecf20Sopenharmony_ci	int err, enable;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	switch (direction) {
3538c2ecf20Sopenharmony_ci	case SNDRV_PCM_STREAM_PLAYBACK:
3548c2ecf20Sopenharmony_ci		mask = TX_ENABLE_MASK;
3558c2ecf20Sopenharmony_ci		enable = TX_ENABLE;
3568c2ecf20Sopenharmony_ci		dir_name = "TX";
3578c2ecf20Sopenharmony_ci		enable_reg = CH_TX_REG(TEGRA_ADMAIF_TX_ENABLE, dai->id);
3588c2ecf20Sopenharmony_ci		status_reg = CH_TX_REG(TEGRA_ADMAIF_TX_STATUS, dai->id);
3598c2ecf20Sopenharmony_ci		reset_reg = CH_TX_REG(TEGRA_ADMAIF_TX_SOFT_RESET, dai->id);
3608c2ecf20Sopenharmony_ci		break;
3618c2ecf20Sopenharmony_ci	case SNDRV_PCM_STREAM_CAPTURE:
3628c2ecf20Sopenharmony_ci		mask = RX_ENABLE_MASK;
3638c2ecf20Sopenharmony_ci		enable = RX_ENABLE;
3648c2ecf20Sopenharmony_ci		dir_name = "RX";
3658c2ecf20Sopenharmony_ci		enable_reg = CH_RX_REG(TEGRA_ADMAIF_RX_ENABLE, dai->id);
3668c2ecf20Sopenharmony_ci		status_reg = CH_RX_REG(TEGRA_ADMAIF_RX_STATUS, dai->id);
3678c2ecf20Sopenharmony_ci		reset_reg = CH_RX_REG(TEGRA_ADMAIF_RX_SOFT_RESET, dai->id);
3688c2ecf20Sopenharmony_ci		break;
3698c2ecf20Sopenharmony_ci	default:
3708c2ecf20Sopenharmony_ci		return -EINVAL;
3718c2ecf20Sopenharmony_ci	}
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	/* Disable TX/RX channel */
3748c2ecf20Sopenharmony_ci	regmap_update_bits(admaif->regmap, enable_reg, mask, ~enable);
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	/* Wait until ADMAIF TX/RX status is disabled */
3778c2ecf20Sopenharmony_ci	err = regmap_read_poll_timeout_atomic(admaif->regmap, status_reg, val,
3788c2ecf20Sopenharmony_ci					      !(val & enable), 10, 10000);
3798c2ecf20Sopenharmony_ci	if (err < 0)
3808c2ecf20Sopenharmony_ci		dev_warn(dai->dev, "timeout: failed to disable ADMAIF%d_%s\n",
3818c2ecf20Sopenharmony_ci			 dai->id + 1, dir_name);
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	/* SW reset */
3848c2ecf20Sopenharmony_ci	regmap_update_bits(admaif->regmap, reset_reg, SW_RESET_MASK, SW_RESET);
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	/* Wait till SW reset is complete */
3878c2ecf20Sopenharmony_ci	err = regmap_read_poll_timeout_atomic(admaif->regmap, reset_reg, val,
3888c2ecf20Sopenharmony_ci					      !(val & SW_RESET_MASK & SW_RESET),
3898c2ecf20Sopenharmony_ci					      10, 10000);
3908c2ecf20Sopenharmony_ci	if (err) {
3918c2ecf20Sopenharmony_ci		dev_err(dai->dev, "timeout: SW reset failed for ADMAIF%d_%s\n",
3928c2ecf20Sopenharmony_ci			dai->id + 1, dir_name);
3938c2ecf20Sopenharmony_ci		return err;
3948c2ecf20Sopenharmony_ci	}
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	return 0;
3978c2ecf20Sopenharmony_ci}
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_cistatic int tegra_admaif_trigger(struct snd_pcm_substream *substream, int cmd,
4008c2ecf20Sopenharmony_ci				struct snd_soc_dai *dai)
4018c2ecf20Sopenharmony_ci{
4028c2ecf20Sopenharmony_ci	int err;
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	err = snd_dmaengine_pcm_trigger(substream, cmd);
4058c2ecf20Sopenharmony_ci	if (err)
4068c2ecf20Sopenharmony_ci		return err;
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	switch (cmd) {
4098c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_START:
4108c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
4118c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_RESUME:
4128c2ecf20Sopenharmony_ci		return tegra_admaif_start(dai, substream->stream);
4138c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_STOP:
4148c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
4158c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_SUSPEND:
4168c2ecf20Sopenharmony_ci		return tegra_admaif_stop(dai, substream->stream);
4178c2ecf20Sopenharmony_ci	default:
4188c2ecf20Sopenharmony_ci		return -EINVAL;
4198c2ecf20Sopenharmony_ci	}
4208c2ecf20Sopenharmony_ci}
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_cistatic const struct snd_soc_dai_ops tegra_admaif_dai_ops = {
4238c2ecf20Sopenharmony_ci	.hw_params	= tegra_admaif_hw_params,
4248c2ecf20Sopenharmony_ci	.trigger	= tegra_admaif_trigger,
4258c2ecf20Sopenharmony_ci};
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_cistatic int tegra210_admaif_pget_mono_to_stereo(struct snd_kcontrol *kcontrol,
4288c2ecf20Sopenharmony_ci	struct snd_ctl_elem_value *ucontrol)
4298c2ecf20Sopenharmony_ci{
4308c2ecf20Sopenharmony_ci	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
4318c2ecf20Sopenharmony_ci	struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);
4328c2ecf20Sopenharmony_ci	struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	ucontrol->value.enumerated.item[0] =
4358c2ecf20Sopenharmony_ci		admaif->mono_to_stereo[ADMAIF_TX_PATH][ec->reg];
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	return 0;
4388c2ecf20Sopenharmony_ci}
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_cistatic int tegra210_admaif_pput_mono_to_stereo(struct snd_kcontrol *kcontrol,
4418c2ecf20Sopenharmony_ci	struct snd_ctl_elem_value *ucontrol)
4428c2ecf20Sopenharmony_ci{
4438c2ecf20Sopenharmony_ci	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
4448c2ecf20Sopenharmony_ci	struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);
4458c2ecf20Sopenharmony_ci	struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
4468c2ecf20Sopenharmony_ci	unsigned int value = ucontrol->value.enumerated.item[0];
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	if (value == admaif->mono_to_stereo[ADMAIF_TX_PATH][ec->reg])
4498c2ecf20Sopenharmony_ci		return 0;
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	admaif->mono_to_stereo[ADMAIF_TX_PATH][ec->reg] = value;
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	return 1;
4548c2ecf20Sopenharmony_ci}
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_cistatic int tegra210_admaif_cget_mono_to_stereo(struct snd_kcontrol *kcontrol,
4578c2ecf20Sopenharmony_ci	struct snd_ctl_elem_value *ucontrol)
4588c2ecf20Sopenharmony_ci{
4598c2ecf20Sopenharmony_ci	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
4608c2ecf20Sopenharmony_ci	struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);
4618c2ecf20Sopenharmony_ci	struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	ucontrol->value.enumerated.item[0] =
4648c2ecf20Sopenharmony_ci		admaif->mono_to_stereo[ADMAIF_RX_PATH][ec->reg];
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	return 0;
4678c2ecf20Sopenharmony_ci}
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_cistatic int tegra210_admaif_cput_mono_to_stereo(struct snd_kcontrol *kcontrol,
4708c2ecf20Sopenharmony_ci	struct snd_ctl_elem_value *ucontrol)
4718c2ecf20Sopenharmony_ci{
4728c2ecf20Sopenharmony_ci	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
4738c2ecf20Sopenharmony_ci	struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);
4748c2ecf20Sopenharmony_ci	struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
4758c2ecf20Sopenharmony_ci	unsigned int value = ucontrol->value.enumerated.item[0];
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	if (value == admaif->mono_to_stereo[ADMAIF_RX_PATH][ec->reg])
4788c2ecf20Sopenharmony_ci		return 0;
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	admaif->mono_to_stereo[ADMAIF_RX_PATH][ec->reg] = value;
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci	return 1;
4838c2ecf20Sopenharmony_ci}
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_cistatic int tegra210_admaif_pget_stereo_to_mono(struct snd_kcontrol *kcontrol,
4868c2ecf20Sopenharmony_ci	struct snd_ctl_elem_value *ucontrol)
4878c2ecf20Sopenharmony_ci{
4888c2ecf20Sopenharmony_ci	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
4898c2ecf20Sopenharmony_ci	struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);
4908c2ecf20Sopenharmony_ci	struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	ucontrol->value.enumerated.item[0] =
4938c2ecf20Sopenharmony_ci		admaif->stereo_to_mono[ADMAIF_TX_PATH][ec->reg];
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	return 0;
4968c2ecf20Sopenharmony_ci}
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_cistatic int tegra210_admaif_pput_stereo_to_mono(struct snd_kcontrol *kcontrol,
4998c2ecf20Sopenharmony_ci	struct snd_ctl_elem_value *ucontrol)
5008c2ecf20Sopenharmony_ci{
5018c2ecf20Sopenharmony_ci	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
5028c2ecf20Sopenharmony_ci	struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);
5038c2ecf20Sopenharmony_ci	struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
5048c2ecf20Sopenharmony_ci	unsigned int value = ucontrol->value.enumerated.item[0];
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	if (value == admaif->stereo_to_mono[ADMAIF_TX_PATH][ec->reg])
5078c2ecf20Sopenharmony_ci		return 0;
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	admaif->stereo_to_mono[ADMAIF_TX_PATH][ec->reg] = value;
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	return 1;
5128c2ecf20Sopenharmony_ci}
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_cistatic int tegra210_admaif_cget_stereo_to_mono(struct snd_kcontrol *kcontrol,
5158c2ecf20Sopenharmony_ci	struct snd_ctl_elem_value *ucontrol)
5168c2ecf20Sopenharmony_ci{
5178c2ecf20Sopenharmony_ci	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
5188c2ecf20Sopenharmony_ci	struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);
5198c2ecf20Sopenharmony_ci	struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci	ucontrol->value.enumerated.item[0] =
5228c2ecf20Sopenharmony_ci		admaif->stereo_to_mono[ADMAIF_RX_PATH][ec->reg];
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci	return 0;
5258c2ecf20Sopenharmony_ci}
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_cistatic int tegra210_admaif_cput_stereo_to_mono(struct snd_kcontrol *kcontrol,
5288c2ecf20Sopenharmony_ci	struct snd_ctl_elem_value *ucontrol)
5298c2ecf20Sopenharmony_ci{
5308c2ecf20Sopenharmony_ci	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
5318c2ecf20Sopenharmony_ci	struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);
5328c2ecf20Sopenharmony_ci	struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
5338c2ecf20Sopenharmony_ci	unsigned int value = ucontrol->value.enumerated.item[0];
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	if (value == admaif->stereo_to_mono[ADMAIF_RX_PATH][ec->reg])
5368c2ecf20Sopenharmony_ci		return 0;
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci	admaif->stereo_to_mono[ADMAIF_RX_PATH][ec->reg] = value;
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	return 1;
5418c2ecf20Sopenharmony_ci}
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_cistatic int tegra_admaif_dai_probe(struct snd_soc_dai *dai)
5448c2ecf20Sopenharmony_ci{
5458c2ecf20Sopenharmony_ci	struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai);
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci	dai->capture_dma_data = &admaif->capture_dma_data[dai->id];
5488c2ecf20Sopenharmony_ci	dai->playback_dma_data = &admaif->playback_dma_data[dai->id];
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	return 0;
5518c2ecf20Sopenharmony_ci}
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci#define DAI(dai_name)					\
5548c2ecf20Sopenharmony_ci	{							\
5558c2ecf20Sopenharmony_ci		.name = dai_name,				\
5568c2ecf20Sopenharmony_ci		.probe = tegra_admaif_dai_probe,		\
5578c2ecf20Sopenharmony_ci		.playback = {					\
5588c2ecf20Sopenharmony_ci			.stream_name = dai_name " Playback",	\
5598c2ecf20Sopenharmony_ci			.channels_min = 1,			\
5608c2ecf20Sopenharmony_ci			.channels_max = 16,			\
5618c2ecf20Sopenharmony_ci			.rates = SNDRV_PCM_RATE_8000_192000,	\
5628c2ecf20Sopenharmony_ci			.formats = SNDRV_PCM_FMTBIT_S8 |	\
5638c2ecf20Sopenharmony_ci				SNDRV_PCM_FMTBIT_S16_LE |	\
5648c2ecf20Sopenharmony_ci				SNDRV_PCM_FMTBIT_S32_LE,	\
5658c2ecf20Sopenharmony_ci		},						\
5668c2ecf20Sopenharmony_ci		.capture = {					\
5678c2ecf20Sopenharmony_ci			.stream_name = dai_name " Capture",	\
5688c2ecf20Sopenharmony_ci			.channels_min = 1,			\
5698c2ecf20Sopenharmony_ci			.channels_max = 16,			\
5708c2ecf20Sopenharmony_ci			.rates = SNDRV_PCM_RATE_8000_192000,	\
5718c2ecf20Sopenharmony_ci			.formats = SNDRV_PCM_FMTBIT_S8 |	\
5728c2ecf20Sopenharmony_ci				SNDRV_PCM_FMTBIT_S16_LE |	\
5738c2ecf20Sopenharmony_ci				SNDRV_PCM_FMTBIT_S32_LE,	\
5748c2ecf20Sopenharmony_ci		},						\
5758c2ecf20Sopenharmony_ci		.ops = &tegra_admaif_dai_ops,			\
5768c2ecf20Sopenharmony_ci	}
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_cistatic struct snd_soc_dai_driver tegra210_admaif_cmpnt_dais[] = {
5798c2ecf20Sopenharmony_ci	DAI("ADMAIF1"),
5808c2ecf20Sopenharmony_ci	DAI("ADMAIF2"),
5818c2ecf20Sopenharmony_ci	DAI("ADMAIF3"),
5828c2ecf20Sopenharmony_ci	DAI("ADMAIF4"),
5838c2ecf20Sopenharmony_ci	DAI("ADMAIF5"),
5848c2ecf20Sopenharmony_ci	DAI("ADMAIF6"),
5858c2ecf20Sopenharmony_ci	DAI("ADMAIF7"),
5868c2ecf20Sopenharmony_ci	DAI("ADMAIF8"),
5878c2ecf20Sopenharmony_ci	DAI("ADMAIF9"),
5888c2ecf20Sopenharmony_ci	DAI("ADMAIF10"),
5898c2ecf20Sopenharmony_ci};
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_cistatic struct snd_soc_dai_driver tegra186_admaif_cmpnt_dais[] = {
5928c2ecf20Sopenharmony_ci	DAI("ADMAIF1"),
5938c2ecf20Sopenharmony_ci	DAI("ADMAIF2"),
5948c2ecf20Sopenharmony_ci	DAI("ADMAIF3"),
5958c2ecf20Sopenharmony_ci	DAI("ADMAIF4"),
5968c2ecf20Sopenharmony_ci	DAI("ADMAIF5"),
5978c2ecf20Sopenharmony_ci	DAI("ADMAIF6"),
5988c2ecf20Sopenharmony_ci	DAI("ADMAIF7"),
5998c2ecf20Sopenharmony_ci	DAI("ADMAIF8"),
6008c2ecf20Sopenharmony_ci	DAI("ADMAIF9"),
6018c2ecf20Sopenharmony_ci	DAI("ADMAIF10"),
6028c2ecf20Sopenharmony_ci	DAI("ADMAIF11"),
6038c2ecf20Sopenharmony_ci	DAI("ADMAIF12"),
6048c2ecf20Sopenharmony_ci	DAI("ADMAIF13"),
6058c2ecf20Sopenharmony_ci	DAI("ADMAIF14"),
6068c2ecf20Sopenharmony_ci	DAI("ADMAIF15"),
6078c2ecf20Sopenharmony_ci	DAI("ADMAIF16"),
6088c2ecf20Sopenharmony_ci	DAI("ADMAIF17"),
6098c2ecf20Sopenharmony_ci	DAI("ADMAIF18"),
6108c2ecf20Sopenharmony_ci	DAI("ADMAIF19"),
6118c2ecf20Sopenharmony_ci	DAI("ADMAIF20"),
6128c2ecf20Sopenharmony_ci};
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_cistatic const char * const tegra_admaif_stereo_conv_text[] = {
6158c2ecf20Sopenharmony_ci	"CH0", "CH1", "AVG",
6168c2ecf20Sopenharmony_ci};
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_cistatic const char * const tegra_admaif_mono_conv_text[] = {
6198c2ecf20Sopenharmony_ci	"Zero", "Copy",
6208c2ecf20Sopenharmony_ci};
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci/*
6238c2ecf20Sopenharmony_ci * Below macro is added to avoid looping over all ADMAIFx controls related
6248c2ecf20Sopenharmony_ci * to mono/stereo conversions in get()/put() callbacks.
6258c2ecf20Sopenharmony_ci */
6268c2ecf20Sopenharmony_ci#define NV_SOC_ENUM_EXT(xname, xreg, xhandler_get, xhandler_put, xenum_text)   \
6278c2ecf20Sopenharmony_ci{									       \
6288c2ecf20Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,				       \
6298c2ecf20Sopenharmony_ci	.info = snd_soc_info_enum_double,				       \
6308c2ecf20Sopenharmony_ci	.name = xname,							       \
6318c2ecf20Sopenharmony_ci	.get = xhandler_get,						       \
6328c2ecf20Sopenharmony_ci	.put = xhandler_put,						       \
6338c2ecf20Sopenharmony_ci	.private_value = (unsigned long)&(struct soc_enum)		       \
6348c2ecf20Sopenharmony_ci		SOC_ENUM_SINGLE(xreg, 0, ARRAY_SIZE(xenum_text), xenum_text)   \
6358c2ecf20Sopenharmony_ci}
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci#define TEGRA_ADMAIF_CIF_CTRL(reg)					       \
6388c2ecf20Sopenharmony_ci	NV_SOC_ENUM_EXT("ADMAIF" #reg " Playback Mono To Stereo", reg - 1,     \
6398c2ecf20Sopenharmony_ci			tegra210_admaif_pget_mono_to_stereo,		       \
6408c2ecf20Sopenharmony_ci			tegra210_admaif_pput_mono_to_stereo,		       \
6418c2ecf20Sopenharmony_ci			tegra_admaif_mono_conv_text),			       \
6428c2ecf20Sopenharmony_ci	NV_SOC_ENUM_EXT("ADMAIF" #reg " Playback Stereo To Mono", reg - 1,     \
6438c2ecf20Sopenharmony_ci			tegra210_admaif_pget_stereo_to_mono,		       \
6448c2ecf20Sopenharmony_ci			tegra210_admaif_pput_stereo_to_mono,		       \
6458c2ecf20Sopenharmony_ci			tegra_admaif_stereo_conv_text),			       \
6468c2ecf20Sopenharmony_ci	NV_SOC_ENUM_EXT("ADMAIF" #reg " Capture Mono To Stereo", reg - 1,      \
6478c2ecf20Sopenharmony_ci			tegra210_admaif_cget_mono_to_stereo,		       \
6488c2ecf20Sopenharmony_ci			tegra210_admaif_cput_mono_to_stereo,		       \
6498c2ecf20Sopenharmony_ci			tegra_admaif_mono_conv_text),			       \
6508c2ecf20Sopenharmony_ci	NV_SOC_ENUM_EXT("ADMAIF" #reg " Capture Stereo To Mono", reg - 1,      \
6518c2ecf20Sopenharmony_ci			tegra210_admaif_cget_stereo_to_mono,		       \
6528c2ecf20Sopenharmony_ci			tegra210_admaif_cput_stereo_to_mono,		       \
6538c2ecf20Sopenharmony_ci			tegra_admaif_stereo_conv_text)
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_cistatic struct snd_kcontrol_new tegra210_admaif_controls[] = {
6568c2ecf20Sopenharmony_ci	TEGRA_ADMAIF_CIF_CTRL(1),
6578c2ecf20Sopenharmony_ci	TEGRA_ADMAIF_CIF_CTRL(2),
6588c2ecf20Sopenharmony_ci	TEGRA_ADMAIF_CIF_CTRL(3),
6598c2ecf20Sopenharmony_ci	TEGRA_ADMAIF_CIF_CTRL(4),
6608c2ecf20Sopenharmony_ci	TEGRA_ADMAIF_CIF_CTRL(5),
6618c2ecf20Sopenharmony_ci	TEGRA_ADMAIF_CIF_CTRL(6),
6628c2ecf20Sopenharmony_ci	TEGRA_ADMAIF_CIF_CTRL(7),
6638c2ecf20Sopenharmony_ci	TEGRA_ADMAIF_CIF_CTRL(8),
6648c2ecf20Sopenharmony_ci	TEGRA_ADMAIF_CIF_CTRL(9),
6658c2ecf20Sopenharmony_ci	TEGRA_ADMAIF_CIF_CTRL(10),
6668c2ecf20Sopenharmony_ci};
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_cistatic struct snd_kcontrol_new tegra186_admaif_controls[] = {
6698c2ecf20Sopenharmony_ci	TEGRA_ADMAIF_CIF_CTRL(1),
6708c2ecf20Sopenharmony_ci	TEGRA_ADMAIF_CIF_CTRL(2),
6718c2ecf20Sopenharmony_ci	TEGRA_ADMAIF_CIF_CTRL(3),
6728c2ecf20Sopenharmony_ci	TEGRA_ADMAIF_CIF_CTRL(4),
6738c2ecf20Sopenharmony_ci	TEGRA_ADMAIF_CIF_CTRL(5),
6748c2ecf20Sopenharmony_ci	TEGRA_ADMAIF_CIF_CTRL(6),
6758c2ecf20Sopenharmony_ci	TEGRA_ADMAIF_CIF_CTRL(7),
6768c2ecf20Sopenharmony_ci	TEGRA_ADMAIF_CIF_CTRL(8),
6778c2ecf20Sopenharmony_ci	TEGRA_ADMAIF_CIF_CTRL(9),
6788c2ecf20Sopenharmony_ci	TEGRA_ADMAIF_CIF_CTRL(10),
6798c2ecf20Sopenharmony_ci	TEGRA_ADMAIF_CIF_CTRL(11),
6808c2ecf20Sopenharmony_ci	TEGRA_ADMAIF_CIF_CTRL(12),
6818c2ecf20Sopenharmony_ci	TEGRA_ADMAIF_CIF_CTRL(13),
6828c2ecf20Sopenharmony_ci	TEGRA_ADMAIF_CIF_CTRL(14),
6838c2ecf20Sopenharmony_ci	TEGRA_ADMAIF_CIF_CTRL(15),
6848c2ecf20Sopenharmony_ci	TEGRA_ADMAIF_CIF_CTRL(16),
6858c2ecf20Sopenharmony_ci	TEGRA_ADMAIF_CIF_CTRL(17),
6868c2ecf20Sopenharmony_ci	TEGRA_ADMAIF_CIF_CTRL(18),
6878c2ecf20Sopenharmony_ci	TEGRA_ADMAIF_CIF_CTRL(19),
6888c2ecf20Sopenharmony_ci	TEGRA_ADMAIF_CIF_CTRL(20),
6898c2ecf20Sopenharmony_ci};
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver tegra210_admaif_cmpnt = {
6928c2ecf20Sopenharmony_ci	.controls		= tegra210_admaif_controls,
6938c2ecf20Sopenharmony_ci	.num_controls		= ARRAY_SIZE(tegra210_admaif_controls),
6948c2ecf20Sopenharmony_ci	.pcm_construct		= tegra_pcm_construct,
6958c2ecf20Sopenharmony_ci	.pcm_destruct		= tegra_pcm_destruct,
6968c2ecf20Sopenharmony_ci	.open			= tegra_pcm_open,
6978c2ecf20Sopenharmony_ci	.close			= tegra_pcm_close,
6988c2ecf20Sopenharmony_ci	.hw_params		= tegra_pcm_hw_params,
6998c2ecf20Sopenharmony_ci	.hw_free		= tegra_pcm_hw_free,
7008c2ecf20Sopenharmony_ci	.mmap			= tegra_pcm_mmap,
7018c2ecf20Sopenharmony_ci	.pointer		= tegra_pcm_pointer,
7028c2ecf20Sopenharmony_ci};
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver tegra186_admaif_cmpnt = {
7058c2ecf20Sopenharmony_ci	.controls		= tegra186_admaif_controls,
7068c2ecf20Sopenharmony_ci	.num_controls		= ARRAY_SIZE(tegra186_admaif_controls),
7078c2ecf20Sopenharmony_ci	.pcm_construct		= tegra_pcm_construct,
7088c2ecf20Sopenharmony_ci	.pcm_destruct		= tegra_pcm_destruct,
7098c2ecf20Sopenharmony_ci	.open			= tegra_pcm_open,
7108c2ecf20Sopenharmony_ci	.close			= tegra_pcm_close,
7118c2ecf20Sopenharmony_ci	.hw_params		= tegra_pcm_hw_params,
7128c2ecf20Sopenharmony_ci	.hw_free		= tegra_pcm_hw_free,
7138c2ecf20Sopenharmony_ci	.mmap			= tegra_pcm_mmap,
7148c2ecf20Sopenharmony_ci	.pointer		= tegra_pcm_pointer,
7158c2ecf20Sopenharmony_ci};
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_cistatic const struct tegra_admaif_soc_data soc_data_tegra210 = {
7188c2ecf20Sopenharmony_ci	.num_ch		= TEGRA210_ADMAIF_CHANNEL_COUNT,
7198c2ecf20Sopenharmony_ci	.cmpnt		= &tegra210_admaif_cmpnt,
7208c2ecf20Sopenharmony_ci	.dais		= tegra210_admaif_cmpnt_dais,
7218c2ecf20Sopenharmony_ci	.regmap_conf	= &tegra210_admaif_regmap_config,
7228c2ecf20Sopenharmony_ci	.global_base	= TEGRA210_ADMAIF_GLOBAL_BASE,
7238c2ecf20Sopenharmony_ci	.tx_base	= TEGRA210_ADMAIF_TX_BASE,
7248c2ecf20Sopenharmony_ci	.rx_base	= TEGRA210_ADMAIF_RX_BASE,
7258c2ecf20Sopenharmony_ci};
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_cistatic const struct tegra_admaif_soc_data soc_data_tegra186 = {
7288c2ecf20Sopenharmony_ci	.num_ch		= TEGRA186_ADMAIF_CHANNEL_COUNT,
7298c2ecf20Sopenharmony_ci	.cmpnt		= &tegra186_admaif_cmpnt,
7308c2ecf20Sopenharmony_ci	.dais		= tegra186_admaif_cmpnt_dais,
7318c2ecf20Sopenharmony_ci	.regmap_conf	= &tegra186_admaif_regmap_config,
7328c2ecf20Sopenharmony_ci	.global_base	= TEGRA186_ADMAIF_GLOBAL_BASE,
7338c2ecf20Sopenharmony_ci	.tx_base	= TEGRA186_ADMAIF_TX_BASE,
7348c2ecf20Sopenharmony_ci	.rx_base	= TEGRA186_ADMAIF_RX_BASE,
7358c2ecf20Sopenharmony_ci};
7368c2ecf20Sopenharmony_ci
7378c2ecf20Sopenharmony_cistatic const struct of_device_id tegra_admaif_of_match[] = {
7388c2ecf20Sopenharmony_ci	{ .compatible = "nvidia,tegra210-admaif", .data = &soc_data_tegra210 },
7398c2ecf20Sopenharmony_ci	{ .compatible = "nvidia,tegra186-admaif", .data = &soc_data_tegra186 },
7408c2ecf20Sopenharmony_ci	{},
7418c2ecf20Sopenharmony_ci};
7428c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, tegra_admaif_of_match);
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_cistatic int tegra_admaif_probe(struct platform_device *pdev)
7458c2ecf20Sopenharmony_ci{
7468c2ecf20Sopenharmony_ci	struct tegra_admaif *admaif;
7478c2ecf20Sopenharmony_ci	void __iomem *regs;
7488c2ecf20Sopenharmony_ci	struct resource *res;
7498c2ecf20Sopenharmony_ci	int err, i;
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci	admaif = devm_kzalloc(&pdev->dev, sizeof(*admaif), GFP_KERNEL);
7528c2ecf20Sopenharmony_ci	if (!admaif)
7538c2ecf20Sopenharmony_ci		return -ENOMEM;
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_ci	admaif->soc_data = of_device_get_match_data(&pdev->dev);
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_ci	dev_set_drvdata(&pdev->dev, admaif);
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci	admaif->capture_dma_data =
7608c2ecf20Sopenharmony_ci		devm_kcalloc(&pdev->dev,
7618c2ecf20Sopenharmony_ci			     admaif->soc_data->num_ch,
7628c2ecf20Sopenharmony_ci			     sizeof(struct snd_dmaengine_dai_dma_data),
7638c2ecf20Sopenharmony_ci			     GFP_KERNEL);
7648c2ecf20Sopenharmony_ci	if (!admaif->capture_dma_data)
7658c2ecf20Sopenharmony_ci		return -ENOMEM;
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci	admaif->playback_dma_data =
7688c2ecf20Sopenharmony_ci		devm_kcalloc(&pdev->dev,
7698c2ecf20Sopenharmony_ci			     admaif->soc_data->num_ch,
7708c2ecf20Sopenharmony_ci			     sizeof(struct snd_dmaengine_dai_dma_data),
7718c2ecf20Sopenharmony_ci			     GFP_KERNEL);
7728c2ecf20Sopenharmony_ci	if (!admaif->playback_dma_data)
7738c2ecf20Sopenharmony_ci		return -ENOMEM;
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci	for (i = 0; i < ADMAIF_PATHS; i++) {
7768c2ecf20Sopenharmony_ci		admaif->mono_to_stereo[i] =
7778c2ecf20Sopenharmony_ci			devm_kcalloc(&pdev->dev, admaif->soc_data->num_ch,
7788c2ecf20Sopenharmony_ci				     sizeof(unsigned int), GFP_KERNEL);
7798c2ecf20Sopenharmony_ci		if (!admaif->mono_to_stereo[i])
7808c2ecf20Sopenharmony_ci			return -ENOMEM;
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci		admaif->stereo_to_mono[i] =
7838c2ecf20Sopenharmony_ci			devm_kcalloc(&pdev->dev, admaif->soc_data->num_ch,
7848c2ecf20Sopenharmony_ci				     sizeof(unsigned int), GFP_KERNEL);
7858c2ecf20Sopenharmony_ci		if (!admaif->stereo_to_mono[i])
7868c2ecf20Sopenharmony_ci			return -ENOMEM;
7878c2ecf20Sopenharmony_ci	}
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_ci	regs = devm_ioremap_resource(&pdev->dev, res);
7928c2ecf20Sopenharmony_ci	if (IS_ERR(regs))
7938c2ecf20Sopenharmony_ci		return PTR_ERR(regs);
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_ci	admaif->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
7968c2ecf20Sopenharmony_ci					       admaif->soc_data->regmap_conf);
7978c2ecf20Sopenharmony_ci	if (IS_ERR(admaif->regmap)) {
7988c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "regmap init failed\n");
7998c2ecf20Sopenharmony_ci		return PTR_ERR(admaif->regmap);
8008c2ecf20Sopenharmony_ci	}
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_ci	regcache_cache_only(admaif->regmap, true);
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_ci	regmap_update_bits(admaif->regmap, admaif->soc_data->global_base +
8058c2ecf20Sopenharmony_ci			   TEGRA_ADMAIF_GLOBAL_ENABLE, 1, 1);
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_ci	for (i = 0; i < admaif->soc_data->num_ch; i++) {
8088c2ecf20Sopenharmony_ci		admaif->playback_dma_data[i].addr = res->start +
8098c2ecf20Sopenharmony_ci			CH_TX_REG(TEGRA_ADMAIF_TX_FIFO_WRITE, i);
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci		admaif->capture_dma_data[i].addr = res->start +
8128c2ecf20Sopenharmony_ci			CH_RX_REG(TEGRA_ADMAIF_RX_FIFO_READ, i);
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci		admaif->playback_dma_data[i].addr_width = 32;
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_ci		if (of_property_read_string_index(pdev->dev.of_node,
8178c2ecf20Sopenharmony_ci				"dma-names", (i * 2) + 1,
8188c2ecf20Sopenharmony_ci				&admaif->playback_dma_data[i].chan_name) < 0) {
8198c2ecf20Sopenharmony_ci			dev_err(&pdev->dev,
8208c2ecf20Sopenharmony_ci				"missing property nvidia,dma-names\n");
8218c2ecf20Sopenharmony_ci
8228c2ecf20Sopenharmony_ci			return -ENODEV;
8238c2ecf20Sopenharmony_ci		}
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci		admaif->capture_dma_data[i].addr_width = 32;
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_ci		if (of_property_read_string_index(pdev->dev.of_node,
8288c2ecf20Sopenharmony_ci				"dma-names",
8298c2ecf20Sopenharmony_ci				(i * 2),
8308c2ecf20Sopenharmony_ci				&admaif->capture_dma_data[i].chan_name) < 0) {
8318c2ecf20Sopenharmony_ci			dev_err(&pdev->dev,
8328c2ecf20Sopenharmony_ci				"missing property nvidia,dma-names\n");
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ci			return -ENODEV;
8358c2ecf20Sopenharmony_ci		}
8368c2ecf20Sopenharmony_ci	}
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_ci	err = devm_snd_soc_register_component(&pdev->dev,
8398c2ecf20Sopenharmony_ci					      admaif->soc_data->cmpnt,
8408c2ecf20Sopenharmony_ci					      admaif->soc_data->dais,
8418c2ecf20Sopenharmony_ci					      admaif->soc_data->num_ch);
8428c2ecf20Sopenharmony_ci	if (err) {
8438c2ecf20Sopenharmony_ci		dev_err(&pdev->dev,
8448c2ecf20Sopenharmony_ci			"can't register ADMAIF component, err: %d\n", err);
8458c2ecf20Sopenharmony_ci		return err;
8468c2ecf20Sopenharmony_ci	}
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_ci	pm_runtime_enable(&pdev->dev);
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_ci	return 0;
8518c2ecf20Sopenharmony_ci}
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_cistatic int tegra_admaif_remove(struct platform_device *pdev)
8548c2ecf20Sopenharmony_ci{
8558c2ecf20Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_ci	return 0;
8588c2ecf20Sopenharmony_ci}
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_cistatic const struct dev_pm_ops tegra_admaif_pm_ops = {
8618c2ecf20Sopenharmony_ci	SET_RUNTIME_PM_OPS(tegra_admaif_runtime_suspend,
8628c2ecf20Sopenharmony_ci			   tegra_admaif_runtime_resume, NULL)
8638c2ecf20Sopenharmony_ci	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
8648c2ecf20Sopenharmony_ci				pm_runtime_force_resume)
8658c2ecf20Sopenharmony_ci};
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_cistatic struct platform_driver tegra_admaif_driver = {
8688c2ecf20Sopenharmony_ci	.probe = tegra_admaif_probe,
8698c2ecf20Sopenharmony_ci	.remove = tegra_admaif_remove,
8708c2ecf20Sopenharmony_ci	.driver = {
8718c2ecf20Sopenharmony_ci		.name = "tegra210-admaif",
8728c2ecf20Sopenharmony_ci		.of_match_table = tegra_admaif_of_match,
8738c2ecf20Sopenharmony_ci		.pm = &tegra_admaif_pm_ops,
8748c2ecf20Sopenharmony_ci	},
8758c2ecf20Sopenharmony_ci};
8768c2ecf20Sopenharmony_cimodule_platform_driver(tegra_admaif_driver);
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_ciMODULE_AUTHOR("Songhee Baek <sbaek@nvidia.com>");
8798c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Tegra210 ASoC ADMAIF driver");
8808c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
881