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