File Index
Files and directories
Sign in
FILE

tegra210_amx.c

File preview with syntax highlighting.

linux-6.19.14/sound/soc/tegra/tegra210_amx.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_amx.c - Tegra210 AMX 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/platform_device.h>
 13#include <linux/pm_runtime.h>
 14#include <linux/regmap.h>
 15#include <sound/core.h>
 16#include <sound/pcm.h>
 17#include <sound/pcm_params.h>
 18#include <sound/soc.h>
 19
 20#include "tegra210_amx.h"
 21#include "tegra_cif.h"
 22
 23/*
 24 * The counter is in terms of AHUB clock cycles. If a frame is not
 25 * received within these clock cycles, the AMX input channel gets
 26 * automatically disabled. For now the counter is calculated as a
 27 * function of sample rate (8 kHz) and AHUB clock (49.152 MHz).
 28 * If later an accurate number is needed, the counter needs to be
 29 * calculated at runtime.
 30 *
 31 *     count = ahub_clk / sample_rate
 32 */
 33#define TEGRA194_MAX_FRAME_IDLE_COUNT	0x1800
 34
 35#define AMX_CH_REG(id, reg) ((reg) + ((id) * TEGRA210_AMX_AUDIOCIF_CH_STRIDE))
 36
 37static const struct reg_default tegra210_amx_reg_defaults[] = {
 38	{ TEGRA210_AMX_RX_INT_MASK, 0x0000000f},
 39	{ TEGRA210_AMX_RX1_CIF_CTRL, 0x00007000},
 40	{ TEGRA210_AMX_RX2_CIF_CTRL, 0x00007000},
 41	{ TEGRA210_AMX_RX3_CIF_CTRL, 0x00007000},
 42	{ TEGRA210_AMX_RX4_CIF_CTRL, 0x00007000},
 43	{ TEGRA210_AMX_TX_INT_MASK, 0x00000001},
 44	{ TEGRA210_AMX_TX_CIF_CTRL, 0x00007000},
 45	{ TEGRA210_AMX_CG, 0x1},
 46	{ TEGRA210_AMX_CFG_RAM_CTRL, 0x00004000},
 47};
 48
 49static const struct reg_default tegra264_amx_reg_defaults[] = {
 50	{ TEGRA210_AMX_RX_INT_MASK, 0x0000000f},
 51	{ TEGRA210_AMX_RX1_CIF_CTRL, 0x00003800},
 52	{ TEGRA210_AMX_RX2_CIF_CTRL, 0x00003800},
 53	{ TEGRA210_AMX_RX3_CIF_CTRL, 0x00003800},
 54	{ TEGRA210_AMX_RX4_CIF_CTRL, 0x00003800},
 55	{ TEGRA210_AMX_TX_INT_MASK, 0x00000001},
 56	{ TEGRA210_AMX_TX_CIF_CTRL, 0x00003800},
 57	{ TEGRA210_AMX_CG, 0x1},
 58	{ TEGRA264_AMX_CFG_RAM_CTRL, 0x00004000},
 59};
 60
 61static void tegra210_amx_write_map_ram(struct tegra210_amx *amx)
 62{
 63	int i;
 64
 65	regmap_write(amx->regmap, TEGRA210_AMX_CFG_RAM_CTRL + amx->soc_data->reg_offset,
 66		     TEGRA210_AMX_CFG_RAM_CTRL_SEQ_ACCESS_EN |
 67		     TEGRA210_AMX_CFG_RAM_CTRL_ADDR_INIT_EN |
 68		     TEGRA210_AMX_CFG_RAM_CTRL_RW_WRITE);
 69
 70	for (i = 0; i < amx->soc_data->ram_depth; i++)
 71		regmap_write(amx->regmap, TEGRA210_AMX_CFG_RAM_DATA + amx->soc_data->reg_offset,
 72			     amx->map[i]);
 73
 74	for (i = 0; i < amx->soc_data->byte_mask_size; i++)
 75		regmap_write(amx->regmap,
 76			     TEGRA210_AMX_OUT_BYTE_EN0 + (i * TEGRA210_AMX_AUDIOCIF_CH_STRIDE),
 77			     amx->byte_mask[i]);
 78}
 79
 80static int tegra210_amx_startup(struct snd_pcm_substream *substream,
 81				struct snd_soc_dai *dai)
 82{
 83	struct tegra210_amx *amx = snd_soc_dai_get_drvdata(dai);
 84	unsigned int val;
 85	int err;
 86
 87	/* Ensure if AMX is disabled */
 88	err = regmap_read_poll_timeout(amx->regmap, TEGRA210_AMX_STATUS, val,
 89				       !(val & 0x1), 10, 10000);
 90	if (err < 0) {
 91		dev_err(dai->dev, "failed to stop AMX, err = %d\n", err);
 92		return err;
 93	}
 94
 95	/*
 96	 * Soft Reset: Below performs module soft reset which clears
 97	 * all FSM logic, flushes flow control of FIFO and resets the
 98	 * state register. It also brings module back to disabled
 99	 * state (without flushing the data in the pipe).
100	 */
101	regmap_update_bits(amx->regmap, TEGRA210_AMX_SOFT_RESET,
102			   TEGRA210_AMX_SOFT_RESET_SOFT_RESET_MASK,
103			   TEGRA210_AMX_SOFT_RESET_SOFT_EN);
104
105	err = regmap_read_poll_timeout(amx->regmap, TEGRA210_AMX_SOFT_RESET,
106				       val, !(val & 0x1), 10, 10000);
107	if (err < 0) {
108		dev_err(dai->dev, "failed to reset AMX, err = %d\n", err);
109		return err;
110	}
111
112	return 0;
113}
114
115static int tegra210_amx_runtime_suspend(struct device *dev)
116{
117	struct tegra210_amx *amx = dev_get_drvdata(dev);
118
119	regcache_cache_only(amx->regmap, true);
120	regcache_mark_dirty(amx->regmap);
121
122	return 0;
123}
124
125static int tegra210_amx_runtime_resume(struct device *dev)
126{
127	struct tegra210_amx *amx = dev_get_drvdata(dev);
128
129	regcache_cache_only(amx->regmap, false);
130	regcache_sync(amx->regmap);
131
132	regmap_update_bits(amx->regmap,
133		TEGRA210_AMX_CTRL,
134		TEGRA210_AMX_CTRL_RX_DEP_MASK,
135		TEGRA210_AMX_WAIT_ON_ANY << TEGRA210_AMX_CTRL_RX_DEP_SHIFT);
136
137	tegra210_amx_write_map_ram(amx);
138
139	return 0;
140}
141
142static int tegra210_amx_set_audio_cif(struct snd_soc_dai *dai,
143				      struct snd_pcm_hw_params *params,
144				      unsigned int reg)
145{
146	struct tegra210_amx *amx = snd_soc_dai_get_drvdata(dai);
147	int channels, audio_bits;
148	struct tegra_cif_conf cif_conf;
149
150	memset(&cif_conf, 0, sizeof(struct tegra_cif_conf));
151
152	channels = params_channels(params);
153
154	switch (params_format(params)) {
155	case SNDRV_PCM_FORMAT_S8:
156		audio_bits = TEGRA_ACIF_BITS_8;
157		break;
158	case SNDRV_PCM_FORMAT_S16_LE:
159		audio_bits = TEGRA_ACIF_BITS_16;
160		break;
161	case SNDRV_PCM_FORMAT_S24_LE:
162	case SNDRV_PCM_FORMAT_S32_LE:
163		audio_bits = TEGRA_ACIF_BITS_32;
164		break;
165	default:
166		return -EINVAL;
167	}
168
169	cif_conf.audio_ch = channels;
170	cif_conf.client_ch = channels;
171	cif_conf.audio_bits = audio_bits;
172	cif_conf.client_bits = audio_bits;
173
174	if (amx->soc_data->max_ch == TEGRA264_AMX_MAX_CHANNEL)
175		tegra264_set_cif(amx->regmap, reg, &cif_conf);
176	else
177		tegra_set_cif(amx->regmap, reg, &cif_conf);
178
179	return 0;
180}
181
182static int tegra210_amx_in_hw_params(struct snd_pcm_substream *substream,
183				     struct snd_pcm_hw_params *params,
184				     struct snd_soc_dai *dai)
185{
186	struct tegra210_amx *amx = snd_soc_dai_get_drvdata(dai);
187
188	if (amx->soc_data->auto_disable) {
189		regmap_write(amx->regmap,
190			     AMX_CH_REG(dai->id, TEGRA194_AMX_RX1_FRAME_PERIOD +
191				amx->soc_data->reg_offset),
192			     TEGRA194_MAX_FRAME_IDLE_COUNT);
193		regmap_write(amx->regmap, TEGRA210_AMX_CYA + amx->soc_data->reg_offset, 1);
194	}
195
196	return tegra210_amx_set_audio_cif(dai, params,
197			AMX_CH_REG(dai->id, TEGRA210_AMX_RX1_CIF_CTRL));
198}
199
200static int tegra210_amx_out_hw_params(struct snd_pcm_substream *substream,
201				      struct snd_pcm_hw_params *params,
202				      struct snd_soc_dai *dai)
203{
204	return tegra210_amx_set_audio_cif(dai, params,
205					  TEGRA210_AMX_TX_CIF_CTRL);
206}
207
208static int tegra210_amx_get_byte_map(struct snd_kcontrol *kcontrol,
209				     struct snd_ctl_elem_value *ucontrol)
210{
211	struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
212	struct soc_mixer_control *mc =
213		(struct soc_mixer_control *)kcontrol->private_value;
214	struct tegra210_amx *amx = snd_soc_component_get_drvdata(cmpnt);
215	unsigned char *bytes_map = (unsigned char *)amx->map;
216	int reg = mc->reg;
217	int enabled;
218
219	enabled = amx->byte_mask[reg / 32] & (1 << (reg % 32));
220
221	/*
222	 * TODO: Simplify this logic to just return from bytes_map[]
223	 *
224	 * Presently below is required since bytes_map[] is
225	 * tightly packed and cannot store the control value of 256.
226	 * Byte mask state is used to know if 256 needs to be returned.
227	 * Note that for control value of 256, the put() call stores 0
228	 * in the bytes_map[] and disables the corresponding bit in
229	 * byte_mask[].
230	 */
231	if (enabled)
232		ucontrol->value.integer.value[0] = bytes_map[reg];
233	else
234		ucontrol->value.integer.value[0] = 256;
235
236	return 0;
237}
238
239static int tegra210_amx_put_byte_map(struct snd_kcontrol *kcontrol,
240				     struct snd_ctl_elem_value *ucontrol)
241{
242	struct soc_mixer_control *mc =
243		(struct soc_mixer_control *)kcontrol->private_value;
244	struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
245	struct tegra210_amx *amx = snd_soc_component_get_drvdata(cmpnt);
246	unsigned char *bytes_map = (unsigned char *)amx->map;
247	int reg = mc->reg;
248	int value = ucontrol->value.integer.value[0];
249	unsigned int mask_val = amx->byte_mask[reg / 32];
250
251	if (value >= 0 && value <= 255)
252		mask_val |= (1 << (reg % 32));
253	else
254		mask_val &= ~(1 << (reg % 32));
255
256	if (mask_val == amx->byte_mask[reg / 32])
257		return 0;
258
259	/* Update byte map and slot */
260	bytes_map[reg] = value % 256;
261	amx->byte_mask[reg / 32] = mask_val;
262
263	return 1;
264}
265
266static const struct snd_soc_dai_ops tegra210_amx_out_dai_ops = {
267	.hw_params	= tegra210_amx_out_hw_params,
268	.startup	= tegra210_amx_startup,
269};
270
271static const struct snd_soc_dai_ops tegra210_amx_in_dai_ops = {
272	.hw_params	= tegra210_amx_in_hw_params,
273};
274
275#define IN_DAI(id)						\
276	{							\
277		.name = "AMX-RX-CIF" #id,			\
278		.playback = {					\
279			.stream_name = "RX" #id "-CIF-Playback",\
280			.channels_min = 1,			\
281			.channels_max = 16,			\
282			.rates = SNDRV_PCM_RATE_8000_192000,	\
283			.formats = SNDRV_PCM_FMTBIT_S8 |	\
284				   SNDRV_PCM_FMTBIT_S16_LE |	\
285				   SNDRV_PCM_FMTBIT_S24_LE |	\
286				   SNDRV_PCM_FMTBIT_S32_LE,	\
287		},						\
288		.capture = {					\
289			.stream_name = "RX" #id "-CIF-Capture",	\
290			.channels_min = 1,			\
291			.channels_max = 16,			\
292			.rates = SNDRV_PCM_RATE_8000_192000,	\
293			.formats = SNDRV_PCM_FMTBIT_S8 |	\
294				   SNDRV_PCM_FMTBIT_S16_LE |	\
295				   SNDRV_PCM_FMTBIT_S24_LE |	\
296				   SNDRV_PCM_FMTBIT_S32_LE,	\
297		},						\
298		.ops = &tegra210_amx_in_dai_ops,		\
299	}
300
301#define OUT_DAI							\
302	{							\
303		.name = "AMX-TX-CIF",				\
304		.playback = {					\
305			.stream_name = "TX-CIF-Playback",	\
306			.channels_min = 1,			\
307			.channels_max = 16,			\
308			.rates = SNDRV_PCM_RATE_8000_192000,	\
309			.formats = SNDRV_PCM_FMTBIT_S8 |	\
310				   SNDRV_PCM_FMTBIT_S16_LE |	\
311				   SNDRV_PCM_FMTBIT_S24_LE |	\
312				   SNDRV_PCM_FMTBIT_S32_LE,	\
313		},						\
314		.capture = {					\
315			.stream_name = "TX-CIF-Capture",	\
316			.channels_min = 1,			\
317			.channels_max = 16,			\
318			.rates = SNDRV_PCM_RATE_8000_192000,	\
319			.formats = SNDRV_PCM_FMTBIT_S8 |	\
320				   SNDRV_PCM_FMTBIT_S16_LE |	\
321				   SNDRV_PCM_FMTBIT_S24_LE |	\
322				   SNDRV_PCM_FMTBIT_S32_LE,	\
323		},						\
324		.ops = &tegra210_amx_out_dai_ops,		\
325	}
326
327static struct snd_soc_dai_driver tegra210_amx_dais[] = {
328	IN_DAI(1),
329	IN_DAI(2),
330	IN_DAI(3),
331	IN_DAI(4),
332	OUT_DAI,
333};
334
335static const struct snd_soc_dapm_widget tegra210_amx_widgets[] = {
336	SND_SOC_DAPM_AIF_IN("RX1", NULL, 0, TEGRA210_AMX_CTRL, 0, 0),
337	SND_SOC_DAPM_AIF_IN("RX2", NULL, 0, TEGRA210_AMX_CTRL, 1, 0),
338	SND_SOC_DAPM_AIF_IN("RX3", NULL, 0, TEGRA210_AMX_CTRL, 2, 0),
339	SND_SOC_DAPM_AIF_IN("RX4", NULL, 0, TEGRA210_AMX_CTRL, 3, 0),
340	SND_SOC_DAPM_AIF_OUT("TX", NULL, 0, TEGRA210_AMX_ENABLE,
341			     TEGRA210_AMX_ENABLE_SHIFT, 0),
342};
343
344#define STREAM_ROUTES(id, sname)					  \
345	{ "RX" #id " XBAR-" sname,	NULL,	"RX" #id " XBAR-TX" },	  \
346	{ "RX" #id "-CIF-" sname,	NULL,	"RX" #id " XBAR-" sname },\
347	{ "RX" #id,			NULL,	"RX" #id "-CIF-" sname }, \
348	{ "TX",				NULL,	"RX" #id },		  \
349	{ "TX-CIF-" sname,		NULL,	"TX" },			  \
350	{ "XBAR-" sname,		NULL,	"TX-CIF-" sname },	  \
351	{ "XBAR-RX",			NULL,	"XBAR-" sname }
352
353#define AMX_ROUTES(id)			\
354	STREAM_ROUTES(id, "Playback"),	\
355	STREAM_ROUTES(id, "Capture")
356
357static const struct snd_soc_dapm_route tegra210_amx_routes[] = {
358	AMX_ROUTES(1),
359	AMX_ROUTES(2),
360	AMX_ROUTES(3),
361	AMX_ROUTES(4),
362};
363
364#define TEGRA210_AMX_BYTE_MAP_CTRL(reg)					\
365	SOC_SINGLE_EXT("Byte Map " #reg, reg, 0, 256, 0,		\
366		       tegra210_amx_get_byte_map,			\
367		       tegra210_amx_put_byte_map)
368
369static struct snd_kcontrol_new tegra210_amx_controls[] = {
370	TEGRA210_AMX_BYTE_MAP_CTRL(0),
371	TEGRA210_AMX_BYTE_MAP_CTRL(1),
372	TEGRA210_AMX_BYTE_MAP_CTRL(2),
373	TEGRA210_AMX_BYTE_MAP_CTRL(3),
374	TEGRA210_AMX_BYTE_MAP_CTRL(4),
375	TEGRA210_AMX_BYTE_MAP_CTRL(5),
376	TEGRA210_AMX_BYTE_MAP_CTRL(6),
377	TEGRA210_AMX_BYTE_MAP_CTRL(7),
378	TEGRA210_AMX_BYTE_MAP_CTRL(8),
379	TEGRA210_AMX_BYTE_MAP_CTRL(9),
380	TEGRA210_AMX_BYTE_MAP_CTRL(10),
381	TEGRA210_AMX_BYTE_MAP_CTRL(11),
382	TEGRA210_AMX_BYTE_MAP_CTRL(12),
383	TEGRA210_AMX_BYTE_MAP_CTRL(13),
384	TEGRA210_AMX_BYTE_MAP_CTRL(14),
385	TEGRA210_AMX_BYTE_MAP_CTRL(15),
386	TEGRA210_AMX_BYTE_MAP_CTRL(16),
387	TEGRA210_AMX_BYTE_MAP_CTRL(17),
388	TEGRA210_AMX_BYTE_MAP_CTRL(18),
389	TEGRA210_AMX_BYTE_MAP_CTRL(19),
390	TEGRA210_AMX_BYTE_MAP_CTRL(20),
391	TEGRA210_AMX_BYTE_MAP_CTRL(21),
392	TEGRA210_AMX_BYTE_MAP_CTRL(22),
393	TEGRA210_AMX_BYTE_MAP_CTRL(23),
394	TEGRA210_AMX_BYTE_MAP_CTRL(24),
395	TEGRA210_AMX_BYTE_MAP_CTRL(25),
396	TEGRA210_AMX_BYTE_MAP_CTRL(26),
397	TEGRA210_AMX_BYTE_MAP_CTRL(27),
398	TEGRA210_AMX_BYTE_MAP_CTRL(28),
399	TEGRA210_AMX_BYTE_MAP_CTRL(29),
400	TEGRA210_AMX_BYTE_MAP_CTRL(30),
401	TEGRA210_AMX_BYTE_MAP_CTRL(31),
402	TEGRA210_AMX_BYTE_MAP_CTRL(32),
403	TEGRA210_AMX_BYTE_MAP_CTRL(33),
404	TEGRA210_AMX_BYTE_MAP_CTRL(34),
405	TEGRA210_AMX_BYTE_MAP_CTRL(35),
406	TEGRA210_AMX_BYTE_MAP_CTRL(36),
407	TEGRA210_AMX_BYTE_MAP_CTRL(37),
408	TEGRA210_AMX_BYTE_MAP_CTRL(38),
409	TEGRA210_AMX_BYTE_MAP_CTRL(39),
410	TEGRA210_AMX_BYTE_MAP_CTRL(40),
411	TEGRA210_AMX_BYTE_MAP_CTRL(41),
412	TEGRA210_AMX_BYTE_MAP_CTRL(42),
413	TEGRA210_AMX_BYTE_MAP_CTRL(43),
414	TEGRA210_AMX_BYTE_MAP_CTRL(44),
415	TEGRA210_AMX_BYTE_MAP_CTRL(45),
416	TEGRA210_AMX_BYTE_MAP_CTRL(46),
417	TEGRA210_AMX_BYTE_MAP_CTRL(47),
418	TEGRA210_AMX_BYTE_MAP_CTRL(48),
419	TEGRA210_AMX_BYTE_MAP_CTRL(49),
420	TEGRA210_AMX_BYTE_MAP_CTRL(50),
421	TEGRA210_AMX_BYTE_MAP_CTRL(51),
422	TEGRA210_AMX_BYTE_MAP_CTRL(52),
423	TEGRA210_AMX_BYTE_MAP_CTRL(53),
424	TEGRA210_AMX_BYTE_MAP_CTRL(54),
425	TEGRA210_AMX_BYTE_MAP_CTRL(55),
426	TEGRA210_AMX_BYTE_MAP_CTRL(56),
427	TEGRA210_AMX_BYTE_MAP_CTRL(57),
428	TEGRA210_AMX_BYTE_MAP_CTRL(58),
429	TEGRA210_AMX_BYTE_MAP_CTRL(59),
430	TEGRA210_AMX_BYTE_MAP_CTRL(60),
431	TEGRA210_AMX_BYTE_MAP_CTRL(61),
432	TEGRA210_AMX_BYTE_MAP_CTRL(62),
433	TEGRA210_AMX_BYTE_MAP_CTRL(63),
434};
435
436static struct snd_kcontrol_new tegra264_amx_controls[] = {
437	TEGRA210_AMX_BYTE_MAP_CTRL(64),
438	TEGRA210_AMX_BYTE_MAP_CTRL(65),
439	TEGRA210_AMX_BYTE_MAP_CTRL(66),
440	TEGRA210_AMX_BYTE_MAP_CTRL(67),
441	TEGRA210_AMX_BYTE_MAP_CTRL(68),
442	TEGRA210_AMX_BYTE_MAP_CTRL(69),
443	TEGRA210_AMX_BYTE_MAP_CTRL(70),
444	TEGRA210_AMX_BYTE_MAP_CTRL(71),
445	TEGRA210_AMX_BYTE_MAP_CTRL(72),
446	TEGRA210_AMX_BYTE_MAP_CTRL(73),
447	TEGRA210_AMX_BYTE_MAP_CTRL(74),
448	TEGRA210_AMX_BYTE_MAP_CTRL(75),
449	TEGRA210_AMX_BYTE_MAP_CTRL(76),
450	TEGRA210_AMX_BYTE_MAP_CTRL(77),
451	TEGRA210_AMX_BYTE_MAP_CTRL(78),
452	TEGRA210_AMX_BYTE_MAP_CTRL(79),
453	TEGRA210_AMX_BYTE_MAP_CTRL(80),
454	TEGRA210_AMX_BYTE_MAP_CTRL(81),
455	TEGRA210_AMX_BYTE_MAP_CTRL(82),
456	TEGRA210_AMX_BYTE_MAP_CTRL(83),
457	TEGRA210_AMX_BYTE_MAP_CTRL(84),
458	TEGRA210_AMX_BYTE_MAP_CTRL(85),
459	TEGRA210_AMX_BYTE_MAP_CTRL(86),
460	TEGRA210_AMX_BYTE_MAP_CTRL(87),
461	TEGRA210_AMX_BYTE_MAP_CTRL(88),
462	TEGRA210_AMX_BYTE_MAP_CTRL(89),
463	TEGRA210_AMX_BYTE_MAP_CTRL(90),
464	TEGRA210_AMX_BYTE_MAP_CTRL(91),
465	TEGRA210_AMX_BYTE_MAP_CTRL(92),
466	TEGRA210_AMX_BYTE_MAP_CTRL(93),
467	TEGRA210_AMX_BYTE_MAP_CTRL(94),
468	TEGRA210_AMX_BYTE_MAP_CTRL(95),
469	TEGRA210_AMX_BYTE_MAP_CTRL(96),
470	TEGRA210_AMX_BYTE_MAP_CTRL(97),
471	TEGRA210_AMX_BYTE_MAP_CTRL(98),
472	TEGRA210_AMX_BYTE_MAP_CTRL(99),
473	TEGRA210_AMX_BYTE_MAP_CTRL(100),
474	TEGRA210_AMX_BYTE_MAP_CTRL(101),
475	TEGRA210_AMX_BYTE_MAP_CTRL(102),
476	TEGRA210_AMX_BYTE_MAP_CTRL(103),
477	TEGRA210_AMX_BYTE_MAP_CTRL(104),
478	TEGRA210_AMX_BYTE_MAP_CTRL(105),
479	TEGRA210_AMX_BYTE_MAP_CTRL(106),
480	TEGRA210_AMX_BYTE_MAP_CTRL(107),
481	TEGRA210_AMX_BYTE_MAP_CTRL(108),
482	TEGRA210_AMX_BYTE_MAP_CTRL(109),
483	TEGRA210_AMX_BYTE_MAP_CTRL(110),
484	TEGRA210_AMX_BYTE_MAP_CTRL(111),
485	TEGRA210_AMX_BYTE_MAP_CTRL(112),
486	TEGRA210_AMX_BYTE_MAP_CTRL(113),
487	TEGRA210_AMX_BYTE_MAP_CTRL(114),
488	TEGRA210_AMX_BYTE_MAP_CTRL(115),
489	TEGRA210_AMX_BYTE_MAP_CTRL(116),
490	TEGRA210_AMX_BYTE_MAP_CTRL(117),
491	TEGRA210_AMX_BYTE_MAP_CTRL(118),
492	TEGRA210_AMX_BYTE_MAP_CTRL(119),
493	TEGRA210_AMX_BYTE_MAP_CTRL(120),
494	TEGRA210_AMX_BYTE_MAP_CTRL(121),
495	TEGRA210_AMX_BYTE_MAP_CTRL(122),
496	TEGRA210_AMX_BYTE_MAP_CTRL(123),
497	TEGRA210_AMX_BYTE_MAP_CTRL(124),
498	TEGRA210_AMX_BYTE_MAP_CTRL(125),
499	TEGRA210_AMX_BYTE_MAP_CTRL(126),
500	TEGRA210_AMX_BYTE_MAP_CTRL(127),
501};
502
503static int tegra210_amx_component_probe(struct snd_soc_component *component)
504{
505	struct tegra210_amx *amx = snd_soc_component_get_drvdata(component);
506	int err = 0;
507
508	if (amx->soc_data->num_controls) {
509		err = snd_soc_add_component_controls(component, amx->soc_data->controls,
510						     amx->soc_data->num_controls);
511		if (err)
512			dev_err(component->dev, "can't add AMX controls, err: %d\n", err);
513	}
514
515	return err;
516}
517
518static const struct snd_soc_component_driver tegra210_amx_cmpnt = {
519	.probe			= tegra210_amx_component_probe,
520	.dapm_widgets		= tegra210_amx_widgets,
521	.num_dapm_widgets	= ARRAY_SIZE(tegra210_amx_widgets),
522	.dapm_routes		= tegra210_amx_routes,
523	.num_dapm_routes	= ARRAY_SIZE(tegra210_amx_routes),
524	.controls		= tegra210_amx_controls,
525	.num_controls		= ARRAY_SIZE(tegra210_amx_controls),
526};
527
528static bool tegra210_amx_wr_reg(struct device *dev, unsigned int reg)
529{
530	switch (reg) {
531	case TEGRA210_AMX_RX_INT_MASK ... TEGRA210_AMX_RX4_CIF_CTRL:
532	case TEGRA210_AMX_TX_INT_MASK ... TEGRA210_AMX_CG:
533	case TEGRA210_AMX_CTRL ... TEGRA210_AMX_CYA:
534	case TEGRA210_AMX_CFG_RAM_CTRL ... TEGRA210_AMX_CFG_RAM_DATA:
535		return true;
536	default:
537		return false;
538	}
539}
540
541static bool tegra194_amx_wr_reg(struct device *dev, unsigned int reg)
542{
543	switch (reg) {
544	case TEGRA194_AMX_RX1_FRAME_PERIOD ... TEGRA194_AMX_RX4_FRAME_PERIOD:
545		return true;
546	default:
547		return tegra210_amx_wr_reg(dev, reg);
548	}
549}
550
551static bool tegra264_amx_wr_reg(struct device *dev,
552				unsigned int reg)
553{
554	switch (reg) {
555	case TEGRA210_AMX_RX_INT_MASK ... TEGRA210_AMX_RX4_CIF_CTRL:
556	case TEGRA210_AMX_TX_INT_MASK ... TEGRA210_AMX_TX_CIF_CTRL:
557	case TEGRA210_AMX_ENABLE ... TEGRA210_AMX_CG:
558	case TEGRA210_AMX_CTRL ... TEGRA264_AMX_STREAMS_AUTO_DISABLE:
559	case TEGRA264_AMX_CFG_RAM_CTRL ... TEGRA264_AMX_CFG_RAM_DATA:
560	case TEGRA264_AMX_RX1_FRAME_PERIOD ... TEGRA264_AMX_RX4_FRAME_PERIOD:
561		return true;
562	default:
563		return false;
564	}
565}
566
567static bool tegra210_amx_rd_reg(struct device *dev, unsigned int reg)
568{
569	switch (reg) {
570	case TEGRA210_AMX_RX_STATUS ... TEGRA210_AMX_CFG_RAM_DATA:
571		return true;
572	default:
573		return false;
574	}
575}
576
577static bool tegra194_amx_rd_reg(struct device *dev, unsigned int reg)
578{
579	switch (reg) {
580	case TEGRA194_AMX_RX1_FRAME_PERIOD ... TEGRA194_AMX_RX4_FRAME_PERIOD:
581		return true;
582	default:
583		return tegra210_amx_rd_reg(dev, reg);
584	}
585}
586
587static bool tegra264_amx_rd_reg(struct device *dev,
588				unsigned int reg)
589{
590	switch (reg) {
591	case TEGRA210_AMX_RX_STATUS ... TEGRA210_AMX_RX4_CIF_CTRL:
592	case TEGRA210_AMX_TX_STATUS ... TEGRA210_AMX_TX_CIF_CTRL:
593	case TEGRA210_AMX_ENABLE ... TEGRA210_AMX_INT_STATUS:
594	case TEGRA210_AMX_CTRL ... TEGRA264_AMX_CFG_RAM_DATA:
595	case TEGRA264_AMX_RX1_FRAME_PERIOD ... TEGRA264_AMX_RX4_FRAME_PERIOD:
596		return true;
597	default:
598		return false;
599	}
600}
601
602static bool tegra210_amx_volatile_reg(struct device *dev, unsigned int reg)
603{
604	switch (reg) {
605	case TEGRA210_AMX_RX_STATUS:
606	case TEGRA210_AMX_RX_INT_STATUS:
607	case TEGRA210_AMX_RX_INT_SET:
608	case TEGRA210_AMX_TX_STATUS:
609	case TEGRA210_AMX_TX_INT_STATUS:
610	case TEGRA210_AMX_TX_INT_SET:
611	case TEGRA210_AMX_SOFT_RESET:
612	case TEGRA210_AMX_STATUS:
613	case TEGRA210_AMX_INT_STATUS:
614	case TEGRA210_AMX_CFG_RAM_CTRL:
615	case TEGRA210_AMX_CFG_RAM_DATA:
616		return true;
617	default:
618		break;
619	}
620
621	return false;
622}
623
624static bool tegra264_amx_volatile_reg(struct device *dev,
625				      unsigned int reg)
626{
627	switch (reg) {
628	case TEGRA210_AMX_RX_STATUS:
629	case TEGRA210_AMX_RX_INT_STATUS:
630	case TEGRA210_AMX_RX_INT_SET:
631	case TEGRA210_AMX_TX_STATUS:
632	case TEGRA210_AMX_TX_INT_STATUS:
633	case TEGRA210_AMX_TX_INT_SET:
634	case TEGRA210_AMX_SOFT_RESET:
635	case TEGRA210_AMX_STATUS:
636	case TEGRA210_AMX_INT_STATUS:
637	case TEGRA264_AMX_CFG_RAM_CTRL:
638	case TEGRA264_AMX_CFG_RAM_DATA:
639		return true;
640	default:
641		break;
642	}
643
644	return false;
645}
646
647static const struct regmap_config tegra210_amx_regmap_config = {
648	.reg_bits		= 32,
649	.reg_stride		= 4,
650	.val_bits		= 32,
651	.max_register		= TEGRA210_AMX_CFG_RAM_DATA,
652	.writeable_reg		= tegra210_amx_wr_reg,
653	.readable_reg		= tegra210_amx_rd_reg,
654	.volatile_reg		= tegra210_amx_volatile_reg,
655	.reg_defaults		= tegra210_amx_reg_defaults,
656	.num_reg_defaults	= ARRAY_SIZE(tegra210_amx_reg_defaults),
657	.cache_type		= REGCACHE_FLAT,
658};
659
660static const struct regmap_config tegra194_amx_regmap_config = {
661	.reg_bits		= 32,
662	.reg_stride		= 4,
663	.val_bits		= 32,
664	.max_register		= TEGRA194_AMX_RX4_LAST_FRAME_PERIOD,
665	.writeable_reg		= tegra194_amx_wr_reg,
666	.readable_reg		= tegra194_amx_rd_reg,
667	.volatile_reg		= tegra210_amx_volatile_reg,
668	.reg_defaults		= tegra210_amx_reg_defaults,
669	.num_reg_defaults	= ARRAY_SIZE(tegra210_amx_reg_defaults),
670	.cache_type		= REGCACHE_FLAT,
671};
672
673static const struct regmap_config tegra264_amx_regmap_config = {
674	.reg_bits		= 32,
675	.reg_stride		= 4,
676	.val_bits		= 32,
677	.max_register		= TEGRA264_AMX_RX4_LAST_FRAME_PERIOD,
678	.writeable_reg		= tegra264_amx_wr_reg,
679	.readable_reg		= tegra264_amx_rd_reg,
680	.volatile_reg		= tegra264_amx_volatile_reg,
681	.reg_defaults		= tegra264_amx_reg_defaults,
682	.num_reg_defaults	= ARRAY_SIZE(tegra264_amx_reg_defaults),
683	.cache_type		= REGCACHE_FLAT,
684};
685
686static const struct tegra210_amx_soc_data soc_data_tegra210 = {
687	.regmap_conf	= &tegra210_amx_regmap_config,
688	.max_ch		= TEGRA210_AMX_MAX_CHANNEL,
689	.ram_depth	= TEGRA210_AMX_RAM_DEPTH,
690	.byte_mask_size = TEGRA210_AMX_BYTE_MASK_COUNT,
691	.reg_offset	= TEGRA210_AMX_AUTO_DISABLE_OFFSET,
692};
693
694static const struct tegra210_amx_soc_data soc_data_tegra194 = {
695	.regmap_conf	= &tegra194_amx_regmap_config,
696	.auto_disable	= true,
697	.max_ch		= TEGRA210_AMX_MAX_CHANNEL,
698	.ram_depth	= TEGRA210_AMX_RAM_DEPTH,
699	.byte_mask_size	= TEGRA210_AMX_BYTE_MASK_COUNT,
700	.reg_offset	= TEGRA210_AMX_AUTO_DISABLE_OFFSET,
701};
702
703static const struct tegra210_amx_soc_data soc_data_tegra264 = {
704	.regmap_conf	= &tegra264_amx_regmap_config,
705	.auto_disable	= true,
706	.max_ch		= TEGRA264_AMX_MAX_CHANNEL,
707	.ram_depth	= TEGRA264_AMX_RAM_DEPTH,
708	.byte_mask_size = TEGRA264_AMX_BYTE_MASK_COUNT,
709	.reg_offset	= TEGRA264_AMX_AUTO_DISABLE_OFFSET,
710	.controls	= tegra264_amx_controls,
711	.num_controls	= ARRAY_SIZE(tegra264_amx_controls),
712};
713
714static const struct of_device_id tegra210_amx_of_match[] = {
715	{ .compatible = "nvidia,tegra210-amx", .data = &soc_data_tegra210 },
716	{ .compatible = "nvidia,tegra194-amx", .data = &soc_data_tegra194 },
717	{ .compatible = "nvidia,tegra264-amx", .data = &soc_data_tegra264 },
718	{},
719};
720MODULE_DEVICE_TABLE(of, tegra210_amx_of_match);
721
722static int tegra210_amx_platform_probe(struct platform_device *pdev)
723{
724	struct device *dev = &pdev->dev;
725	struct tegra210_amx *amx;
726	void __iomem *regs;
727	int err;
728
729	amx = devm_kzalloc(dev, sizeof(*amx), GFP_KERNEL);
730	if (!amx)
731		return -ENOMEM;
732
733	amx->soc_data = device_get_match_data(dev);
734
735	dev_set_drvdata(dev, amx);
736
737	regs = devm_platform_ioremap_resource(pdev, 0);
738	if (IS_ERR(regs))
739		return PTR_ERR(regs);
740
741	amx->regmap = devm_regmap_init_mmio(dev, regs,
742					    amx->soc_data->regmap_conf);
743	if (IS_ERR(amx->regmap)) {
744		dev_err(dev, "regmap init failed\n");
745		return PTR_ERR(amx->regmap);
746	}
747
748	regcache_cache_only(amx->regmap, true);
749
750	amx->map = devm_kzalloc(dev, amx->soc_data->ram_depth * sizeof(*amx->map),
751				GFP_KERNEL);
752	if (!amx->map)
753		return -ENOMEM;
754
755	amx->byte_mask = devm_kzalloc(dev,
756				      amx->soc_data->byte_mask_size * sizeof(*amx->byte_mask),
757				      GFP_KERNEL);
758	if (!amx->byte_mask)
759		return -ENOMEM;
760
761	tegra210_amx_dais[TEGRA_AMX_OUT_DAI_ID].capture.channels_max =
762			amx->soc_data->max_ch;
763
764	err = devm_snd_soc_register_component(dev, &tegra210_amx_cmpnt,
765					      tegra210_amx_dais,
766					      ARRAY_SIZE(tegra210_amx_dais));
767	if (err) {
768		dev_err(dev, "can't register AMX component, err: %d\n", err);
769		return err;
770	}
771
772	pm_runtime_enable(dev);
773
774	return 0;
775}
776
777static void tegra210_amx_platform_remove(struct platform_device *pdev)
778{
779	pm_runtime_disable(&pdev->dev);
780}
781
782static const struct dev_pm_ops tegra210_amx_pm_ops = {
783	RUNTIME_PM_OPS(tegra210_amx_runtime_suspend,
784		       tegra210_amx_runtime_resume, NULL)
785	SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
786};
787
788static struct platform_driver tegra210_amx_driver = {
789	.driver = {
790		.name = "tegra210-amx",
791		.of_match_table = tegra210_amx_of_match,
792		.pm = pm_ptr(&tegra210_amx_pm_ops),
793	},
794	.probe = tegra210_amx_platform_probe,
795	.remove = tegra210_amx_platform_remove,
796};
797module_platform_driver(tegra210_amx_driver);
798
799MODULE_AUTHOR("Songhee Baek <sbaek@nvidia.com>");
800MODULE_DESCRIPTION("Tegra210 AMX ASoC driver");
801MODULE_LICENSE("GPL v2");
~/ Read-only file preview.