From 6b7e887d5742406d988cb6f797846a83f00a31bb Mon Sep 17 00:00:00 2001 From: Nitin Pai Date: Tue, 24 Apr 2012 15:57:51 +0530 Subject: asoc: tegra: Add TDM mode support Added TDM mode support in I2S driver. Added support functions in AHUB to pass audio/client bits. Added support functions in AHUB to pass audio/client channels. Fixed the stopping of I2S/TDM by clearing the fifo. Bug 948478 Signed-off-by: Nitin Pai Change-Id: I560f4ab5b71e4833931934275272a094241241fe Reviewed-on: http://git-master/r/103840 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Ravindra Lokhande Reviewed-by: Scott Peterson --- sound/soc/tegra/tegra30_ahub.c | 127 ++++++++++++++++++++++ sound/soc/tegra/tegra30_ahub.h | 14 +++ sound/soc/tegra/tegra30_i2s.c | 236 ++++++++++++++++++++++++++++++++++++++++- sound/soc/tegra/tegra30_i2s.h | 14 ++- 4 files changed, 386 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c index 710d9465b4b0..30b7e481acc4 100644 --- a/sound/soc/tegra/tegra30_ahub.c +++ b/sound/soc/tegra/tegra30_ahub.c @@ -116,6 +116,15 @@ void tegra30_ahub_disable_clocks(void) clk_disable(ahub->clk_d_audio); } +/* + * for TDM mode, ahub has to run faster than I2S controller. This will avoid + * FIFO overflow/underflow, the causes of slot-hopping symptoms + */ +void tegra30_ahub_clock_set_rate(int rate) +{ + clk_set_rate(ahub->clk_d_audio, rate); +} + #ifdef CONFIG_DEBUG_FS static inline u32 tegra30_ahub_read(u32 space, u32 reg) { @@ -272,6 +281,75 @@ int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif, return 0; } +int tegra30_ahub_rx_fifo_is_enabled(int i2s_id) +{ + int val, mask; + + val = tegra30_apbif_read(TEGRA30_AHUB_I2S_LIVE_STATUS); + mask = (TEGRA30_AHUB_I2S_LIVE_STATUS_I2S0_RX_FIFO_ENABLED << (i2s_id*2)); + val &= mask; + return val; +} + +int tegra30_ahub_tx_fifo_is_enabled(int i2s_id) +{ + int val, mask; + + val = tegra30_apbif_read(TEGRA30_AHUB_I2S_LIVE_STATUS); + mask = (TEGRA30_AHUB_I2S_LIVE_STATUS_I2S0_TX_FIFO_ENABLED << (i2s_id*2)); + val &= mask; + + return val; +} + +int tegra30_ahub_set_rx_fifo_pack_mode(enum tegra30_ahub_rxcif rxcif, + unsigned int pack_mode) +{ + int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0; + int reg, val; + + tegra30_ahub_enable_clocks(); + reg = TEGRA30_AHUB_CHANNEL_CTRL + + (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE); + val = tegra30_apbif_read(reg); + + val &= ~TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_MASK; + val &= ~TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_EN; + + if ((pack_mode == TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_16) || + (pack_mode == TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_8_4)) + val |= (TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_EN | + pack_mode); + tegra30_apbif_write(reg, val); + tegra30_ahub_disable_clocks(); + + return 0; +} + +int tegra30_ahub_set_tx_fifo_pack_mode(enum tegra30_ahub_txcif txcif, + unsigned int pack_mode) +{ + int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0; + int reg, val; + + tegra30_ahub_enable_clocks(); + reg = TEGRA30_AHUB_CHANNEL_CTRL + + (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE); + val = tegra30_apbif_read(reg); + + val &= ~TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_MASK; + val &= ~TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_EN; + + if ((pack_mode == TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_16) || + (pack_mode == TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_8_4)) + val |= (TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_EN | + pack_mode); + tegra30_apbif_write(reg, val); + tegra30_ahub_disable_clocks(); + + return 0; +} + int tegra30_ahub_enable_rx_fifo(enum tegra30_ahub_rxcif rxcif) { int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0; @@ -480,6 +558,54 @@ int tegra30_ahub_set_tx_cif_channels(enum tegra30_ahub_txcif txcif, return 0; } +int tegra30_ahub_set_rx_cif_bits(enum tegra30_ahub_rxcif rxcif, + unsigned int audio_bits, + unsigned int client_bits) +{ + int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0; + unsigned int reg, val; + + tegra30_ahub_enable_clocks(); + + reg = TEGRA30_AHUB_CIF_RX_CTRL + + (channel * TEGRA30_AHUB_CIF_RX_CTRL_STRIDE); + val = tegra30_apbif_read(reg); + val &= ~(TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_MASK | + TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_MASK); + val |= ((audio_bits) << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) | + ((client_bits) << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT); + tegra30_apbif_write(reg, val); + + tegra30_ahub_disable_clocks(); + + return 0; +} + +int tegra30_ahub_set_tx_cif_bits(enum tegra30_ahub_txcif txcif, + unsigned int audio_bits, + unsigned int client_bits) +{ + int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0; + unsigned int reg, val; + + tegra30_ahub_enable_clocks(); + + reg = TEGRA30_AHUB_CIF_TX_CTRL + + (channel * TEGRA30_AHUB_CIF_TX_CTRL_STRIDE); + val = tegra30_apbif_read(reg); + val &= ~(TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_MASK | + TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_MASK); + val |= ((audio_bits) << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) | + ((client_bits) << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT); + + tegra30_apbif_write(reg, val); + + tegra30_ahub_disable_clocks(); + + return 0; +} + + static int __devinit tegra30_ahub_probe(struct platform_device *pdev) { struct resource *res0, *res1, *region; @@ -507,6 +633,7 @@ static int __devinit tegra30_ahub_probe(struct platform_device *pdev) goto err_free; } clkm_rate = clk_get_rate(clk_get_parent(ahub->clk_d_audio)); + while (clkm_rate > 12000000) clkm_rate >>= 1; diff --git a/sound/soc/tegra/tegra30_ahub.h b/sound/soc/tegra/tegra30_ahub.h index 7de1b7c86c7f..8dc27abc5aed 100644 --- a/sound/soc/tegra/tegra30_ahub.h +++ b/sound/soc/tegra/tegra30_ahub.h @@ -464,6 +464,7 @@ enum tegra30_ahub_rxcif { extern void tegra30_ahub_enable_clocks(void); extern void tegra30_ahub_disable_clocks(void); +extern void tegra30_ahub_clock_set_rate(int rate); extern int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif, unsigned long *fiforeg, @@ -471,8 +472,13 @@ extern int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif, extern int tegra30_ahub_set_rx_cif_channels(enum tegra30_ahub_rxcif rxcif, unsigned int audio_ch, unsigned int client_ch); +extern int tegra30_ahub_set_rx_cif_bits(enum tegra30_ahub_rxcif rxcif, + unsigned int audio_bits, + unsigned int client_bits); extern int tegra30_ahub_enable_rx_fifo(enum tegra30_ahub_rxcif rxcif); extern int tegra30_ahub_disable_rx_fifo(enum tegra30_ahub_rxcif rxcif); +extern int tegra30_ahub_set_rx_fifo_pack_mode(enum tegra30_ahub_rxcif rxcif, + unsigned int pack_mode); extern int tegra30_ahub_free_rx_fifo(enum tegra30_ahub_rxcif rxcif); extern int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif, @@ -481,14 +487,22 @@ extern int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif, extern int tegra30_ahub_set_tx_cif_channels(enum tegra30_ahub_txcif txcif, unsigned int audio_ch, unsigned int client_ch); +extern int tegra30_ahub_set_tx_cif_bits(enum tegra30_ahub_txcif txcif, + unsigned int audio_bits, + unsigned int client_bits); extern int tegra30_ahub_enable_tx_fifo(enum tegra30_ahub_txcif txcif); extern int tegra30_ahub_disable_tx_fifo(enum tegra30_ahub_txcif txcif); +extern int tegra30_ahub_set_tx_fifo_pack_mode(enum tegra30_ahub_txcif txcif, + unsigned int pack_mode); extern int tegra30_ahub_free_tx_fifo(enum tegra30_ahub_txcif txcif); extern int tegra30_ahub_set_rx_cif_source(enum tegra30_ahub_rxcif rxcif, enum tegra30_ahub_txcif txcif); extern int tegra30_ahub_unset_rx_cif_source(enum tegra30_ahub_rxcif rxcif); +extern int tegra30_ahub_rx_fifo_is_enabled(int i2s_id); +extern int tegra30_ahub_tx_fifo_is_enabled(int i2s_id); + #ifdef CONFIG_PM extern int tegra30_ahub_apbif_resume(void); #endif diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c index aba964281349..449359837efb 100644 --- a/sound/soc/tegra/tegra30_i2s.c +++ b/sound/soc/tegra/tegra30_i2s.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -280,6 +281,194 @@ static int tegra30_i2s_set_fmt(struct snd_soc_dai *dai, return 0; } +static void tegra30_i2s_set_channel_bit_count(struct tegra30_i2s *i2s, + int i2sclock, int srate) +{ + int sym_bitclk, bitcnt; + u32 val; + + bitcnt = (i2sclock / (2 * srate)) - 1; + sym_bitclk = !(i2sclock % (2 * srate)); + + val = bitcnt << TEGRA30_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT; + + if (!sym_bitclk) + val |= TEGRA30_I2S_TIMING_NON_SYM_ENABLE; + + tegra30_i2s_write(i2s, TEGRA30_I2S_TIMING, val); +} + +static void tegra30_i2s_set_data_offset(struct tegra30_i2s *i2s) +{ + u32 val; + int rx_data_offset = i2s->dsp_config.rx_data_offset; + int tx_data_offset = i2s->dsp_config.tx_data_offset; + + val = (rx_data_offset << + TEGRA30_I2S_OFFSET_RX_DATA_OFFSET_SHIFT) | + (tx_data_offset << + TEGRA30_I2S_OFFSET_TX_DATA_OFFSET_SHIFT); + + tegra30_i2s_write(i2s, TEGRA30_I2S_OFFSET, val); +} + +static void tegra30_i2s_set_slot_control(struct tegra30_i2s *i2s, int stream) +{ + u32 val; + int tx_mask = i2s->dsp_config.tx_mask; + int rx_mask = i2s->dsp_config.rx_mask; + + val = tegra30_i2s_read(i2s, TEGRA30_I2S_SLOT_CTRL); + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + val &= ~TEGRA30_I2S_SLOT_CTRL_TX_SLOT_ENABLES_MASK; + val |= (tx_mask << TEGRA30_I2S_SLOT_CTRL_TX_SLOT_ENABLES_SHIFT); + } else { + val &= ~TEGRA30_I2S_SLOT_CTRL_RX_SLOT_ENABLES_MASK; + val |= (rx_mask << TEGRA30_I2S_SLOT_CTRL_RX_SLOT_ENABLES_SHIFT); + } + + val &= ~TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_MASK; + val |= (i2s->dsp_config.num_slots - 1) + << TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_SHIFT; + + tegra30_i2s_write(i2s, TEGRA30_I2S_SLOT_CTRL, val); +} + +static int tegra30_i2s_tdm_setup_clocks(struct device *dev, + struct tegra30_i2s *i2s, int *i2sclock) +{ + int ret; + + if (i2s->reg_ctrl & TEGRA30_I2S_CTRL_MASTER_ENABLE) { + + ret = clk_set_parent(i2s->clk_i2s, i2s->clk_pll_a_out0); + if (ret) { + dev_err(dev, "Can't set parent of I2S clock\n"); + return ret; + } + ret = clk_set_rate(i2s->clk_i2s, *i2sclock); + if (ret) { + dev_err(dev, "Can't set I2S clock rate: %d\n", ret); + return ret; + } + } else { + + ret = clk_set_rate(i2s->clk_i2s_sync, *i2sclock); + if (ret) { + dev_err(dev, "Can't set I2S sync clock rate\n"); + return ret; + } + + ret = clk_set_rate(i2s->clk_audio_2x, *i2sclock); + if (ret) { + dev_err(dev, "Can't set audio2x clock rate\n"); + return ret; + } + + ret = clk_set_parent(i2s->clk_i2s, i2s->clk_audio_2x); + if (ret) { + dev_err(dev, "Can't set parent of audio2x clock\n"); + return ret; + } + } + return ret; +} + + +static int tegra30_i2s_tdm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct device *dev = substream->pcm->card->dev; + struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai); + u32 val; + int i2s_client_ch, i2s_audio_ch, i2s_audio_bits, i2s_client_bits; + int i2sclock, srate; + int ret; + + srate = params_rate(params); + + i2sclock = srate * + i2s->dsp_config.num_slots * + i2s->dsp_config.slot_width; + + ret = tegra30_i2s_tdm_setup_clocks(dev, i2s, &i2sclock); + if (ret) + return -EINVAL; + + /* Run ahub clock greater than i2sclock */ + tegra30_ahub_clock_set_rate(i2sclock*2); + + tegra30_i2s_enable_clocks(i2s); + + tegra30_i2s_set_channel_bit_count(i2s, i2sclock*2, srate); + + i2s_client_ch = i2s->dsp_config.num_slots; + i2s_audio_ch = i2s->dsp_config.num_slots; + + i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_BIT_SIZE_MASK; + switch (i2s->dsp_config.slot_width) { + case 16: + i2s_audio_bits = TEGRA30_AUDIOCIF_BITS_16; + i2s_client_bits = TEGRA30_AUDIOCIF_BITS_16; + i2s->reg_ctrl |= TEGRA30_I2S_CTRL_BIT_SIZE_16; + break; + case 32: + i2s_audio_bits = TEGRA30_AUDIOCIF_BITS_32; + i2s_client_bits = TEGRA30_AUDIOCIF_BITS_32; + i2s->reg_ctrl |= TEGRA30_I2S_CTRL_BIT_SIZE_32; + break; + } + + val = (0 << TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) | + ((i2s_audio_ch - 1) << + TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) | + ((i2s_client_ch - 1) << + TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) | + (i2s_audio_bits << + TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) | + (i2s_client_bits << + TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + val |= TEGRA30_AUDIOCIF_CTRL_DIRECTION_RX; + tegra30_i2s_write(i2s, TEGRA30_I2S_CIF_RX_CTRL, val); + + tegra30_ahub_set_tx_cif_channels(i2s->txcif, + i2s_audio_ch, + i2s_client_ch); + tegra30_ahub_set_tx_cif_bits(i2s->txcif, + i2s_audio_bits, + i2s_client_bits); + tegra30_ahub_set_tx_fifo_pack_mode(i2s->txcif, 0); + + } else { + val |= TEGRA30_AUDIOCIF_CTRL_DIRECTION_TX; + tegra30_i2s_write(i2s, TEGRA30_I2S_CIF_TX_CTRL, val); + + tegra30_ahub_set_rx_cif_channels(i2s->rxcif, + i2s_audio_ch, + i2s_client_ch); + tegra30_ahub_set_rx_cif_bits(i2s->rxcif, + i2s_audio_bits, + i2s_client_bits); + tegra30_ahub_set_rx_fifo_pack_mode(i2s->rxcif, 0); + } + + tegra30_i2s_set_slot_control(i2s, substream->stream); + + tegra30_i2s_set_data_offset(i2s); + + i2s->reg_ch_ctrl &= ~TEGRA30_I2S_CH_CTRL_FSYNC_WIDTH_MASK; + i2s->reg_ch_ctrl |= (i2s->dsp_config.slot_width - 1) << + TEGRA30_I2S_CH_CTRL_FSYNC_WIDTH_SHIFT; + tegra30_i2s_write(i2s, TEGRA30_I2S_CH_CTRL, i2s->reg_ch_ctrl); + + tegra30_i2s_disable_clocks(i2s); + + return 0; +} + static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -300,6 +489,12 @@ static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } + /* TDM mode */ + if ((i2s->reg_ctrl & TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC) && + (i2s->dsp_config.slot_width > 2)) + return tegra30_i2s_tdm_hw_params(substream, params, dai); + + srate = params_rate(params); if (i2s->reg_ctrl & TEGRA30_I2S_CTRL_MASTER_ENABLE) { @@ -423,12 +618,15 @@ static void tegra30_i2s_start_playback(struct tegra30_i2s *i2s) static void tegra30_i2s_stop_playback(struct tegra30_i2s *i2s) { - tegra30_ahub_disable_tx_fifo(i2s->txcif); + int dcnt = 10; /* if this is the only user of i2s tx then disable it*/ + tegra30_ahub_disable_tx_fifo(i2s->txcif); if (i2s->playback_ref_count == 1) { i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_TX; tegra30_i2s_write(i2s, TEGRA30_I2S_CTRL, i2s->reg_ctrl); } + while (tegra30_ahub_tx_fifo_is_enabled(i2s->id) && dcnt--) + udelay(100); } static void tegra30_i2s_start_capture(struct tegra30_i2s *i2s) @@ -442,11 +640,14 @@ static void tegra30_i2s_start_capture(struct tegra30_i2s *i2s) static void tegra30_i2s_stop_capture(struct tegra30_i2s *i2s) { + int dcnt = 10; tegra30_ahub_disable_rx_fifo(i2s->rxcif); if (!i2s->is_call_mode_rec) { i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_RX; tegra30_i2s_write(i2s, TEGRA30_I2S_CTRL, i2s->reg_ctrl); } + while (tegra30_ahub_rx_fifo_is_enabled(i2s->id) && dcnt--) + udelay(100); } static int tegra30_i2s_trigger(struct snd_pcm_substream *substream, int cmd, @@ -500,6 +701,33 @@ static int tegra30_i2s_probe(struct snd_soc_dai *dai) tegra30_i2s_disable_clocks(i2s); #endif + /* Default values for DSP mode */ + i2s->dsp_config.num_slots = 1; + i2s->dsp_config.slot_width = 2; + i2s->dsp_config.tx_mask = 1; + i2s->dsp_config.rx_mask = 1; + i2s->dsp_config.rx_data_offset = 1; + i2s->dsp_config.tx_data_offset = 1; + + + return 0; +} + +int tegra30_i2s_set_tdm_slot(struct snd_soc_dai *cpu_dai, + unsigned int tx_mask, + unsigned int rx_mask, + int slots, + int slot_width) +{ + struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(cpu_dai); + + i2s->dsp_config.num_slots = slots; + i2s->dsp_config.slot_width = slot_width; + i2s->dsp_config.tx_mask = tx_mask; + i2s->dsp_config.rx_mask = rx_mask; + i2s->dsp_config.rx_data_offset = 0; + i2s->dsp_config.tx_data_offset = 0; + return 0; } @@ -534,6 +762,7 @@ static struct snd_soc_dai_ops tegra30_i2s_dai_ops = { .set_fmt = tegra30_i2s_set_fmt, .hw_params = tegra30_i2s_hw_params, .trigger = tegra30_i2s_trigger, + .set_tdm_slot = tegra30_i2s_set_tdm_slot, }; #define TEGRA30_I2S_DAI(id) \ @@ -543,13 +772,13 @@ static struct snd_soc_dai_ops tegra30_i2s_dai_ops = { .resume = tegra30_i2s_resume, \ .playback = { \ .channels_min = 1, \ - .channels_max = 2, \ + .channels_max = 16, \ .rates = SNDRV_PCM_RATE_8000_96000, \ .formats = SNDRV_PCM_FMTBIT_S16_LE, \ }, \ .capture = { \ .channels_min = 1, \ - .channels_max = 2, \ + .channels_max = 16, \ .rates = SNDRV_PCM_RATE_8000_96000, \ .formats = SNDRV_PCM_FMTBIT_S16_LE, \ }, \ @@ -824,7 +1053,6 @@ static __devinit int tegra30_i2s_platform_probe(struct platform_device *pdev) ret = PTR_ERR(i2s->clk_i2s); goto exit; } - i2s->clk_i2s_sync = clk_get(&pdev->dev, "ext_audio_sync"); if (IS_ERR(i2s->clk_i2s_sync)) { dev_err(&pdev->dev, "Can't retrieve i2s_sync clock\n"); diff --git a/sound/soc/tegra/tegra30_i2s.h b/sound/soc/tegra/tegra30_i2s.h index b9baddd5db8e..0992bf0d5b17 100644 --- a/sound/soc/tegra/tegra30_i2s.h +++ b/sound/soc/tegra/tegra30_i2s.h @@ -176,7 +176,7 @@ /* Number of slots in frame, minus 1 */ #define TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_SHIFT 16 #define TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_MASK_US 7 -#define TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_MASK (TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOT_MASK_US << TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOT_SHIFT) +#define TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_MASK (TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_MASK_US << TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_SHIFT) /* TDM mode slot enable bitmask */ #define TEGRA30_I2S_SLOT_CTRL_RX_SLOT_ENABLES_SHIFT 8 @@ -231,6 +231,16 @@ /* Number of i2s controllers*/ #define TEGRA30_NR_I2S_IFC 5 +struct dsp_config_t { + int num_slots; + int rx_mask; + int tx_mask; + int slot_width; + int rx_data_offset; + int tx_data_offset; +}; + + struct tegra30_i2s { int id; struct clk *clk_i2s; @@ -254,6 +264,8 @@ struct tegra30_i2s { #endif int call_record_dam_ifc; int is_call_mode_rec; + + struct dsp_config_t dsp_config; }; struct codec_config { -- cgit v1.2.3