sound/soc/tegra/tegra210_amx.c

Source file repositories/reference/linux-study-clean/sound/soc/tegra/tegra210_amx.c

File Facts

System
Linux kernel
Corpus path
sound/soc/tegra/tegra210_amx.c
Extension
.c
Size
23920 bytes
Lines
809
Domain
Driver Families
Bucket
sound/soc
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2021-2025 NVIDIA CORPORATION & AFFILIATES.
// All rights reserved.
//
// tegra210_amx.c - Tegra210 AMX driver

#include <linux/bits.h>
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/io.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>

#include "tegra210_amx.h"
#include "tegra_cif.h"

/*
 * The counter is in terms of AHUB clock cycles. If a frame is not
 * received within these clock cycles, the AMX input channel gets
 * automatically disabled. For now the counter is calculated as a
 * function of sample rate (8 kHz) and AHUB clock (49.152 MHz).
 * If later an accurate number is needed, the counter needs to be
 * calculated at runtime.
 *
 *     count = ahub_clk / sample_rate
 */
#define TEGRA194_MAX_FRAME_IDLE_COUNT	0x1800

#define AMX_CH_REG(id, reg) ((reg) + ((id) * TEGRA210_AMX_AUDIOCIF_CH_STRIDE))

static const struct reg_default tegra210_amx_reg_defaults[] = {
	{ TEGRA210_AMX_RX_INT_MASK, 0x0000000f},
	{ TEGRA210_AMX_RX1_CIF_CTRL, 0x00007000},
	{ TEGRA210_AMX_RX2_CIF_CTRL, 0x00007000},
	{ TEGRA210_AMX_RX3_CIF_CTRL, 0x00007000},
	{ TEGRA210_AMX_RX4_CIF_CTRL, 0x00007000},
	{ TEGRA210_AMX_TX_INT_MASK, 0x00000001},
	{ TEGRA210_AMX_TX_CIF_CTRL, 0x00007000},
	{ TEGRA210_AMX_CG, 0x1},
	{ TEGRA210_AMX_CFG_RAM_CTRL, 0x00004000},
};

static const struct reg_default tegra264_amx_reg_defaults[] = {
	{ TEGRA210_AMX_RX_INT_MASK, 0x0000000f},
	{ TEGRA210_AMX_RX1_CIF_CTRL, 0x00003800},
	{ TEGRA210_AMX_RX2_CIF_CTRL, 0x00003800},
	{ TEGRA210_AMX_RX3_CIF_CTRL, 0x00003800},
	{ TEGRA210_AMX_RX4_CIF_CTRL, 0x00003800},
	{ TEGRA210_AMX_TX_INT_MASK, 0x00000001},
	{ TEGRA210_AMX_TX_CIF_CTRL, 0x00003800},
	{ TEGRA210_AMX_CG, 0x1},
	{ TEGRA264_AMX_CFG_RAM_CTRL, 0x00004000},
};

static void tegra210_amx_write_map_ram(struct tegra210_amx *amx)
{
	const unsigned int bits_per_mask = BITS_PER_TYPE(*amx->byte_mask);
	int i;

	memset(amx->byte_mask, 0,
	       amx->soc_data->byte_mask_size * sizeof(*amx->byte_mask));

	regmap_write(amx->regmap, TEGRA210_AMX_CFG_RAM_CTRL + amx->soc_data->reg_offset,
		     TEGRA210_AMX_CFG_RAM_CTRL_SEQ_ACCESS_EN |
		     TEGRA210_AMX_CFG_RAM_CTRL_ADDR_INIT_EN |
		     TEGRA210_AMX_CFG_RAM_CTRL_RW_WRITE);

	for (i = 0; i < amx->soc_data->ram_depth; i++) {
		u32 word = 0;
		int b;

		for (b = 0; b < TEGRA_AMX_SLOTS_PER_WORD; b++) {
			unsigned int slot = i * TEGRA_AMX_SLOTS_PER_WORD + b;
			u16 val = amx->map[slot];

			if (val >= 256)
				continue;

			word |= (u32)val << (b * BITS_PER_BYTE);
			amx->byte_mask[slot / bits_per_mask] |=
				1U << (slot % bits_per_mask);
		}
		regmap_write(amx->regmap, TEGRA210_AMX_CFG_RAM_DATA + amx->soc_data->reg_offset,

Annotation

Implementation Notes