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