File Index
Files and directories
Sign in
FILE

tegra210_adx.c

File preview with syntax highlighting.

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