summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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);