mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-22 09:11:26 +03:00
sound: safety-i2s: Add support for always-on rx/tx
Add support for keeping RX/TX always ON by using amixer commands and to not disable clocks after playback/capture usecases finish. This is to prevent A2B master from losing internal state. Bug 3742979 Change-Id: I01dacaa3f54c98a7a14be101d8f0a315b006d7d8 Signed-off-by: Niranjan Dighe <ndighe@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/2966000 Reviewed-by: Uday Gupta <udayg@nvidia.com> Reviewed-by: Laxman Dewangan <ldewangan@nvidia.com> GVS: Gerrit_Virtual_Submit <buildbot_gerritrpt@nvidia.com> Tested-by: Purvi Medawala <pmedawala@nvidia.com>
This commit is contained in:
committed by
mobile promotions
parent
36531e7e1d
commit
aaa19719df
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2021-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
* Copyright (c) 2021-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
@@ -90,6 +90,9 @@ unsigned int i2s_enable_tx(unsigned int id)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
if (is_i2s_tx_enabled(id))
|
||||
return 0;
|
||||
|
||||
val = readl(I2S_BASE(id) + T234_I2S_TX_ENABLE);
|
||||
val |= T234_I2S_TX_EN;
|
||||
writel(val, I2S_BASE(id) + T234_I2S_TX_ENABLE);
|
||||
@@ -110,6 +113,9 @@ unsigned int i2s_enable_rx(unsigned int id)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
if (is_i2s_rx_enabled(id))
|
||||
return 0;
|
||||
|
||||
val = readl(I2S_BASE(id) + T234_I2S_RX_ENABLE);
|
||||
val |= T234_I2S_RX_EN;
|
||||
writel(val, I2S_BASE(id) + T234_I2S_RX_ENABLE);
|
||||
@@ -150,8 +156,6 @@ unsigned int i2s_set_loopback(unsigned int id, unsigned int loopback_enable)
|
||||
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);
|
||||
@@ -160,8 +164,6 @@ unsigned int i2s_set_loopback(unsigned int id, unsigned int loopback_enable)
|
||||
writel(val, I2S_BASE(id) + T234_I2S_CTRL);
|
||||
|
||||
if (enable) {
|
||||
i2s_enable(id);
|
||||
|
||||
if (rx_enable)
|
||||
i2s_enable_rx(id);
|
||||
|
||||
@@ -262,6 +264,9 @@ unsigned int i2s_disable_rx(unsigned int id)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
if (i2s_inst(id)->config.rx_always_on)
|
||||
return 0;
|
||||
|
||||
val = readl(I2S_BASE(id) + T234_I2S_RX_ENABLE);
|
||||
val &= ~T234_I2S_RX_EN;
|
||||
writel(val, I2S_BASE(id) + T234_I2S_RX_ENABLE);
|
||||
@@ -297,6 +302,9 @@ unsigned int i2s_disable_tx(unsigned int id)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
if (i2s_inst(id)->config.tx_always_on)
|
||||
return 0;
|
||||
|
||||
val = readl(I2S_BASE(id) + T234_I2S_TX_ENABLE);
|
||||
val &= ~T234_I2S_TX_EN;
|
||||
writel(val, I2S_BASE(id) + T234_I2S_TX_ENABLE);
|
||||
@@ -472,5 +480,7 @@ int i2s_configure(unsigned int id, struct i2s_config *config)
|
||||
writel(fifo_ctrl, i2s_base + T234_I2S_TX_FIFO_CTRL);
|
||||
writel(threshold, i2s_base + T234_I2S_TX_START_THRESHOLD);
|
||||
|
||||
i2s_enable(id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2021-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
* Copyright (c) 2021-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
*/
|
||||
|
||||
#define pr_fmt(msg) "Safety I2S: " msg
|
||||
@@ -94,6 +94,41 @@ static int loopback_control_get(struct snd_kcontrol *kctl,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int alwayson_control_put(struct snd_kcontrol *kctl,
|
||||
struct snd_ctl_elem_value *uc)
|
||||
{
|
||||
int rx = (int)kctl->private_value & 1;
|
||||
int id = (int)kctl->private_value >> 1;
|
||||
int enable = uc->value.integer.value[0];
|
||||
struct i2s_config *i2s_config = &i2s[id].config;
|
||||
|
||||
if (rx)
|
||||
i2s_config->rx_always_on = enable;
|
||||
else
|
||||
i2s_config->tx_always_on = enable;
|
||||
|
||||
if (enable && rx)
|
||||
i2s_enable_rx(id);
|
||||
|
||||
if (enable && !rx)
|
||||
i2s_enable_tx(id);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static int alwayson_control_get(struct snd_kcontrol *kctl,
|
||||
struct snd_ctl_elem_value *uc)
|
||||
{
|
||||
int rx = (int)kctl->private_value & 1;
|
||||
int id = (int)kctl->private_value >> 1;
|
||||
struct i2s_config *i2s_config = &i2s[id].config;
|
||||
|
||||
if (rx)
|
||||
return i2s_config->rx_always_on;
|
||||
|
||||
return i2s_config->tx_always_on;
|
||||
}
|
||||
|
||||
static int snd_myctl_mono_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
@@ -105,7 +140,27 @@ static int snd_myctl_mono_info(struct snd_kcontrol *kcontrol,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_kcontrol_new controls[] = {
|
||||
static const struct snd_kcontrol_new controls_i2s7[] = {
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "I2S7-RX ON",
|
||||
.index = 0,
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
|
||||
.put = alwayson_control_put,
|
||||
.get = alwayson_control_get,
|
||||
.info = snd_myctl_mono_info,
|
||||
.private_value = 0
|
||||
},
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "I2S7-TX ON",
|
||||
.index = 0,
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
|
||||
.put = alwayson_control_put,
|
||||
.get = alwayson_control_get,
|
||||
.info = snd_myctl_mono_info,
|
||||
.private_value = 1
|
||||
},
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "I2S7 Loopback",
|
||||
@@ -115,7 +170,10 @@ static const struct snd_kcontrol_new controls[] = {
|
||||
.get = loopback_control_get,
|
||||
.info = snd_myctl_mono_info,
|
||||
.private_value = 0
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new controls_i2s8[] = {
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "I2S8 Loopback",
|
||||
@@ -125,12 +183,43 @@ static const struct snd_kcontrol_new controls[] = {
|
||||
.get = loopback_control_get,
|
||||
.info = snd_myctl_mono_info,
|
||||
.private_value = 1
|
||||
},
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "I2S8-RX ON",
|
||||
.index = 0,
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
|
||||
.put = alwayson_control_put,
|
||||
.get = alwayson_control_get,
|
||||
.info = snd_myctl_mono_info,
|
||||
.private_value = 2
|
||||
},
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "I2S8-TX ON",
|
||||
.index = 0,
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
|
||||
.put = alwayson_control_put,
|
||||
.get = alwayson_control_get,
|
||||
.info = snd_myctl_mono_info,
|
||||
.private_value = 3
|
||||
}
|
||||
};
|
||||
|
||||
static int safety_i2s_add_kcontrols(struct snd_card *card, int id)
|
||||
{
|
||||
return snd_ctl_add(card, snd_ctl_new1(&controls[id], i2s));
|
||||
int num_of_controls, i, ret;
|
||||
|
||||
if (id == 0) {
|
||||
num_of_controls = ARRAY_SIZE(controls_i2s7);
|
||||
for (i = 0; i < num_of_controls; i++)
|
||||
ret = snd_ctl_add(card, snd_ctl_new1(&controls_i2s7[i], i2s));
|
||||
} else if (id == 1) {
|
||||
num_of_controls = ARRAY_SIZE(controls_i2s8);
|
||||
for (i = 0; i < num_of_controls; i++)
|
||||
ret = snd_ctl_add(card, snd_ctl_new1(&controls_i2s8[i], i2s));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int prealloc_dma_buff(struct snd_pcm *pcm, unsigned int stream, size_t size)
|
||||
@@ -404,7 +493,6 @@ static void safety_i2s_start(struct snd_pcm_substream *substream)
|
||||
else
|
||||
i2s_enable_tx(id);
|
||||
|
||||
i2s_enable(id);
|
||||
data->triggered = 1;
|
||||
}
|
||||
|
||||
@@ -715,6 +803,15 @@ static int t234_safety_audio_probe(struct platform_device *pdev)
|
||||
|
||||
static int t234_safety_audio_remove(struct platform_device *pdev)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_SAFETY_I2S_INST; i++) {
|
||||
if (!enabled_i2s_mask[i])
|
||||
continue;
|
||||
|
||||
i2s_disable(i);
|
||||
}
|
||||
|
||||
snd_card_free(priv->card);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2021-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
* Copyright (c) 2021-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _TEGRA_I2S_H_
|
||||
@@ -61,6 +61,8 @@ struct i2s_config {
|
||||
unsigned int pcm_mask_bits;
|
||||
unsigned int highz_ctrl;
|
||||
unsigned int clock_trim;
|
||||
unsigned int tx_always_on;
|
||||
unsigned int rx_always_on;
|
||||
};
|
||||
|
||||
struct dma_data {
|
||||
|
||||
Reference in New Issue
Block a user