nvidia: oot: add tegra-safety-audio build support

Copied sound/tegra-safety-audio source files to nvidia-oot folder

Bug 3735757

Change-Id: I8a18ee25a6c33a00e6b28a2e09b6576197a35652
Signed-off-by: pmedawala <pmedawala@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/2783432
Reviewed-by: Bitan Biswas <bbiswas@nvidia.com>
Reviewed-by: Uday Gupta <udayg@nvidia.com>
Reviewed-by: Laxman Dewangan <ldewangan@nvidia.com>
Tested-by: Uday Gupta <udayg@nvidia.com>
GVS: Gerrit_Virtual_Submit <buildbot_gerritrpt@nvidia.com>
This commit is contained in:
pmedawala
2022-09-28 06:58:55 +00:00
committed by mobile promotions
parent 19292f7cb8
commit 2852d2419f
6 changed files with 1582 additions and 0 deletions

View File

@@ -3,3 +3,6 @@
obj-m += drivers/
obj-m += sound/soc/tegra/
ifeq ($(shell test $$VERSION -lt 6; echo $$?),0)
obj-m += sound/tegra-safety-audio/
endif

View File

@@ -0,0 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
# Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
safety-i2s-objs := i2s.o sound-card.o
obj-m += safety-i2s.o

View File

@@ -0,0 +1,476 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2021-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
*/
#include <linux/kernel.h>
#include <linux/io.h>
#include <linux/delay.h>
#include "tegra_i2s_regs.h"
#include "tegra_i2s.h"
#include <asm-generic/delay.h>
static inline struct i2s_dev *i2s_inst(unsigned int id)
{
static struct i2s_dev *i2s;
if (!i2s)
i2s = safety_i2s_get_priv();
WARN_ON(id >= NUM_SAFETY_I2S_INST);
return &i2s[id];
}
#define I2S_BASE(id) ((i2s_inst(id))->base)
#ifdef SAFETY_I2S_DEBUG
void i2s_dump_all_regs(unsigned int id)
{
int i;
pr_alert("RX Registers:\n");
for (i = 0; i <= 0x2c; i += 4)
pr_alert("0x%08x = 0x%08x\n", 0x02450000 + id * 0x10000 + i,
readl(I2S_BASE(id) + i));
pr_alert("TX Registers:\n");
for (i = 0x80; i <= 0xb0; i += 4)
pr_alert("0x%08x = 0x%08x\n", 0x02450000 + id * 0x10000 + i,
readl(I2S_BASE(id) + i));
pr_alert("Common Registers:\n");
for (i = 0x100; i <= 0x120; i += 4)
pr_alert("0x%08x = 0x%08x\n", 0x02450000 + id * 0x10000 + i,
readl(I2S_BASE(id) + i));
}
#endif
static unsigned int is_i2s_enabled(unsigned int id)
{
unsigned int val;
val = readl(I2S_BASE(id) + T234_I2S_ENABLE);
return (val & T234_I2S_EN_MASK);
}
unsigned int i2s_enable(unsigned int id)
{
unsigned int val;
val = readl(I2S_BASE(id) + T234_I2S_ENABLE);
val |= T234_I2S_EN;
writel(val, I2S_BASE(id) + T234_I2S_ENABLE);
return 0;
}
unsigned int i2s_disable(unsigned int id)
{
unsigned int val;
val = readl(I2S_BASE(id) + T234_I2S_ENABLE);
val &= ~T234_I2S_EN;
writel(val, I2S_BASE(id) + T234_I2S_ENABLE);
return 0;
}
static unsigned int is_i2s_tx_enabled(unsigned int id)
{
unsigned int val;
val = readl(I2S_BASE(id) + T234_I2S_TX_ENABLE);
return (val & T234_I2S_EN_MASK);
}
unsigned int i2s_enable_tx(unsigned int id)
{
unsigned int val;
val = readl(I2S_BASE(id) + T234_I2S_TX_ENABLE);
val |= T234_I2S_TX_EN;
writel(val, I2S_BASE(id) + T234_I2S_TX_ENABLE);
return 0;
}
static unsigned int is_i2s_rx_enabled(unsigned int id)
{
unsigned int val;
val = readl(I2S_BASE(id) + T234_I2S_RX_ENABLE);
return (val & T234_I2S_EN_MASK);
}
unsigned int i2s_enable_rx(unsigned int id)
{
unsigned int val;
val = readl(I2S_BASE(id) + T234_I2S_RX_ENABLE);
val |= T234_I2S_RX_EN;
writel(val, I2S_BASE(id) + T234_I2S_RX_ENABLE);
return 0;
}
static unsigned int is_i2s_loopback_enabled(unsigned int id)
{
unsigned int val;
val = readl(I2S_BASE(id) + T234_I2S_CTRL);
return !!(val & T234_I2S_CTRL_LPBK_MASK);
}
unsigned int i2s_set_loopback(unsigned int id, unsigned int loopback_enable)
{
unsigned int val;
unsigned int enable;
unsigned int rx_enable;
unsigned int tx_enable;
if (loopback_enable == is_i2s_loopback_enabled(id)) {
pr_info("I2S%d already has loopback in %s state\n",
(id + 1), loopback_enable ? "enabled" : "disabled");
return 0;
}
/* I2S needs to be disabled before enabling Loopback */
enable = is_i2s_enabled(id);
if (enable) {
tx_enable = is_i2s_tx_enabled(id);
if (tx_enable)
i2s_disable_tx(id);
rx_enable = is_i2s_rx_enabled(id);
if (rx_enable)
i2s_disable_rx(id);
i2s_disable(id);
}
val = readl(I2S_BASE(id) + T234_I2S_CTRL);
val = loopback_enable ? (val | T234_I2S_CTRL_LPBK_EN) :
(val & ~T234_I2S_CTRL_LPBK_MASK);
writel(val, I2S_BASE(id) + T234_I2S_CTRL);
if (enable) {
i2s_enable(id);
if (rx_enable)
i2s_enable_rx(id);
if (tx_enable)
i2s_enable_tx(id);
}
pr_info("I2S%d loopback set to %s state\n",
(id + 1), loopback_enable ? "enabled" : "disabled");
return 0;
}
static int i2s_sw_reset(unsigned int id, int direction, int timeout)
{
unsigned int sw_reset_reg, sw_reset_mask;
unsigned int sw_reset_en, sw_reset_default;
unsigned int tx_fifo_ctrl, rx_fifo_ctrl, tx_ctrl, rx_ctrl, ctrl, val;
int wait = timeout;
tx_fifo_ctrl = readl(I2S_BASE(id) + T234_I2S_TX_FIFO_CTRL);
rx_fifo_ctrl = readl(I2S_BASE(id) + T234_I2S_RX_FIFO_CTRL);
tx_ctrl = readl(I2S_BASE(id) + T234_I2S_TX_CTRL);
rx_ctrl = readl(I2S_BASE(id) + T234_I2S_RX_CTRL);
ctrl = readl(I2S_BASE(id) + T234_I2S_CTRL);
if (direction == PCM_STREAM_CAPTURE) {
sw_reset_reg = T234_I2S_RX_SOFT_RESET;
sw_reset_mask = T234_I2S_RX_SOFT_RESET_MASK;
sw_reset_en = T234_I2S_RX_SOFT_RESET_EN;
sw_reset_default = T234_I2S_RX_SOFT_RESET_DEFAULT;
} else {
sw_reset_reg = T234_I2S_TX_SOFT_RESET;
sw_reset_mask = T234_I2S_TX_SOFT_RESET_MASK;
sw_reset_en = T234_I2S_TX_SOFT_RESET_EN;
sw_reset_default = T234_I2S_TX_SOFT_RESET_DEFAULT;
}
updatel(I2S_BASE(id) + sw_reset_reg, sw_reset_mask, sw_reset_en);
do {
val = readl(I2S_BASE(id) + sw_reset_reg);
wait--;
udelay(10);
if (!wait) {
pr_err("RESET bit not cleared yet\n");
return -1;
}
} while (val & sw_reset_mask);
updatel(I2S_BASE(id) + sw_reset_reg, sw_reset_mask, sw_reset_default);
writel(tx_fifo_ctrl, I2S_BASE(id) + T234_I2S_TX_FIFO_CTRL);
writel(rx_fifo_ctrl, I2S_BASE(id) + T234_I2S_RX_FIFO_CTRL);
writel(tx_ctrl, I2S_BASE(id) + T234_I2S_TX_CTRL);
writel(rx_ctrl, I2S_BASE(id) + T234_I2S_RX_CTRL);
writel(ctrl, I2S_BASE(id) + T234_I2S_CTRL);
return 0;
}
static int i2s_get_status(unsigned int id, int direction)
{
unsigned int status_reg;
status_reg = (direction == PCM_STREAM_CAPTURE) ?
T234_I2S_RX_STATUS :
T234_I2S_TX_STATUS;
return readl(I2S_BASE(id) + status_reg);
}
/* Should be called after disabling RX */
static int i2s_rx_stop(unsigned int id)
{
int dcnt = 10, ret;
int status;
/* wait until I2S RX ENABLE bit is cleared
* and FIFO becomes empty as the DMA is still on
*/
while (((status = i2s_get_status(id, PCM_STREAM_CAPTURE)) &
T234_I2S_RX_STATUS_ENABLED) && dcnt--)
udelay(10);
if (dcnt < 0 || !(status & T234_I2S_RX_STATUS_FIFO_EMPTY)) {
/* HW needs sw reset to make sure previous trans be clean */
ret = i2s_sw_reset(id, PCM_STREAM_CAPTURE, 0xffff);
if (ret) {
pr_err("Failed at I2S%d_RX sw reset\n", id + 7);
return ret;
}
}
return 0;
}
unsigned int i2s_disable_rx(unsigned int id)
{
unsigned int val;
val = readl(I2S_BASE(id) + T234_I2S_RX_ENABLE);
val &= ~T234_I2S_RX_EN;
writel(val, I2S_BASE(id) + T234_I2S_RX_ENABLE);
i2s_rx_stop(id);
return 0;
}
/* Should be called after disabling TX */
static int i2s_tx_stop(unsigned int id)
{
int dcnt = 10, ret;
int status;
/* wait until I2S TX ENABLE bit is cleared */
while ((status = i2s_get_status(id, PCM_STREAM_PLAYBACK) &
T234_I2S_TX_STATUS_ENABLED) && dcnt--)
udelay(10);
if (dcnt < 0 || !(status & T234_I2S_TX_STATUS_FIFO_EMPTY)) {
/* HW needs sw reset to make sure previous trans be clean */
ret = i2s_sw_reset(id, PCM_STREAM_PLAYBACK, 0xffff);
if (ret) {
pr_err("Failed at I2S%d_TX sw reset\n", id + 7);
return ret;
}
}
return 0;
}
unsigned int i2s_disable_tx(unsigned int id)
{
unsigned int val;
val = readl(I2S_BASE(id) + T234_I2S_TX_ENABLE);
val &= ~T234_I2S_TX_EN;
writel(val, I2S_BASE(id) + T234_I2S_TX_ENABLE);
i2s_tx_stop(id);
return 0;
}
int i2s_configure(unsigned int id, struct i2s_config *config)
{
unsigned int ctrl = 0, timing = 0, rxctrl = 0, txctrl = 0;
unsigned int slotctrl = 0, tx_slotctrl = 0, rx_slotctrl = 0;
unsigned int i2sclock, bitcnt;
unsigned int clock_trim = config->clock_trim;
unsigned int fifo_ctrl = 0, threshold = 0;
volatile void __iomem *i2s_base = I2S_BASE(id);
switch (config->mode) {
case I2S_FRAME_FORMAT_I2S:
if (config->clock_mode == I2S_MASTER)
ctrl |= T234_I2S_CTRL_MASTER_EN;
ctrl |= (config->fsync_width <<
T234_I2S_CTRL_FSYNC_WIDTH_SHIFT);
ctrl &= ~T234_I2S_CTRL_EDGE_CTRL_MASK;
if (config->edge_ctrl == I2S_CLK_NEG_EDGE)
ctrl |= T234_I2S_CTRL_EDGE_CTRL_NEG_EDGE;
/* LRCK_MODE */
ctrl &= ~T234_I2S_CTRL_FRAME_FORMAT_MASK;
ctrl &= ~T234_I2S_CTRL_LRCK_POLARITY_MASK;
if (config->clock_polarity == LRCK_HIGH)
ctrl |= T234_I2S_CTRL_LRCK_POLARITY_HIGH;
i2sclock = config->srate * config->bit_size * config->channels;
if (config->bclk_ratio != 0)
i2sclock *= config->bclk_ratio;
bitcnt = (i2sclock / config->srate) - 1;
if (i2sclock % (2 * config->srate))
timing |= T234_I2S_TIMING_NON_SYM_EN;
timing |= ((bitcnt >> 1) <<
T234_I2S_TIMING_CHANNEL_BIT_CNT_SHIFT);
ctrl |= (((config->bit_size >> 2) - 1) <<
T234_I2S_CTRL_BIT_SIZE_SHIFT);
rxctrl |= (config->offset <<
T234_I2S_RX_CTRL_DATA_OFFSET_SHIFT) &
T234_I2S_RX_CTRL_DATA_OFFSET_MASK;
txctrl |= (config->offset <<
T234_I2S_TX_CTRL_DATA_OFFSET_SHIFT) &
T234_I2S_TX_CTRL_DATA_OFFSET_MASK;
if (config->pcm_mask_bits) {
rxctrl |= ((config->pcm_mask_bits) <<
T234_I2S_RX_CTRL_MASK_BITS_SHIFT);
txctrl |= ((config->pcm_mask_bits) <<
T234_I2S_TX_CTRL_MASK_BITS_SHIFT);
}
txctrl &= ~T234_I2S_TX_CTRL_HIGHZ_CTRL_MASK;
if (config->highz_ctrl == 1)
txctrl |= T234_I2S_TX_CTRL_HIGHZ_CTRL_HIGHZ;
else if (config->highz_ctrl == 2)
txctrl |=
T234_I2S_TX_CTRL_HIGHZ_CTRL_HIGHZ_ON_HALF_BIT_CLK;
writel(timing, i2s_base + T234_I2S_TIMING);
break;
case I2S_FRAME_FORMAT_TDM:
if (config->clock_mode == I2S_MASTER)
ctrl |= T234_I2S_CTRL_MASTER_EN;
ctrl |= (config->fsync_width <<
T234_I2S_CTRL_FSYNC_WIDTH_SHIFT);
ctrl &= ~T234_I2S_CTRL_EDGE_CTRL_MASK;
if (config->edge_ctrl == I2S_CLK_NEG_EDGE)
ctrl |= T234_I2S_CTRL_EDGE_CTRL_NEG_EDGE;
ctrl &= ~T234_I2S_CTRL_FRAME_FORMAT_MASK;
ctrl |= T234_I2S_CTRL_FRAME_FORMAT_FSYNC_MODE;
ctrl &= ~T234_I2S_CTRL_LRCK_POLARITY_MASK;
if (config->clock_polarity == LRCK_HIGH)
ctrl |= T234_I2S_CTRL_LRCK_POLARITY_HIGH;
ctrl |= (((config->bit_size >> 2) - 1) <<
T234_I2S_CTRL_BIT_SIZE_SHIFT);
i2sclock = config->srate * config->bit_size * config->channels;
if (config->bclk_ratio != 0)
i2sclock *= config->bclk_ratio;
bitcnt = (i2sclock / config->srate) - 1;
if (i2sclock % (2 * config->srate))
timing |= T234_I2S_TIMING_NON_SYM_EN;
timing |= (bitcnt << T234_I2S_TIMING_CHANNEL_BIT_CNT_SHIFT);
rxctrl |= (config->offset <<
T234_I2S_RX_CTRL_DATA_OFFSET_SHIFT) &
T234_I2S_RX_CTRL_DATA_OFFSET_MASK;
txctrl |= (config->offset <<
T234_I2S_TX_CTRL_DATA_OFFSET_SHIFT) &
T234_I2S_TX_CTRL_DATA_OFFSET_MASK;
if (config->pcm_mask_bits) {
rxctrl |= ((config->pcm_mask_bits) <<
T234_I2S_RX_CTRL_MASK_BITS_SHIFT);
txctrl |= ((config->pcm_mask_bits) <<
T234_I2S_TX_CTRL_MASK_BITS_SHIFT);
}
txctrl &= ~T234_I2S_TX_CTRL_HIGHZ_CTRL_MASK;
if (config->highz_ctrl == 1)
txctrl |= T234_I2S_TX_CTRL_HIGHZ_CTRL_HIGHZ;
else if (config->highz_ctrl == 2)
txctrl |=
T234_I2S_TX_CTRL_HIGHZ_CTRL_HIGHZ_ON_HALF_BIT_CLK;
slotctrl |= ((config->total_slots - 1) <<
T234_I2S_SLOT_CTRL_TOTAL_SLOTS_SHIFT);
tx_slotctrl |= (config->tx_mask <<
T234_I2S_TX_SLOT_CTRL_SLOT_ENABLES_SHIFT);
rx_slotctrl |= (config->rx_mask <<
T234_I2S_RX_SLOT_CTRL_SLOT_ENABLES_SHIFT);
writel(timing, i2s_base + T234_I2S_TIMING);
break;
default:
return -1;
}
if (clock_trim > T234_I2S_SCLK_TRIM_SEL_MASK) {
pr_alert("Clock trim invalid\n");
return -1;
}
clock_trim = ((clock_trim & T234_I2S_SCLK_TRIM_SEL_MASK) <<
T234_I2S_SCLK_TRIM_SEL_SHIFT);
//TODO: Add proper register offset macros and masks etc.
fifo_ctrl = (((config->channels - 1) << 4) & (0xf << 4)) |
(((config->channels) << 16) & (0x7f << 16)) |
(1 << 24);
threshold = 0;
/* Overwrite the timing register only in the master mode.
* Setting it to 0x0 causes noise during slave mode playback.
* Setting the I2S control registers
*/
writel(ctrl, i2s_base + T234_I2S_CTRL);
writel(rxctrl, i2s_base + T234_I2S_RX_CTRL);
writel(txctrl, i2s_base + T234_I2S_TX_CTRL);
writel(slotctrl, i2s_base + T234_I2S_SLOT_CTRL);
writel(tx_slotctrl, i2s_base + T234_I2S_TX_SLOT_CTRL);
writel(rx_slotctrl, i2s_base + T234_I2S_RX_SLOT_CTRL);
writel(clock_trim, i2s_base + T234_I2S_CLK_TRIM);
writel(fifo_ctrl, i2s_base + T234_I2S_RX_FIFO_CTRL);
writel(fifo_ctrl, i2s_base + T234_I2S_TX_FIFO_CTRL);
writel(threshold, i2s_base + T234_I2S_TX_START_THRESHOLD);
return 0;
}

