summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVinod G <vinodg@nvidia.com>2011-05-20 18:39:52 -0700
committerNiket Sirsi <nsirsi@nvidia.com>2011-07-07 12:19:53 -0700
commit696378cdf4647e45c0af7608f4293a8bdb56470a (patch)
tree221023112767ec38f3b331dc2a7698f67ec36cd5
parent5ba9e86ceebcff712a959225879b802e47274662 (diff)
arm: tegra: use DAM for playback path
DAM rx1 is used for playback path. DAM is added as default so for voicecall no need to teardown the existing connection that is being used. Needed for bug 804696 Change-Id: Iba4cec350595a32dfd71ede9e224620ebe84b1ba Reviewed-on: http://git-master/r/38676 Reviewed-by: Ravindra Lokhande <rlokhande@nvidia.com> Tested-by: Ravindra Lokhande <rlokhande@nvidia.com> Reviewed-by: Niket Sirsi <nsirsi@nvidia.com> Tested-by: Niket Sirsi <nsirsi@nvidia.com>
-rw-r--r--arch/arm/mach-tegra/audio_manager.c295
-rw-r--r--arch/arm/mach-tegra/audio_switch.c31
-rw-r--r--arch/arm/mach-tegra/dam.c149
-rw-r--r--arch/arm/mach-tegra/include/mach/audio_switch.h18
-rw-r--r--arch/arm/mach-tegra/include/mach/spdif.h2
-rw-r--r--arch/arm/mach-tegra/include/mach/tegra3_i2s.h1
-rw-r--r--arch/arm/mach-tegra/spdif.c70
-rw-r--r--arch/arm/mach-tegra/tegra3_i2s.c37
-rw-r--r--sound/soc/tegra/tegra_spdif.c31
9 files changed, 519 insertions, 115 deletions
diff --git a/arch/arm/mach-tegra/audio_manager.c b/arch/arm/mach-tegra/audio_manager.c
index ac517b6c5002..4275adb93be7 100644
--- a/arch/arm/mach-tegra/audio_manager.c
+++ b/arch/arm/mach-tegra/audio_manager.c
@@ -35,9 +35,19 @@
#include <mach/pinmux.h>
#include <mach/tegra_das.h>
#include <mach/tegra_i2s.h>
+#include <mach/tegra3_i2s.h>
#include <mach/spdif.h>
#include <mach/audio_manager.h>
+#define ENABLE_AM_DEBUG_PRINT 0
+
+#if ENABLE_AM_DEBUG_PRINT
+#define AM_DEBUG_PRINT(fmt, arg...) printk(fmt, ## arg)
+#else
+#define AM_DEBUG_PRINT(fmt, arg...) do {} while (0)
+#endif
+
+#define LINEAR_UNITY_GAIN 0x1000
static struct am_dev_fns init_am_dev_fns[] = {
[AUDIO_I2S_DEVICE] = {
@@ -76,6 +86,14 @@ static struct am_dev_fns init_am_dev_fns[] = {
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+/* dummy calls */
+int audio_switch_open(void) { return 0; }
+int audio_switch_close(void) { return 0; }
+int audio_switch_suspend(void) { return 0; }
+int audio_switch_resume(void) { return 0; }
+int audio_switch_enable_clock(void) { return 0; }
+void audio_switch_disable_clock(void) {}
+
int am_suspend(aud_dev_info* devinfo)
{
struct am_dev_fns* am_fn = &init_am_dev_fns[devinfo->dev_type];
@@ -180,21 +198,23 @@ int am_device_deinit(aud_dev_info* devinfo)
int am_set_stream_format(aud_dev_info* devinfo, am_stream_format_info *format)
{
+ int dev_id = devinfo->dev_id;
+
if (devinfo->dev_type == AUDIO_I2S_DEVICE) {
- i2s_set_bit_size(devinfo->dev_id, format->bitsize);
- i2s_set_samplerate(devinfo->dev_id, format->samplerate);
- i2s_set_channels(devinfo->dev_id, format->channels);
- i2s_set_fifo_attention(devinfo->dev_id,
+ i2s_set_bit_size(dev_id, format->bitsize);
+ i2s_set_samplerate(dev_id, format->samplerate);
+ i2s_set_channels(dev_id, format->channels);
+ i2s_set_fifo_attention(dev_id,
devinfo->fifo_mode, format->buffersize);
} else if (devinfo->dev_type == AUDIO_SPDIF_DEVICE) {
- spdif_set_bit_mode(devinfo->dev_id, format->bitsize);
+ spdif_set_bit_mode(dev_id, format->bitsize);
/* fixme - move to appropriate locn later */
- spdif_set_fifo_packed(devinfo->dev_id, 1);
+ spdif_set_fifo_packed(dev_id, 1);
- spdif_set_sample_rate(devinfo->dev_id,
+ spdif_set_sample_rate(dev_id,
devinfo->fifo_mode, format->samplerate);
- spdif_set_fifo_attention(devinfo->dev_id,
+ spdif_set_fifo_attention(dev_id,
devinfo->fifo_mode, format->buffersize);
}
return 0;
@@ -261,17 +281,123 @@ int am_device_init(aud_dev_info* devinfo, void *dev_fmt, void *strm_fmt)
#else
+struct am_ch_info {
+ bool inuse[AUDIO_FIFO_CNT];
+ int outsample;
+ int ahubrx_index;
+ int ahubtx_index;
+ int damch[AUDIO_FIFO_CNT];
+ int dmach[AUDIO_FIFO_CNT];
+ int dmach_refcnt[AUDIO_FIFO_CNT];
+ am_stream_format_info sfmt;
+ struct audio_cif inacif;
+ struct audio_cif outcif;
+};
+
struct audio_manager_context {
struct clk *mclk;
struct clk *pmc_clk;
int mclk_refcnt;
int mclk_rate;
int mclk_parent;
+ struct am_ch_info i2s_ch[NR_I2S_IFC];
+ struct am_ch_info spdif_ch;
};
+
struct audio_manager_context *aud_manager;
-int am_suspend(aud_dev_info* devinfo)
+int default_record_connection(aud_dev_info *devinfo)
+{
+ struct am_dev_fns *am_fn = &init_am_dev_fns[devinfo->dev_type];
+ return am_fn->aud_dev_get_dma_requestor(devinfo->dev_id,
+ AUDIO_RX_MODE);
+
+}
+
+int default_playback_connection(struct am_ch_info *ch, int ifc, int fifo_mode)
+{
+ /* get unused dam channel first */
+ ch->damch[fifo_mode] = dam_get_controller();
+
+ if (ch->damch[fifo_mode] < 0) {
+ pr_err("unable to get the dam channel\n");
+ return -ENOENT;
+ }
+
+ if (fifo_mode == AUDIO_TX_MODE)
+ ch->ahubtx_index = ahubtx_dam0 + ch->damch[fifo_mode];
+/* else if (fifo_mode == AUDIO_RX_MODE)
+ ch->ahubrx_index = ahubrx1_dam0 + (ch->damch[fifo_mode] << 1);
+ */
+
+ /* Enable the clock if needed */
+
+ /* FIXME: Take the property from the destination device
+ - it shoule the stream format also*/
+ dam_set_samplerate(ch->damch[fifo_mode],
+ dam_ch_out, ch->sfmt.samplerate);
+
+ /*ch 0 expecting as 8Khz */
+ dam_set_samplerate(ch->damch[fifo_mode],
+ dam_ch_in0, AUDIO_SAMPLERATE_8000);
+
+ /*Apbif dma going through DAM */
+ ch->dmach[fifo_mode] = dam_get_dma_requestor(ch->damch[fifo_mode],
+ dam_ch_in1, fifo_mode);
+
+ if (ch->dmach[fifo_mode] < 0)
+ goto conn_fail;
+
+ audio_switch_set_rx_port(ch->ahubrx_index, ch->ahubtx_index);
+
+ ch->inacif.audio_channels = ch->sfmt.channels;
+ ch->inacif.client_channels = ch->sfmt.channels;
+ ch->inacif.audio_bits = ch->sfmt.bitsize;
+ ch->inacif.client_bits = ch->sfmt.bitsize;
+
+ dam_set_acif(ch->damch[fifo_mode], dam_ch_out, &ch->inacif);
+ dam_set_acif(ch->damch[fifo_mode], dam_ch_in1, &ch->inacif);
+
+ /* set unity gain to damch1 */
+ dam_set_gain(ch->damch[fifo_mode], dam_ch_in1, LINEAR_UNITY_GAIN);
+ return 0;
+
+conn_fail:
+
+ dam_free_controller(ch->damch[fifo_mode]);
+ return -ENOENT;
+}
+
+int test_free_dam_connection(aud_dev_info *devinfo, int fifo_mode)
+{
+ struct am_ch_info *ch = NULL;
+ int dev_id = devinfo->dev_id;
+
+ if (devinfo->dev_type == AUDIO_I2S_DEVICE)
+ ch = &aud_manager->i2s_ch[dev_id];
+ else if (devinfo->dev_type == AUDIO_SPDIF_DEVICE)
+ ch = &aud_manager->spdif_ch;
+
+ if (fifo_mode == AUDIO_TX_MODE) {
+ dam_free_dma_requestor(ch->damch[fifo_mode], dam_ch_in1,
+ fifo_mode);
+
+ audio_switch_clear_rx_port(ch->ahubrx_index);
+
+ dam_free_controller(ch->damch[fifo_mode]);
+
+ } else {
+ struct am_dev_fns *am_fn = &init_am_dev_fns[devinfo->dev_type];
+
+ am_fn->aud_dev_free_dma_requestor(devinfo->dev_id, fifo_mode);
+ i2s_clock_disable(devinfo->dev_id, fifo_mode);
+ }
+ ch->damch[fifo_mode] = -1;
+ return 0;
+}
+
+int am_suspend(aud_dev_info *devinfo)
{
struct am_dev_fns* am_fn = &init_am_dev_fns[devinfo->dev_type];
return am_fn->aud_dev_suspend(devinfo->dev_id);
@@ -285,27 +411,118 @@ int am_resume(aud_dev_info* devinfo)
int am_set_stream_state(aud_dev_info* devinfo, bool enable)
{
+ struct am_ch_info *ch = NULL;
struct am_dev_fns* am_fn = &init_am_dev_fns[devinfo->dev_type];
- return am_fn->aud_dev_set_stream_state(
- devinfo->dev_id,
- devinfo->fifo_mode,
- ((enable)? 1 : 0));
+ int dev_id = devinfo->dev_id;
+ int fifo_mode = devinfo->fifo_mode;
+ int on_off = (enable) ? 1 : 0;
+
+ if (devinfo->dev_type == AUDIO_I2S_DEVICE)
+ ch = &aud_manager->i2s_ch[dev_id];
+ else if (devinfo->dev_type == AUDIO_SPDIF_DEVICE)
+ ch = &aud_manager->spdif_ch;
+
+ if (ch->damch[fifo_mode] >= 0)
+ dam_enable(ch->damch[fifo_mode], on_off, dam_ch_in1);
+
+ return am_fn->aud_dev_set_stream_state(dev_id, fifo_mode, on_off);
}
int am_get_dma_requestor(aud_dev_info* devinfo)
{
- struct am_dev_fns* am_fn = &init_am_dev_fns[devinfo->dev_type];
- return am_fn->aud_dev_get_dma_requestor(
- devinfo->dev_id,
- devinfo->fifo_mode);
+ int err = 0;
+ struct am_ch_info *ch = NULL;
+ int ahubindex = 0;
+ int dev_id = devinfo->dev_id;
+ int fifo_mode = devinfo->fifo_mode;
+
+ if (devinfo->dev_type == AUDIO_I2S_DEVICE) {
+ ch = &aud_manager->i2s_ch[dev_id];
+ ahubindex = dev_id + ahubrx_i2s0;
+
+ if (fifo_mode == AUDIO_RX_MODE)
+ ahubindex = dev_id + ahubtx_i2s0;
+
+ } else if (devinfo->dev_type == AUDIO_SPDIF_DEVICE) {
+ ch = &aud_manager->spdif_ch;
+ ahubindex = ahubrx0_spdif;
+
+ if (fifo_mode == AUDIO_RX_MODE)
+ ahubindex = ahubtx0_spdif;
+ }
+
+ if (ch->inuse[fifo_mode] == false) {
+
+ ch->ahubrx_index = ahubindex;
+
+ if (fifo_mode == AUDIO_RX_MODE)
+ ch->ahubtx_index = ahubindex;
+
+ if (fifo_mode == AUDIO_TX_MODE) {
+
+ err = default_playback_connection(ch,
+ dev_id, fifo_mode);
+ if (err)
+ goto fail_conn;
+
+ if (devinfo->dev_type == AUDIO_I2S_DEVICE) {
+ i2s_set_dma_channel(dev_id,
+ fifo_mode, (ch->dmach[fifo_mode] - 1));
+ i2s_set_acif(dev_id, fifo_mode, &ch->inacif);
+ } else if (devinfo->dev_type == AUDIO_SPDIF_DEVICE) {
+ spdif_set_dma_channel(dev_id,
+ fifo_mode, (ch->dmach[fifo_mode] - 1));
+ spdif_set_acif(dev_id,
+ fifo_mode, (void *)&ch->inacif);
+ }
+ } else {
+ if (devinfo->dev_type == AUDIO_I2S_DEVICE)
+ i2s_clock_enable(dev_id, fifo_mode);
+ ch->dmach[fifo_mode] =
+ default_record_connection(devinfo);
+ }
+ }
+
+ if (!err) {
+ ch->inuse[fifo_mode] = true;
+ ch->dmach_refcnt[fifo_mode]++;
+ return ch->dmach[fifo_mode];
+ }
+
+ return err;
+
+fail_conn:
+ /*free connection */
+ return err;
}
int am_free_dma_requestor(aud_dev_info* devinfo)
{
- struct am_dev_fns* am_fn = &init_am_dev_fns[devinfo->dev_type];
- return am_fn->aud_dev_free_dma_requestor(
- devinfo->dev_id,
- devinfo->fifo_mode);
+ struct am_ch_info *ch = NULL;
+ int dev_id = devinfo->dev_id;
+ int fifo_mode = devinfo->fifo_mode;
+
+ if (devinfo->dev_type == AUDIO_I2S_DEVICE)
+ ch = &aud_manager->i2s_ch[dev_id];
+ else if (devinfo->dev_type == AUDIO_SPDIF_DEVICE)
+ ch = &aud_manager->spdif_ch;
+
+ AM_DEBUG_PRINT("%s++ %d refcnt %d\n", __func__,
+ ch->dmach[fifo_mode],
+ ch->dmach_refcnt[fifo_mode]);
+
+ if (ch->dmach_refcnt[fifo_mode] > 0)
+ ch->dmach_refcnt[fifo_mode]--;
+
+ if (ch->dmach_refcnt[fifo_mode] == 0) {
+ test_free_dam_connection(devinfo, fifo_mode);
+ ch->inuse[fifo_mode] = false;
+ }
+ AM_DEBUG_PRINT("%s++ %d refcnt %d\n", __func__,
+ ch->dmach[fifo_mode],
+ ch->dmach_refcnt[fifo_mode]);
+ return 0;
+
}
phys_addr_t am_get_fifo_phy_base(aud_dev_info* devinfo)
@@ -375,22 +592,42 @@ int am_device_deinit(aud_dev_info* devinfo)
int am_set_stream_format(aud_dev_info* devinfo, am_stream_format_info *format)
{
+ int dev_id = devinfo->dev_id;
+ struct am_ch_info *ch = NULL;
+
if (devinfo->dev_type == AUDIO_I2S_DEVICE) {
- i2s_set_bit_size(devinfo->dev_id, format->bitsize);
- i2s_set_samplerate(devinfo->dev_id, format->samplerate);
- i2s_set_channels(devinfo->dev_id, format->channels);
- i2s_set_fifo_attention(devinfo->dev_id,
+ ch = &aud_manager->i2s_ch[dev_id];
+ i2s_set_bit_size(dev_id, format->bitsize);
+ i2s_set_samplerate(dev_id, format->samplerate);
+ i2s_set_channels(dev_id, format->channels);
+ i2s_set_fifo_attention(dev_id,
devinfo->fifo_mode, format->buffersize);
} else if (devinfo->dev_type == AUDIO_SPDIF_DEVICE) {
- spdif_set_bit_mode(devinfo->dev_id, format->bitsize);
- spdif_set_sample_rate(
- devinfo->dev_id,
+ ch = &aud_manager->spdif_ch;
+ spdif_set_bit_mode(dev_id, format->bitsize);
+ spdif_set_sample_rate(dev_id,
devinfo->fifo_mode,
format->samplerate);
- spdif_set_fifo_attention(devinfo->dev_id,
+ spdif_set_fifo_attention(dev_id,
devinfo->fifo_mode, format->buffersize);
}
+
+ memcpy(&ch->sfmt, format, sizeof(am_stream_format_info));
+
+ if (devinfo->dev_type == AUDIO_SPDIF_DEVICE) {
+ switch (format->bitsize) {
+ case SPDIF_BIT_MODE_MODE24BIT:
+ ch->sfmt.bitsize = AUDIO_BIT_SIZE_24;
+ break;
+ case SPDIF_BIT_MODE_MODERAW:
+ ch->sfmt.bitsize = AUDIO_BIT_SIZE_32;
+ break;
+ default:
+ ch->sfmt.bitsize = AUDIO_BIT_SIZE_16;
+ break;
+ }
+ }
return 0;
}
diff --git a/arch/arm/mach-tegra/audio_switch.c b/arch/arm/mach-tegra/audio_switch.c
index 77429c07b6c0..7484ba6c748b 100644
--- a/arch/arm/mach-tegra/audio_switch.c
+++ b/arch/arm/mach-tegra/audio_switch.c
@@ -262,14 +262,16 @@ static inline u32 audio_switch_readl(u32 reg)
void audio_switch_dump_registers(int ifc)
{
int i = 0;
- pr_info("%s: \n",__func__);
+ pr_info("%s:\n", __func__);
for (i = 0; i < ahubrx_maxnum; i++)
audio_switch_readl(ahub_reginfo[i].regbase);
}
-
+void audio_switch_clear_rx_port(int rxport)
+{
+ audio_switch_writel(ahub_reginfo[rxport].regbase, 0);
+}
void audio_switch_set_rx_port(int rxport, int txport)
{
- /*Get audioswitch base address*/
audio_switch_writel(ahub_reginfo[rxport].regbase, (1 << txport));
}
@@ -424,6 +426,13 @@ int audio_apbif_free_channel(int ifc, int fifo_mode)
if (ch->fifo_inuse[fifo_mode] == true) {
ch->fifo_refcnt[fifo_mode] -= 1;
if (ch->fifo_refcnt[fifo_mode] <= 0) {
+
+ if (fifo_mode == AUDIO_TX_MODE)
+ audio_switch_clear_rx_port(
+ ch->fifo_req[fifo_mode]);
+ else
+ audio_switch_clear_rx_port(ifc);
+
ch->fifo_inuse[fifo_mode] = false;
ch->fifo_req[fifo_mode] = 0;
ch->fifo_refcnt[fifo_mode] = 0;
@@ -444,7 +453,7 @@ static int get_apbif_channel(int fifo_req, int fifo_mode)
struct apbif_channel_info *ch = 0;
int i = 0;
- AHUB_DEBUG_PRINT(" %s ++ fifo_req 0x%x mode %d \n",
+ AHUB_DEBUG_PRINT("%s ++ fifo_req 0x%x mode %d\n",
__func__, (unsigned int)fifo_req, fifo_mode);
for (i = 0; i < NR_APBIF_CHANNELS; i++) {
@@ -695,7 +704,7 @@ void audio_switch_disable_clock(void)
clk_disable(acinfo->apbif_clk);
}
}
- AHUB_DEBUG_PRINT(" %s clk cnt %d \n",__func__, acinfo->clk_refcnt);
+ AHUB_DEBUG_PRINT(" %s clk cnt %d\n", __func__, acinfo->clk_refcnt);
}
@@ -734,7 +743,7 @@ int audio_switch_enable_clock(void)
}
acinfo->clk_refcnt++;
- AHUB_DEBUG_PRINT(" %s clk cnt %d \n",__func__, acinfo->clk_refcnt);
+ AHUB_DEBUG_PRINT(" %s clk cnt %d\n", __func__, acinfo->clk_refcnt);
return err;
fail_audio_clock:
@@ -800,7 +809,7 @@ int audio_switch_open(void)
{
int err = 0, i = 0;
- AHUB_DEBUG_PRINT(" %s 0x%x ++ \n", __func__, (unsigned int)acinfo);
+ AHUB_DEBUG_PRINT(" %s 0x%x ++\n", __func__, (unsigned int)acinfo);
if (!acinfo) {
struct apbif_channel_info *ch;
@@ -845,9 +854,13 @@ int audio_switch_open(void)
}
}
+ err = dam_open();
+ if (err)
+ goto fail_audio_open;
+
acinfo->refcnt++;
- AHUB_DEBUG_PRINT(" %s -- acinfo 0x%x refcnt %d \n", __func__,
+ AHUB_DEBUG_PRINT("%s-- acinfo 0x%x refcnt %d\n", __func__,
(unsigned int)acinfo, acinfo->refcnt);
return 0;
@@ -879,5 +892,7 @@ int audio_switch_close(void)
acinfo = NULL;
}
}
+
+ dam_close();
return 0;
}
diff --git a/arch/arm/mach-tegra/dam.c b/arch/arm/mach-tegra/dam.c
index 7fb8d9d39386..0a1eb41dc961 100644
--- a/arch/arm/mach-tegra/dam.c
+++ b/arch/arm/mach-tegra/dam.c
@@ -132,6 +132,7 @@ struct dam_context {
int ctrlreg_cache[DAM_CTRL_REGINDEX];
struct clk *dam_clk;
int clk_refcnt;
+ int dma_ch[dam_ch_maxnum];
};
struct dam_context dam_cont_info[NR_DAM_IFC];
@@ -142,6 +143,23 @@ static char* damclk_info[NR_DAM_IFC] = {
"dam2"
};
+struct dam_src_step_table {
+ int insample;
+ int outsample;
+ int stepreset;
+};
+/* FIXME : recheck all these values */
+struct dam_src_step_table step_table[] = {
+ { 8000, 44100, 80 },
+ { 8000, 48000, 0 }, /* 0 worked for A01 - 1 is suggested for A02 */
+ { 16000, 44100, 160 },
+ { 16000, 48000, 1 },
+ { 44100, 8000, 441 },
+ { 48000, 8000, 6 },
+ { 44100, 16000, 441 },
+ { 48000, 16000, 3 },
+};
+
struct dam_module_context {
int refcnt;
bool inuse[NR_DAM_IFC];
@@ -170,13 +188,13 @@ void dam_ch1_set_gain(int ifc,int gain);
static inline void dam_writel(int ifc, u32 val, u32 reg)
{
__raw_writel(val, dam_base[ifc] + reg);
- pr_info("dam write offset 0x%x: %08x\n", reg, val);
+ DAM_DEBUG_PRINT("dam write 0x%lx: %08x\n", dam_base[ifc] + reg, val);
}
static inline u32 dam_readl(int ifc, u32 reg)
{
u32 val = __raw_readl(dam_base[ifc] + reg);
- pr_info("dam read offset 0x%x: %08x\n", reg, val);
+ DAM_DEBUG_PRINT("dam read offset 0x%x: %08x\n", reg, val);
return val;
}
@@ -235,6 +253,37 @@ void dam_enable_clip_counter(int ifc, int on)
dam_writel(ifc, val, DAM_CLIP_0);
}
+int dam_set_step_reset(int ifc, int insample, int outsample)
+{
+ int step_reset = 0;
+ int i = 0;
+
+ for (i = 0; i < ARRAY_SIZE(step_table); i++) {
+ if ((insample == step_table[i].insample) &&
+ (outsample == step_table[i].outsample))
+ step_reset = step_table[i].stepreset;
+ }
+
+ dam_ch0_set_step(ifc, step_reset);
+ return 0;
+}
+
+int dam_set_gain(int ifc, int chtype, int gain)
+{
+
+ switch (chtype) {
+ case dam_ch_in0:
+ dam_ch0_set_gain(ifc, gain);
+ break;
+ case dam_ch_in1:
+ dam_ch1_set_gain(ifc, gain);
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
void dam_set_samplerate(int ifc, int chtype, int samplerate)
{
struct dam_context *ch = &dam_cont_info[ifc];
@@ -243,6 +292,7 @@ void dam_set_samplerate(int ifc, int chtype, int samplerate)
case dam_ch_in0:
dam_set_input_samplerate(ifc, samplerate);
ch->ch_insamplerate[dam_ch_in0] = samplerate;
+ dam_set_step_reset(ifc, samplerate, ch->outsamplerate);
break;
case dam_ch_in1:
ch->ch_insamplerate[dam_ch_in1] = samplerate;
@@ -356,7 +406,7 @@ void dam_ch0_set_datasync(int ifc,int datasync)
dam_writel(ifc, val, DAM_CH0_CTRL_0);
}
-void dam_ch0_control_set_gain(int ifc,int gain)
+void dam_ch0_set_gain(int ifc, int gain)
{
u32 val;
@@ -490,7 +540,8 @@ void dam_disable_clock(int ifc)
}
}
- DAM_DEBUG_PRINT(" %s clk cnt %d \n",__func__, ch->clk_refcnt);
+ audio_switch_disable_clock();
+ DAM_DEBUG_PRINT("%s clk cnt %d\n", __func__, ch->clk_refcnt);
}
int dam_enable_clock(int ifc)
@@ -500,6 +551,10 @@ int dam_enable_clock(int ifc)
ch = &dam_cont_info[ifc];
+ err = audio_switch_enable_clock();
+ if (err)
+ return err;
+
if (!ch->clk_refcnt) {
if (clk_enable(ch->dam_clk)) {
err = PTR_ERR(ch->dam_clk);
@@ -509,7 +564,7 @@ int dam_enable_clock(int ifc)
ch->clk_refcnt++;
- DAM_DEBUG_PRINT(" %s clk cnt %d \n",__func__, ch->clk_refcnt);
+ DAM_DEBUG_PRINT(" %s clk cnt %d\n", __func__, ch->clk_refcnt);
return err;
fail_dam_clock:
@@ -520,40 +575,45 @@ fail_dam_clock:
int dam_set_acif(int ifc, int chtype, struct audio_cif *cifInfo)
{
- struct dam_context *ch;
- unsigned int reg_addr = 0;
- ch = &dam_cont_info[ifc];
+ unsigned int reg_addr = (unsigned int)dam_base[ifc];
+ bool found = true;
switch (chtype) {
case dam_ch_out:
- reg_addr = (unsigned int)dam_base + DAM_AUDIOCIF_OUT_CTRL_0;
+ reg_addr += DAM_AUDIOCIF_OUT_CTRL_0;
break;
case dam_ch_in0:
- reg_addr = (unsigned int)dam_base + DAM_AUDIOCIF_CH0_CTRL_0;
+ reg_addr += DAM_AUDIOCIF_CH0_CTRL_0;
break;
case dam_ch_in1:
- reg_addr = (unsigned int)dam_base + DAM_AUDIOCIF_CH1_CTRL_0;
+ reg_addr += DAM_AUDIOCIF_CH1_CTRL_0;
break;
default:
+ found = false;
break;
}
- if (reg_addr) {
+ if (found == true)
audio_switch_set_acif(reg_addr, cifInfo);
- }
return 0;
}
int dam_get_controller(void)
{
- int i = 0;
+ int i = 0, err = 0;
if (!dam_info)
return -ENOENT;
for (i = 0; i < NR_DAM_IFC; i++) {
if (dam_info->inuse[i] == false) {
+
+ err = dam_enable_clock(i);
+ if (err) {
+ pr_err("unable to enable the dam channel\n");
+ return -ENOENT;
+ }
dam_info->inuse[i] = true;
return i;
}
@@ -563,19 +623,60 @@ int dam_get_controller(void)
int dam_free_controller(int ifc)
{
+ struct dam_context *ch = NULL;
+
+ check_dam_ifc(ifc , -EINVAL);
+
+ ch = &dam_cont_info[ifc];
+ DAM_DEBUG_PRINT("%s\n", __func__);
+
if (!dam_info)
return -ENOENT;
- /* FIXME: make sure the caller is done with the channels */
- dam_info->inuse[ifc] = false;
+ dam_disable_clock(ifc);
+
+ if (ch->clk_refcnt == 0)
+ dam_info->inuse[ifc] = false;
+
+ return 0;
+}
+
+int dam_get_dma_requestor(int ifc, int chtype, int fifo_mode)
+{
+ int dma_index = -1;
+ struct dam_context *ch;
+ int regIndex = ifc + ahubrx0_dam0 + chtype;
+
+ if (fifo_mode == AUDIO_RX_MODE)
+ regIndex = ifc + ahubtx_dam0;
+
+ dma_index = apbif_get_channel(regIndex, fifo_mode);
+
+ if (dma_index >= 0) {
+ ch = &dam_cont_info[ifc];
+ ch->dma_ch[chtype] = dma_index-1;
+ }
+
+ return dma_index;
+}
+
+int dam_free_dma_requestor(int ifc, int chtype, int fifo_mode)
+{
+ struct dam_context *ch;
+ ch = &dam_cont_info[ifc];
+ if (ch->dma_ch[chtype] >= 0) {
+ audio_apbif_free_channel(ch->dma_ch[chtype], fifo_mode);
+ DAM_DEBUG_PRINT("free dam ch %d\n", ch->dma_ch[chtype]);
+ ch->dma_ch[chtype] = -ENOENT;
+ }
return 0;
}
int dam_open(void)
{
- int err = 0, i = 0;
+ int err = 0, i, j;
- DAM_DEBUG_PRINT("%s ++ \n", __func__);
+ DAM_DEBUG_PRINT("%s ++\n", __func__);
if (!dam_info) {
struct dam_context *ch;
@@ -592,17 +693,19 @@ int dam_open(void)
ch = &dam_cont_info[i];
ch->dam_clk = tegra_get_clock_by_name(damclk_info[i]);
if (!ch->dam_clk) {
+ pr_err("unable to get dam%d clock\n", i);
err = -ENOENT;
goto fail_dam_open;
}
dam_set_clock_parent(i, 0);
+
+ for (j = 0; j < dam_ch_maxnum; j++)
+ ch->dma_ch[j] = -1;
}
- dam_info->refcnt++;
- } else {
- dam_info->refcnt++;
}
+ dam_info->refcnt++;
- DAM_DEBUG_PRINT(" %s -- \n", __func__);
+ DAM_DEBUG_PRINT("%s-- refcnt 0x%x\n", __func__ , dam_info->refcnt);
return 0;
@@ -617,7 +720,7 @@ int dam_close(void)
struct dam_context *ch;
int i = 0;
- DAM_DEBUG_PRINT("%s \n", __func__);
+ DAM_DEBUG_PRINT("%s\n", __func__);
if (dam_info) {
dam_info->refcnt--;
diff --git a/arch/arm/mach-tegra/include/mach/audio_switch.h b/arch/arm/mach-tegra/include/mach/audio_switch.h
index 5af6b74ff7be..d24cfa64cf4c 100644
--- a/arch/arm/mach-tegra/include/mach/audio_switch.h
+++ b/arch/arm/mach-tegra/include/mach/audio_switch.h
@@ -122,11 +122,12 @@ u32 apbif_fifo_read(int ifc, int fifo_mode);
void audio_switch_set_acif(int addr, struct audio_cif *cifInfo);
int audio_switch_get_rx_port(int rxport);
void audio_switch_set_rx_port(int rxport, int txport);
+void audio_switch_clear_rx_port(int rxport);
-int audio_switch_close(void);
-int audio_switch_open(void);
int audio_apbif_free_channel(int ifc, int fifo_mode);
int audio_apbif_set_acif(int ifc, int fifo_mode, struct audio_cif *cifInfo);
+int audio_switch_close(void);
+int audio_switch_open(void);
int audio_switch_suspend(void);
int audio_switch_resume(void);
int audio_switch_enable_clock(void);
@@ -147,15 +148,8 @@ int dam_set_clock_rate(int rate);
int dam_set_clock_parent(int ifc, int parent);
int dam_enable_clock(int ifc);
void dam_disable_clock(int ifc);
-
-#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
- /* dummy calls */
-int audio_switch_open(void) { return 0; }
-int audio_switch_close(void) { return 0; }
-int audio_switch_suspend(void) { return 0; }
-int audio_switch_resume(void) { return 0; }
-int audio_switch_enable_clock(void) { return 0; }
-void audio_switch_disable_clock(void) {}
-#endif
+int dam_free_dma_requestor(int ifc, int chtype, int fifo_mode);
+int dam_get_dma_requestor(int ifc, int chtype, int fifo_mode);
+int dam_set_gain(int ifc, int chtype, int gain);
#endif /* __ARCH_ARM_MACH_AUDIO_SWITCH_H */
diff --git a/arch/arm/mach-tegra/include/mach/spdif.h b/arch/arm/mach-tegra/include/mach/spdif.h
index db8be466aeb2..24c404cc9b47 100644
--- a/arch/arm/mach-tegra/include/mach/spdif.h
+++ b/arch/arm/mach-tegra/include/mach/spdif.h
@@ -513,6 +513,7 @@ int spdif_fifo_enable(int ifc, int mode, int on);
int spdif_get_dma_requestor(int ifc, int mode);
int spdif_free_dma_requestor(int ifc, int mode);
phys_addr_t spdif_get_fifo_phy_base(int ifc, int mode);
+int spdif_set_dma_channel(int ifc, int fifo_mode, int dma_ch);
int spdif_set_fifo_attention(int ifc, int fifo_mode, int buffersize);
int spdif_fifo_clear(int ifc, int mode);
int spdif_fifo_set_attention_level(int ifc, int mode, unsigned int level);
@@ -526,6 +527,7 @@ int spdif_resume(int ifc);
int spdif_set_bit_mode(int ifc, unsigned mode);
int spdif_set_fifo_packed(int ifc, unsigned on);
int spdif_set_sample_rate(int ifc, int fifo_mode, unsigned int sample_rate);
+int spdif_set_acif(int ifc, int fifo_mode, void *cifInfo);
u32 spdif_get_control(int ifc);
int spdif_ack_status(int ifc);
diff --git a/arch/arm/mach-tegra/include/mach/tegra3_i2s.h b/arch/arm/mach-tegra/include/mach/tegra3_i2s.h
index 546d0730674c..cab4578c0638 100644
--- a/arch/arm/mach-tegra/include/mach/tegra3_i2s.h
+++ b/arch/arm/mach-tegra/include/mach/tegra3_i2s.h
@@ -321,6 +321,7 @@ int i2s_set_bit_mask(int ifc, int tx, int maskbit);
int i2s_set_flow_control(int ifc, int enable, int filtertype, int stepsize);
int i2s_set_acif(int ifc, int fifo_mode, struct audio_cif *cifInfo);
+int i2s_set_dma_channel(int ifc, int fifo_mode, int dma_ch);
#endif /* __ARCH_ARM_MACH_TEGRA3_I2S_H */
diff --git a/arch/arm/mach-tegra/spdif.c b/arch/arm/mach-tegra/spdif.c
index ff31e30bad9a..f04e6edb333f 100644
--- a/arch/arm/mach-tegra/spdif.c
+++ b/arch/arm/mach-tegra/spdif.c
@@ -158,7 +158,7 @@ u32 spdif_get_control(int ifc)
int spdif_close(int ifc)
{
- SPDIF_DEBUG_PRINT(" %s \n", __func__);
+ SPDIF_DEBUG_PRINT(" %s\n", __func__);
if (!spinfo)
return -ENOENT;
@@ -182,7 +182,7 @@ static int spdif_open(void)
{
int err = 0;
- SPDIF_DEBUG_PRINT(" %s ++ \n", __func__);
+ SPDIF_DEBUG_PRINT(" %s ++\n", __func__);
if (!spinfo) {
spinfo =
@@ -229,7 +229,7 @@ static int spdif_open(void)
spinfo->refcnt++;
- SPDIF_DEBUG_PRINT(" %s -- \n", __func__);
+ SPDIF_DEBUG_PRINT(" %s --\n", __func__);
return err;
fail_spdif_open:
@@ -258,7 +258,7 @@ int spdif_init(unsigned long base, phys_addr_t phy_base, int mode,
{
int err = 0;
- SPDIF_DEBUG_PRINT(" %s ++ \n", __func__);
+ SPDIF_DEBUG_PRINT(" %s ++\n", __func__);
if (spdif_open())
return err;
@@ -285,7 +285,7 @@ int spdif_init(unsigned long base, phys_addr_t phy_base, int mode,
spdif_initialize(base, mode);
spdif_clock_disable(0, mode);
- SPDIF_DEBUG_PRINT(" %s -- \n", __func__);
+ SPDIF_DEBUG_PRINT(" %s --\n", __func__);
return 0;
}
@@ -297,7 +297,7 @@ int spdif_clock_enable(int ifc, int mode)
if (!spinfo)
return -ENOENT;
- SPDIF_DEBUG_PRINT(" %s ++ \n", __func__);
+ SPDIF_DEBUG_PRINT(" %s ++\n", __func__);
err = audio_switch_enable_clock();
if (err)
@@ -333,7 +333,7 @@ int spdif_clock_enable(int ifc, int mode)
spinfo->spdev[mode].clk_refs++;
}
- SPDIF_DEBUG_PRINT("%s clk cnt 0x%x \n",
+ SPDIF_DEBUG_PRINT("%s clk cnt 0x%x\n",
__func__, spinfo->spdev[mode].clk_refs);
return err;
@@ -345,7 +345,7 @@ spdif_clock_enable_failed:
int spdif_clock_disable(int ifc, int mode)
{
- SPDIF_DEBUG_PRINT(" %s ++ \n", __func__);
+ SPDIF_DEBUG_PRINT(" %s ++\n", __func__);
if (!spinfo)
return -ENOENT;
@@ -368,7 +368,7 @@ int spdif_clock_disable(int ifc, int mode)
audio_switch_disable_clock();
- SPDIF_DEBUG_PRINT("%s clock count 0x%x \n",
+ SPDIF_DEBUG_PRINT("%s clock count 0x%x\n",
__func__, spinfo->spdev[mode].clk_refs);
return 0;
}
@@ -394,7 +394,7 @@ int spdif_clock_set_parent(int ifc, int mode, int parent)
int spdif_suspend(int ifc)
{
- SPDIF_DEBUG_PRINT(" %s ++ \n", __func__);
+ SPDIF_DEBUG_PRINT(" %s ++\n", __func__);
/* FIXME : check for Rx mode if needed */
if (spinfo->spdev[AUDIO_TX_MODE].clk_refs == 0)
@@ -410,7 +410,7 @@ int spdif_suspend(int ifc)
int spdif_resume(int ifc)
{
- SPDIF_DEBUG_PRINT(" %s ++ \n", __func__);
+ SPDIF_DEBUG_PRINT(" %s ++\n", __func__);
/* FIXME : check for Rx mode if needed */
spdif_clock_enable(0, AUDIO_TX_MODE);
audio_switch_resume();
@@ -533,6 +533,16 @@ int spdif_free_dma_requestor(int ifc, int fifo_mode)
return 0;
}
+int spdif_set_dma_channel(int ifc, int fifo_mode, int dma_ch)
+{
+ return 0;
+}
+
+int spdif_set_acif(int ifc, int fifo_mode, void *fmt)
+{
+ return 0;
+}
+
int spdif_set_fifo_attention(int ifc, int fifo_mode, int buffersize)
{
int fifoattn = SPDIF_FIFO_ATN_LVL_FOUR_SLOTS;
@@ -706,6 +716,12 @@ u32 spdif_get_fifo_full_empty_count(int ifc, int mode)
return 0;
}
+int spdif_set_dma_channel(int ifc, int fifo_mode, int dma_ch)
+{
+ spinfo->spdev[fifo_mode].dma_ch = dma_ch;
+ return 0;
+}
+
int spdif_free_dma_requestor(int ifc, int fifo_mode)
{
int apbif_ifc = spdif_get_apbif_channel(fifo_mode);
@@ -718,30 +734,21 @@ int spdif_free_dma_requestor(int ifc, int fifo_mode)
static struct audio_cif spdif_audiocif;
-int spdif_set_acif(int fifo_mode, struct audio_cif *cifInfo)
+int spdif_set_acif(int ifc, int fifo_mode, void *fmt)
{
- struct audio_cif *tx_audio_cif = &spdif_audiocif;
-
- /* set spdif audiocif */
- /* setting base value for acif */
- memset(tx_audio_cif, 0 , sizeof(struct audio_cif));
- tx_audio_cif->audio_channels = AUDIO_CHANNEL_2;
- tx_audio_cif->client_channels = AUDIO_CHANNEL_2;
- tx_audio_cif->audio_bits = AUDIO_BIT_SIZE_16;
- tx_audio_cif->client_bits = AUDIO_BIT_SIZE_16;
-
+ struct audio_cif *cifInfo = (struct audio_cif *)fmt;
if (fifo_mode == AUDIO_TX_MODE)
audio_switch_set_acif(spinfo->base +
- SPDIF_AUDIOCIF_TXDATA_CTRL_0, tx_audio_cif);
+ SPDIF_AUDIOCIF_TXDATA_CTRL_0, cifInfo);
else
audio_switch_set_acif(spinfo->base +
- SPDIF_AUDIOCIF_RXDATA_CTRL_0, tx_audio_cif);
+ SPDIF_AUDIOCIF_RXDATA_CTRL_0, cifInfo);
apbif_set_pack_mode(spdif_get_apbif_channel(fifo_mode),
fifo_mode, AUDIO_FIFO_PACK_16);
audio_apbif_set_acif(spdif_get_apbif_channel(fifo_mode),
- fifo_mode, tx_audio_cif);
+ fifo_mode, cifInfo);
return 0;
}
@@ -749,6 +756,7 @@ int spdif_set_acif(int fifo_mode, struct audio_cif *cifInfo)
int spdif_get_dma_requestor(int ifc, int fifo_mode)
{
int dma_index = 0;
+ struct audio_cif *tx_audio_cif = &spdif_audiocif;
int apbif_ifc = ahubrx0_spdif;
if (fifo_mode == AUDIO_RX_MODE)
@@ -758,9 +766,15 @@ int spdif_get_dma_requestor(int ifc, int fifo_mode)
if (dma_index != -ENOENT) {
spinfo->spdev[fifo_mode].dma_ch = dma_index - 1;
- /* FIXME : this need to be called on connection request
- */
- spdif_set_acif(fifo_mode, 0);
+
+ /* set spdif audiocif */
+ /* setting base value for acif */
+ memset(tx_audio_cif, 0 , sizeof(struct audio_cif));
+ tx_audio_cif->audio_channels = AUDIO_CHANNEL_2;
+ tx_audio_cif->client_channels = AUDIO_CHANNEL_2;
+ tx_audio_cif->audio_bits = AUDIO_BIT_SIZE_16;
+ tx_audio_cif->client_bits = AUDIO_BIT_SIZE_16;
+ spdif_set_acif(0, fifo_mode, (void *)tx_audio_cif);
}
return dma_index;
diff --git a/arch/arm/mach-tegra/tegra3_i2s.c b/arch/arm/mach-tegra/tegra3_i2s.c
index 074abde72732..b66d66083607 100644
--- a/arch/arm/mach-tegra/tegra3_i2s.c
+++ b/arch/arm/mach-tegra/tegra3_i2s.c
@@ -70,6 +70,7 @@ static struct i2s_clk_info i2sclk_info[NR_I2S_IFC] = {
{"i2s3", "i2s3_sync", "audio3", "audio3_2x"},
{"i2s4", "i2s4_sync", "audio4", "audio4_2x"}
};
+static struct audio_cif audiocif;
static inline void i2s_writel(int ifc, u32 val, u32 reg)
{
@@ -146,6 +147,12 @@ static void i2s_restore_registers(int ifc)
}
+int i2s_set_dma_channel(int ifc, int fifo_mode, int dma_ch)
+{
+ i2s_cont_info[ifc].i2s_ch_prop[fifo_mode].dma_ch = dma_ch;
+ return 0;
+}
+
int i2s_suspend(int ifc)
{
struct i2s_controller_info *info = &i2s_cont_info[ifc];
@@ -724,6 +731,8 @@ u32 i2s_get_fifo_full_empty_count(int ifc, int fifo)
int i2s_get_dma_requestor(int ifc, int fifo_mode)
{
int dma_index = 0;
+ struct audio_cif *tx_audio_cif = &audiocif;
+ struct i2s_controller_info *info = &i2s_cont_info[ifc];
int regIndex = ifc + ahubrx_i2s0;
if (fifo_mode == AUDIO_TX_MODE)
@@ -733,8 +742,15 @@ int i2s_get_dma_requestor(int ifc, int fifo_mode)
if (dma_index != -ENOENT) {
i2s_cont_info[ifc].i2s_ch_prop[fifo_mode].dma_ch = dma_index-1;
- /* FIXME : this need to be called on connection request */
- i2s_set_acif(ifc, fifo_mode, 0);
+
+ /* set i2s audiocif */
+ /* setting base value for acif */
+ memset(tx_audio_cif, 0 , sizeof(struct audio_cif));
+ tx_audio_cif->audio_channels = info->i2sprop.channels;
+ tx_audio_cif->client_channels = info->i2sprop.channels;
+ tx_audio_cif->audio_bits = info->i2sprop.bit_size;
+ tx_audio_cif->client_bits = info->i2sprop.bit_size;
+ i2s_set_acif(ifc, fifo_mode, tx_audio_cif);
}
return dma_index;
@@ -755,33 +771,24 @@ struct clk *i2s_get_clock_by_name(const char *name)
return tegra_get_clock_by_name(name);
}
-static struct audio_cif audiocif;
+
int i2s_set_acif(int ifc, int fifo_mode, struct audio_cif *cifInfo)
{
- struct audio_cif *tx_audio_cif = &audiocif;
struct i2s_controller_info *info = &i2s_cont_info[ifc];
- /* set i2s audiocif */
- /* setting base value for acif */
- memset(tx_audio_cif, 0 , sizeof(struct audio_cif));
- tx_audio_cif->audio_channels = info->i2sprop.channels;
- tx_audio_cif->client_channels = info->i2sprop.channels;
- tx_audio_cif->audio_bits = info->i2sprop.bit_size;
- tx_audio_cif->client_bits = info->i2sprop.bit_size;
-
if (fifo_mode == AUDIO_TX_MODE)
audio_switch_set_acif((unsigned int)i2s_base[ifc] +
- I2S_AUDIOCIF_I2STX_CTRL_0, tx_audio_cif);
+ I2S_AUDIOCIF_I2STX_CTRL_0, cifInfo);
else
audio_switch_set_acif((unsigned int)i2s_base[ifc] +
- I2S_AUDIOCIF_I2SRX_CTRL_0, tx_audio_cif);
+ I2S_AUDIOCIF_I2SRX_CTRL_0, cifInfo);
apbif_set_pack_mode(i2s_get_apbif_channel(ifc, fifo_mode),
fifo_mode, info->i2sprop.fifo_fmt);
audio_apbif_set_acif(i2s_get_apbif_channel(ifc, fifo_mode),
- fifo_mode, tx_audio_cif);
+ fifo_mode, cifInfo);
return 0;
}
diff --git a/sound/soc/tegra/tegra_spdif.c b/sound/soc/tegra/tegra_spdif.c
index 10a8abe630dc..84f36120f4c3 100644
--- a/sound/soc/tegra/tegra_spdif.c
+++ b/sound/soc/tegra/tegra_spdif.c
@@ -160,7 +160,38 @@ static int tegra_spdif_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
+ fmt.samplerate = val;
+
+ switch (params_channels(params)) {
+ case 1:
+ val = AUDIO_CHANNEL_1;
+ break;
+ case 2:
+ val = AUDIO_CHANNEL_2;
+ break;
+ case 3:
+ val = AUDIO_CHANNEL_3;
+ break;
+ case 4:
+ val = AUDIO_CHANNEL_4;
+ break;
+ case 5:
+ val = AUDIO_CHANNEL_5;
+ break;
+ case 6:
+ val = AUDIO_CHANNEL_6;
+ break;
+ case 7:
+ val = AUDIO_CHANNEL_7;
+ break;
+ case 8:
+ val = AUDIO_CHANNEL_8;
+ break;
+ default:
+ return -EINVAL;
+ }
fmt.channels = val;
+
fmt.buffersize = params_period_bytes(params);
am_set_stream_format(&info->spdev_info, &fmt);