diff options
-rw-r--r-- | arch/arm/mach-tegra/audio_manager.c | 295 | ||||
-rw-r--r-- | arch/arm/mach-tegra/audio_switch.c | 31 | ||||
-rw-r--r-- | arch/arm/mach-tegra/dam.c | 149 | ||||
-rw-r--r-- | arch/arm/mach-tegra/include/mach/audio_switch.h | 18 | ||||
-rw-r--r-- | arch/arm/mach-tegra/include/mach/spdif.h | 2 | ||||
-rw-r--r-- | arch/arm/mach-tegra/include/mach/tegra3_i2s.h | 1 | ||||
-rw-r--r-- | arch/arm/mach-tegra/spdif.c | 70 | ||||
-rw-r--r-- | arch/arm/mach-tegra/tegra3_i2s.c | 37 | ||||
-rw-r--r-- | sound/soc/tegra/tegra_spdif.c | 31 |
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); |