View File

@@ -0,0 +1,731 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2021-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
*/
#define pr_fmt(msg) "Safety I2S: " msg
#include <linux/module.h>
#include <sound/core.h>
#include <sound/dmaengine_pcm.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/clk.h>
#include <linux/reset.h>
#include "tegra_i2s.h"
struct safety_audio_priv {
struct snd_card *card;
};
static int safety_i2s_trigger(struct snd_pcm_substream *substream, int cmd);
static const char * const clk_names[] = {
"pll_a_out0",
"i2s7", "i2s7_clk_parent", "i2s7_ext_audio_sync",
"i2s7_audio_sync", "i2s7_sync_input",
"i2s8", "i2s8_clk_parent", "i2s8_ext_audio_sync",
"i2s8_audio_sync", "i2s8_sync_input",
};
static const char * const reset_names[] = {
"i2s7_reset", "i2s8_reset"
};
//TODO: Either encapsulate it or allocate dynamically
static struct i2s_dev i2s[NUM_SAFETY_I2S_INST];
static unsigned int enabled_i2s_mask[NUM_SAFETY_I2S_INST];
static struct safety_audio_priv *priv;
static const struct snd_pcm_hardware t234_pcm_hardware = {
.rates = SNDRV_PCM_RATE_48000,
.rate_min = 48000,
.rate_max = 48000,
.channels_min = 1,
.channels_max = 16,
.info = SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_PAUSE |
SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_INTERLEAVED,
.formats = SNDRV_PCM_FMTBIT_S8 |
SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.period_bytes_min = PAGE_SIZE * 16,
.period_bytes_max = PAGE_SIZE * 32,
.periods_min = 1,
.periods_max = 4,
.fifo_size = 256,
.buffer_bytes_max = PAGE_SIZE * 128,
};
static const struct i2s_config i2s_defaults = {
.srate = 48000,
.channels = 8,
.fsync_width = 255,
.bclk_ratio = 1,
.pcm_mask_bits = 0,
.highz_ctrl = 0,
.bit_size = 32,
.total_slots = 8
};
struct i2s_dev *safety_i2s_get_priv(void)
{
return i2s;
}
static int loopback_control_put(struct snd_kcontrol *kctl,
struct snd_ctl_elem_value *uc)
{
int id = (int)kctl->private_value;
int enable = uc->value.integer.value[0];
return i2s_set_loopback(id, enable);
}
static int loopback_control_get(struct snd_kcontrol *kctl,
struct snd_ctl_elem_value *uc)
{
return 0;
}
static int snd_myctl_mono_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
uinfo->count = 1;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = 1;
return 0;
}
static const struct snd_kcontrol_new controls[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "I2S7 Loopback",
.index = 0,
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
.put = loopback_control_put,
.get = loopback_control_get,
.info = snd_myctl_mono_info,
.private_value = 0
},
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "I2S8 Loopback",
.index = 0,
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
.put = loopback_control_put,
.get = loopback_control_get,
.info = snd_myctl_mono_info,
.private_value = 1
}
};
static int safety_i2s_add_kcontrols(struct snd_card *card, int id)
{
return snd_ctl_add(card, snd_ctl_new1(&controls[id], i2s));
}
static int prealloc_dma_buff(struct snd_pcm *pcm, unsigned int stream, size_t size)
{
struct snd_pcm_substream *substream = pcm->streams[stream].substream;
struct snd_dma_buffer *buff = &substream->dma_buffer;
buff->area = dma_alloc_coherent(pcm->card->dev, size,
&buff->addr, GFP_KERNEL);
if (!buff->area)
return -ENOMEM;
buff->private_data = NULL;
buff->dev.type = SNDRV_DMA_TYPE_DEV;
buff->dev.dev = pcm->card->dev;
buff->bytes = size;
return 0;
}
static int setup_plls(struct device *dev)
{
/* Do nothing for now */
return 0;
}
static int i2s_reset_init_and_deassert(struct device *dev, unsigned int id)
{
struct reset_control *reset;
int ret;
reset = of_reset_control_get(dev->of_node, reset_names[id]);
if (IS_ERR(reset)) {
pr_alert("No reset information found in DT, skipping...");
return PTR_ERR(reset);
}
i2s[id].reset = reset;
pr_alert("Clearing reset for i2s%d... ", id + 7);
ret = reset_control_deassert(reset);
if (ret)
pr_alert("Failed!\n");
else
pr_alert("Success!\n");
return ret;
}
static int i2s_clock_init(struct device *dev, unsigned int id)
{
i2s[id].audio_sync_input = devm_clk_get(dev,
clk_names[id * CLK_NUM_ENTRIES + CLK_AUDIO_INPUT_SYNC]);
if (IS_ERR(i2s[id].audio_sync_input)) {
pr_alert("Could not get audio_sync_input clock from DT\n");
return -EINVAL;
}
i2s[id].audio_sync = devm_clk_get(dev,
clk_names[id * CLK_NUM_ENTRIES + CLK_AUDIO_SYNC]);
if (IS_ERR(i2s[id].audio_sync)) {
pr_alert("Could not get audio_sync clock from DT\n");
return -EINVAL;
}
i2s[id].i2s_sync = devm_clk_get(dev,
clk_names[id * CLK_NUM_ENTRIES + CLK_I2S_SYNC]);
if (IS_ERR(i2s[id].i2s_sync)) {
pr_alert("Could not get i2s_sync clock from DT\n");
return -EINVAL;
}
i2s[id].clk_i2s = devm_clk_get(dev,
clk_names[id * CLK_NUM_ENTRIES + CLK_I2S]);
if (IS_ERR(i2s[id].clk_i2s)) {
pr_alert("Could not get clk_i2s clock from DT\n");
return -EINVAL;
}
i2s[id].clk_i2s_src = devm_clk_get(dev,
clk_names[id * CLK_NUM_ENTRIES + CLK_I2S_SOURCE]);
if (IS_ERR(i2s[id].clk_i2s_src)) {
pr_alert("Could not get clk_i2s_src clock from DT\n");
return -EINVAL;
}
return 0;
}
static int32_t
i2s_get_mode(const void *mode, uint32_t *tx_mode, uint32_t *data_offset)
{
uint32_t i;
struct {
char *name;
uint32_t mode;
uint32_t data_offset;
} i2s_mode[] = {
{"dsp_a", 1, 1},
{"dsp_b", 1, 0},
{"i2s", 0, 1},
};
for (i = 0; i < ARRAY_SIZE(i2s_mode); i++) {
if (strcmp(mode, i2s_mode[i].name) == 0) {
*tx_mode = i2s_mode[i].mode;
*data_offset = i2s_mode[i].data_offset;
return 0;
}
}
return -1;
}
#ifdef SAFETY_I2S_DEBUG
static void dump_config(struct i2s_config *config)
{
#define dump(x) pr_alert("%s = %u\n", #x, x)
dump(config->mode);
dump(config->clock_mode);
dump(config->clock_polarity);
dump(config->edge_ctrl);
dump(config->total_slots);
dump(config->bclk);
dump(config->bit_size);
dump(config->channels);
dump(config->offset);
dump(config->tx_mask);
dump(config->rx_mask);
dump(config->srate);
dump(config->bclk_ratio);
dump(config->fsync_width);
dump(config->pcm_mask_bits);
dump(config->highz_ctrl);
dump(config->clock_trim);
}
#endif
static int i2s_parse_dt(struct device *dev, unsigned int id)
{
char name[5];
struct device_node *i2s_node;
struct i2s_config *i2s_config;
const void *prop;
int ret = 0;
ret = sprintf(name, I2S_DT_NODE, I2S_NODE_START_INDEX + id);
if (ret < 0)
return -EINVAL;
i2s_config = &i2s[id].config;
memcpy(i2s_config, &i2s_defaults, sizeof(i2s_config[0]));
i2s_config->clock_polarity = 1;
i2s_node = of_get_child_by_name(dev->of_node, name);
if (i2s_node == NULL) {
pr_alert("Invalid device tree node\n");
return -EINVAL;
}
if (of_find_property(i2s_node, "frame-slave", NULL))
i2s_config->clock_mode = 1;
prop = of_get_property(i2s_node, "format", NULL);
if (prop != NULL) {
i2s_get_mode(prop, &i2s_config->mode, &i2s_config->offset);
if (strcmp("i2s", prop) == 0)
i2s_config->clock_polarity = 0;
}
if (of_find_property(i2s_node, "bitclock-inversion", NULL))
i2s_config->edge_ctrl = 1;
if (of_find_property(i2s_node, "frame-inversion", NULL))
i2s_config->clock_polarity = !i2s_config->clock_polarity;
prop = of_get_property(i2s_node, "tx-mask", NULL);
if (prop != NULL)
i2s_config->tx_mask = be32_to_cpup(prop);
prop = of_get_property(i2s_node, "rx-mask", NULL);
if (prop != NULL)
i2s_config->rx_mask = be32_to_cpup(prop);
prop = of_get_property(i2s_node, "clk-trim", NULL);
if (prop != NULL)
i2s_config->clock_trim = be32_to_cpup(prop);
prop = of_get_property(i2s_node, "fsync-width", NULL);
if (prop != NULL)
i2s_config->fsync_width = be32_to_cpup(prop);
prop = of_get_property(i2s_node, "srate", NULL);
if (prop != NULL)
i2s_config->srate = be32_to_cpup(prop);
prop = of_get_property(i2s_node, "num-channel", NULL);
if (prop != NULL)
i2s_config->channels = be32_to_cpup(prop);
prop = of_get_property(i2s_node, "bit-format", NULL);
if (prop != NULL)
i2s_config->bit_size = be32_to_cpup(prop);
#ifdef SAFETY_I2S_DEBUG
dump_config(i2s_config);
#endif
return 0;
}
static int is_supported_rate(int rate)
{
return 1;
}
static int i2s_set_rate(unsigned int id, int rate)
{
unsigned long i2s_clk_freq;
int err;
if (!is_supported_rate(rate))
return -EINVAL;
i2s_clk_freq = i2s[id].config.channels * i2s[id].config.srate *
i2s[id].config.bit_size * i2s[id].config.bclk_ratio;
if (i2s[id].config.clock_mode == I2S_MASTER) {
err = clk_set_parent(i2s[id].audio_sync, i2s[id].i2s_sync);
if (err != 0)
return -EINVAL;
err = clk_set_parent(i2s[id].clk_i2s, i2s[id].clk_i2s_src);
if (err != 0)
return -EINVAL;
err = clk_set_rate(i2s[id].clk_i2s, i2s_clk_freq);
if (err != 0)
return -EINVAL;
err = clk_prepare_enable(i2s[id].clk_i2s);
if (err != 0)
return -EINVAL;
}
err = clk_set_rate(i2s[id].audio_sync_input, i2s_clk_freq);
if (err != 0)
return -EINVAL;
return 0;
}
static void i2s_setup(unsigned int id)
{
i2s_set_rate(id, i2s[id].config.srate);
i2s_configure(id, &i2s[id].config);
}
static void safety_i2s_start(struct snd_pcm_substream *substream)
{
struct dma_data *data = substream->private_data;
unsigned int id = data->req_sel - 1;
int rx = (substream->stream == SNDRV_PCM_STREAM_CAPTURE) ? 1 : 0;
if (rx)
i2s_enable_rx(id);
else
i2s_enable_tx(id);
i2s_enable(id);
data->triggered = 1;
}
static void safety_i2s_stop(struct snd_pcm_substream *substream)
{
struct dma_data *data = substream->private_data;
unsigned int id = data->req_sel - 1;
int rx = (substream->stream == SNDRV_PCM_STREAM_CAPTURE) ? 1 : 0;
if (rx)
i2s_disable_rx(id);
else
i2s_disable_tx(id);
data->triggered = 0;
}
static int gpcdma_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct dma_slave_config slave_config;
struct dma_data *dma_data = substream->private_data;
struct dma_chan *chan;
int ret;
chan = snd_dmaengine_pcm_get_chan(substream);
ret = snd_hwparams_to_dma_slave_config(substream, params,
&slave_config);
if (ret) {
pr_alert("gpcdma hw params failed, err = %d\n", ret);
return ret;
}
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
slave_config.dst_addr_width = (dma_data->width == 16) ?
DMA_SLAVE_BUSWIDTH_2_BYTES :
DMA_SLAVE_BUSWIDTH_4_BYTES;
slave_config.dst_addr = dma_data->addr;
/* MC burst should be multiple of this for proper
* stopping of GPCDMA during CYCLIC transfer.
* Currently, GPCDMA configures the MC burst
* to 2 words unless MMIO supports 64 so we just match it.
*/
slave_config.dst_maxburst = 2;
} else {
slave_config.src_addr_width = (dma_data->width == 16) ?
DMA_SLAVE_BUSWIDTH_2_BYTES :
DMA_SLAVE_BUSWIDTH_4_BYTES;
slave_config.src_addr = dma_data->addr;
slave_config.src_maxburst = 2;
}
slave_config.slave_id = dma_data->req_sel;
ret = dmaengine_slave_config(chan, &slave_config);
if (ret < 0) {
pr_alert("dma slave config failed, err = %d\n", ret);
return ret;
}
snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
return 0;
}
static int i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
return 0;
}
static int safety_i2s_probe(struct device *dev, unsigned int id)
{
i2s_parse_dt(dev, id);
setup_plls(dev);
i2s_reset_init_and_deassert(dev, id);
i2s_clock_init(dev, id);
i2s_setup(id);
return 0;
}
static int safety_i2s_open(struct snd_pcm_substream *substream)
{
struct i2s_dev *i2s = snd_pcm_substream_chip(substream);
struct dma_data *dma_data =
(substream->stream == SNDRV_PCM_STREAM_CAPTURE) ?
&i2s->capture_data : &i2s->playback_data;
struct snd_pcm_runtime *runtime = substream->runtime;
struct dma_chan *chan;
int ret;
/* overwrite pcm->private_data and
* maintain only substram specific data
*/
substream->private_data = dma_data;
runtime->hw.info = t234_pcm_hardware.info;
runtime->hw.rates = t234_pcm_hardware.rates;
runtime->hw.rate_min = t234_pcm_hardware.rate_min;
runtime->hw.rate_max = t234_pcm_hardware.rate_max;
runtime->hw.formats = t234_pcm_hardware.formats;
runtime->hw.period_bytes_min = t234_pcm_hardware.period_bytes_min;
runtime->hw.period_bytes_max = t234_pcm_hardware.period_bytes_max;
runtime->hw.periods_min = t234_pcm_hardware.periods_min;
runtime->hw.periods_max = t234_pcm_hardware.periods_max;
runtime->hw.channels_min = t234_pcm_hardware.channels_min;
runtime->hw.channels_max = t234_pcm_hardware.channels_max;
runtime->hw.buffer_bytes_max = t234_pcm_hardware.buffer_bytes_max;
runtime->hw.fifo_size = t234_pcm_hardware.fifo_size;
//TODO: Support buffer size update from device tree
ret = snd_pcm_hw_constraint_step(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 0x8);
if (ret) {
pr_alert("Failed to set constraint %d\n", ret);
return ret;
}
chan = dma_request_slave_channel(substream->pcm->card->dev,
dma_data->dma_chan_name);
if (!chan) {
pr_alert("failed to allocate dma channel\n");
return -ENODEV;
}
ret = snd_dmaengine_pcm_open(substream, chan);
if (ret) {
pr_alert("failed to open dmaengine\n");
return ret;
}
return 0;
}
static int safety_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
int ret;
/* configure hardware according to the following params
* channels, bits per sample, samples per second, period size
* and num periods
*/
ret = gpcdma_hw_params(substream, params);
if (!ret)
ret = i2s_hw_params(substream, params);
return ret;
}
static int safety_i2s_prepare(struct snd_pcm_substream *substream)
{
return 0;
}
static int safety_i2s_close(struct snd_pcm_substream *substream)
{
struct dma_data *data = substream->private_data;
if (data->triggered) {
safety_i2s_trigger(substream, SNDRV_PCM_TRIGGER_STOP);
data->triggered = 0;
}
snd_dmaengine_pcm_close_release_chan(substream);
return 0;
}
static int safety_i2s_trigger(struct snd_pcm_substream *substream, int cmd)
{
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
snd_dmaengine_pcm_trigger(substream, cmd);
safety_i2s_start(substream);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
case SNDRV_PCM_TRIGGER_SUSPEND:
safety_i2s_stop(substream);
snd_dmaengine_pcm_trigger(substream, cmd);
break;
default:
return -EINVAL;
}
return 0;
}
static struct snd_pcm_ops playback_ops = {
.open = safety_i2s_open,
.close = safety_i2s_close,
.hw_params = safety_i2s_hw_params,
.prepare = safety_i2s_prepare,
.pointer = snd_dmaengine_pcm_pointer,
.trigger = safety_i2s_trigger
};
static const struct of_device_id match_table[] = {
{ .compatible = "nvidia,tegra234-safety-audio" },
{}
};
static unsigned int parse_enabled_i2s_mask(struct device *dev)
{
unsigned int num_enabled = 0;
int i;
i = of_property_read_variable_u32_array(dev->of_node,
"enabled-i2s-mask", enabled_i2s_mask,
NUM_SAFETY_I2S_INST, 0);
WARN_ON(i != NUM_SAFETY_I2S_INST);
for (i = 0; i < NUM_SAFETY_I2S_INST; i++)
num_enabled += !!(enabled_i2s_mask[i]);
return num_enabled;
}
static int t234_safety_audio_probe(struct platform_device *pdev)
{
struct snd_card *card;
int ret, pcm_instance = 0;
unsigned int i = 0;
struct snd_pcm *pcm;
char name[5] = {0};
if (parse_enabled_i2s_mask(&pdev->dev) == 0) {
pr_err("No safety-i2s interfaces are available on this board\n");
return -ENODEV;
}
ret = snd_card_new(&pdev->dev, -1, "Safety I2S sound card",
THIS_MODULE, sizeof(*priv), &card);
if (ret < 0)
return ret;
priv = card->private_data;
priv->card = card;
for (i = 0; i < NUM_SAFETY_I2S_INST; i++) {
struct resource *r;
size_t buffer_size = t234_pcm_hardware.buffer_bytes_max;
void __iomem *base;
if (!enabled_i2s_mask[i])
continue;
if ((sprintf(name, I2S_DT_NODE, I2S_NODE_START_INDEX + i)) < 0)
return -EINVAL;
ret = snd_pcm_new(card, name, pcm_instance++, 1, 1, &pcm);
if (ret < 0) {
pr_alert("Could not register i2s pcm, ret: %d\n", ret);
return ret;
}
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &playback_ops);
base = devm_platform_get_and_ioremap_resource(pdev, i, &r);
if (IS_ERR(base)) {
pr_alert("could not remap base\n");
return -EINVAL;
}
i2s[i].base = base;
safety_i2s_probe(&pdev->dev, i);
i2s[i].capture_data.addr = r->start + 0x20;
//TODO: Read from DT later on
i2s[i].capture_data.size = buffer_size;
i2s[i].capture_data.width = i2s[i].config.bit_size;
i2s[i].capture_data.req_sel = i + 1;
i2s[i].capture_data.dma_chan_name =
(i ? "i2s8-rx" : "i2s7-rx");
i2s[i].playback_data.addr = r->start + 0xa0;
//TODO: Read from DT later on
i2s[i].playback_data.size = buffer_size;
i2s[i].playback_data.width = i2s[i].config.bit_size;
i2s[i].playback_data.req_sel = i + 1;
i2s[i].playback_data.dma_chan_name =
(i ? "i2s8-tx" : "i2s7-tx");
pcm->private_data = &i2s[i];
//TODO: check the return value
prealloc_dma_buff(pcm, SNDRV_PCM_STREAM_PLAYBACK, buffer_size);
prealloc_dma_buff(pcm, SNDRV_PCM_STREAM_CAPTURE, buffer_size);
safety_i2s_add_kcontrols(card, i);
}
ret = snd_card_register(card);
if (ret < 0)
pr_alert("Error registering I2S card, ret = %d\n", ret);
else
pr_alert("Sound card registered successfully\n");
return ret;
}
static int t234_safety_audio_remove(struct platform_device *pdev)
{
snd_card_free(priv->card);
return 0;
}
static struct platform_driver t234_safety_audio_driver = {
.probe = t234_safety_audio_probe,
.remove = t234_safety_audio_remove,
.driver = {
.name = "tegra234-safety-audio",
.owner = THIS_MODULE,
.of_match_table = match_table,
},
};
MODULE_DEVICE_TABLE(of, match_table);
MODULE_LICENSE("GPL");
module_platform_driver(t234_safety_audio_driver);

