xref: /linux/sound/soc/tegra/tegra210_admaif.c (revision ab93e0dd72c37d378dd936f031ffb83ff2bd87ce)
1f74028e1SSameer Pujar // SPDX-License-Identifier: GPL-2.0-only
24a91fe4cSSheetal // SPDX-FileCopyrightText: Copyright (c) 2020-2025 NVIDIA CORPORATION & AFFILIATES.
34204ecccSRitu Chaudhary // All rights reserved.
4f74028e1SSameer Pujar //
5f74028e1SSameer Pujar // tegra210_admaif.c - Tegra ADMAIF driver
6f74028e1SSameer Pujar 
7f74028e1SSameer Pujar #include <linux/clk.h>
8f74028e1SSameer Pujar #include <linux/device.h>
9f74028e1SSameer Pujar #include <linux/module.h>
10f74028e1SSameer Pujar #include <linux/of_platform.h>
11f74028e1SSameer Pujar #include <linux/platform_device.h>
12f74028e1SSameer Pujar #include <linux/pm_runtime.h>
13f74028e1SSameer Pujar #include <linux/regmap.h>
14f74028e1SSameer Pujar #include <sound/pcm_params.h>
15f74028e1SSameer Pujar #include <sound/soc.h>
164a91fe4cSSheetal #include "tegra_isomgr_bw.h"
17f74028e1SSameer Pujar #include "tegra210_admaif.h"
18f74028e1SSameer Pujar #include "tegra_cif.h"
19f74028e1SSameer Pujar #include "tegra_pcm.h"
20f74028e1SSameer Pujar 
21f74028e1SSameer Pujar #define CH_REG(offset, reg, id)						       \
22f74028e1SSameer Pujar 	((offset) + (reg) + (TEGRA_ADMAIF_CHANNEL_REG_STRIDE * (id)))
23f74028e1SSameer Pujar 
24f74028e1SSameer Pujar #define CH_TX_REG(reg, id) CH_REG(admaif->soc_data->tx_base, reg, id)
25f74028e1SSameer Pujar 
26f74028e1SSameer Pujar #define CH_RX_REG(reg, id) CH_REG(admaif->soc_data->rx_base, reg, id)
27f74028e1SSameer Pujar 
28*7668c637SSheetal #define REG_DEFAULTS(id, rx_ctrl, tx_ctrl, tx_base, rx_base, cif_ctrl)	       \
29f74028e1SSameer Pujar 	{ CH_REG(rx_base, TEGRA_ADMAIF_RX_INT_MASK, id), 0x00000001 },	       \
30*7668c637SSheetal 	{ CH_REG(rx_base, TEGRA_ADMAIF_CH_ACIF_RX_CTRL, id), cif_ctrl },     \
31f74028e1SSameer Pujar 	{ CH_REG(rx_base, TEGRA_ADMAIF_RX_FIFO_CTRL, id), rx_ctrl },	       \
32f74028e1SSameer Pujar 	{ CH_REG(tx_base, TEGRA_ADMAIF_TX_INT_MASK, id), 0x00000001 },	       \
33*7668c637SSheetal 	{ CH_REG(tx_base, TEGRA_ADMAIF_CH_ACIF_TX_CTRL, id), cif_ctrl },     \
34f74028e1SSameer Pujar 	{ CH_REG(tx_base, TEGRA_ADMAIF_TX_FIFO_CTRL, id), tx_ctrl }
35f74028e1SSameer Pujar 
36f74028e1SSameer Pujar #define ADMAIF_REG_DEFAULTS(id, chip)					       \
37f74028e1SSameer Pujar 	REG_DEFAULTS((id) - 1,						       \
38f74028e1SSameer Pujar 		chip ## _ADMAIF_RX ## id ## _FIFO_CTRL_REG_DEFAULT,	       \
39f74028e1SSameer Pujar 		chip ## _ADMAIF_TX ## id ## _FIFO_CTRL_REG_DEFAULT,	       \
40f74028e1SSameer Pujar 		chip ## _ADMAIF_TX_BASE,				       \
41*7668c637SSheetal 		chip ## _ADMAIF_RX_BASE,				       \
42*7668c637SSheetal 		chip ## _ADMAIF_CIF_REG_DEFAULT)
43f74028e1SSameer Pujar 
44f74028e1SSameer Pujar static const struct reg_default tegra186_admaif_reg_defaults[] = {
45f74028e1SSameer Pujar 	{(TEGRA_ADMAIF_GLOBAL_CG_0 + TEGRA186_ADMAIF_GLOBAL_BASE), 0x00000003},
46f74028e1SSameer Pujar 	ADMAIF_REG_DEFAULTS(1, TEGRA186),
47f74028e1SSameer Pujar 	ADMAIF_REG_DEFAULTS(2, TEGRA186),
48f74028e1SSameer Pujar 	ADMAIF_REG_DEFAULTS(3, TEGRA186),
49f74028e1SSameer Pujar 	ADMAIF_REG_DEFAULTS(4, TEGRA186),
50f74028e1SSameer Pujar 	ADMAIF_REG_DEFAULTS(5, TEGRA186),
51f74028e1SSameer Pujar 	ADMAIF_REG_DEFAULTS(6, TEGRA186),
52f74028e1SSameer Pujar 	ADMAIF_REG_DEFAULTS(7, TEGRA186),
53f74028e1SSameer Pujar 	ADMAIF_REG_DEFAULTS(8, TEGRA186),
54f74028e1SSameer Pujar 	ADMAIF_REG_DEFAULTS(9, TEGRA186),
55f74028e1SSameer Pujar 	ADMAIF_REG_DEFAULTS(10, TEGRA186),
56f74028e1SSameer Pujar 	ADMAIF_REG_DEFAULTS(11, TEGRA186),
57f74028e1SSameer Pujar 	ADMAIF_REG_DEFAULTS(12, TEGRA186),
58f74028e1SSameer Pujar 	ADMAIF_REG_DEFAULTS(13, TEGRA186),
59f74028e1SSameer Pujar 	ADMAIF_REG_DEFAULTS(14, TEGRA186),
60f74028e1SSameer Pujar 	ADMAIF_REG_DEFAULTS(15, TEGRA186),
61f74028e1SSameer Pujar 	ADMAIF_REG_DEFAULTS(16, TEGRA186),
62f74028e1SSameer Pujar 	ADMAIF_REG_DEFAULTS(17, TEGRA186),
63f74028e1SSameer Pujar 	ADMAIF_REG_DEFAULTS(18, TEGRA186),
64f74028e1SSameer Pujar 	ADMAIF_REG_DEFAULTS(19, TEGRA186),
65f74028e1SSameer Pujar 	ADMAIF_REG_DEFAULTS(20, TEGRA186)
66f74028e1SSameer Pujar };
67f74028e1SSameer Pujar 
68f74028e1SSameer Pujar static const struct reg_default tegra210_admaif_reg_defaults[] = {
69f74028e1SSameer Pujar 	{(TEGRA_ADMAIF_GLOBAL_CG_0 + TEGRA210_ADMAIF_GLOBAL_BASE), 0x00000003},
70f74028e1SSameer Pujar 	ADMAIF_REG_DEFAULTS(1, TEGRA210),
71f74028e1SSameer Pujar 	ADMAIF_REG_DEFAULTS(2, TEGRA210),
72f74028e1SSameer Pujar 	ADMAIF_REG_DEFAULTS(3, TEGRA210),
73f74028e1SSameer Pujar 	ADMAIF_REG_DEFAULTS(4, TEGRA210),
74f74028e1SSameer Pujar 	ADMAIF_REG_DEFAULTS(5, TEGRA210),
75f74028e1SSameer Pujar 	ADMAIF_REG_DEFAULTS(6, TEGRA210),
76f74028e1SSameer Pujar 	ADMAIF_REG_DEFAULTS(7, TEGRA210),
77f74028e1SSameer Pujar 	ADMAIF_REG_DEFAULTS(8, TEGRA210),
78f74028e1SSameer Pujar 	ADMAIF_REG_DEFAULTS(9, TEGRA210),
79f74028e1SSameer Pujar 	ADMAIF_REG_DEFAULTS(10, TEGRA210)
80f74028e1SSameer Pujar };
81f74028e1SSameer Pujar 
82*7668c637SSheetal static const struct reg_default tegra264_admaif_reg_defaults[] = {
83*7668c637SSheetal 	{(TEGRA_ADMAIF_GLOBAL_CG_0 + TEGRA264_ADMAIF_GLOBAL_BASE), 0x00000003},
84*7668c637SSheetal 	ADMAIF_REG_DEFAULTS(1, TEGRA264),
85*7668c637SSheetal 	ADMAIF_REG_DEFAULTS(2, TEGRA264),
86*7668c637SSheetal 	ADMAIF_REG_DEFAULTS(3, TEGRA264),
87*7668c637SSheetal 	ADMAIF_REG_DEFAULTS(4, TEGRA264),
88*7668c637SSheetal 	ADMAIF_REG_DEFAULTS(5, TEGRA264),
89*7668c637SSheetal 	ADMAIF_REG_DEFAULTS(6, TEGRA264),
90*7668c637SSheetal 	ADMAIF_REG_DEFAULTS(7, TEGRA264),
91*7668c637SSheetal 	ADMAIF_REG_DEFAULTS(8, TEGRA264),
92*7668c637SSheetal 	ADMAIF_REG_DEFAULTS(9, TEGRA264),
93*7668c637SSheetal 	ADMAIF_REG_DEFAULTS(10, TEGRA264),
94*7668c637SSheetal 	ADMAIF_REG_DEFAULTS(11, TEGRA264),
95*7668c637SSheetal 	ADMAIF_REG_DEFAULTS(12, TEGRA264),
96*7668c637SSheetal 	ADMAIF_REG_DEFAULTS(13, TEGRA264),
97*7668c637SSheetal 	ADMAIF_REG_DEFAULTS(14, TEGRA264),
98*7668c637SSheetal 	ADMAIF_REG_DEFAULTS(15, TEGRA264),
99*7668c637SSheetal 	ADMAIF_REG_DEFAULTS(16, TEGRA264),
100*7668c637SSheetal 	ADMAIF_REG_DEFAULTS(17, TEGRA264),
101*7668c637SSheetal 	ADMAIF_REG_DEFAULTS(18, TEGRA264),
102*7668c637SSheetal 	ADMAIF_REG_DEFAULTS(19, TEGRA264),
103*7668c637SSheetal 	ADMAIF_REG_DEFAULTS(20, TEGRA264),
104*7668c637SSheetal 	ADMAIF_REG_DEFAULTS(21, TEGRA264),
105*7668c637SSheetal 	ADMAIF_REG_DEFAULTS(22, TEGRA264),
106*7668c637SSheetal 	ADMAIF_REG_DEFAULTS(23, TEGRA264),
107*7668c637SSheetal 	ADMAIF_REG_DEFAULTS(24, TEGRA264),
108*7668c637SSheetal 	ADMAIF_REG_DEFAULTS(25, TEGRA264),
109*7668c637SSheetal 	ADMAIF_REG_DEFAULTS(26, TEGRA264),
110*7668c637SSheetal 	ADMAIF_REG_DEFAULTS(27, TEGRA264),
111*7668c637SSheetal 	ADMAIF_REG_DEFAULTS(28, TEGRA264),
112*7668c637SSheetal 	ADMAIF_REG_DEFAULTS(29, TEGRA264),
113*7668c637SSheetal 	ADMAIF_REG_DEFAULTS(30, TEGRA264),
114*7668c637SSheetal 	ADMAIF_REG_DEFAULTS(31, TEGRA264),
115*7668c637SSheetal 	ADMAIF_REG_DEFAULTS(32, TEGRA264)
116*7668c637SSheetal };
117*7668c637SSheetal 
tegra_admaif_wr_reg(struct device * dev,unsigned int reg)118f74028e1SSameer Pujar static bool tegra_admaif_wr_reg(struct device *dev, unsigned int reg)
119f74028e1SSameer Pujar {
120f74028e1SSameer Pujar 	struct tegra_admaif *admaif = dev_get_drvdata(dev);
121f74028e1SSameer Pujar 	unsigned int ch_stride = TEGRA_ADMAIF_CHANNEL_REG_STRIDE;
122f74028e1SSameer Pujar 	unsigned int num_ch = admaif->soc_data->num_ch;
123f74028e1SSameer Pujar 	unsigned int rx_base = admaif->soc_data->rx_base;
124f74028e1SSameer Pujar 	unsigned int tx_base = admaif->soc_data->tx_base;
125f74028e1SSameer Pujar 	unsigned int global_base = admaif->soc_data->global_base;
126f74028e1SSameer Pujar 	unsigned int reg_max = admaif->soc_data->regmap_conf->max_register;
127f74028e1SSameer Pujar 	unsigned int rx_max = rx_base + (num_ch * ch_stride);
128f74028e1SSameer Pujar 	unsigned int tx_max = tx_base + (num_ch * ch_stride);
129f74028e1SSameer Pujar 
130f74028e1SSameer Pujar 	if ((reg >= rx_base) && (reg < rx_max)) {
131f74028e1SSameer Pujar 		reg = (reg - rx_base) % ch_stride;
132f74028e1SSameer Pujar 		if ((reg == TEGRA_ADMAIF_RX_ENABLE) ||
133f74028e1SSameer Pujar 		    (reg == TEGRA_ADMAIF_RX_FIFO_CTRL) ||
134f74028e1SSameer Pujar 		    (reg == TEGRA_ADMAIF_RX_SOFT_RESET) ||
135f74028e1SSameer Pujar 		    (reg == TEGRA_ADMAIF_CH_ACIF_RX_CTRL))
136f74028e1SSameer Pujar 			return true;
137f74028e1SSameer Pujar 	} else if ((reg >= tx_base) && (reg < tx_max)) {
138f74028e1SSameer Pujar 		reg = (reg - tx_base) % ch_stride;
139f74028e1SSameer Pujar 		if ((reg == TEGRA_ADMAIF_TX_ENABLE) ||
140f74028e1SSameer Pujar 		    (reg == TEGRA_ADMAIF_TX_FIFO_CTRL) ||
141f74028e1SSameer Pujar 		    (reg == TEGRA_ADMAIF_TX_SOFT_RESET) ||
142f74028e1SSameer Pujar 		    (reg == TEGRA_ADMAIF_CH_ACIF_TX_CTRL))
143f74028e1SSameer Pujar 			return true;
144f74028e1SSameer Pujar 	} else if ((reg >= global_base) && (reg < reg_max)) {
145f74028e1SSameer Pujar 		if (reg == (global_base + TEGRA_ADMAIF_GLOBAL_ENABLE))
146f74028e1SSameer Pujar 			return true;
147f74028e1SSameer Pujar 	}
148f74028e1SSameer Pujar 
149f74028e1SSameer Pujar 	return false;
150f74028e1SSameer Pujar }
151f74028e1SSameer Pujar 
tegra_admaif_rd_reg(struct device * dev,unsigned int reg)152f74028e1SSameer Pujar static bool tegra_admaif_rd_reg(struct device *dev, unsigned int reg)
153f74028e1SSameer Pujar {
154f74028e1SSameer Pujar 	struct tegra_admaif *admaif = dev_get_drvdata(dev);
155f74028e1SSameer Pujar 	unsigned int ch_stride = TEGRA_ADMAIF_CHANNEL_REG_STRIDE;
156f74028e1SSameer Pujar 	unsigned int num_ch = admaif->soc_data->num_ch;
157f74028e1SSameer Pujar 	unsigned int rx_base = admaif->soc_data->rx_base;
158f74028e1SSameer Pujar 	unsigned int tx_base = admaif->soc_data->tx_base;
159f74028e1SSameer Pujar 	unsigned int global_base = admaif->soc_data->global_base;
160f74028e1SSameer Pujar 	unsigned int reg_max = admaif->soc_data->regmap_conf->max_register;
161f74028e1SSameer Pujar 	unsigned int rx_max = rx_base + (num_ch * ch_stride);
162f74028e1SSameer Pujar 	unsigned int tx_max = tx_base + (num_ch * ch_stride);
163f74028e1SSameer Pujar 
164f74028e1SSameer Pujar 	if ((reg >= rx_base) && (reg < rx_max)) {
165f74028e1SSameer Pujar 		reg = (reg - rx_base) % ch_stride;
166f74028e1SSameer Pujar 		if ((reg == TEGRA_ADMAIF_RX_ENABLE) ||
167f74028e1SSameer Pujar 		    (reg == TEGRA_ADMAIF_RX_STATUS) ||
168f74028e1SSameer Pujar 		    (reg == TEGRA_ADMAIF_RX_INT_STATUS) ||
169f74028e1SSameer Pujar 		    (reg == TEGRA_ADMAIF_RX_FIFO_CTRL) ||
170f74028e1SSameer Pujar 		    (reg == TEGRA_ADMAIF_RX_SOFT_RESET) ||
171f74028e1SSameer Pujar 		    (reg == TEGRA_ADMAIF_CH_ACIF_RX_CTRL))
172f74028e1SSameer Pujar 			return true;
173f74028e1SSameer Pujar 	} else if ((reg >= tx_base) && (reg < tx_max)) {
174f74028e1SSameer Pujar 		reg = (reg - tx_base) % ch_stride;
175f74028e1SSameer Pujar 		if ((reg == TEGRA_ADMAIF_TX_ENABLE) ||
176f74028e1SSameer Pujar 		    (reg == TEGRA_ADMAIF_TX_STATUS) ||
177f74028e1SSameer Pujar 		    (reg == TEGRA_ADMAIF_TX_INT_STATUS) ||
178f74028e1SSameer Pujar 		    (reg == TEGRA_ADMAIF_TX_FIFO_CTRL) ||
179f74028e1SSameer Pujar 		    (reg == TEGRA_ADMAIF_TX_SOFT_RESET) ||
180f74028e1SSameer Pujar 		    (reg == TEGRA_ADMAIF_CH_ACIF_TX_CTRL))
181f74028e1SSameer Pujar 			return true;
182f74028e1SSameer Pujar 	} else if ((reg >= global_base) && (reg < reg_max)) {
183f74028e1SSameer Pujar 		if ((reg == (global_base + TEGRA_ADMAIF_GLOBAL_ENABLE)) ||
184f74028e1SSameer Pujar 		    (reg == (global_base + TEGRA_ADMAIF_GLOBAL_CG_0)) ||
185f74028e1SSameer Pujar 		    (reg == (global_base + TEGRA_ADMAIF_GLOBAL_STATUS)) ||
186f74028e1SSameer Pujar 		    (reg == (global_base +
187f74028e1SSameer Pujar 				TEGRA_ADMAIF_GLOBAL_RX_ENABLE_STATUS)) ||
188f74028e1SSameer Pujar 		    (reg == (global_base +
189f74028e1SSameer Pujar 				TEGRA_ADMAIF_GLOBAL_TX_ENABLE_STATUS)))
190f74028e1SSameer Pujar 			return true;
191f74028e1SSameer Pujar 	}
192f74028e1SSameer Pujar 
193f74028e1SSameer Pujar 	return false;
194f74028e1SSameer Pujar }
195f74028e1SSameer Pujar 
tegra_admaif_volatile_reg(struct device * dev,unsigned int reg)196f74028e1SSameer Pujar static bool tegra_admaif_volatile_reg(struct device *dev, unsigned int reg)
197f74028e1SSameer Pujar {
198f74028e1SSameer Pujar 	struct tegra_admaif *admaif = dev_get_drvdata(dev);
199f74028e1SSameer Pujar 	unsigned int ch_stride = TEGRA_ADMAIF_CHANNEL_REG_STRIDE;
200f74028e1SSameer Pujar 	unsigned int num_ch = admaif->soc_data->num_ch;
201f74028e1SSameer Pujar 	unsigned int rx_base = admaif->soc_data->rx_base;
202f74028e1SSameer Pujar 	unsigned int tx_base = admaif->soc_data->tx_base;
203f74028e1SSameer Pujar 	unsigned int global_base = admaif->soc_data->global_base;
204f74028e1SSameer Pujar 	unsigned int reg_max = admaif->soc_data->regmap_conf->max_register;
205f74028e1SSameer Pujar 	unsigned int rx_max = rx_base + (num_ch * ch_stride);
206f74028e1SSameer Pujar 	unsigned int tx_max = tx_base + (num_ch * ch_stride);
207f74028e1SSameer Pujar 
208f74028e1SSameer Pujar 	if ((reg >= rx_base) && (reg < rx_max)) {
209f74028e1SSameer Pujar 		reg = (reg - rx_base) % ch_stride;
210f74028e1SSameer Pujar 		if ((reg == TEGRA_ADMAIF_RX_ENABLE) ||
211f74028e1SSameer Pujar 		    (reg == TEGRA_ADMAIF_RX_STATUS) ||
212f74028e1SSameer Pujar 		    (reg == TEGRA_ADMAIF_RX_INT_STATUS) ||
213f74028e1SSameer Pujar 		    (reg == TEGRA_ADMAIF_RX_SOFT_RESET))
214f74028e1SSameer Pujar 			return true;
215f74028e1SSameer Pujar 	} else if ((reg >= tx_base) && (reg < tx_max)) {
216f74028e1SSameer Pujar 		reg = (reg - tx_base) % ch_stride;
217f74028e1SSameer Pujar 		if ((reg == TEGRA_ADMAIF_TX_ENABLE) ||
218f74028e1SSameer Pujar 		    (reg == TEGRA_ADMAIF_TX_STATUS) ||
219f74028e1SSameer Pujar 		    (reg == TEGRA_ADMAIF_TX_INT_STATUS) ||
220f74028e1SSameer Pujar 		    (reg == TEGRA_ADMAIF_TX_SOFT_RESET))
221f74028e1SSameer Pujar 			return true;
222f74028e1SSameer Pujar 	} else if ((reg >= global_base) && (reg < reg_max)) {
223f74028e1SSameer Pujar 		if ((reg == (global_base + TEGRA_ADMAIF_GLOBAL_STATUS)) ||
224f74028e1SSameer Pujar 		    (reg == (global_base +
225f74028e1SSameer Pujar 				TEGRA_ADMAIF_GLOBAL_RX_ENABLE_STATUS)) ||
226f74028e1SSameer Pujar 		    (reg == (global_base +
227f74028e1SSameer Pujar 				TEGRA_ADMAIF_GLOBAL_TX_ENABLE_STATUS)))
228f74028e1SSameer Pujar 			return true;
229f74028e1SSameer Pujar 	}
230f74028e1SSameer Pujar 
231f74028e1SSameer Pujar 	return false;
232f74028e1SSameer Pujar }
233f74028e1SSameer Pujar 
234f74028e1SSameer Pujar static const struct regmap_config tegra210_admaif_regmap_config = {
235f74028e1SSameer Pujar 	.reg_bits		= 32,
236f74028e1SSameer Pujar 	.reg_stride		= 4,
237f74028e1SSameer Pujar 	.val_bits		= 32,
238f74028e1SSameer Pujar 	.max_register		= TEGRA210_ADMAIF_LAST_REG,
239f74028e1SSameer Pujar 	.writeable_reg		= tegra_admaif_wr_reg,
240f74028e1SSameer Pujar 	.readable_reg		= tegra_admaif_rd_reg,
241f74028e1SSameer Pujar 	.volatile_reg		= tegra_admaif_volatile_reg,
242f74028e1SSameer Pujar 	.reg_defaults		= tegra210_admaif_reg_defaults,
243f74028e1SSameer Pujar 	.num_reg_defaults	= TEGRA210_ADMAIF_CHANNEL_COUNT * 6 + 1,
244f74028e1SSameer Pujar 	.cache_type		= REGCACHE_FLAT,
245f74028e1SSameer Pujar };
246f74028e1SSameer Pujar 
247f74028e1SSameer Pujar static const struct regmap_config tegra186_admaif_regmap_config = {
248f74028e1SSameer Pujar 	.reg_bits		= 32,
249f74028e1SSameer Pujar 	.reg_stride		= 4,
250f74028e1SSameer Pujar 	.val_bits		= 32,
251f74028e1SSameer Pujar 	.max_register		= TEGRA186_ADMAIF_LAST_REG,
252f74028e1SSameer Pujar 	.writeable_reg		= tegra_admaif_wr_reg,
253f74028e1SSameer Pujar 	.readable_reg		= tegra_admaif_rd_reg,
254f74028e1SSameer Pujar 	.volatile_reg		= tegra_admaif_volatile_reg,
255f74028e1SSameer Pujar 	.reg_defaults		= tegra186_admaif_reg_defaults,
256f74028e1SSameer Pujar 	.num_reg_defaults	= TEGRA186_ADMAIF_CHANNEL_COUNT * 6 + 1,
257f74028e1SSameer Pujar 	.cache_type		= REGCACHE_FLAT,
258f74028e1SSameer Pujar };
259f74028e1SSameer Pujar 
260*7668c637SSheetal static const struct regmap_config tegra264_admaif_regmap_config = {
261*7668c637SSheetal 	.reg_bits		= 32,
262*7668c637SSheetal 	.reg_stride		= 4,
263*7668c637SSheetal 	.val_bits		= 32,
264*7668c637SSheetal 	.max_register		= TEGRA264_ADMAIF_LAST_REG,
265*7668c637SSheetal 	.writeable_reg		= tegra_admaif_wr_reg,
266*7668c637SSheetal 	.readable_reg		= tegra_admaif_rd_reg,
267*7668c637SSheetal 	.volatile_reg		= tegra_admaif_volatile_reg,
268*7668c637SSheetal 	.reg_defaults		= tegra264_admaif_reg_defaults,
269*7668c637SSheetal 	.num_reg_defaults	= TEGRA264_ADMAIF_CHANNEL_COUNT * 6 + 1,
270*7668c637SSheetal 	.cache_type		= REGCACHE_FLAT,
271*7668c637SSheetal };
272*7668c637SSheetal 
tegra_admaif_runtime_suspend(struct device * dev)273083c6a6fSTakashi Iwai static int tegra_admaif_runtime_suspend(struct device *dev)
274f74028e1SSameer Pujar {
275f74028e1SSameer Pujar 	struct tegra_admaif *admaif = dev_get_drvdata(dev);
276f74028e1SSameer Pujar 
277f74028e1SSameer Pujar 	regcache_cache_only(admaif->regmap, true);
278f74028e1SSameer Pujar 	regcache_mark_dirty(admaif->regmap);
279f74028e1SSameer Pujar 
280f74028e1SSameer Pujar 	return 0;
281f74028e1SSameer Pujar }
282f74028e1SSameer Pujar 
tegra_admaif_runtime_resume(struct device * dev)283083c6a6fSTakashi Iwai static int tegra_admaif_runtime_resume(struct device *dev)
284f74028e1SSameer Pujar {
285f74028e1SSameer Pujar 	struct tegra_admaif *admaif = dev_get_drvdata(dev);
286f74028e1SSameer Pujar 
287f74028e1SSameer Pujar 	regcache_cache_only(admaif->regmap, false);
288f74028e1SSameer Pujar 	regcache_sync(admaif->regmap);
289f74028e1SSameer Pujar 
290f74028e1SSameer Pujar 	return 0;
291f74028e1SSameer Pujar }
292f74028e1SSameer Pujar 
tegra_admaif_set_pack_mode(struct regmap * map,unsigned int reg,int valid_bit)293f74028e1SSameer Pujar static int tegra_admaif_set_pack_mode(struct regmap *map, unsigned int reg,
294f74028e1SSameer Pujar 				      int valid_bit)
295f74028e1SSameer Pujar {
296f74028e1SSameer Pujar 	switch (valid_bit) {
297f74028e1SSameer Pujar 	case DATA_8BIT:
298f74028e1SSameer Pujar 		regmap_update_bits(map, reg, PACK8_EN_MASK, PACK8_EN);
299f74028e1SSameer Pujar 		regmap_update_bits(map, reg, PACK16_EN_MASK, 0);
300f74028e1SSameer Pujar 		break;
301f74028e1SSameer Pujar 	case DATA_16BIT:
302f74028e1SSameer Pujar 		regmap_update_bits(map, reg, PACK16_EN_MASK, PACK16_EN);
303f74028e1SSameer Pujar 		regmap_update_bits(map, reg, PACK8_EN_MASK, 0);
304f74028e1SSameer Pujar 		break;
305f74028e1SSameer Pujar 	case DATA_32BIT:
306f74028e1SSameer Pujar 		regmap_update_bits(map, reg, PACK16_EN_MASK, 0);
307f74028e1SSameer Pujar 		regmap_update_bits(map, reg, PACK8_EN_MASK, 0);
308f74028e1SSameer Pujar 		break;
309f74028e1SSameer Pujar 	default:
310f74028e1SSameer Pujar 		return -EINVAL;
311f74028e1SSameer Pujar 	}
312f74028e1SSameer Pujar 
313f74028e1SSameer Pujar 	return 0;
314f74028e1SSameer Pujar }
315f74028e1SSameer Pujar 
tegra_admaif_prepare(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)3164a91fe4cSSheetal static int tegra_admaif_prepare(struct snd_pcm_substream *substream,
3174a91fe4cSSheetal 				struct snd_soc_dai *dai)
3184a91fe4cSSheetal {
3194a91fe4cSSheetal 	return tegra_isomgr_adma_setbw(substream, dai, true);
3204a91fe4cSSheetal }
3214a91fe4cSSheetal 
tegra_admaif_shutdown(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)3224a91fe4cSSheetal static void tegra_admaif_shutdown(struct snd_pcm_substream *substream,
3234a91fe4cSSheetal 				  struct snd_soc_dai *dai)
3244a91fe4cSSheetal {
3254a91fe4cSSheetal 	tegra_isomgr_adma_setbw(substream, dai, false);
3264a91fe4cSSheetal }
3274a91fe4cSSheetal 
tegra_admaif_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)328f74028e1SSameer Pujar static int tegra_admaif_hw_params(struct snd_pcm_substream *substream,
329f74028e1SSameer Pujar 				  struct snd_pcm_hw_params *params,
330f74028e1SSameer Pujar 				  struct snd_soc_dai *dai)
331f74028e1SSameer Pujar {
332f74028e1SSameer Pujar 	struct device *dev = dai->dev;
333f74028e1SSameer Pujar 	struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai);
334f74028e1SSameer Pujar 	struct tegra_cif_conf cif_conf;
335f74028e1SSameer Pujar 	unsigned int reg, path;
336f74028e1SSameer Pujar 	int valid_bit, channels;
337f74028e1SSameer Pujar 
338f74028e1SSameer Pujar 	memset(&cif_conf, 0, sizeof(struct tegra_cif_conf));
339f74028e1SSameer Pujar 
340f74028e1SSameer Pujar 	switch (params_format(params)) {
341f74028e1SSameer Pujar 	case SNDRV_PCM_FORMAT_S8:
342f74028e1SSameer Pujar 		cif_conf.audio_bits = TEGRA_ACIF_BITS_8;
343f74028e1SSameer Pujar 		cif_conf.client_bits = TEGRA_ACIF_BITS_8;
344f74028e1SSameer Pujar 		valid_bit = DATA_8BIT;
345f74028e1SSameer Pujar 		break;
346f74028e1SSameer Pujar 	case SNDRV_PCM_FORMAT_S16_LE:
347f74028e1SSameer Pujar 		cif_conf.audio_bits = TEGRA_ACIF_BITS_16;
348f74028e1SSameer Pujar 		cif_conf.client_bits = TEGRA_ACIF_BITS_16;
349f74028e1SSameer Pujar 		valid_bit = DATA_16BIT;
350f74028e1SSameer Pujar 		break;
3514204ecccSRitu Chaudhary 	case SNDRV_PCM_FORMAT_S24_LE:
3524204ecccSRitu Chaudhary 		cif_conf.audio_bits = TEGRA_ACIF_BITS_32;
3534204ecccSRitu Chaudhary 		cif_conf.client_bits = TEGRA_ACIF_BITS_24;
3544204ecccSRitu Chaudhary 		valid_bit = DATA_32BIT;
3554204ecccSRitu Chaudhary 		break;
356f74028e1SSameer Pujar 	case SNDRV_PCM_FORMAT_S32_LE:
357f74028e1SSameer Pujar 		cif_conf.audio_bits = TEGRA_ACIF_BITS_32;
358f74028e1SSameer Pujar 		cif_conf.client_bits = TEGRA_ACIF_BITS_32;
359f74028e1SSameer Pujar 		valid_bit  = DATA_32BIT;
360f74028e1SSameer Pujar 		break;
361f74028e1SSameer Pujar 	default:
362f74028e1SSameer Pujar 		dev_err(dev, "unsupported format!\n");
363f74028e1SSameer Pujar 		return -EOPNOTSUPP;
364f74028e1SSameer Pujar 	}
365f74028e1SSameer Pujar 
366f74028e1SSameer Pujar 	channels = params_channels(params);
367f74028e1SSameer Pujar 	cif_conf.client_ch = channels;
368f74028e1SSameer Pujar 	cif_conf.audio_ch = channels;
369f74028e1SSameer Pujar 
370f74028e1SSameer Pujar 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
371f74028e1SSameer Pujar 		path = ADMAIF_TX_PATH;
372f74028e1SSameer Pujar 		reg = CH_TX_REG(TEGRA_ADMAIF_CH_ACIF_TX_CTRL, dai->id);
373f74028e1SSameer Pujar 	} else {
374f74028e1SSameer Pujar 		path = ADMAIF_RX_PATH;
375f74028e1SSameer Pujar 		reg = CH_RX_REG(TEGRA_ADMAIF_CH_ACIF_RX_CTRL, dai->id);
376f74028e1SSameer Pujar 	}
377f74028e1SSameer Pujar 
378f74028e1SSameer Pujar 	cif_conf.mono_conv = admaif->mono_to_stereo[path][dai->id];
379f74028e1SSameer Pujar 	cif_conf.stereo_conv = admaif->stereo_to_mono[path][dai->id];
380f74028e1SSameer Pujar 
381f74028e1SSameer Pujar 	tegra_admaif_set_pack_mode(admaif->regmap, reg, valid_bit);
382f74028e1SSameer Pujar 
383*7668c637SSheetal 	if (admaif->soc_data->max_stream_ch == TEGRA264_ADMAIF_MAX_CHANNEL)
384*7668c637SSheetal 		tegra264_set_cif(admaif->regmap, reg, &cif_conf);
385*7668c637SSheetal 	else
386f74028e1SSameer Pujar 		tegra_set_cif(admaif->regmap, reg, &cif_conf);
387f74028e1SSameer Pujar 
388f74028e1SSameer Pujar 	return 0;
389f74028e1SSameer Pujar }
390f74028e1SSameer Pujar 
tegra_admaif_start(struct snd_soc_dai * dai,int direction)391f74028e1SSameer Pujar static int tegra_admaif_start(struct snd_soc_dai *dai, int direction)
392f74028e1SSameer Pujar {
393f74028e1SSameer Pujar 	struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai);
394f74028e1SSameer Pujar 	unsigned int reg, mask, val;
395f74028e1SSameer Pujar 
396f74028e1SSameer Pujar 	switch (direction) {
397f74028e1SSameer Pujar 	case SNDRV_PCM_STREAM_PLAYBACK:
398f74028e1SSameer Pujar 		mask = TX_ENABLE_MASK;
399f74028e1SSameer Pujar 		val = TX_ENABLE;
400f74028e1SSameer Pujar 		reg = CH_TX_REG(TEGRA_ADMAIF_TX_ENABLE, dai->id);
401f74028e1SSameer Pujar 		break;
402f74028e1SSameer Pujar 	case SNDRV_PCM_STREAM_CAPTURE:
403f74028e1SSameer Pujar 		mask = RX_ENABLE_MASK;
404f74028e1SSameer Pujar 		val = RX_ENABLE;
405f74028e1SSameer Pujar 		reg = CH_RX_REG(TEGRA_ADMAIF_RX_ENABLE, dai->id);
406f74028e1SSameer Pujar 		break;
407f74028e1SSameer Pujar 	default:
408f74028e1SSameer Pujar 		return -EINVAL;
409f74028e1SSameer Pujar 	}
410f74028e1SSameer Pujar 
411f74028e1SSameer Pujar 	regmap_update_bits(admaif->regmap, reg, mask, val);
412f74028e1SSameer Pujar 
413f74028e1SSameer Pujar 	return 0;
414f74028e1SSameer Pujar }
415f74028e1SSameer Pujar 
tegra_admaif_stop(struct snd_soc_dai * dai,int direction)416f74028e1SSameer Pujar static int tegra_admaif_stop(struct snd_soc_dai *dai, int direction)
417f74028e1SSameer Pujar {
418f74028e1SSameer Pujar 	struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai);
419f74028e1SSameer Pujar 	unsigned int enable_reg, status_reg, reset_reg, mask, val;
420f74028e1SSameer Pujar 	char *dir_name;
421f74028e1SSameer Pujar 	int err, enable;
422f74028e1SSameer Pujar 
423f74028e1SSameer Pujar 	switch (direction) {
424f74028e1SSameer Pujar 	case SNDRV_PCM_STREAM_PLAYBACK:
425f74028e1SSameer Pujar 		mask = TX_ENABLE_MASK;
426f74028e1SSameer Pujar 		enable = TX_ENABLE;
427f74028e1SSameer Pujar 		dir_name = "TX";
428f74028e1SSameer Pujar 		enable_reg = CH_TX_REG(TEGRA_ADMAIF_TX_ENABLE, dai->id);
429f74028e1SSameer Pujar 		status_reg = CH_TX_REG(TEGRA_ADMAIF_TX_STATUS, dai->id);
430f74028e1SSameer Pujar 		reset_reg = CH_TX_REG(TEGRA_ADMAIF_TX_SOFT_RESET, dai->id);
431f74028e1SSameer Pujar 		break;
432f74028e1SSameer Pujar 	case SNDRV_PCM_STREAM_CAPTURE:
433f74028e1SSameer Pujar 		mask = RX_ENABLE_MASK;
434f74028e1SSameer Pujar 		enable = RX_ENABLE;
435f74028e1SSameer Pujar 		dir_name = "RX";
436f74028e1SSameer Pujar 		enable_reg = CH_RX_REG(TEGRA_ADMAIF_RX_ENABLE, dai->id);
437f74028e1SSameer Pujar 		status_reg = CH_RX_REG(TEGRA_ADMAIF_RX_STATUS, dai->id);
438f74028e1SSameer Pujar 		reset_reg = CH_RX_REG(TEGRA_ADMAIF_RX_SOFT_RESET, dai->id);
439f74028e1SSameer Pujar 		break;
440f74028e1SSameer Pujar 	default:
441f74028e1SSameer Pujar 		return -EINVAL;
442f74028e1SSameer Pujar 	}
443f74028e1SSameer Pujar 
444f74028e1SSameer Pujar 	/* Disable TX/RX channel */
445f74028e1SSameer Pujar 	regmap_update_bits(admaif->regmap, enable_reg, mask, ~enable);
446f74028e1SSameer Pujar 
447f74028e1SSameer Pujar 	/* Wait until ADMAIF TX/RX status is disabled */
448f74028e1SSameer Pujar 	err = regmap_read_poll_timeout_atomic(admaif->regmap, status_reg, val,
449f74028e1SSameer Pujar 					      !(val & enable), 10, 10000);
450f74028e1SSameer Pujar 	if (err < 0)
451f74028e1SSameer Pujar 		dev_warn(dai->dev, "timeout: failed to disable ADMAIF%d_%s\n",
452f74028e1SSameer Pujar 			 dai->id + 1, dir_name);
453f74028e1SSameer Pujar 
454f74028e1SSameer Pujar 	/* SW reset */
455f74028e1SSameer Pujar 	regmap_update_bits(admaif->regmap, reset_reg, SW_RESET_MASK, SW_RESET);
456f74028e1SSameer Pujar 
457f74028e1SSameer Pujar 	/* Wait till SW reset is complete */
458f74028e1SSameer Pujar 	err = regmap_read_poll_timeout_atomic(admaif->regmap, reset_reg, val,
459f74028e1SSameer Pujar 					      !(val & SW_RESET_MASK & SW_RESET),
460f74028e1SSameer Pujar 					      10, 10000);
461f74028e1SSameer Pujar 	if (err) {
462f74028e1SSameer Pujar 		dev_err(dai->dev, "timeout: SW reset failed for ADMAIF%d_%s\n",
463f74028e1SSameer Pujar 			dai->id + 1, dir_name);
464f74028e1SSameer Pujar 		return err;
465f74028e1SSameer Pujar 	}
466f74028e1SSameer Pujar 
467f74028e1SSameer Pujar 	return 0;
468f74028e1SSameer Pujar }
469f74028e1SSameer Pujar 
tegra_admaif_trigger(struct snd_pcm_substream * substream,int cmd,struct snd_soc_dai * dai)470f74028e1SSameer Pujar static int tegra_admaif_trigger(struct snd_pcm_substream *substream, int cmd,
471f74028e1SSameer Pujar 				struct snd_soc_dai *dai)
472f74028e1SSameer Pujar {
473f74028e1SSameer Pujar 	int err;
474f74028e1SSameer Pujar 
475f74028e1SSameer Pujar 	err = snd_dmaengine_pcm_trigger(substream, cmd);
476f74028e1SSameer Pujar 	if (err)
477f74028e1SSameer Pujar 		return err;
478f74028e1SSameer Pujar 
479f74028e1SSameer Pujar 	switch (cmd) {
480f74028e1SSameer Pujar 	case SNDRV_PCM_TRIGGER_START:
481f74028e1SSameer Pujar 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
482f74028e1SSameer Pujar 	case SNDRV_PCM_TRIGGER_RESUME:
483f74028e1SSameer Pujar 		return tegra_admaif_start(dai, substream->stream);
484f74028e1SSameer Pujar 	case SNDRV_PCM_TRIGGER_STOP:
485f74028e1SSameer Pujar 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
486f74028e1SSameer Pujar 	case SNDRV_PCM_TRIGGER_SUSPEND:
487f74028e1SSameer Pujar 		return tegra_admaif_stop(dai, substream->stream);
488f74028e1SSameer Pujar 	default:
489f74028e1SSameer Pujar 		return -EINVAL;
490f74028e1SSameer Pujar 	}
491f74028e1SSameer Pujar }
492f74028e1SSameer Pujar 
tegra210_admaif_pget_mono_to_stereo(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)493e2b87a18SSameer Pujar static int tegra210_admaif_pget_mono_to_stereo(struct snd_kcontrol *kcontrol,
494f74028e1SSameer Pujar 	struct snd_ctl_elem_value *ucontrol)
495f74028e1SSameer Pujar {
496f74028e1SSameer Pujar 	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
497f74028e1SSameer Pujar 	struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);
498e2b87a18SSameer Pujar 	struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
499f74028e1SSameer Pujar 
500e2b87a18SSameer Pujar 	ucontrol->value.enumerated.item[0] =
501e2b87a18SSameer Pujar 		admaif->mono_to_stereo[ADMAIF_TX_PATH][ec->reg];
502f74028e1SSameer Pujar 
503f74028e1SSameer Pujar 	return 0;
504f74028e1SSameer Pujar }
505f74028e1SSameer Pujar 
tegra210_admaif_pput_mono_to_stereo(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)506e2b87a18SSameer Pujar static int tegra210_admaif_pput_mono_to_stereo(struct snd_kcontrol *kcontrol,
507f74028e1SSameer Pujar 	struct snd_ctl_elem_value *ucontrol)
508f74028e1SSameer Pujar {
509f74028e1SSameer Pujar 	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
510f74028e1SSameer Pujar 	struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);
511e2b87a18SSameer Pujar 	struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
512884c6cb3SSameer Pujar 	unsigned int value = ucontrol->value.enumerated.item[0];
513f74028e1SSameer Pujar 
514e2b87a18SSameer Pujar 	if (value == admaif->mono_to_stereo[ADMAIF_TX_PATH][ec->reg])
515e2b87a18SSameer Pujar 		return 0;
516e2b87a18SSameer Pujar 
517f74028e1SSameer Pujar 	admaif->mono_to_stereo[ADMAIF_TX_PATH][ec->reg] = value;
518e2b87a18SSameer Pujar 
519e2b87a18SSameer Pujar 	return 1;
520e2b87a18SSameer Pujar }
521e2b87a18SSameer Pujar 
tegra210_admaif_cget_mono_to_stereo(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)522e2b87a18SSameer Pujar static int tegra210_admaif_cget_mono_to_stereo(struct snd_kcontrol *kcontrol,
523e2b87a18SSameer Pujar 	struct snd_ctl_elem_value *ucontrol)
524e2b87a18SSameer Pujar {
525e2b87a18SSameer Pujar 	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
526e2b87a18SSameer Pujar 	struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);
527e2b87a18SSameer Pujar 	struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
528e2b87a18SSameer Pujar 
529e2b87a18SSameer Pujar 	ucontrol->value.enumerated.item[0] =
530e2b87a18SSameer Pujar 		admaif->mono_to_stereo[ADMAIF_RX_PATH][ec->reg];
531f74028e1SSameer Pujar 
532f74028e1SSameer Pujar 	return 0;
533f74028e1SSameer Pujar }
534f74028e1SSameer Pujar 
tegra210_admaif_cput_mono_to_stereo(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)535e2b87a18SSameer Pujar static int tegra210_admaif_cput_mono_to_stereo(struct snd_kcontrol *kcontrol,
536e2b87a18SSameer Pujar 	struct snd_ctl_elem_value *ucontrol)
537e2b87a18SSameer Pujar {
538e2b87a18SSameer Pujar 	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
539e2b87a18SSameer Pujar 	struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);
540e2b87a18SSameer Pujar 	struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
541e2b87a18SSameer Pujar 	unsigned int value = ucontrol->value.enumerated.item[0];
542e2b87a18SSameer Pujar 
543e2b87a18SSameer Pujar 	if (value == admaif->mono_to_stereo[ADMAIF_RX_PATH][ec->reg])
544e2b87a18SSameer Pujar 		return 0;
545e2b87a18SSameer Pujar 
546e2b87a18SSameer Pujar 	admaif->mono_to_stereo[ADMAIF_RX_PATH][ec->reg] = value;
547e2b87a18SSameer Pujar 
548e2b87a18SSameer Pujar 	return 1;
549e2b87a18SSameer Pujar }
550e2b87a18SSameer Pujar 
tegra210_admaif_pget_stereo_to_mono(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)551e2b87a18SSameer Pujar static int tegra210_admaif_pget_stereo_to_mono(struct snd_kcontrol *kcontrol,
552e2b87a18SSameer Pujar 	struct snd_ctl_elem_value *ucontrol)
553e2b87a18SSameer Pujar {
554e2b87a18SSameer Pujar 	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
555e2b87a18SSameer Pujar 	struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);
556e2b87a18SSameer Pujar 	struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
557e2b87a18SSameer Pujar 
558e2b87a18SSameer Pujar 	ucontrol->value.enumerated.item[0] =
559e2b87a18SSameer Pujar 		admaif->stereo_to_mono[ADMAIF_TX_PATH][ec->reg];
560e2b87a18SSameer Pujar 
561e2b87a18SSameer Pujar 	return 0;
562e2b87a18SSameer Pujar }
563e2b87a18SSameer Pujar 
tegra210_admaif_pput_stereo_to_mono(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)564e2b87a18SSameer Pujar static int tegra210_admaif_pput_stereo_to_mono(struct snd_kcontrol *kcontrol,
565e2b87a18SSameer Pujar 	struct snd_ctl_elem_value *ucontrol)
566e2b87a18SSameer Pujar {
567e2b87a18SSameer Pujar 	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
568e2b87a18SSameer Pujar 	struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);
569e2b87a18SSameer Pujar 	struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
570e2b87a18SSameer Pujar 	unsigned int value = ucontrol->value.enumerated.item[0];
571e2b87a18SSameer Pujar 
572e2b87a18SSameer Pujar 	if (value == admaif->stereo_to_mono[ADMAIF_TX_PATH][ec->reg])
573e2b87a18SSameer Pujar 		return 0;
574e2b87a18SSameer Pujar 
575e2b87a18SSameer Pujar 	admaif->stereo_to_mono[ADMAIF_TX_PATH][ec->reg] = value;
576e2b87a18SSameer Pujar 
577e2b87a18SSameer Pujar 	return 1;
578e2b87a18SSameer Pujar }
579e2b87a18SSameer Pujar 
tegra210_admaif_cget_stereo_to_mono(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)580e2b87a18SSameer Pujar static int tegra210_admaif_cget_stereo_to_mono(struct snd_kcontrol *kcontrol,
581e2b87a18SSameer Pujar 	struct snd_ctl_elem_value *ucontrol)
582e2b87a18SSameer Pujar {
583e2b87a18SSameer Pujar 	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
584e2b87a18SSameer Pujar 	struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);
585e2b87a18SSameer Pujar 	struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
586e2b87a18SSameer Pujar 
587e2b87a18SSameer Pujar 	ucontrol->value.enumerated.item[0] =
588e2b87a18SSameer Pujar 		admaif->stereo_to_mono[ADMAIF_RX_PATH][ec->reg];
589e2b87a18SSameer Pujar 
590e2b87a18SSameer Pujar 	return 0;
591e2b87a18SSameer Pujar }
592e2b87a18SSameer Pujar 
tegra210_admaif_cput_stereo_to_mono(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)593e2b87a18SSameer Pujar static int tegra210_admaif_cput_stereo_to_mono(struct snd_kcontrol *kcontrol,
594e2b87a18SSameer Pujar 	struct snd_ctl_elem_value *ucontrol)
595e2b87a18SSameer Pujar {
596e2b87a18SSameer Pujar 	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
597e2b87a18SSameer Pujar 	struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);
598e2b87a18SSameer Pujar 	struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
599e2b87a18SSameer Pujar 	unsigned int value = ucontrol->value.enumerated.item[0];
600e2b87a18SSameer Pujar 
601e2b87a18SSameer Pujar 	if (value == admaif->stereo_to_mono[ADMAIF_RX_PATH][ec->reg])
602e2b87a18SSameer Pujar 		return 0;
603e2b87a18SSameer Pujar 
604e2b87a18SSameer Pujar 	admaif->stereo_to_mono[ADMAIF_RX_PATH][ec->reg] = value;
605e2b87a18SSameer Pujar 
606e2b87a18SSameer Pujar 	return 1;
607e2b87a18SSameer Pujar }
608e2b87a18SSameer Pujar 
tegra_admaif_dai_probe(struct snd_soc_dai * dai)609f74028e1SSameer Pujar static int tegra_admaif_dai_probe(struct snd_soc_dai *dai)
610f74028e1SSameer Pujar {
611f74028e1SSameer Pujar 	struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai);
612f74028e1SSameer Pujar 
6131c1a7784SKuninori Morimoto 	snd_soc_dai_init_dma_data(dai,	&admaif->playback_dma_data[dai->id],
6141c1a7784SKuninori Morimoto 					&admaif->capture_dma_data[dai->id]);
615f74028e1SSameer Pujar 
616f74028e1SSameer Pujar 	return 0;
617f74028e1SSameer Pujar }
618f74028e1SSameer Pujar 
619516ee700SKuninori Morimoto static const struct snd_soc_dai_ops tegra_admaif_dai_ops = {
620516ee700SKuninori Morimoto 	.probe		= tegra_admaif_dai_probe,
621516ee700SKuninori Morimoto 	.hw_params	= tegra_admaif_hw_params,
622516ee700SKuninori Morimoto 	.trigger	= tegra_admaif_trigger,
6234a91fe4cSSheetal 	.shutdown	= tegra_admaif_shutdown,
6244a91fe4cSSheetal 	.prepare	= tegra_admaif_prepare,
625516ee700SKuninori Morimoto };
626516ee700SKuninori Morimoto 
627*7668c637SSheetal #define DAI(dai_name, channel)					\
628f74028e1SSameer Pujar 	{							\
629f74028e1SSameer Pujar 		.name = dai_name,				\
630f74028e1SSameer Pujar 		.playback = {					\
631f74028e1SSameer Pujar 			.stream_name = dai_name " Playback",	\
632f74028e1SSameer Pujar 			.channels_min = 1,			\
633*7668c637SSheetal 			.channels_max = channel,		\
634f74028e1SSameer Pujar 			.rates = SNDRV_PCM_RATE_8000_192000,	\
635f74028e1SSameer Pujar 			.formats = SNDRV_PCM_FMTBIT_S8 |	\
636f74028e1SSameer Pujar 				SNDRV_PCM_FMTBIT_S16_LE |	\
6374204ecccSRitu Chaudhary 				SNDRV_PCM_FMTBIT_S24_LE |	\
638f74028e1SSameer Pujar 				SNDRV_PCM_FMTBIT_S32_LE,	\
639f74028e1SSameer Pujar 		},						\
640f74028e1SSameer Pujar 		.capture = {					\
641f74028e1SSameer Pujar 			.stream_name = dai_name " Capture",	\
642f74028e1SSameer Pujar 			.channels_min = 1,			\
643*7668c637SSheetal 			.channels_max = channel,		\
644f74028e1SSameer Pujar 			.rates = SNDRV_PCM_RATE_8000_192000,	\
645f74028e1SSameer Pujar 			.formats = SNDRV_PCM_FMTBIT_S8 |	\
646f74028e1SSameer Pujar 				SNDRV_PCM_FMTBIT_S16_LE |	\
6474204ecccSRitu Chaudhary 				SNDRV_PCM_FMTBIT_S24_LE |	\
648f74028e1SSameer Pujar 				SNDRV_PCM_FMTBIT_S32_LE,	\
649f74028e1SSameer Pujar 		},						\
650f74028e1SSameer Pujar 		.ops = &tegra_admaif_dai_ops,			\
651f74028e1SSameer Pujar 	}
652f74028e1SSameer Pujar 
653f74028e1SSameer Pujar static struct snd_soc_dai_driver tegra210_admaif_cmpnt_dais[] = {
654*7668c637SSheetal 	DAI("ADMAIF1", TEGRA210_ADMAIF_MAX_CHANNEL),
655*7668c637SSheetal 	DAI("ADMAIF2", TEGRA210_ADMAIF_MAX_CHANNEL),
656*7668c637SSheetal 	DAI("ADMAIF3", TEGRA210_ADMAIF_MAX_CHANNEL),
657*7668c637SSheetal 	DAI("ADMAIF4", TEGRA210_ADMAIF_MAX_CHANNEL),
658*7668c637SSheetal 	DAI("ADMAIF5", TEGRA210_ADMAIF_MAX_CHANNEL),
659*7668c637SSheetal 	DAI("ADMAIF6", TEGRA210_ADMAIF_MAX_CHANNEL),
660*7668c637SSheetal 	DAI("ADMAIF7", TEGRA210_ADMAIF_MAX_CHANNEL),
661*7668c637SSheetal 	DAI("ADMAIF8", TEGRA210_ADMAIF_MAX_CHANNEL),
662*7668c637SSheetal 	DAI("ADMAIF9", TEGRA210_ADMAIF_MAX_CHANNEL),
663*7668c637SSheetal 	DAI("ADMAIF10", TEGRA210_ADMAIF_MAX_CHANNEL),
664f74028e1SSameer Pujar };
665f74028e1SSameer Pujar 
666f74028e1SSameer Pujar static struct snd_soc_dai_driver tegra186_admaif_cmpnt_dais[] = {
667*7668c637SSheetal 	DAI("ADMAIF1", TEGRA186_ADMAIF_MAX_CHANNEL),
668*7668c637SSheetal 	DAI("ADMAIF2", TEGRA186_ADMAIF_MAX_CHANNEL),
669*7668c637SSheetal 	DAI("ADMAIF3", TEGRA186_ADMAIF_MAX_CHANNEL),
670*7668c637SSheetal 	DAI("ADMAIF4", TEGRA186_ADMAIF_MAX_CHANNEL),
671*7668c637SSheetal 	DAI("ADMAIF5", TEGRA186_ADMAIF_MAX_CHANNEL),
672*7668c637SSheetal 	DAI("ADMAIF6", TEGRA186_ADMAIF_MAX_CHANNEL),
673*7668c637SSheetal 	DAI("ADMAIF7", TEGRA186_ADMAIF_MAX_CHANNEL),
674*7668c637SSheetal 	DAI("ADMAIF8", TEGRA186_ADMAIF_MAX_CHANNEL),
675*7668c637SSheetal 	DAI("ADMAIF9", TEGRA186_ADMAIF_MAX_CHANNEL),
676*7668c637SSheetal 	DAI("ADMAIF10", TEGRA186_ADMAIF_MAX_CHANNEL),
677*7668c637SSheetal 	DAI("ADMAIF11", TEGRA186_ADMAIF_MAX_CHANNEL),
678*7668c637SSheetal 	DAI("ADMAIF12", TEGRA186_ADMAIF_MAX_CHANNEL),
679*7668c637SSheetal 	DAI("ADMAIF13", TEGRA186_ADMAIF_MAX_CHANNEL),
680*7668c637SSheetal 	DAI("ADMAIF14", TEGRA186_ADMAIF_MAX_CHANNEL),
681*7668c637SSheetal 	DAI("ADMAIF15", TEGRA186_ADMAIF_MAX_CHANNEL),
682*7668c637SSheetal 	DAI("ADMAIF16", TEGRA186_ADMAIF_MAX_CHANNEL),
683*7668c637SSheetal 	DAI("ADMAIF17", TEGRA186_ADMAIF_MAX_CHANNEL),
684*7668c637SSheetal 	DAI("ADMAIF18", TEGRA186_ADMAIF_MAX_CHANNEL),
685*7668c637SSheetal 	DAI("ADMAIF19", TEGRA186_ADMAIF_MAX_CHANNEL),
686*7668c637SSheetal 	DAI("ADMAIF20", TEGRA186_ADMAIF_MAX_CHANNEL),
687*7668c637SSheetal };
688*7668c637SSheetal 
689*7668c637SSheetal static struct snd_soc_dai_driver tegra264_admaif_cmpnt_dais[] = {
690*7668c637SSheetal 	DAI("ADMAIF1", TEGRA264_ADMAIF_MAX_CHANNEL),
691*7668c637SSheetal 	DAI("ADMAIF2", TEGRA264_ADMAIF_MAX_CHANNEL),
692*7668c637SSheetal 	DAI("ADMAIF3", TEGRA264_ADMAIF_MAX_CHANNEL),
693*7668c637SSheetal 	DAI("ADMAIF4", TEGRA264_ADMAIF_MAX_CHANNEL),
694*7668c637SSheetal 	DAI("ADMAIF5", TEGRA264_ADMAIF_MAX_CHANNEL),
695*7668c637SSheetal 	DAI("ADMAIF6", TEGRA264_ADMAIF_MAX_CHANNEL),
696*7668c637SSheetal 	DAI("ADMAIF7", TEGRA264_ADMAIF_MAX_CHANNEL),
697*7668c637SSheetal 	DAI("ADMAIF8", TEGRA264_ADMAIF_MAX_CHANNEL),
698*7668c637SSheetal 	DAI("ADMAIF9", TEGRA264_ADMAIF_MAX_CHANNEL),
699*7668c637SSheetal 	DAI("ADMAIF10", TEGRA264_ADMAIF_MAX_CHANNEL),
700*7668c637SSheetal 	DAI("ADMAIF11", TEGRA264_ADMAIF_MAX_CHANNEL),
701*7668c637SSheetal 	DAI("ADMAIF12", TEGRA264_ADMAIF_MAX_CHANNEL),
702*7668c637SSheetal 	DAI("ADMAIF13", TEGRA264_ADMAIF_MAX_CHANNEL),
703*7668c637SSheetal 	DAI("ADMAIF14", TEGRA264_ADMAIF_MAX_CHANNEL),
704*7668c637SSheetal 	DAI("ADMAIF15", TEGRA264_ADMAIF_MAX_CHANNEL),
705*7668c637SSheetal 	DAI("ADMAIF16", TEGRA264_ADMAIF_MAX_CHANNEL),
706*7668c637SSheetal 	DAI("ADMAIF17", TEGRA264_ADMAIF_MAX_CHANNEL),
707*7668c637SSheetal 	DAI("ADMAIF18", TEGRA264_ADMAIF_MAX_CHANNEL),
708*7668c637SSheetal 	DAI("ADMAIF19", TEGRA264_ADMAIF_MAX_CHANNEL),
709*7668c637SSheetal 	DAI("ADMAIF20", TEGRA264_ADMAIF_MAX_CHANNEL),
710*7668c637SSheetal 	DAI("ADMAIF21", TEGRA264_ADMAIF_MAX_CHANNEL),
711*7668c637SSheetal 	DAI("ADMAIF22", TEGRA264_ADMAIF_MAX_CHANNEL),
712*7668c637SSheetal 	DAI("ADMAIF23", TEGRA264_ADMAIF_MAX_CHANNEL),
713*7668c637SSheetal 	DAI("ADMAIF24", TEGRA264_ADMAIF_MAX_CHANNEL),
714*7668c637SSheetal 	DAI("ADMAIF25", TEGRA264_ADMAIF_MAX_CHANNEL),
715*7668c637SSheetal 	DAI("ADMAIF26", TEGRA264_ADMAIF_MAX_CHANNEL),
716*7668c637SSheetal 	DAI("ADMAIF27", TEGRA264_ADMAIF_MAX_CHANNEL),
717*7668c637SSheetal 	DAI("ADMAIF28", TEGRA264_ADMAIF_MAX_CHANNEL),
718*7668c637SSheetal 	DAI("ADMAIF29", TEGRA264_ADMAIF_MAX_CHANNEL),
719*7668c637SSheetal 	DAI("ADMAIF30", TEGRA264_ADMAIF_MAX_CHANNEL),
720*7668c637SSheetal 	DAI("ADMAIF31", TEGRA264_ADMAIF_MAX_CHANNEL),
721*7668c637SSheetal 	DAI("ADMAIF32", TEGRA264_ADMAIF_MAX_CHANNEL),
722f74028e1SSameer Pujar };
723f74028e1SSameer Pujar 
724f74028e1SSameer Pujar static const char * const tegra_admaif_stereo_conv_text[] = {
725f74028e1SSameer Pujar 	"CH0", "CH1", "AVG",
726f74028e1SSameer Pujar };
727f74028e1SSameer Pujar 
728f74028e1SSameer Pujar static const char * const tegra_admaif_mono_conv_text[] = {
729f74028e1SSameer Pujar 	"Zero", "Copy",
730f74028e1SSameer Pujar };
731f74028e1SSameer Pujar 
732f74028e1SSameer Pujar /*
733f74028e1SSameer Pujar  * Below macro is added to avoid looping over all ADMAIFx controls related
734f74028e1SSameer Pujar  * to mono/stereo conversions in get()/put() callbacks.
735f74028e1SSameer Pujar  */
736f74028e1SSameer Pujar #define NV_SOC_ENUM_EXT(xname, xreg, xhandler_get, xhandler_put, xenum_text)   \
737f74028e1SSameer Pujar {									       \
738f74028e1SSameer Pujar 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,				       \
739f74028e1SSameer Pujar 	.info = snd_soc_info_enum_double,				       \
740f74028e1SSameer Pujar 	.name = xname,							       \
741f74028e1SSameer Pujar 	.get = xhandler_get,						       \
742f74028e1SSameer Pujar 	.put = xhandler_put,						       \
743f74028e1SSameer Pujar 	.private_value = (unsigned long)&(struct soc_enum)		       \
744f74028e1SSameer Pujar 		SOC_ENUM_SINGLE(xreg, 0, ARRAY_SIZE(xenum_text), xenum_text)   \
745f74028e1SSameer Pujar }
746f74028e1SSameer Pujar 
747f74028e1SSameer Pujar #define TEGRA_ADMAIF_CIF_CTRL(reg)					       \
748f74028e1SSameer Pujar 	NV_SOC_ENUM_EXT("ADMAIF" #reg " Playback Mono To Stereo", reg - 1,     \
749e2b87a18SSameer Pujar 			tegra210_admaif_pget_mono_to_stereo,		       \
750e2b87a18SSameer Pujar 			tegra210_admaif_pput_mono_to_stereo,		       \
751f74028e1SSameer Pujar 			tegra_admaif_mono_conv_text),			       \
752f74028e1SSameer Pujar 	NV_SOC_ENUM_EXT("ADMAIF" #reg " Playback Stereo To Mono", reg - 1,     \
753e2b87a18SSameer Pujar 			tegra210_admaif_pget_stereo_to_mono,		       \
754e2b87a18SSameer Pujar 			tegra210_admaif_pput_stereo_to_mono,		       \
755f74028e1SSameer Pujar 			tegra_admaif_stereo_conv_text),			       \
756f74028e1SSameer Pujar 	NV_SOC_ENUM_EXT("ADMAIF" #reg " Capture Mono To Stereo", reg - 1,      \
757e2b87a18SSameer Pujar 			tegra210_admaif_cget_mono_to_stereo,		       \
758e2b87a18SSameer Pujar 			tegra210_admaif_cput_mono_to_stereo,		       \
759f74028e1SSameer Pujar 			tegra_admaif_mono_conv_text),			       \
760f74028e1SSameer Pujar 	NV_SOC_ENUM_EXT("ADMAIF" #reg " Capture Stereo To Mono", reg - 1,      \
761e2b87a18SSameer Pujar 			tegra210_admaif_cget_stereo_to_mono,		       \
762e2b87a18SSameer Pujar 			tegra210_admaif_cput_stereo_to_mono,		       \
763f74028e1SSameer Pujar 			tegra_admaif_stereo_conv_text)
764f74028e1SSameer Pujar 
765f74028e1SSameer Pujar static struct snd_kcontrol_new tegra210_admaif_controls[] = {
766f74028e1SSameer Pujar 	TEGRA_ADMAIF_CIF_CTRL(1),
767f74028e1SSameer Pujar 	TEGRA_ADMAIF_CIF_CTRL(2),
768f74028e1SSameer Pujar 	TEGRA_ADMAIF_CIF_CTRL(3),
769f74028e1SSameer Pujar 	TEGRA_ADMAIF_CIF_CTRL(4),
770f74028e1SSameer Pujar 	TEGRA_ADMAIF_CIF_CTRL(5),
771f74028e1SSameer Pujar 	TEGRA_ADMAIF_CIF_CTRL(6),
772f74028e1SSameer Pujar 	TEGRA_ADMAIF_CIF_CTRL(7),
773f74028e1SSameer Pujar 	TEGRA_ADMAIF_CIF_CTRL(8),
774f74028e1SSameer Pujar 	TEGRA_ADMAIF_CIF_CTRL(9),
775f74028e1SSameer Pujar 	TEGRA_ADMAIF_CIF_CTRL(10),
776f74028e1SSameer Pujar };
777f74028e1SSameer Pujar 
778f74028e1SSameer Pujar static struct snd_kcontrol_new tegra186_admaif_controls[] = {
779f74028e1SSameer Pujar 	TEGRA_ADMAIF_CIF_CTRL(1),
780f74028e1SSameer Pujar 	TEGRA_ADMAIF_CIF_CTRL(2),
781f74028e1SSameer Pujar 	TEGRA_ADMAIF_CIF_CTRL(3),
782f74028e1SSameer Pujar 	TEGRA_ADMAIF_CIF_CTRL(4),
783f74028e1SSameer Pujar 	TEGRA_ADMAIF_CIF_CTRL(5),
784f74028e1SSameer Pujar 	TEGRA_ADMAIF_CIF_CTRL(6),
785f74028e1SSameer Pujar 	TEGRA_ADMAIF_CIF_CTRL(7),
786f74028e1SSameer Pujar 	TEGRA_ADMAIF_CIF_CTRL(8),
787f74028e1SSameer Pujar 	TEGRA_ADMAIF_CIF_CTRL(9),
788f74028e1SSameer Pujar 	TEGRA_ADMAIF_CIF_CTRL(10),
789f74028e1SSameer Pujar 	TEGRA_ADMAIF_CIF_CTRL(11),
790f74028e1SSameer Pujar 	TEGRA_ADMAIF_CIF_CTRL(12),
791f74028e1SSameer Pujar 	TEGRA_ADMAIF_CIF_CTRL(13),
792f74028e1SSameer Pujar 	TEGRA_ADMAIF_CIF_CTRL(14),
793f74028e1SSameer Pujar 	TEGRA_ADMAIF_CIF_CTRL(15),
794f74028e1SSameer Pujar 	TEGRA_ADMAIF_CIF_CTRL(16),
795f74028e1SSameer Pujar 	TEGRA_ADMAIF_CIF_CTRL(17),
796f74028e1SSameer Pujar 	TEGRA_ADMAIF_CIF_CTRL(18),
797f74028e1SSameer Pujar 	TEGRA_ADMAIF_CIF_CTRL(19),
798f74028e1SSameer Pujar 	TEGRA_ADMAIF_CIF_CTRL(20),
799f74028e1SSameer Pujar };
800f74028e1SSameer Pujar 
801*7668c637SSheetal static struct snd_kcontrol_new tegra264_admaif_controls[] = {
802*7668c637SSheetal 	TEGRA_ADMAIF_CIF_CTRL(1),
803*7668c637SSheetal 	TEGRA_ADMAIF_CIF_CTRL(2),
804*7668c637SSheetal 	TEGRA_ADMAIF_CIF_CTRL(3),
805*7668c637SSheetal 	TEGRA_ADMAIF_CIF_CTRL(4),
806*7668c637SSheetal 	TEGRA_ADMAIF_CIF_CTRL(5),
807*7668c637SSheetal 	TEGRA_ADMAIF_CIF_CTRL(6),
808*7668c637SSheetal 	TEGRA_ADMAIF_CIF_CTRL(7),
809*7668c637SSheetal 	TEGRA_ADMAIF_CIF_CTRL(8),
810*7668c637SSheetal 	TEGRA_ADMAIF_CIF_CTRL(9),
811*7668c637SSheetal 	TEGRA_ADMAIF_CIF_CTRL(10),
812*7668c637SSheetal 	TEGRA_ADMAIF_CIF_CTRL(11),
813*7668c637SSheetal 	TEGRA_ADMAIF_CIF_CTRL(12),
814*7668c637SSheetal 	TEGRA_ADMAIF_CIF_CTRL(13),
815*7668c637SSheetal 	TEGRA_ADMAIF_CIF_CTRL(14),
816*7668c637SSheetal 	TEGRA_ADMAIF_CIF_CTRL(15),
817*7668c637SSheetal 	TEGRA_ADMAIF_CIF_CTRL(16),
818*7668c637SSheetal 	TEGRA_ADMAIF_CIF_CTRL(17),
819*7668c637SSheetal 	TEGRA_ADMAIF_CIF_CTRL(18),
820*7668c637SSheetal 	TEGRA_ADMAIF_CIF_CTRL(19),
821*7668c637SSheetal 	TEGRA_ADMAIF_CIF_CTRL(20),
822*7668c637SSheetal 	TEGRA_ADMAIF_CIF_CTRL(21),
823*7668c637SSheetal 	TEGRA_ADMAIF_CIF_CTRL(22),
824*7668c637SSheetal 	TEGRA_ADMAIF_CIF_CTRL(23),
825*7668c637SSheetal 	TEGRA_ADMAIF_CIF_CTRL(24),
826*7668c637SSheetal 	TEGRA_ADMAIF_CIF_CTRL(25),
827*7668c637SSheetal 	TEGRA_ADMAIF_CIF_CTRL(26),
828*7668c637SSheetal 	TEGRA_ADMAIF_CIF_CTRL(27),
829*7668c637SSheetal 	TEGRA_ADMAIF_CIF_CTRL(28),
830*7668c637SSheetal 	TEGRA_ADMAIF_CIF_CTRL(29),
831*7668c637SSheetal 	TEGRA_ADMAIF_CIF_CTRL(30),
832*7668c637SSheetal 	TEGRA_ADMAIF_CIF_CTRL(31),
833*7668c637SSheetal 	TEGRA_ADMAIF_CIF_CTRL(32),
834*7668c637SSheetal };
835*7668c637SSheetal 
836f74028e1SSameer Pujar static const struct snd_soc_component_driver tegra210_admaif_cmpnt = {
837f74028e1SSameer Pujar 	.controls		= tegra210_admaif_controls,
838f74028e1SSameer Pujar 	.num_controls		= ARRAY_SIZE(tegra210_admaif_controls),
839f74028e1SSameer Pujar 	.pcm_construct		= tegra_pcm_construct,
840f74028e1SSameer Pujar 	.open			= tegra_pcm_open,
841f74028e1SSameer Pujar 	.close			= tegra_pcm_close,
842f74028e1SSameer Pujar 	.hw_params		= tegra_pcm_hw_params,
843f74028e1SSameer Pujar 	.pointer		= tegra_pcm_pointer,
844f74028e1SSameer Pujar };
845f74028e1SSameer Pujar 
846f74028e1SSameer Pujar static const struct snd_soc_component_driver tegra186_admaif_cmpnt = {
847f74028e1SSameer Pujar 	.controls		= tegra186_admaif_controls,
848f74028e1SSameer Pujar 	.num_controls		= ARRAY_SIZE(tegra186_admaif_controls),
849f74028e1SSameer Pujar 	.pcm_construct		= tegra_pcm_construct,
850f74028e1SSameer Pujar 	.open			= tegra_pcm_open,
851f74028e1SSameer Pujar 	.close			= tegra_pcm_close,
852f74028e1SSameer Pujar 	.hw_params		= tegra_pcm_hw_params,
853f74028e1SSameer Pujar 	.pointer		= tegra_pcm_pointer,
854f74028e1SSameer Pujar };
855f74028e1SSameer Pujar 
856*7668c637SSheetal static const struct snd_soc_component_driver tegra264_admaif_cmpnt = {
857*7668c637SSheetal 	.controls		= tegra264_admaif_controls,
858*7668c637SSheetal 	.num_controls		= ARRAY_SIZE(tegra264_admaif_controls),
859*7668c637SSheetal 	.pcm_construct		= tegra_pcm_construct,
860*7668c637SSheetal 	.open			= tegra_pcm_open,
861*7668c637SSheetal 	.close			= tegra_pcm_close,
862*7668c637SSheetal 	.hw_params		= tegra_pcm_hw_params,
863*7668c637SSheetal 	.pointer		= tegra_pcm_pointer,
864*7668c637SSheetal };
865*7668c637SSheetal 
866f74028e1SSameer Pujar static const struct tegra_admaif_soc_data soc_data_tegra210 = {
867f74028e1SSameer Pujar 	.num_ch		= TEGRA210_ADMAIF_CHANNEL_COUNT,
868*7668c637SSheetal 	.max_stream_ch	= TEGRA210_ADMAIF_MAX_CHANNEL,
869f74028e1SSameer Pujar 	.cmpnt		= &tegra210_admaif_cmpnt,
870f74028e1SSameer Pujar 	.dais		= tegra210_admaif_cmpnt_dais,
871f74028e1SSameer Pujar 	.regmap_conf	= &tegra210_admaif_regmap_config,
872f74028e1SSameer Pujar 	.global_base	= TEGRA210_ADMAIF_GLOBAL_BASE,
873f74028e1SSameer Pujar 	.tx_base	= TEGRA210_ADMAIF_TX_BASE,
874f74028e1SSameer Pujar 	.rx_base	= TEGRA210_ADMAIF_RX_BASE,
875f74028e1SSameer Pujar };
876f74028e1SSameer Pujar 
877f74028e1SSameer Pujar static const struct tegra_admaif_soc_data soc_data_tegra186 = {
878f74028e1SSameer Pujar 	.num_ch		= TEGRA186_ADMAIF_CHANNEL_COUNT,
879*7668c637SSheetal 	.max_stream_ch	= TEGRA186_ADMAIF_MAX_CHANNEL,
880f74028e1SSameer Pujar 	.cmpnt		= &tegra186_admaif_cmpnt,
881f74028e1SSameer Pujar 	.dais		= tegra186_admaif_cmpnt_dais,
882f74028e1SSameer Pujar 	.regmap_conf	= &tegra186_admaif_regmap_config,
883f74028e1SSameer Pujar 	.global_base	= TEGRA186_ADMAIF_GLOBAL_BASE,
884f74028e1SSameer Pujar 	.tx_base	= TEGRA186_ADMAIF_TX_BASE,
885f74028e1SSameer Pujar 	.rx_base	= TEGRA186_ADMAIF_RX_BASE,
886f74028e1SSameer Pujar };
887f74028e1SSameer Pujar 
888*7668c637SSheetal static const struct tegra_admaif_soc_data soc_data_tegra264 = {
889*7668c637SSheetal 	.num_ch		= TEGRA264_ADMAIF_CHANNEL_COUNT,
890*7668c637SSheetal 	.max_stream_ch	= TEGRA264_ADMAIF_MAX_CHANNEL,
891*7668c637SSheetal 	.cmpnt		= &tegra264_admaif_cmpnt,
892*7668c637SSheetal 	.dais		= tegra264_admaif_cmpnt_dais,
893*7668c637SSheetal 	.regmap_conf	= &tegra264_admaif_regmap_config,
894*7668c637SSheetal 	.global_base	= TEGRA264_ADMAIF_GLOBAL_BASE,
895*7668c637SSheetal 	.tx_base	= TEGRA264_ADMAIF_TX_BASE,
896*7668c637SSheetal 	.rx_base	= TEGRA264_ADMAIF_RX_BASE,
897*7668c637SSheetal };
898*7668c637SSheetal 
899f74028e1SSameer Pujar static const struct of_device_id tegra_admaif_of_match[] = {
900f74028e1SSameer Pujar 	{ .compatible = "nvidia,tegra210-admaif", .data = &soc_data_tegra210 },
901f74028e1SSameer Pujar 	{ .compatible = "nvidia,tegra186-admaif", .data = &soc_data_tegra186 },
902*7668c637SSheetal 	{ .compatible = "nvidia,tegra264-admaif", .data = &soc_data_tegra264 },
903f74028e1SSameer Pujar 	{},
904f74028e1SSameer Pujar };
905f74028e1SSameer Pujar MODULE_DEVICE_TABLE(of, tegra_admaif_of_match);
906f74028e1SSameer Pujar 
tegra_admaif_probe(struct platform_device * pdev)907f74028e1SSameer Pujar static int tegra_admaif_probe(struct platform_device *pdev)
908f74028e1SSameer Pujar {
909f74028e1SSameer Pujar 	struct tegra_admaif *admaif;
910f74028e1SSameer Pujar 	void __iomem *regs;
911f74028e1SSameer Pujar 	struct resource *res;
912f74028e1SSameer Pujar 	int err, i;
913f74028e1SSameer Pujar 
914f74028e1SSameer Pujar 	admaif = devm_kzalloc(&pdev->dev, sizeof(*admaif), GFP_KERNEL);
915f74028e1SSameer Pujar 	if (!admaif)
916f74028e1SSameer Pujar 		return -ENOMEM;
917f74028e1SSameer Pujar 
918f74028e1SSameer Pujar 	admaif->soc_data = of_device_get_match_data(&pdev->dev);
919f74028e1SSameer Pujar 
920f74028e1SSameer Pujar 	dev_set_drvdata(&pdev->dev, admaif);
921f74028e1SSameer Pujar 
922f74028e1SSameer Pujar 	admaif->capture_dma_data =
923f74028e1SSameer Pujar 		devm_kcalloc(&pdev->dev,
924f74028e1SSameer Pujar 			     admaif->soc_data->num_ch,
925f74028e1SSameer Pujar 			     sizeof(struct snd_dmaengine_dai_dma_data),
926f74028e1SSameer Pujar 			     GFP_KERNEL);
927f74028e1SSameer Pujar 	if (!admaif->capture_dma_data)
928f74028e1SSameer Pujar 		return -ENOMEM;
929f74028e1SSameer Pujar 
930f74028e1SSameer Pujar 	admaif->playback_dma_data =
931f74028e1SSameer Pujar 		devm_kcalloc(&pdev->dev,
932f74028e1SSameer Pujar 			     admaif->soc_data->num_ch,
933f74028e1SSameer Pujar 			     sizeof(struct snd_dmaengine_dai_dma_data),
934f74028e1SSameer Pujar 			     GFP_KERNEL);
935f74028e1SSameer Pujar 	if (!admaif->playback_dma_data)
936f74028e1SSameer Pujar 		return -ENOMEM;
937f74028e1SSameer Pujar 
938f74028e1SSameer Pujar 	for (i = 0; i < ADMAIF_PATHS; i++) {
939f74028e1SSameer Pujar 		admaif->mono_to_stereo[i] =
940f74028e1SSameer Pujar 			devm_kcalloc(&pdev->dev, admaif->soc_data->num_ch,
941f74028e1SSameer Pujar 				     sizeof(unsigned int), GFP_KERNEL);
942f74028e1SSameer Pujar 		if (!admaif->mono_to_stereo[i])
943f74028e1SSameer Pujar 			return -ENOMEM;
944f74028e1SSameer Pujar 
945f74028e1SSameer Pujar 		admaif->stereo_to_mono[i] =
946f74028e1SSameer Pujar 			devm_kcalloc(&pdev->dev, admaif->soc_data->num_ch,
947f74028e1SSameer Pujar 				     sizeof(unsigned int), GFP_KERNEL);
948f74028e1SSameer Pujar 		if (!admaif->stereo_to_mono[i])
949f74028e1SSameer Pujar 			return -ENOMEM;
950f74028e1SSameer Pujar 	}
951f74028e1SSameer Pujar 
952c29b6382SYang Yingliang 	regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
953f74028e1SSameer Pujar 	if (IS_ERR(regs))
954f74028e1SSameer Pujar 		return PTR_ERR(regs);
955f74028e1SSameer Pujar 
956f74028e1SSameer Pujar 	admaif->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
957f74028e1SSameer Pujar 					       admaif->soc_data->regmap_conf);
958f74028e1SSameer Pujar 	if (IS_ERR(admaif->regmap)) {
959f74028e1SSameer Pujar 		dev_err(&pdev->dev, "regmap init failed\n");
960f74028e1SSameer Pujar 		return PTR_ERR(admaif->regmap);
961f74028e1SSameer Pujar 	}
962f74028e1SSameer Pujar 
963f74028e1SSameer Pujar 	regcache_cache_only(admaif->regmap, true);
964f74028e1SSameer Pujar 
9654a91fe4cSSheetal 	err = tegra_isomgr_adma_register(&pdev->dev);
9664a91fe4cSSheetal 	if (err) {
9674a91fe4cSSheetal 		dev_err(&pdev->dev, "Failed to add interconnect path\n");
9684a91fe4cSSheetal 		return err;
9694a91fe4cSSheetal 	}
9704a91fe4cSSheetal 
971f74028e1SSameer Pujar 	regmap_update_bits(admaif->regmap, admaif->soc_data->global_base +
972f74028e1SSameer Pujar 			   TEGRA_ADMAIF_GLOBAL_ENABLE, 1, 1);
973f74028e1SSameer Pujar 
974f74028e1SSameer Pujar 	for (i = 0; i < admaif->soc_data->num_ch; i++) {
975f74028e1SSameer Pujar 		admaif->playback_dma_data[i].addr = res->start +
976f74028e1SSameer Pujar 			CH_TX_REG(TEGRA_ADMAIF_TX_FIFO_WRITE, i);
977f74028e1SSameer Pujar 
978f74028e1SSameer Pujar 		admaif->capture_dma_data[i].addr = res->start +
979f74028e1SSameer Pujar 			CH_RX_REG(TEGRA_ADMAIF_RX_FIFO_READ, i);
980f74028e1SSameer Pujar 
981f74028e1SSameer Pujar 		admaif->playback_dma_data[i].addr_width = 32;
982f74028e1SSameer Pujar 
983f74028e1SSameer Pujar 		if (of_property_read_string_index(pdev->dev.of_node,
984f74028e1SSameer Pujar 				"dma-names", (i * 2) + 1,
985f74028e1SSameer Pujar 				&admaif->playback_dma_data[i].chan_name) < 0) {
986f74028e1SSameer Pujar 			dev_err(&pdev->dev,
987f74028e1SSameer Pujar 				"missing property nvidia,dma-names\n");
988f74028e1SSameer Pujar 
989f74028e1SSameer Pujar 			return -ENODEV;
990f74028e1SSameer Pujar 		}
991f74028e1SSameer Pujar 
992f74028e1SSameer Pujar 		admaif->capture_dma_data[i].addr_width = 32;
993f74028e1SSameer Pujar 
994f74028e1SSameer Pujar 		if (of_property_read_string_index(pdev->dev.of_node,
995f74028e1SSameer Pujar 				"dma-names",
996f74028e1SSameer Pujar 				(i * 2),
997f74028e1SSameer Pujar 				&admaif->capture_dma_data[i].chan_name) < 0) {
998f74028e1SSameer Pujar 			dev_err(&pdev->dev,
999f74028e1SSameer Pujar 				"missing property nvidia,dma-names\n");
1000f74028e1SSameer Pujar 
1001f74028e1SSameer Pujar 			return -ENODEV;
1002f74028e1SSameer Pujar 		}
1003f74028e1SSameer Pujar 	}
1004f74028e1SSameer Pujar 
1005f74028e1SSameer Pujar 	err = devm_snd_soc_register_component(&pdev->dev,
1006f74028e1SSameer Pujar 					      admaif->soc_data->cmpnt,
1007f74028e1SSameer Pujar 					      admaif->soc_data->dais,
1008f74028e1SSameer Pujar 					      admaif->soc_data->num_ch);
1009f74028e1SSameer Pujar 	if (err) {
1010f74028e1SSameer Pujar 		dev_err(&pdev->dev,
1011f74028e1SSameer Pujar 			"can't register ADMAIF component, err: %d\n", err);
1012f74028e1SSameer Pujar 		return err;
1013f74028e1SSameer Pujar 	}
1014f74028e1SSameer Pujar 
1015f74028e1SSameer Pujar 	pm_runtime_enable(&pdev->dev);
1016f74028e1SSameer Pujar 
1017f74028e1SSameer Pujar 	return 0;
1018f74028e1SSameer Pujar }
1019f74028e1SSameer Pujar 
tegra_admaif_remove(struct platform_device * pdev)10208097e8afSUwe Kleine-König static void tegra_admaif_remove(struct platform_device *pdev)
1021f74028e1SSameer Pujar {
10224a91fe4cSSheetal 	tegra_isomgr_adma_unregister(&pdev->dev);
1023f74028e1SSameer Pujar 	pm_runtime_disable(&pdev->dev);
1024f74028e1SSameer Pujar }
1025f74028e1SSameer Pujar 
1026f74028e1SSameer Pujar static const struct dev_pm_ops tegra_admaif_pm_ops = {
1027083c6a6fSTakashi Iwai 	RUNTIME_PM_OPS(tegra_admaif_runtime_suspend,
1028f74028e1SSameer Pujar 		       tegra_admaif_runtime_resume, NULL)
1029083c6a6fSTakashi Iwai 	SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
1030f74028e1SSameer Pujar };
1031f74028e1SSameer Pujar 
1032f74028e1SSameer Pujar static struct platform_driver tegra_admaif_driver = {
1033f74028e1SSameer Pujar 	.probe = tegra_admaif_probe,
1034130af75bSUwe Kleine-König 	.remove = tegra_admaif_remove,
1035f74028e1SSameer Pujar 	.driver = {
1036f74028e1SSameer Pujar 		.name = "tegra210-admaif",
1037f74028e1SSameer Pujar 		.of_match_table = tegra_admaif_of_match,
1038083c6a6fSTakashi Iwai 		.pm = pm_ptr(&tegra_admaif_pm_ops),
1039f74028e1SSameer Pujar 	},
1040f74028e1SSameer Pujar };
1041f74028e1SSameer Pujar module_platform_driver(tegra_admaif_driver);
1042f74028e1SSameer Pujar 
1043f74028e1SSameer Pujar MODULE_AUTHOR("Songhee Baek <sbaek@nvidia.com>");
1044f74028e1SSameer Pujar MODULE_DESCRIPTION("Tegra210 ASoC ADMAIF driver");
1045f74028e1SSameer Pujar MODULE_LICENSE("GPL v2");
1046