1// SPDX-License-Identifier: GPL-2.0-only
2//
3// tegra210_admaif.c - Tegra ADMAIF driver
4//
5// Copyright (c) 2020 NVIDIA CORPORATION. All rights reserved.
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(map: admaif->regmap, enable: true);
227 regcache_mark_dirty(map: 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(map: admaif->regmap, enable: false);
237 regcache_sync(map: 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, val: 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, val: 0);
253 break;
254 case DATA_32BIT:
255 regmap_update_bits(map, reg, PACK16_EN_MASK, val: 0);
256 regmap_update_bits(map, reg, PACK8_EN_MASK, val: 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(p: 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(p: 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(map: admaif->regmap, reg, valid_bit);
314
315 tegra_set_cif(regmap: admaif->regmap, reg, conf: &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(map: 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 /* Disable TX/RX channel */
374 regmap_update_bits(map: admaif->regmap, reg: enable_reg, mask, val: ~enable);
375
376 /* Wait until ADMAIF TX/RX status is disabled */
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 /* SW reset */
384 regmap_update_bits(map: admaif->regmap, reg: reset_reg, SW_RESET_MASK, SW_RESET);
385
386 /* Wait till SW reset is complete */
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, direction: 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, direction: substream->stream);
417 default:
418 return -EINVAL;
419 }
420}
421
422static int tegra210_admaif_pget_mono_to_stereo(struct snd_kcontrol *kcontrol,
423 struct snd_ctl_elem_value *ucontrol)
424{
425 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
426 struct tegra_admaif *admaif = snd_soc_component_get_drvdata(c: cmpnt);
427 struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
428
429 ucontrol->value.enumerated.item[0] =
430 admaif->mono_to_stereo[ADMAIF_TX_PATH][ec->reg];
431
432 return 0;
433}
434
435static int tegra210_admaif_pput_mono_to_stereo(struct snd_kcontrol *kcontrol,
436 struct snd_ctl_elem_value *ucontrol)
437{
438 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
439 struct tegra_admaif *admaif = snd_soc_component_get_drvdata(c: cmpnt);
440 struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
441 unsigned int value = ucontrol->value.enumerated.item[0];
442
443 if (value == admaif->mono_to_stereo[ADMAIF_TX_PATH][ec->reg])
444 return 0;
445
446 admaif->mono_to_stereo[ADMAIF_TX_PATH][ec->reg] = value;
447
448 return 1;
449}
450
451static int tegra210_admaif_cget_mono_to_stereo(struct snd_kcontrol *kcontrol,
452 struct snd_ctl_elem_value *ucontrol)
453{
454 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
455 struct tegra_admaif *admaif = snd_soc_component_get_drvdata(c: cmpnt);
456 struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
457
458 ucontrol->value.enumerated.item[0] =
459 admaif->mono_to_stereo[ADMAIF_RX_PATH][ec->reg];
460
461 return 0;
462}
463
464static int tegra210_admaif_cput_mono_to_stereo(struct snd_kcontrol *kcontrol,
465 struct snd_ctl_elem_value *ucontrol)
466{
467 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
468 struct tegra_admaif *admaif = snd_soc_component_get_drvdata(c: cmpnt);
469 struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
470 unsigned int value = ucontrol->value.enumerated.item[0];
471
472 if (value == admaif->mono_to_stereo[ADMAIF_RX_PATH][ec->reg])
473 return 0;
474
475 admaif->mono_to_stereo[ADMAIF_RX_PATH][ec->reg] = value;
476
477 return 1;
478}
479
480static int tegra210_admaif_pget_stereo_to_mono(struct snd_kcontrol *kcontrol,
481 struct snd_ctl_elem_value *ucontrol)
482{
483 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
484 struct tegra_admaif *admaif = snd_soc_component_get_drvdata(c: cmpnt);
485 struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
486
487 ucontrol->value.enumerated.item[0] =
488 admaif->stereo_to_mono[ADMAIF_TX_PATH][ec->reg];
489
490 return 0;
491}
492
493static int tegra210_admaif_pput_stereo_to_mono(struct snd_kcontrol *kcontrol,
494 struct snd_ctl_elem_value *ucontrol)
495{
496 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
497 struct tegra_admaif *admaif = snd_soc_component_get_drvdata(c: cmpnt);
498 struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
499 unsigned int value = ucontrol->value.enumerated.item[0];
500
501 if (value == admaif->stereo_to_mono[ADMAIF_TX_PATH][ec->reg])
502 return 0;
503
504 admaif->stereo_to_mono[ADMAIF_TX_PATH][ec->reg] = value;
505
506 return 1;
507}
508
509static int tegra210_admaif_cget_stereo_to_mono(struct snd_kcontrol *kcontrol,
510 struct snd_ctl_elem_value *ucontrol)
511{
512 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
513 struct tegra_admaif *admaif = snd_soc_component_get_drvdata(c: cmpnt);
514 struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
515
516 ucontrol->value.enumerated.item[0] =
517 admaif->stereo_to_mono[ADMAIF_RX_PATH][ec->reg];
518
519 return 0;
520}
521
522static int tegra210_admaif_cput_stereo_to_mono(struct snd_kcontrol *kcontrol,
523 struct snd_ctl_elem_value *ucontrol)
524{
525 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
526 struct tegra_admaif *admaif = snd_soc_component_get_drvdata(c: cmpnt);
527 struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
528 unsigned int value = ucontrol->value.enumerated.item[0];
529
530 if (value == admaif->stereo_to_mono[ADMAIF_RX_PATH][ec->reg])
531 return 0;
532
533 admaif->stereo_to_mono[ADMAIF_RX_PATH][ec->reg] = value;
534
535 return 1;
536}
537
538static int tegra_admaif_dai_probe(struct snd_soc_dai *dai)
539{
540 struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai);
541
542 snd_soc_dai_init_dma_data(dai, playback: &admaif->playback_dma_data[dai->id],
543 capture: &admaif->capture_dma_data[dai->id]);
544
545 return 0;
546}
547
548static const struct snd_soc_dai_ops tegra_admaif_dai_ops = {
549 .probe = tegra_admaif_dai_probe,
550 .hw_params = tegra_admaif_hw_params,
551 .trigger = tegra_admaif_trigger,
552};
553
554#define DAI(dai_name) \
555 { \
556 .name = dai_name, \
557 .playback = { \
558 .stream_name = dai_name " Playback", \
559 .channels_min = 1, \
560 .channels_max = 16, \
561 .rates = SNDRV_PCM_RATE_8000_192000, \
562 .formats = SNDRV_PCM_FMTBIT_S8 | \
563 SNDRV_PCM_FMTBIT_S16_LE | \
564 SNDRV_PCM_FMTBIT_S32_LE, \
565 }, \
566 .capture = { \
567 .stream_name = dai_name " Capture", \
568 .channels_min = 1, \
569 .channels_max = 16, \
570 .rates = SNDRV_PCM_RATE_8000_192000, \
571 .formats = SNDRV_PCM_FMTBIT_S8 | \
572 SNDRV_PCM_FMTBIT_S16_LE | \
573 SNDRV_PCM_FMTBIT_S32_LE, \
574 }, \
575 .ops = &tegra_admaif_dai_ops, \
576 }
577
578static struct snd_soc_dai_driver tegra210_admaif_cmpnt_dais[] = {
579 DAI("ADMAIF1"),
580 DAI("ADMAIF2"),
581 DAI("ADMAIF3"),
582 DAI("ADMAIF4"),
583 DAI("ADMAIF5"),
584 DAI("ADMAIF6"),
585 DAI("ADMAIF7"),
586 DAI("ADMAIF8"),
587 DAI("ADMAIF9"),
588 DAI("ADMAIF10"),
589};
590
591static struct snd_soc_dai_driver tegra186_admaif_cmpnt_dais[] = {
592 DAI("ADMAIF1"),
593 DAI("ADMAIF2"),
594 DAI("ADMAIF3"),
595 DAI("ADMAIF4"),
596 DAI("ADMAIF5"),
597 DAI("ADMAIF6"),
598 DAI("ADMAIF7"),
599 DAI("ADMAIF8"),
600 DAI("ADMAIF9"),
601 DAI("ADMAIF10"),
602 DAI("ADMAIF11"),
603 DAI("ADMAIF12"),
604 DAI("ADMAIF13"),
605 DAI("ADMAIF14"),
606 DAI("ADMAIF15"),
607 DAI("ADMAIF16"),
608 DAI("ADMAIF17"),
609 DAI("ADMAIF18"),
610 DAI("ADMAIF19"),
611 DAI("ADMAIF20"),
612};
613
614static const char * const tegra_admaif_stereo_conv_text[] = {
615 "CH0", "CH1", "AVG",
616};
617
618static const char * const tegra_admaif_mono_conv_text[] = {
619 "Zero", "Copy",
620};
621
622/*
623 * Below macro is added to avoid looping over all ADMAIFx controls related
624 * to mono/stereo conversions in get()/put() callbacks.
625 */
626#define NV_SOC_ENUM_EXT(xname, xreg, xhandler_get, xhandler_put, xenum_text) \
627{ \
628 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
629 .info = snd_soc_info_enum_double, \
630 .name = xname, \
631 .get = xhandler_get, \
632 .put = xhandler_put, \
633 .private_value = (unsigned long)&(struct soc_enum) \
634 SOC_ENUM_SINGLE(xreg, 0, ARRAY_SIZE(xenum_text), xenum_text) \
635}
636
637#define TEGRA_ADMAIF_CIF_CTRL(reg) \
638 NV_SOC_ENUM_EXT("ADMAIF" #reg " Playback Mono To Stereo", reg - 1, \
639 tegra210_admaif_pget_mono_to_stereo, \
640 tegra210_admaif_pput_mono_to_stereo, \
641 tegra_admaif_mono_conv_text), \
642 NV_SOC_ENUM_EXT("ADMAIF" #reg " Playback Stereo To Mono", reg - 1, \
643 tegra210_admaif_pget_stereo_to_mono, \
644 tegra210_admaif_pput_stereo_to_mono, \
645 tegra_admaif_stereo_conv_text), \
646 NV_SOC_ENUM_EXT("ADMAIF" #reg " Capture Mono To Stereo", reg - 1, \
647 tegra210_admaif_cget_mono_to_stereo, \
648 tegra210_admaif_cput_mono_to_stereo, \
649 tegra_admaif_mono_conv_text), \
650 NV_SOC_ENUM_EXT("ADMAIF" #reg " Capture Stereo To Mono", reg - 1, \
651 tegra210_admaif_cget_stereo_to_mono, \
652 tegra210_admaif_cput_stereo_to_mono, \
653 tegra_admaif_stereo_conv_text)
654
655static struct snd_kcontrol_new tegra210_admaif_controls[] = {
656 TEGRA_ADMAIF_CIF_CTRL(1),
657 TEGRA_ADMAIF_CIF_CTRL(2),
658 TEGRA_ADMAIF_CIF_CTRL(3),
659 TEGRA_ADMAIF_CIF_CTRL(4),
660 TEGRA_ADMAIF_CIF_CTRL(5),
661 TEGRA_ADMAIF_CIF_CTRL(6),
662 TEGRA_ADMAIF_CIF_CTRL(7),
663 TEGRA_ADMAIF_CIF_CTRL(8),
664 TEGRA_ADMAIF_CIF_CTRL(9),
665 TEGRA_ADMAIF_CIF_CTRL(10),
666};
667
668static struct snd_kcontrol_new tegra186_admaif_controls[] = {
669 TEGRA_ADMAIF_CIF_CTRL(1),
670 TEGRA_ADMAIF_CIF_CTRL(2),
671 TEGRA_ADMAIF_CIF_CTRL(3),
672 TEGRA_ADMAIF_CIF_CTRL(4),
673 TEGRA_ADMAIF_CIF_CTRL(5),
674 TEGRA_ADMAIF_CIF_CTRL(6),
675 TEGRA_ADMAIF_CIF_CTRL(7),
676 TEGRA_ADMAIF_CIF_CTRL(8),
677 TEGRA_ADMAIF_CIF_CTRL(9),
678 TEGRA_ADMAIF_CIF_CTRL(10),
679 TEGRA_ADMAIF_CIF_CTRL(11),
680 TEGRA_ADMAIF_CIF_CTRL(12),
681 TEGRA_ADMAIF_CIF_CTRL(13),
682 TEGRA_ADMAIF_CIF_CTRL(14),
683 TEGRA_ADMAIF_CIF_CTRL(15),
684 TEGRA_ADMAIF_CIF_CTRL(16),
685 TEGRA_ADMAIF_CIF_CTRL(17),
686 TEGRA_ADMAIF_CIF_CTRL(18),
687 TEGRA_ADMAIF_CIF_CTRL(19),
688 TEGRA_ADMAIF_CIF_CTRL(20),
689};
690
691static const struct snd_soc_component_driver tegra210_admaif_cmpnt = {
692 .controls = tegra210_admaif_controls,
693 .num_controls = ARRAY_SIZE(tegra210_admaif_controls),
694 .pcm_construct = tegra_pcm_construct,
695 .open = tegra_pcm_open,
696 .close = tegra_pcm_close,
697 .hw_params = tegra_pcm_hw_params,
698 .pointer = tegra_pcm_pointer,
699};
700
701static const struct snd_soc_component_driver tegra186_admaif_cmpnt = {
702 .controls = tegra186_admaif_controls,
703 .num_controls = ARRAY_SIZE(tegra186_admaif_controls),
704 .pcm_construct = tegra_pcm_construct,
705 .open = tegra_pcm_open,
706 .close = tegra_pcm_close,
707 .hw_params = tegra_pcm_hw_params,
708 .pointer = tegra_pcm_pointer,
709};
710
711static const struct tegra_admaif_soc_data soc_data_tegra210 = {
712 .num_ch = TEGRA210_ADMAIF_CHANNEL_COUNT,
713 .cmpnt = &tegra210_admaif_cmpnt,
714 .dais = tegra210_admaif_cmpnt_dais,
715 .regmap_conf = &tegra210_admaif_regmap_config,
716 .global_base = TEGRA210_ADMAIF_GLOBAL_BASE,
717 .tx_base = TEGRA210_ADMAIF_TX_BASE,
718 .rx_base = TEGRA210_ADMAIF_RX_BASE,
719};
720
721static const struct tegra_admaif_soc_data soc_data_tegra186 = {
722 .num_ch = TEGRA186_ADMAIF_CHANNEL_COUNT,
723 .cmpnt = &tegra186_admaif_cmpnt,
724 .dais = tegra186_admaif_cmpnt_dais,
725 .regmap_conf = &tegra186_admaif_regmap_config,
726 .global_base = TEGRA186_ADMAIF_GLOBAL_BASE,
727 .tx_base = TEGRA186_ADMAIF_TX_BASE,
728 .rx_base = TEGRA186_ADMAIF_RX_BASE,
729};
730
731static const struct of_device_id tegra_admaif_of_match[] = {
732 { .compatible = "nvidia,tegra210-admaif", .data = &soc_data_tegra210 },
733 { .compatible = "nvidia,tegra186-admaif", .data = &soc_data_tegra186 },
734 {},
735};
736MODULE_DEVICE_TABLE(of, tegra_admaif_of_match);
737
738static int tegra_admaif_probe(struct platform_device *pdev)
739{
740 struct tegra_admaif *admaif;
741 void __iomem *regs;
742 struct resource *res;
743 int err, i;
744
745 admaif = devm_kzalloc(dev: &pdev->dev, size: sizeof(*admaif), GFP_KERNEL);
746 if (!admaif)
747 return -ENOMEM;
748
749 admaif->soc_data = of_device_get_match_data(dev: &pdev->dev);
750
751 dev_set_drvdata(dev: &pdev->dev, data: admaif);
752
753 admaif->capture_dma_data =
754 devm_kcalloc(dev: &pdev->dev,
755 n: admaif->soc_data->num_ch,
756 size: sizeof(struct snd_dmaengine_dai_dma_data),
757 GFP_KERNEL);
758 if (!admaif->capture_dma_data)
759 return -ENOMEM;
760
761 admaif->playback_dma_data =
762 devm_kcalloc(dev: &pdev->dev,
763 n: admaif->soc_data->num_ch,
764 size: sizeof(struct snd_dmaengine_dai_dma_data),
765 GFP_KERNEL);
766 if (!admaif->playback_dma_data)
767 return -ENOMEM;
768
769 for (i = 0; i < ADMAIF_PATHS; i++) {
770 admaif->mono_to_stereo[i] =
771 devm_kcalloc(dev: &pdev->dev, n: admaif->soc_data->num_ch,
772 size: sizeof(unsigned int), GFP_KERNEL);
773 if (!admaif->mono_to_stereo[i])
774 return -ENOMEM;
775
776 admaif->stereo_to_mono[i] =
777 devm_kcalloc(dev: &pdev->dev, n: admaif->soc_data->num_ch,
778 size: sizeof(unsigned int), GFP_KERNEL);
779 if (!admaif->stereo_to_mono[i])
780 return -ENOMEM;
781 }
782
783 regs = devm_platform_get_and_ioremap_resource(pdev, index: 0, res: &res);
784 if (IS_ERR(ptr: regs))
785 return PTR_ERR(ptr: regs);
786
787 admaif->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
788 admaif->soc_data->regmap_conf);
789 if (IS_ERR(ptr: admaif->regmap)) {
790 dev_err(&pdev->dev, "regmap init failed\n");
791 return PTR_ERR(ptr: admaif->regmap);
792 }
793
794 regcache_cache_only(map: admaif->regmap, enable: true);
795
796 regmap_update_bits(map: admaif->regmap, reg: admaif->soc_data->global_base +
797 TEGRA_ADMAIF_GLOBAL_ENABLE, mask: 1, val: 1);
798
799 for (i = 0; i < admaif->soc_data->num_ch; i++) {
800 admaif->playback_dma_data[i].addr = res->start +
801 CH_TX_REG(TEGRA_ADMAIF_TX_FIFO_WRITE, i);
802
803 admaif->capture_dma_data[i].addr = res->start +
804 CH_RX_REG(TEGRA_ADMAIF_RX_FIFO_READ, i);
805
806 admaif->playback_dma_data[i].addr_width = 32;
807
808 if (of_property_read_string_index(np: pdev->dev.of_node,
809 propname: "dma-names", index: (i * 2) + 1,
810 output: &admaif->playback_dma_data[i].chan_name) < 0) {
811 dev_err(&pdev->dev,
812 "missing property nvidia,dma-names\n");
813
814 return -ENODEV;
815 }
816
817 admaif->capture_dma_data[i].addr_width = 32;
818
819 if (of_property_read_string_index(np: pdev->dev.of_node,
820 propname: "dma-names",
821 index: (i * 2),
822 output: &admaif->capture_dma_data[i].chan_name) < 0) {
823 dev_err(&pdev->dev,
824 "missing property nvidia,dma-names\n");
825
826 return -ENODEV;
827 }
828 }
829
830 err = devm_snd_soc_register_component(dev: &pdev->dev,
831 component_driver: admaif->soc_data->cmpnt,
832 dai_drv: admaif->soc_data->dais,
833 num_dai: admaif->soc_data->num_ch);
834 if (err) {
835 dev_err(&pdev->dev,
836 "can't register ADMAIF component, err: %d\n", err);
837 return err;
838 }
839
840 pm_runtime_enable(dev: &pdev->dev);
841
842 return 0;
843}
844
845static void tegra_admaif_remove(struct platform_device *pdev)
846{
847 pm_runtime_disable(dev: &pdev->dev);
848}
849
850static const struct dev_pm_ops tegra_admaif_pm_ops = {
851 SET_RUNTIME_PM_OPS(tegra_admaif_runtime_suspend,
852 tegra_admaif_runtime_resume, NULL)
853 SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
854 pm_runtime_force_resume)
855};
856
857static struct platform_driver tegra_admaif_driver = {
858 .probe = tegra_admaif_probe,
859 .remove_new = tegra_admaif_remove,
860 .driver = {
861 .name = "tegra210-admaif",
862 .of_match_table = tegra_admaif_of_match,
863 .pm = &tegra_admaif_pm_ops,
864 },
865};
866module_platform_driver(tegra_admaif_driver);
867
868MODULE_AUTHOR("Songhee Baek <sbaek@nvidia.com>");
869MODULE_DESCRIPTION("Tegra210 ASoC ADMAIF driver");
870MODULE_LICENSE("GPL v2");
871

source code of linux/sound/soc/tegra/tegra210_admaif.c