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