View File

@@ -0,0 +1,129 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2021-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
*/
#ifndef _TEGRA_I2S_H_
#define _TEGRA_I2S_H_
#define PCM_STREAM_PLAYBACK 0
#define PCM_STREAM_CAPTURE 1
#define NUM_SAFETY_I2S_INST 2
#define I2S_DT_NODE "i2s%u"
#define I2S_NODE_START_INDEX 7
enum clock_mode {
I2S_SLAVE = 0,
I2S_MASTER
};
enum edge_ctrl {
I2S_CLK_POS_EDGE = 0,
I2S_CLK_NEG_EDGE
};
enum clock_polarity {
LRCK_LOW = 0,
LRCK_HIGH
};
enum i2s_mode {
I2S_FRAME_FORMAT_I2S = 0,
I2S_FRAME_FORMAT_TDM
};
enum i2s_clocks {
CLK_PLLA_OUT0,
CLK_I2S,
CLK_I2S_SOURCE,
CLK_I2S_SYNC,
CLK_AUDIO_SYNC,
CLK_AUDIO_INPUT_SYNC,
CLK_NUM_ENTRIES = CLK_AUDIO_INPUT_SYNC
};
struct i2s_config {
unsigned int mode;
unsigned int clock_mode;
unsigned int clock_polarity;
unsigned int edge_ctrl;
unsigned int total_slots;
unsigned int bclk;
unsigned int bit_size;
unsigned int channels;
unsigned int offset;
unsigned int tx_mask;
unsigned int rx_mask;
unsigned int srate;
unsigned int bclk_ratio;
unsigned int fsync_width;
unsigned int pcm_mask_bits;
unsigned int highz_ctrl;
unsigned int clock_trim;
};
struct dma_data {
const char *dma_chan_name;
unsigned long addr;
unsigned int size;
unsigned int width;
unsigned int req_sel;
unsigned int triggered;
};
struct i2s_dev {
volatile void __iomem *base;
struct dma_data capture_data;
struct dma_data playback_data;
struct clk *clk_i2s;
struct clk *clk_i2s_src;
struct clk *audio_sync;
struct clk *i2s_sync;
struct clk *audio_sync_input;
struct reset_control *reset;
struct i2s_config config;
};
struct i2s_dev *safety_i2s_get_priv(void);
#ifdef SAFETY_I2S_DEBUG
void i2s_dump_all_regs(unsigned int id);
#endif
int i2s_configure(unsigned int id, struct i2s_config *config);
/* Enable I2S controller */
unsigned int i2s_enable(unsigned int id);
/* Disable I2S controller */
unsigned int i2s_disable(unsigned int id);
/* Enable the Tx engine on I2S controller IO */
unsigned int i2s_enable_tx(unsigned int id);
/* Disable the Tx engine on I2S controller IO */
unsigned int i2s_disable_tx(unsigned int id);
/* Enable the Rx engine on I2S controller IO */
unsigned int i2s_enable_rx(unsigned int id);
/* Disable the Rx engine on I2S controller IO */
unsigned int i2s_disable_rx(unsigned int id);
static inline void
updatel(volatile void __iomem *addr, unsigned int mask, unsigned int val)
{
unsigned int prev_val, new_val;
prev_val = readl(addr);
new_val = (prev_val & (~mask)) | (val & mask);
writel(new_val, addr);
}
/* Enable/Disable digital loopback with I2S controller */
unsigned int i2s_set_loopback(unsigned int id, unsigned int enable);
#endif /* _TEGRA_I2S_H_ */

