Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0-only
2// SPDX-FileCopyrightText: Copyright (c) 2021-2025 NVIDIA CORPORATION & AFFILIATES.
3// All rights reserved.
4//
5// tegra210_adx.c - Tegra210 ADX driver
6
7#include <linux/clk.h>
8#include <linux/device.h>
9#include <linux/io.h>
10#include <linux/mod_devicetable.h>
11#include <linux/module.h>
12#include <linux/of_device.h>
13#include <linux/platform_device.h>
14#include <linux/pm_runtime.h>
15#include <linux/regmap.h>
16#include <sound/core.h>
17#include <sound/pcm.h>
18#include <sound/pcm_params.h>
19#include <sound/soc.h>
20
21#include "tegra210_adx.h"
22#include "tegra_cif.h"
23
24static const struct reg_default tegra210_adx_reg_defaults[] = {
25 { TEGRA210_ADX_RX_INT_MASK, 0x00000001},
26 { TEGRA210_ADX_RX_CIF_CTRL, 0x00007000},
27 { TEGRA210_ADX_TX_INT_MASK, 0x0000000f },
28 { TEGRA210_ADX_TX1_CIF_CTRL, 0x00007000},
29 { TEGRA210_ADX_TX2_CIF_CTRL, 0x00007000},
30 { TEGRA210_ADX_TX3_CIF_CTRL, 0x00007000},
31 { TEGRA210_ADX_TX4_CIF_CTRL, 0x00007000},
32 { TEGRA210_ADX_CG, 0x1},
33 { TEGRA210_ADX_CFG_RAM_CTRL, 0x00004000},
34};
35
36static const struct reg_default tegra264_adx_reg_defaults[] = {
37 { TEGRA210_ADX_RX_INT_MASK, 0x00000001},
38 { TEGRA210_ADX_RX_CIF_CTRL, 0x00003800},
39 { TEGRA210_ADX_TX_INT_MASK, 0x0000000f },
40 { TEGRA210_ADX_TX1_CIF_CTRL, 0x00003800},
41 { TEGRA210_ADX_TX2_CIF_CTRL, 0x00003800},
42 { TEGRA210_ADX_TX3_CIF_CTRL, 0x00003800},
43 { TEGRA210_ADX_TX4_CIF_CTRL, 0x00003800},
44 { TEGRA210_ADX_CG, 0x1},
45 { TEGRA264_ADX_CFG_RAM_CTRL, 0x00004000},
46};
47
48static void tegra210_adx_write_map_ram(struct tegra210_adx *adx)
49{
50 int i;
51
52 regmap_write(adx->regmap, TEGRA210_ADX_CFG_RAM_CTRL +
53 adx->soc_data->cya_offset,
54 TEGRA210_ADX_CFG_RAM_CTRL_SEQ_ACCESS_EN |
55 TEGRA210_ADX_CFG_RAM_CTRL_ADDR_INIT_EN |
56 TEGRA210_ADX_CFG_RAM_CTRL_RW_WRITE);
57
58 for (i = 0; i < adx->soc_data->ram_depth; i++)
59 regmap_write(adx->regmap, TEGRA210_ADX_CFG_RAM_DATA +
60 adx->soc_data->cya_offset,
61 adx->map[i]);
62
63 for (i = 0; i < adx->soc_data->byte_mask_size; i++)
64 regmap_write(adx->regmap,
65 TEGRA210_ADX_IN_BYTE_EN0 + (i * TEGRA210_ADX_AUDIOCIF_CH_STRIDE),
66 adx->byte_mask[i]);
67}
68
69static int tegra210_adx_startup(struct snd_pcm_substream *substream,
70 struct snd_soc_dai *dai)
71{
72 struct tegra210_adx *adx = snd_soc_dai_get_drvdata(dai);
73 unsigned int val;
74 int err;
75
76 /* Ensure if ADX status is disabled */
77 err = regmap_read_poll_timeout(adx->regmap, TEGRA210_ADX_STATUS,
78 val, !(val & 0x1), 10, 10000);
79 if (err < 0) {
80 dev_err(dai->dev, "failed to stop ADX, err = %d\n", err);
81 return err;
82 }
83
84 /*
85 * Soft Reset: Below performs module soft reset which clears
86 * all FSM logic, flushes flow control of FIFO and resets the
87 * state register. It also brings module back to disabled
88 * state (without flushing the data in the pipe).
89 */
90 regmap_update_bits(adx->regmap, TEGRA210_ADX_SOFT_RESET,
91 TEGRA210_ADX_SOFT_RESET_SOFT_RESET_MASK,
92 TEGRA210_ADX_SOFT_RESET_SOFT_EN);
93
94 err = regmap_read_poll_timeout(adx->regmap, TEGRA210_ADX_SOFT_RESET,
95 val, !(val & 0x1), 10, 10000);
96 if (err < 0) {
97 dev_err(dai->dev, "failed to reset ADX, err = %d\n", err);
98 return err;
99 }
100
101 return 0;
102}
103
104static int tegra210_adx_runtime_suspend(struct device *dev)
105{
106 struct tegra210_adx *adx = dev_get_drvdata(dev);
107
108 regcache_cache_only(adx->regmap, true);
109 regcache_mark_dirty(adx->regmap);
110
111 return 0;
112}
113
114static int tegra210_adx_runtime_resume(struct device *dev)
115{
116 struct tegra210_adx *adx = dev_get_drvdata(dev);
117
118 regcache_cache_only(adx->regmap, false);
119 regcache_sync(adx->regmap);
120
121 tegra210_adx_write_map_ram(adx);
122
123 return 0;
124}
125
126static int tegra210_adx_set_audio_cif(struct snd_soc_dai *dai,
127 unsigned int channels,
128 snd_pcm_format_t format,
129 unsigned int reg)
130{
131 struct tegra210_adx *adx = snd_soc_dai_get_drvdata(dai);
132 struct tegra_cif_conf cif_conf;
133 int audio_bits;
134
135 memset(&cif_conf, 0, sizeof(struct tegra_cif_conf));
136
137 if (channels < 1 || channels > adx->soc_data->max_ch) {
138 dev_err(dai->dev, "invalid channels: %u (max %u)\n",
139 channels, adx->soc_data->max_ch);
140 return -EINVAL;
141 }
142
143 switch (format) {
144 case SNDRV_PCM_FORMAT_S8:
145 audio_bits = TEGRA_ACIF_BITS_8;
146 break;
147 case SNDRV_PCM_FORMAT_S16_LE:
148 audio_bits = TEGRA_ACIF_BITS_16;
149 break;
150 case SNDRV_PCM_FORMAT_S24_LE:
151 case SNDRV_PCM_FORMAT_S32_LE:
152 audio_bits = TEGRA_ACIF_BITS_32;
153 break;
154 default:
155 dev_err(dai->dev, "unsupported format: %d\n", format);
156 return -EINVAL;
157 }
158
159 cif_conf.audio_ch = channels;
160 cif_conf.client_ch = channels;
161 cif_conf.audio_bits = audio_bits;
162 cif_conf.client_bits = audio_bits;
163
164 if (adx->soc_data->max_ch == 32)
165 tegra264_set_cif(adx->regmap, reg, &cif_conf);
166 else
167 tegra_set_cif(adx->regmap, reg, &cif_conf);
168
169 return 0;
170}
171
172static int tegra210_adx_out_hw_params(struct snd_pcm_substream *substream,
173 struct snd_pcm_hw_params *params,
174 struct snd_soc_dai *dai)
175{
176 return tegra210_adx_set_audio_cif(dai, params_channels(params),
177 params_format(params),
178 TEGRA210_ADX_TX1_CIF_CTRL + ((dai->id - 1) * TEGRA210_ADX_AUDIOCIF_CH_STRIDE));
179}
180
181static int tegra210_adx_in_hw_params(struct snd_pcm_substream *substream,
182 struct snd_pcm_hw_params *params,
183 struct snd_soc_dai *dai)
184{
185 return tegra210_adx_set_audio_cif(dai, params_channels(params),
186 params_format(params),
187 TEGRA210_ADX_RX_CIF_CTRL);
188}
189
190static int tegra210_adx_get_byte_map(struct snd_kcontrol *kcontrol,
191 struct snd_ctl_elem_value *ucontrol)
192{
193 struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
194 struct tegra210_adx *adx = snd_soc_component_get_drvdata(cmpnt);
195 struct soc_mixer_control *mc;
196 unsigned char *bytes_map = (unsigned char *)adx->map;
197 int enabled;
198
199 mc = (struct soc_mixer_control *)kcontrol->private_value;
200 enabled = adx->byte_mask[mc->reg / 32] & (1 << (mc->reg % 32));
201
202 /*
203 * TODO: Simplify this logic to just return from bytes_map[]
204 *
205 * Presently below is required since bytes_map[] is
206 * tightly packed and cannot store the control value of 256.
207 * Byte mask state is used to know if 256 needs to be returned.
208 * Note that for control value of 256, the put() call stores 0
209 * in the bytes_map[] and disables the corresponding bit in
210 * byte_mask[].
211 */
212 if (enabled)
213 ucontrol->value.integer.value[0] = bytes_map[mc->reg];
214 else
215 ucontrol->value.integer.value[0] = 256;
216
217 return 0;
218}
219
220static int tegra210_adx_put_byte_map(struct snd_kcontrol *kcontrol,
221 struct snd_ctl_elem_value *ucontrol)
222{
223 struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
224 struct tegra210_adx *adx = snd_soc_component_get_drvdata(cmpnt);
225 unsigned char *bytes_map = (unsigned char *)adx->map;
226 int value = ucontrol->value.integer.value[0];
227 struct soc_mixer_control *mc =
228 (struct soc_mixer_control *)kcontrol->private_value;
229 unsigned int mask_val = adx->byte_mask[mc->reg / 32];
230
231 if (value >= 0 && value <= 255)
232 mask_val |= (1 << (mc->reg % 32));
233 else
234 mask_val &= ~(1 << (mc->reg % 32));
235
236 if (mask_val == adx->byte_mask[mc->reg / 32])
237 return 0;
238
239 /* Update byte map and slot */
240 bytes_map[mc->reg] = value % 256;
241 adx->byte_mask[mc->reg / 32] = mask_val;
242
243 return 1;
244}
245
246static const struct snd_soc_dai_ops tegra210_adx_in_dai_ops = {
247 .hw_params = tegra210_adx_in_hw_params,
248 .startup = tegra210_adx_startup,
249};
250
251static const struct snd_soc_dai_ops tegra210_adx_out_dai_ops = {
252 .hw_params = tegra210_adx_out_hw_params,
253};
254
255#define IN_DAI \
256 { \
257 .name = "ADX-RX-CIF", \
258 .playback = { \
259 .stream_name = "RX-CIF-Playback", \
260 .channels_min = 1, \
261 .channels_max = 16, \
262 .rates = SNDRV_PCM_RATE_8000_192000, \
263 .formats = SNDRV_PCM_FMTBIT_S8 | \
264 SNDRV_PCM_FMTBIT_S16_LE | \
265 SNDRV_PCM_FMTBIT_S24_LE | \
266 SNDRV_PCM_FMTBIT_S32_LE, \
267 }, \
268 .capture = { \
269 .stream_name = "RX-CIF-Capture", \
270 .channels_min = 1, \
271 .channels_max = 16, \
272 .rates = SNDRV_PCM_RATE_8000_192000, \
273 .formats = SNDRV_PCM_FMTBIT_S8 | \
274 SNDRV_PCM_FMTBIT_S16_LE | \
275 SNDRV_PCM_FMTBIT_S24_LE | \
276 SNDRV_PCM_FMTBIT_S32_LE, \
277 }, \
278 .ops = &tegra210_adx_in_dai_ops, \
279 }
280
281#define OUT_DAI(id) \
282 { \
283 .name = "ADX-TX" #id "-CIF", \
284 .playback = { \
285 .stream_name = "TX" #id "-CIF-Playback",\
286 .channels_min = 1, \
287 .channels_max = 16, \
288 .rates = SNDRV_PCM_RATE_8000_192000, \
289 .formats = SNDRV_PCM_FMTBIT_S8 | \
290 SNDRV_PCM_FMTBIT_S16_LE | \
291 SNDRV_PCM_FMTBIT_S24_LE | \
292 SNDRV_PCM_FMTBIT_S32_LE, \
293 }, \
294 .capture = { \
295 .stream_name = "TX" #id "-CIF-Capture", \
296 .channels_min = 1, \
297 .channels_max = 16, \
298 .rates = SNDRV_PCM_RATE_8000_192000, \
299 .formats = SNDRV_PCM_FMTBIT_S8 | \
300 SNDRV_PCM_FMTBIT_S16_LE | \
301 SNDRV_PCM_FMTBIT_S24_LE | \
302 SNDRV_PCM_FMTBIT_S32_LE, \
303 }, \
304 .ops = &tegra210_adx_out_dai_ops, \
305 }
306
307static struct snd_soc_dai_driver tegra210_adx_dais[] = {
308 IN_DAI,
309 OUT_DAI(1),
310 OUT_DAI(2),
311 OUT_DAI(3),
312 OUT_DAI(4),
313};
314
315static const struct snd_soc_dapm_widget tegra210_adx_widgets[] = {
316 SND_SOC_DAPM_AIF_IN("RX", NULL, 0, TEGRA210_ADX_ENABLE,
317 TEGRA210_ADX_ENABLE_SHIFT, 0),
318 SND_SOC_DAPM_AIF_OUT("TX1", NULL, 0, TEGRA210_ADX_CTRL, 0, 0),
319 SND_SOC_DAPM_AIF_OUT("TX2", NULL, 0, TEGRA210_ADX_CTRL, 1, 0),
320 SND_SOC_DAPM_AIF_OUT("TX3", NULL, 0, TEGRA210_ADX_CTRL, 2, 0),
321 SND_SOC_DAPM_AIF_OUT("TX4", NULL, 0, TEGRA210_ADX_CTRL, 3, 0),
322};
323
324#define STREAM_ROUTES(id, sname) \
325 { "XBAR-" sname, NULL, "XBAR-TX" }, \
326 { "RX-CIF-" sname, NULL, "XBAR-" sname }, \
327 { "RX", NULL, "RX-CIF-" sname }, \
328 { "TX" #id, NULL, "RX" }, \
329 { "TX" #id "-CIF-" sname, NULL, "TX" #id }, \
330 { "TX" #id " XBAR-" sname, NULL, "TX" #id "-CIF-" sname }, \
331 { "TX" #id " XBAR-RX", NULL, "TX" #id " XBAR-" sname }
332
333#define ADX_ROUTES(id) \
334 STREAM_ROUTES(id, "Playback"), \
335 STREAM_ROUTES(id, "Capture")
336
337#define STREAM_ROUTES(id, sname) \
338 { "XBAR-" sname, NULL, "XBAR-TX" }, \
339 { "RX-CIF-" sname, NULL, "XBAR-" sname }, \
340 { "RX", NULL, "RX-CIF-" sname }, \
341 { "TX" #id, NULL, "RX" }, \
342 { "TX" #id "-CIF-" sname, NULL, "TX" #id }, \
343 { "TX" #id " XBAR-" sname, NULL, "TX" #id "-CIF-" sname }, \
344 { "TX" #id " XBAR-RX", NULL, "TX" #id " XBAR-" sname }
345
346#define ADX_ROUTES(id) \
347 STREAM_ROUTES(id, "Playback"), \
348 STREAM_ROUTES(id, "Capture")
349
350static const struct snd_soc_dapm_route tegra210_adx_routes[] = {
351 ADX_ROUTES(1),
352 ADX_ROUTES(2),
353 ADX_ROUTES(3),
354 ADX_ROUTES(4),
355};
356
357#define TEGRA210_ADX_BYTE_MAP_CTRL(reg) \
358 SOC_SINGLE_EXT("Byte Map " #reg, reg, 0, 256, 0, \
359 tegra210_adx_get_byte_map, \
360 tegra210_adx_put_byte_map)
361
362static struct snd_kcontrol_new tegra210_adx_controls[] = {
363 TEGRA210_ADX_BYTE_MAP_CTRL(0),
364 TEGRA210_ADX_BYTE_MAP_CTRL(1),
365 TEGRA210_ADX_BYTE_MAP_CTRL(2),
366 TEGRA210_ADX_BYTE_MAP_CTRL(3),
367 TEGRA210_ADX_BYTE_MAP_CTRL(4),
368 TEGRA210_ADX_BYTE_MAP_CTRL(5),
369 TEGRA210_ADX_BYTE_MAP_CTRL(6),
370 TEGRA210_ADX_BYTE_MAP_CTRL(7),
371 TEGRA210_ADX_BYTE_MAP_CTRL(8),
372 TEGRA210_ADX_BYTE_MAP_CTRL(9),
373 TEGRA210_ADX_BYTE_MAP_CTRL(10),
374 TEGRA210_ADX_BYTE_MAP_CTRL(11),
375 TEGRA210_ADX_BYTE_MAP_CTRL(12),
376 TEGRA210_ADX_BYTE_MAP_CTRL(13),
377 TEGRA210_ADX_BYTE_MAP_CTRL(14),
378 TEGRA210_ADX_BYTE_MAP_CTRL(15),
379 TEGRA210_ADX_BYTE_MAP_CTRL(16),
380 TEGRA210_ADX_BYTE_MAP_CTRL(17),
381 TEGRA210_ADX_BYTE_MAP_CTRL(18),
382 TEGRA210_ADX_BYTE_MAP_CTRL(19),
383 TEGRA210_ADX_BYTE_MAP_CTRL(20),
384 TEGRA210_ADX_BYTE_MAP_CTRL(21),
385 TEGRA210_ADX_BYTE_MAP_CTRL(22),
386 TEGRA210_ADX_BYTE_MAP_CTRL(23),
387 TEGRA210_ADX_BYTE_MAP_CTRL(24),
388 TEGRA210_ADX_BYTE_MAP_CTRL(25),
389 TEGRA210_ADX_BYTE_MAP_CTRL(26),
390 TEGRA210_ADX_BYTE_MAP_CTRL(27),
391 TEGRA210_ADX_BYTE_MAP_CTRL(28),
392 TEGRA210_ADX_BYTE_MAP_CTRL(29),
393 TEGRA210_ADX_BYTE_MAP_CTRL(30),
394 TEGRA210_ADX_BYTE_MAP_CTRL(31),
395 TEGRA210_ADX_BYTE_MAP_CTRL(32),
396 TEGRA210_ADX_BYTE_MAP_CTRL(33),
397 TEGRA210_ADX_BYTE_MAP_CTRL(34),
398 TEGRA210_ADX_BYTE_MAP_CTRL(35),
399 TEGRA210_ADX_BYTE_MAP_CTRL(36),
400 TEGRA210_ADX_BYTE_MAP_CTRL(37),
401 TEGRA210_ADX_BYTE_MAP_CTRL(38),
402 TEGRA210_ADX_BYTE_MAP_CTRL(39),
403 TEGRA210_ADX_BYTE_MAP_CTRL(40),
404 TEGRA210_ADX_BYTE_MAP_CTRL(41),
405 TEGRA210_ADX_BYTE_MAP_CTRL(42),
406 TEGRA210_ADX_BYTE_MAP_CTRL(43),
407 TEGRA210_ADX_BYTE_MAP_CTRL(44),
408 TEGRA210_ADX_BYTE_MAP_CTRL(45),
409 TEGRA210_ADX_BYTE_MAP_CTRL(46),
410 TEGRA210_ADX_BYTE_MAP_CTRL(47),
411 TEGRA210_ADX_BYTE_MAP_CTRL(48),
412 TEGRA210_ADX_BYTE_MAP_CTRL(49),
413 TEGRA210_ADX_BYTE_MAP_CTRL(50),
414 TEGRA210_ADX_BYTE_MAP_CTRL(51),
415 TEGRA210_ADX_BYTE_MAP_CTRL(52),
416 TEGRA210_ADX_BYTE_MAP_CTRL(53),
417 TEGRA210_ADX_BYTE_MAP_CTRL(54),
418 TEGRA210_ADX_BYTE_MAP_CTRL(55),
419 TEGRA210_ADX_BYTE_MAP_CTRL(56),
420 TEGRA210_ADX_BYTE_MAP_CTRL(57),
421 TEGRA210_ADX_BYTE_MAP_CTRL(58),
422 TEGRA210_ADX_BYTE_MAP_CTRL(59),
423 TEGRA210_ADX_BYTE_MAP_CTRL(60),
424 TEGRA210_ADX_BYTE_MAP_CTRL(61),
425 TEGRA210_ADX_BYTE_MAP_CTRL(62),
426 TEGRA210_ADX_BYTE_MAP_CTRL(63),
427};
428
429static struct snd_kcontrol_new tegra264_adx_controls[] = {
430 TEGRA210_ADX_BYTE_MAP_CTRL(64),
431 TEGRA210_ADX_BYTE_MAP_CTRL(65),
432 TEGRA210_ADX_BYTE_MAP_CTRL(66),
433 TEGRA210_ADX_BYTE_MAP_CTRL(67),
434 TEGRA210_ADX_BYTE_MAP_CTRL(68),
435 TEGRA210_ADX_BYTE_MAP_CTRL(69),
436 TEGRA210_ADX_BYTE_MAP_CTRL(70),
437 TEGRA210_ADX_BYTE_MAP_CTRL(71),
438 TEGRA210_ADX_BYTE_MAP_CTRL(72),
439 TEGRA210_ADX_BYTE_MAP_CTRL(73),
440 TEGRA210_ADX_BYTE_MAP_CTRL(74),
441 TEGRA210_ADX_BYTE_MAP_CTRL(75),
442 TEGRA210_ADX_BYTE_MAP_CTRL(76),
443 TEGRA210_ADX_BYTE_MAP_CTRL(77),
444 TEGRA210_ADX_BYTE_MAP_CTRL(78),
445 TEGRA210_ADX_BYTE_MAP_CTRL(79),
446 TEGRA210_ADX_BYTE_MAP_CTRL(80),
447 TEGRA210_ADX_BYTE_MAP_CTRL(81),
448 TEGRA210_ADX_BYTE_MAP_CTRL(82),
449 TEGRA210_ADX_BYTE_MAP_CTRL(83),
450 TEGRA210_ADX_BYTE_MAP_CTRL(84),
451 TEGRA210_ADX_BYTE_MAP_CTRL(85),
452 TEGRA210_ADX_BYTE_MAP_CTRL(86),
453 TEGRA210_ADX_BYTE_MAP_CTRL(87),
454 TEGRA210_ADX_BYTE_MAP_CTRL(88),
455 TEGRA210_ADX_BYTE_MAP_CTRL(89),
456 TEGRA210_ADX_BYTE_MAP_CTRL(90),
457 TEGRA210_ADX_BYTE_MAP_CTRL(91),
458 TEGRA210_ADX_BYTE_MAP_CTRL(92),
459 TEGRA210_ADX_BYTE_MAP_CTRL(93),
460 TEGRA210_ADX_BYTE_MAP_CTRL(94),
461 TEGRA210_ADX_BYTE_MAP_CTRL(95),
462 TEGRA210_ADX_BYTE_MAP_CTRL(96),
463 TEGRA210_ADX_BYTE_MAP_CTRL(97),
464 TEGRA210_ADX_BYTE_MAP_CTRL(98),
465 TEGRA210_ADX_BYTE_MAP_CTRL(99),
466 TEGRA210_ADX_BYTE_MAP_CTRL(100),
467 TEGRA210_ADX_BYTE_MAP_CTRL(101),
468 TEGRA210_ADX_BYTE_MAP_CTRL(102),
469 TEGRA210_ADX_BYTE_MAP_CTRL(103),
470 TEGRA210_ADX_BYTE_MAP_CTRL(104),
471 TEGRA210_ADX_BYTE_MAP_CTRL(105),
472 TEGRA210_ADX_BYTE_MAP_CTRL(106),
473 TEGRA210_ADX_BYTE_MAP_CTRL(107),
474 TEGRA210_ADX_BYTE_MAP_CTRL(108),
475 TEGRA210_ADX_BYTE_MAP_CTRL(109),
476 TEGRA210_ADX_BYTE_MAP_CTRL(110),
477 TEGRA210_ADX_BYTE_MAP_CTRL(111),
478 TEGRA210_ADX_BYTE_MAP_CTRL(112),
479 TEGRA210_ADX_BYTE_MAP_CTRL(113),
480 TEGRA210_ADX_BYTE_MAP_CTRL(114),
481 TEGRA210_ADX_BYTE_MAP_CTRL(115),
482 TEGRA210_ADX_BYTE_MAP_CTRL(116),
483 TEGRA210_ADX_BYTE_MAP_CTRL(117),
484 TEGRA210_ADX_BYTE_MAP_CTRL(118),
485 TEGRA210_ADX_BYTE_MAP_CTRL(119),
486 TEGRA210_ADX_BYTE_MAP_CTRL(120),
487 TEGRA210_ADX_BYTE_MAP_CTRL(121),
488 TEGRA210_ADX_BYTE_MAP_CTRL(122),
489 TEGRA210_ADX_BYTE_MAP_CTRL(123),
490 TEGRA210_ADX_BYTE_MAP_CTRL(124),
491 TEGRA210_ADX_BYTE_MAP_CTRL(125),
492 TEGRA210_ADX_BYTE_MAP_CTRL(126),
493 TEGRA210_ADX_BYTE_MAP_CTRL(127),
494};
495
496static int tegra210_adx_component_probe(struct snd_soc_component *component)
497{
498 struct tegra210_adx *adx = snd_soc_component_get_drvdata(component);
499 int err = 0;
500
501 if (adx->soc_data->num_controls) {
502 err = snd_soc_add_component_controls(component, adx->soc_data->controls,
503 adx->soc_data->num_controls);
504 if (err)
505 dev_err(component->dev, "can't add ADX controls, err: %d\n", err);
506 }
507
508 return err;
509}
510
511static const struct snd_soc_component_driver tegra210_adx_cmpnt = {
512 .probe = tegra210_adx_component_probe,
513 .dapm_widgets = tegra210_adx_widgets,
514 .num_dapm_widgets = ARRAY_SIZE(tegra210_adx_widgets),
515 .dapm_routes = tegra210_adx_routes,
516 .num_dapm_routes = ARRAY_SIZE(tegra210_adx_routes),
517 .controls = tegra210_adx_controls,
518 .num_controls = ARRAY_SIZE(tegra210_adx_controls),
519};
520
521static bool tegra210_adx_wr_reg(struct device *dev,
522 unsigned int reg)
523{
524 switch (reg) {
525 case TEGRA210_ADX_TX_INT_MASK ... TEGRA210_ADX_TX4_CIF_CTRL:
526 case TEGRA210_ADX_RX_INT_MASK ... TEGRA210_ADX_RX_CIF_CTRL:
527 case TEGRA210_ADX_ENABLE ... TEGRA210_ADX_CG:
528 case TEGRA210_ADX_CTRL ... TEGRA210_ADX_IN_BYTE_EN1:
529 case TEGRA210_ADX_CFG_RAM_CTRL ... TEGRA210_ADX_CFG_RAM_DATA:
530 return true;
531 default:
532 return false;
533 }
534}
535
536static bool tegra210_adx_rd_reg(struct device *dev,
537 unsigned int reg)
538{
539 switch (reg) {
540 case TEGRA210_ADX_RX_STATUS ... TEGRA210_ADX_CFG_RAM_DATA:
541 return true;
542 default:
543 return false;
544 }
545}
546
547static bool tegra210_adx_volatile_reg(struct device *dev,
548 unsigned int reg)
549{
550 switch (reg) {
551 case TEGRA210_ADX_RX_STATUS:
552 case TEGRA210_ADX_RX_INT_STATUS:
553 case TEGRA210_ADX_RX_INT_SET:
554 case TEGRA210_ADX_TX_STATUS:
555 case TEGRA210_ADX_TX_INT_STATUS:
556 case TEGRA210_ADX_TX_INT_SET:
557 case TEGRA210_ADX_SOFT_RESET:
558 case TEGRA210_ADX_STATUS:
559 case TEGRA210_ADX_INT_STATUS:
560 case TEGRA210_ADX_CFG_RAM_CTRL:
561 case TEGRA210_ADX_CFG_RAM_DATA:
562 return true;
563 default:
564 break;
565 }
566
567 return false;
568}
569
570static bool tegra264_adx_wr_reg(struct device *dev,
571 unsigned int reg)
572{
573 switch (reg) {
574 case TEGRA210_ADX_TX_INT_MASK ... TEGRA210_ADX_TX4_CIF_CTRL:
575 case TEGRA210_ADX_RX_INT_MASK ... TEGRA210_ADX_RX_CIF_CTRL:
576 case TEGRA210_ADX_ENABLE ... TEGRA210_ADX_CG:
577 case TEGRA210_ADX_CTRL ... TEGRA264_ADX_CYA:
578 case TEGRA264_ADX_CFG_RAM_CTRL ... TEGRA264_ADX_CFG_RAM_DATA:
579 return true;
580 default:
581 return false;
582 }
583}
584
585static bool tegra264_adx_rd_reg(struct device *dev,
586 unsigned int reg)
587{
588 switch (reg) {
589 case TEGRA210_ADX_RX_STATUS ... TEGRA210_ADX_RX_CIF_CTRL:
590 case TEGRA210_ADX_TX_STATUS ... TEGRA210_ADX_TX4_CIF_CTRL:
591 case TEGRA210_ADX_ENABLE ... TEGRA210_ADX_INT_STATUS:
592 case TEGRA210_ADX_CTRL ... TEGRA264_ADX_CFG_RAM_DATA:
593 return true;
594 default:
595 return false;
596 }
597}
598
599static bool tegra264_adx_volatile_reg(struct device *dev,
600 unsigned int reg)
601{
602 switch (reg) {
603 case TEGRA210_ADX_RX_STATUS:
604 case TEGRA210_ADX_RX_INT_STATUS:
605 case TEGRA210_ADX_RX_INT_SET:
606 case TEGRA210_ADX_TX_STATUS:
607 case TEGRA210_ADX_TX_INT_STATUS:
608 case TEGRA210_ADX_TX_INT_SET:
609 case TEGRA210_ADX_SOFT_RESET:
610 case TEGRA210_ADX_STATUS:
611 case TEGRA210_ADX_INT_STATUS:
612 case TEGRA264_ADX_CFG_RAM_CTRL:
613 case TEGRA264_ADX_CFG_RAM_DATA:
614 return true;
615 default:
616 break;
617 }
618
619 return false;
620}
621
622static const struct regmap_config tegra210_adx_regmap_config = {
623 .reg_bits = 32,
624 .reg_stride = 4,
625 .val_bits = 32,
626 .max_register = TEGRA210_ADX_CFG_RAM_DATA,
627 .writeable_reg = tegra210_adx_wr_reg,
628 .readable_reg = tegra210_adx_rd_reg,
629 .volatile_reg = tegra210_adx_volatile_reg,
630 .reg_defaults = tegra210_adx_reg_defaults,
631 .num_reg_defaults = ARRAY_SIZE(tegra210_adx_reg_defaults),
632 .reg_default_cb = regmap_default_zero_cb,
633 .cache_type = REGCACHE_FLAT,
634};
635
636static const struct regmap_config tegra264_adx_regmap_config = {
637 .reg_bits = 32,
638 .reg_stride = 4,
639 .val_bits = 32,
640 .max_register = TEGRA264_ADX_CFG_RAM_DATA,
641 .writeable_reg = tegra264_adx_wr_reg,
642 .readable_reg = tegra264_adx_rd_reg,
643 .volatile_reg = tegra264_adx_volatile_reg,
644 .reg_defaults = tegra264_adx_reg_defaults,
645 .num_reg_defaults = ARRAY_SIZE(tegra264_adx_reg_defaults),
646 .reg_default_cb = regmap_default_zero_cb,
647 .cache_type = REGCACHE_FLAT,
648};
649
650static const struct tegra210_adx_soc_data soc_data_tegra210 = {
651 .regmap_conf = &tegra210_adx_regmap_config,
652 .max_ch = TEGRA210_ADX_MAX_CHANNEL,
653 .ram_depth = TEGRA210_ADX_RAM_DEPTH,
654 .byte_mask_size = TEGRA210_ADX_BYTE_MASK_COUNT,
655 .cya_offset = TEGRA210_ADX_CYA_OFFSET,
656};
657
658static const struct tegra210_adx_soc_data soc_data_tegra264 = {
659 .regmap_conf = &tegra264_adx_regmap_config,
660 .max_ch = TEGRA264_ADX_MAX_CHANNEL,
661 .ram_depth = TEGRA264_ADX_RAM_DEPTH,
662 .byte_mask_size = TEGRA264_ADX_BYTE_MASK_COUNT,
663 .cya_offset = TEGRA264_ADX_CYA_OFFSET,
664 .controls = tegra264_adx_controls,
665 .num_controls = ARRAY_SIZE(tegra264_adx_controls),
666};
667
668static const struct of_device_id tegra210_adx_of_match[] = {
669 { .compatible = "nvidia,tegra210-adx", .data = &soc_data_tegra210 },
670 { .compatible = "nvidia,tegra264-adx", .data = &soc_data_tegra264 },
671 {},
672};
673MODULE_DEVICE_TABLE(of, tegra210_adx_of_match);
674
675static int tegra210_adx_platform_probe(struct platform_device *pdev)
676{
677 struct device *dev = &pdev->dev;
678 struct tegra210_adx *adx;
679 const struct of_device_id *match;
680 struct tegra210_adx_soc_data *soc_data;
681 void __iomem *regs;
682 int err;
683
684 adx = devm_kzalloc(dev, sizeof(*adx), GFP_KERNEL);
685 if (!adx)
686 return -ENOMEM;
687
688 match = of_match_device(tegra210_adx_of_match, dev);
689 soc_data = (struct tegra210_adx_soc_data *)match->data;
690 adx->soc_data = soc_data;
691
692 dev_set_drvdata(dev, adx);
693
694 regs = devm_platform_ioremap_resource(pdev, 0);
695 if (IS_ERR(regs))
696 return PTR_ERR(regs);
697
698 adx->regmap = devm_regmap_init_mmio(dev, regs,
699 soc_data->regmap_conf);
700 if (IS_ERR(adx->regmap))
701 return dev_err_probe(dev, PTR_ERR(adx->regmap),
702 "regmap init failed\n");
703
704 regcache_cache_only(adx->regmap, true);
705
706 adx->map = devm_kzalloc(dev, soc_data->ram_depth * sizeof(*adx->map),
707 GFP_KERNEL);
708 if (!adx->map)
709 return -ENOMEM;
710
711 adx->byte_mask = devm_kzalloc(dev,
712 soc_data->byte_mask_size * sizeof(*adx->byte_mask),
713 GFP_KERNEL);
714 if (!adx->byte_mask)
715 return -ENOMEM;
716
717 tegra210_adx_dais[TEGRA_ADX_IN_DAI_ID].playback.channels_max =
718 adx->soc_data->max_ch;
719
720 err = devm_snd_soc_register_component(dev, &tegra210_adx_cmpnt,
721 tegra210_adx_dais,
722 ARRAY_SIZE(tegra210_adx_dais));
723 if (err)
724 return dev_err_probe(dev, err,
725 "can't register ADX component\n");
726
727 pm_runtime_enable(dev);
728
729 return 0;
730}
731
732static void tegra210_adx_platform_remove(struct platform_device *pdev)
733{
734 pm_runtime_disable(&pdev->dev);
735}
736
737static const struct dev_pm_ops tegra210_adx_pm_ops = {
738 RUNTIME_PM_OPS(tegra210_adx_runtime_suspend,
739 tegra210_adx_runtime_resume, NULL)
740 SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
741};
742
743static struct platform_driver tegra210_adx_driver = {
744 .driver = {
745 .name = "tegra210-adx",
746 .of_match_table = tegra210_adx_of_match,
747 .pm = pm_ptr(&tegra210_adx_pm_ops),
748 },
749 .probe = tegra210_adx_platform_probe,
750 .remove = tegra210_adx_platform_remove,
751};
752module_platform_driver(tegra210_adx_driver);
753
754MODULE_AUTHOR("Arun Shamanna Lakshmi <aruns@nvidia.com>");
755MODULE_DESCRIPTION("Tegra210 ADX ASoC driver");
756MODULE_LICENSE("GPL v2");