View File

@@ -0,0 +1,238 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
*/
#ifndef __TEGRA_I2S_REGS_H_
#define __TEGRA_I2S_REGS_H_
#define T234_I2S_RX_ENABLE 0x000
#define T234_I2S_RX_SOFT_RESET 0x004
#define T234_I2S_RX_STATUS 0x008
#define T234_I2S_RX_INT_STATUS 0x00c
#define T234_I2S_RX_INT_SET 0x010
#define T234_I2S_RX_INT_MASK 0x014
#define T234_I2S_RX_INT_CLEAR 0x018
#define T234_I2S_RX_FIFO_CTRL 0x01c
#define T234_I2S_RX_FIFO_RD_DATA 0x020
#define T234_I2S_RX_CTRL 0x024
#define T234_I2S_RX_SLOT_CTRL 0x028
#define T234_I2S_RX_CLK_TRIM 0x02c
#define T234_I2S_TX_ENABLE 0x080
#define T234_I2S_TX_SOFT_RESET 0x084
#define T234_I2S_TX_STATUS 0x088
#define T234_I2S_TX_INT_STATUS 0x08c
#define T234_I2S_TX_INT_SET 0x090
#define T234_I2S_TX_INT_MASK 0x094
#define T234_I2S_TX_INT_CLEAR 0x098
#define T234_I2S_TX_FIFO_CTRL 0x09c
#define T234_I2S_TX_FIFO_WR_DATA 0x0a0
#define T234_I2S_TX_START_THRESHOLD 0x0a4
#define T234_I2S_TX_CTRL 0x0a8
#define T234_I2S_TX_SLOT_CTRL 0x0ac
#define T234_I2S_TX_CLK_TRIM 0x0b0
#define T234_I2S_ENABLE 0x100
#define T234_I2S_SOFT_RESET 0x104
#define T234_I2S_CG 0x108
#define T234_I2S_STATUS 0x10c
#define T234_I2S_INT_STATUS 0x110
#define T234_I2S_CTRL 0x114
#define T234_I2S_TIMING 0x118
#define T234_I2S_SLOT_CTRL 0x11c
#define T234_I2S_CLK_TRIM 0x120
/* Fields in T234_I2S_RX_ENABLE */
#define T234_I2S_RX_EN_SHIFT 0
#define T234_I2S_RX_EN (1 << T234_I2S_RX_EN_SHIFT)
/* Fields in T234_I2S_RX_CTRL */
#define T234_I2S_RX_CTRL_DATA_OFFSET_SHIFT 8
#define T234_I2S_RX_CTRL_DATA_OFFSET_MASK \
(0x7ff << T234_I2S_RX_CTRL_DATA_OFFSET_SHIFT)
#define T234_I2S_RX_CTRL_MASK_BITS_SHIFT 4
#define T234_I2S_RX_CTRL_BIT_ORDER_SHIFT 0
#define T234_I2S_RX_CTRL_BIT_ORDER_MASK \
(1 << T234_I2S_RX_CTRL_BIT_ORDER_SHIFT)
#define T234_I2S_RX_CTRL_BIT_ORDER_MSB_FIRST \
(0 << T234_I2S_RX_CTRL_BIT_ORDER_SHIFT)
#define T234_I2S_RX_CTRL_BIT_ORDER_LSB_FIRST \
(1 << T234_I2S_RX_CTRL_BIT_ORDER_SHIFT)
/* Fields in T234_I2S_TX_ENABLE */
#define T234_I2S_TX_EN_SHIFT 0
#define T234_I2S_TX_EN (1 << T234_I2S_TX_EN_SHIFT)
/* Fields in T234_I2S_TX_CTRL */
#define T234_I2S_TX_CTRL_DATA_OFFSET_SHIFT 8
#define T234_I2S_TX_CTRL_DATA_OFFSET_MASK \
(0x7ff << T234_I2S_TX_CTRL_DATA_OFFSET_SHIFT)
#define T234_I2S_TX_CTRL_MASK_BITS_SHIFT 4
#define T234_I2S_TX_CTRL_HIGHZ_CTRL_SHIFT 1
#define T234_I2S_TX_CTRL_HIGHZ_CTRL_MASK \
(3 << T234_I2S_TX_CTRL_HIGHZ_CTRL_SHIFT)
#define T234_I2S_TX_CTRL_HIGHZ_CTRL_NOHIGHZ \
(0 << T234_I2S_TX_CTRL_HIGHZ_CTRL_SHIFT)
#define T234_I2S_TX_CTRL_HIGHZ_CTRL_HIGHZ \
(1 << T234_I2S_TX_CTRL_HIGHZ_CTRL_SHIFT)
#define T234_I2S_TX_CTRL_HIGHZ_CTRL_HIGHZ_ON_HALF_BIT_CLK \
(2 << T234_I2S_TX_CTRL_HIGHZ_CTRL_SHIFT)
#define T234_I2S_TX_CTRL_BIT_ORDER_SHIFT 0
#define T234_I2S_TX_CTRL_BIT_ORDER_MASK \
(1 << T234_I2S_TX_CTRL_BIT_ORDER_SHIFT)
#define T234_I2S_TX_CTRL_BIT_ORDER_MSB_FIRST \
(0 << T234_I2S_TX_CTRL_BIT_ORDER_SHIFT)
#define T234_I2S_TX_CTRL_BIT_ORDER_LSB_FIRST \
(1 << T234_I2S_TX_CTRL_BIT_ORDER_SHIFT)
/* Fields in T234_I2S_ENABLE */
#define T234_I2S_EN_SHIFT 0
#define T234_I2S_EN_MASK (1 << T234_I2S_EN_SHIFT)
#define T234_I2S_EN (1 << T234_I2S_EN_SHIFT)
/* Fields in T234_I2S_CTRL */
#define T234_I2S_CTRL_FSYNC_WIDTH_SHIFT 16
#define T234_I2S_CTRL_FSYNC_WIDTH_MASK \
(0xff << T234_I2S_CTRL_FSYNC_WIDTH_SHIFT)
#define T234_I2S_POS_EDGE 0
#define T234_I2S_NEG_EDGE 1
#define T234_I2S_CTRL_EDGE_CTRL_SHIFT 10
#define T234_I2S_CTRL_EDGE_CTRL_MASK \
(1 << T234_I2S_CTRL_EDGE_CTRL_SHIFT)
#define T234_I2S_CTRL_EDGE_CTRL_POS_EDGE \
(T234_I2S_POS_EDGE << T234_I2S_CTRL_EDGE_CTRL_SHIFT)
#define T234_I2S_CTRL_EDGE_CTRL_NEG_EDGE \
(T234_I2S_NEG_EDGE << T234_I2S_CTRL_EDGE_CTRL_SHIFT)
#define T234_I2S_CTRL_PIPE_MACRO_EN_SHIFT 9
#define T234_I2S_CTRL_PIPE_MACRO_EN \
(1 << T234_I2S_CTRL_PIPE_MACRO_EN_SHIFT)
#define T234_I2S_FRAME_FORMAT_LRCK 0
#define T234_I2S_FRAME_FORMAT_FSYNC 1
#define T234_I2S_CTRL_FRAME_FORMAT_SHIFT 6
#define T234_I2S_CTRL_FRAME_FORMAT_MASK \
(7 << T234_I2S_CTRL_FRAME_FORMAT_SHIFT)
#define T234_I2S_CTRL_FRAME_FORMAT_LRCK_MODE \
(T234_I2S_FRAME_FORMAT_LRCK << T234_I2S_CTRL_FRAME_FORMAT_SHIFT)
#define T234_I2S_CTRL_FRAME_FORMAT_FSYNC_MODE \
(T234_I2S_FRAME_FORMAT_FSYNC << T234_I2S_CTRL_FRAME_FORMAT_SHIFT)
#define T234_I2S_CTRL_MASTER_EN_SHIFT 5
#define T234_I2S_CTRL_MASTER_EN_MASK \
(1 << T234_I2S_CTRL_MASTER_EN_SHIFT)
#define T234_I2S_CTRL_MASTER_EN \
(1 << T234_I2S_CTRL_MASTER_EN_SHIFT)
#define T234_I2S_CTRL_SLAVE_EN \
(1 << T234_I2S_CTRL_MASTER_EN_SHIFT)
#define T234_I2S_CTRL_LRCK_POLARITY_SHIFT 4
#define T234_I2S_CTRL_LRCK_POLARITY_MASK \
(1 << T234_I2S_CTRL_LRCK_POLARITY_SHIFT)
#define T234_I2S_CTRL_LRCK_POLARITY_LOW \
(0 << T234_I2S_CTRL_LRCK_POLARITY_SHIFT)
#define T234_I2S_CTRL_LRCK_POLARITY_HIGH \
(1 << T234_I2S_CTRL_LRCK_POLARITY_SHIFT)
#define T234_I2S_CTRL_LPBK_SHIFT 3
#define T234_I2S_CTRL_LPBK_MASK (1 << T234_I2S_CTRL_LPBK_SHIFT)
#define T234_I2S_CTRL_LPBK_EN (1 << T234_I2S_CTRL_LPBK_SHIFT)
#define T234_I2S_BITS_8 1
#define T234_I2S_BITS_12 2
#define T234_I2S_BITS_16 3
#define T234_I2S_BITS_20 4
#define T234_I2S_BITS_24 5
#define T234_I2S_BITS_28 6
#define T234_I2S_BITS_32 7
#define T234_I2S_CTRL_BIT_SIZE_SHIFT 0
#define T234_I2S_CTRL_BIT_SIZE_MASK \
(7 << T234_I2S_CTRL_BIT_SIZE_SHIFT)
#define T234_I2S_CTRL_BIT_SIZE_8 \
(T234_I2S_BITS_8 << T234_I2S_CTRL_BIT_SIZE_SHIFT)
#define T234_I2S_CTRL_BIT_SIZE_12 \
(T234_I2S_BITS_12 << T234_I2S_CTRL_BIT_SIZE_SHIFT)
#define T234_I2S_CTRL_BIT_SIZE_16 \
(T234_I2S_BITS_16 << T234_I2S_CTRL_BIT_SIZE_SHIFT)
#define T234_I2S_CTRL_BIT_SIZE_20 \
(T234_I2S_BITS_20 << T234_I2S_CTRL_BIT_SIZE_SHIFT)
#define T234_I2S_CTRL_BIT_SIZE_24 \
(T234_I2S_BITS_24 << T234_I2S_CTRL_BIT_SIZE_SHIFT)
#define T234_I2S_CTRL_BIT_SIZE_28 \
(T234_I2S_BITS_28 << T234_I2S_CTRL_BIT_SIZE_SHIFT)
#define T234_I2S_CTRL_BIT_SIZE_32 \
(T234_I2S_BITS_32 << T234_I2S_CTRL_BIT_SIZE_SHIFT)
/* Fields in T234_I2S_TIMING */
#define T234_I2S_TIMING_NON_SYM_EN_SHIFT 12
#define T234_I2S_TIMING_NON_SYM_EN \
(1 << T234_I2S_TIMING_NON_SYM_EN_SHIFT)
#define T234_I2S_TIMING_CHANNEL_BIT_CNT_MASK 0x3ff
#define T234_I2S_TIMING_CHANNEL_BIT_CNT_SHIFT 0
/* Fields in T234_I2S_RX_SOFT_RESET */
#define T234_I2S_RX_SOFT_RESET_SHIFT 0
#define T234_I2S_RX_SOFT_RESET_MASK \
(1 << T234_I2S_RX_SOFT_RESET_SHIFT)
#define T234_I2S_RX_SOFT_RESET_EN \
(1 << T234_I2S_RX_SOFT_RESET_SHIFT)
#define T234_I2S_RX_SOFT_RESET_DEFAULT \
(0 << T234_I2S_RX_SOFT_RESET_SHIFT)
#define T234_I2S_SCLK_TRIM_SEL_SHIFT 8
#define T234_I2S_SCLK_TRIM_SEL_MASK 0x1F
/* Fields in T234_I2S_RX_STATUS */
#define T234_I2S_RX_STATUS_ENABLED_SHIFT 0
#define T234_I2S_RX_STATUS_ENABLED \
(1 << T234_I2S_RX_STATUS_ENABLED_SHIFT)
#define T234_I2S_RX_STATUS_FIFO_EMPTY_SHIFT 1
#define T234_I2S_RX_STATUS_FIFO_EMPTY \
(1 << T234_I2S_RX_STATUS_FIFO_EMPTY_SHIFT)
#define T234_I2S_RX_STATUS_FIFO_FULL_SHIFT 2
#define T234_I2S_RX_STATUS_FIFO_FULL \
(1 << T234_I2S_RX_STATUS_FIFO_FULL_SHIFT)
#define T234_I2S_RX_STATUS_FIFO_COUNT_SHIFT 8
#define T234_I2S_RX_STATUS_FIFO_COUNT_MASK \
(0x7f << T234_I2S_RX_STATUS_FIFO_COUNT_SHIFT)
/* Fields in T234_I2S_TX_STATUS */
#define T234_I2S_TX_STATUS_ENABLED_SHIFT 0
#define T234_I2S_TX_STATUS_ENABLED \
(1 << T234_I2S_TX_STATUS_ENABLED_SHIFT)
#define T234_I2S_TX_STATUS_FIFO_EMPTY_SHIFT 1
#define T234_I2S_TX_STATUS_FIFO_EMPTY \
(1 << T234_I2S_TX_STATUS_FIFO_EMPTY_SHIFT)
#define T234_I2S_TX_STATUS_FIFO_FULL_SHIFT 2
#define T234_I2S_TX_STATUS_FIFO_FULL \
(1 << T234_I2S_TX_STATUS_FIFO_FULL_SHIFT)
#define T234_I2S_TX_STATUS_FIFO_COUNT_SHIFT 8
#define T234_I2S_TX_STATUS_FIFO_COUNT_MASK \
(0x7f << T234_I2S_TX_STATUS_FIFO_COUNT_SHIFT)
/* Fields in T234_I2S_TX_SOFT_RESET */
#define T234_I2S_TX_SOFT_RESET_SHIFT 0
#define T234_I2S_TX_SOFT_RESET_MASK \
(1 << T234_I2S_TX_SOFT_RESET_SHIFT)
#define T234_I2S_TX_SOFT_RESET_EN \
(1 << T234_I2S_TX_SOFT_RESET_SHIFT)
#define T234_I2S_TX_SOFT_RESET_DEFAULT \
(0 << T234_I2S_TX_SOFT_RESET_SHIFT)
/* Fields in T234_I2S_SLOT_CTRL */
#define T234_I2S_SLOT_CTRL_TOTAL_SLOTS_SHIFT 0
#define T234_I2S_SLOT_CTRL_TOTAL_SLOTS_MASK 0xf
/* Fields in T234_I2S_TX_SLOT_CTRL */
#define T234_I2S_TX_SLOT_CTRL_SLOT_ENABLES_SHIFT 0
#define T234_I2S_TX_SLOT_CTRL_SLOT_ENABLES_MASK 0xffff
/* Fields in T234_I2S_RX_SLOT_CTRL */
#define T234_I2S_RX_SLOT_CTRL_SLOT_ENABLES_SHIFT 0
#define T234_I2S_RX_SLOT_CTRL_SLOT_ENABLES_MASK 0xffff
#endif /* _TEGRA_I2S_REGS_H_ */