summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNitin Pai <npai@nvidia.com>2011-07-18 14:03:00 +0530
committerRohan Somvanshi <rsomvanshi@nvidia.com>2011-07-21 05:10:59 -0700
commitae575be3bc7c8133e7fbbb6f9a5b022bc9d08afc (patch)
treed1314c2cc4ffb18ffe55b41a012f4f1f566b3244
parent94a7cbce6412f8175e0d00042a860d25a6600037 (diff)
tegra: audio_manager: Add support for I2S TDM mode
Added API's for I2S TDM mode programming for Tegra2 Added extra fields to support TDM mode programming. Change-Id: I7cdde70ed2f9efae47ecd9efa0c0d3d701096740 Signed-off-by: Nitin Pai <npai@nvidia.com> Reviewed-on: http://git-master/r/41525 Reviewed-by: Rohan Somvanshi <rsomvanshi@nvidia.com> Tested-by: Rohan Somvanshi <rsomvanshi@nvidia.com>
-rw-r--r--arch/arm/mach-tegra/audio_manager.c9
-rw-r--r--arch/arm/mach-tegra/include/mach/audio.h11
-rw-r--r--arch/arm/mach-tegra/include/mach/audio_manager.h7
-rw-r--r--arch/arm/mach-tegra/include/mach/tegra2_i2s.h65
-rw-r--r--arch/arm/mach-tegra/include/mach/tegra_i2s.h6
-rw-r--r--arch/arm/mach-tegra/tegra2_i2s.c233
6 files changed, 315 insertions, 16 deletions
diff --git a/arch/arm/mach-tegra/audio_manager.c b/arch/arm/mach-tegra/audio_manager.c
index 6431280f615c..eb18e691e77b 100644
--- a/arch/arm/mach-tegra/audio_manager.c
+++ b/arch/arm/mach-tegra/audio_manager.c
@@ -217,6 +217,7 @@ int am_set_stream_format(aud_dev_info* devinfo, am_stream_format_info *format)
spdif_set_fifo_attention(dev_id,
devinfo->fifo_mode, format->buffersize);
}
+
return 0;
}
@@ -257,6 +258,13 @@ int am_device_init(aud_dev_info* devinfo, void *dev_fmt, void *strm_fmt)
i2sprop.audio_mode = dfmt->audiomode;
i2sprop.clk_rate = dfmt->clkrate;
i2sprop.fifo_fmt = dfmt->fifofmt;
+ i2sprop.total_slots = dfmt->total_slots;
+ i2sprop.fsync_width = dfmt->fsync_width;
+ i2sprop.rx_slot_enables = dfmt->rx_slot_enables;
+ i2sprop.tx_slot_enables = dfmt->tx_slot_enables;
+ i2sprop.rx_bit_offset = dfmt->rx_bit_offset;
+ i2sprop.tx_bit_offset = dfmt->tx_bit_offset;
+ i2sprop.tdm_bitsize = dfmt->tdm_bitsize;
}
return i2s_init(devinfo->dev_id, &i2sprop);
@@ -276,6 +284,7 @@ int am_device_init(aud_dev_info* devinfo, void *dev_fmt, void *strm_fmt)
&spdifprop);
}
}
+
return 0;
}
diff --git a/arch/arm/mach-tegra/include/mach/audio.h b/arch/arm/mach-tegra/include/mach/audio.h
index 816361fc6897..bca058766053 100644
--- a/arch/arm/mach-tegra/include/mach/audio.h
+++ b/arch/arm/mach-tegra/include/mach/audio.h
@@ -176,6 +176,17 @@ struct tegra_audio_platform_data {
int mask; /* enable tx and rx? */
bool stereo_capture; /* True if hardware supports stereo */
void *driver_data;
+
+ /* Below Fields are valid for TDM mode*/
+ bool tdm_enable;
+ int total_slots;
+ int rx_bit_offset;
+ int tx_bit_offset;
+ int fsync_width;
+ int rx_slot_enables;
+ int tx_slot_enables;
+ int tdm_bitsize;
+ unsigned int dap_port_num;
};
struct wired_jack_conf {
diff --git a/arch/arm/mach-tegra/include/mach/audio_manager.h b/arch/arm/mach-tegra/include/mach/audio_manager.h
index 9bdd2aa435d1..c39aafc396cc 100644
--- a/arch/arm/mach-tegra/include/mach/audio_manager.h
+++ b/arch/arm/mach-tegra/include/mach/audio_manager.h
@@ -46,6 +46,13 @@ typedef struct am_dev_format_info_{
int clkrate;
int fifofmt;
int loopmode;
+ int total_slots;
+ int fsync_width;
+ int tdm_bitsize;
+ int rx_bit_offset;
+ int tx_bit_offset;
+ int rx_slot_enables;
+ int tx_slot_enables;
}am_dev_format_info;
struct am_dev_fns {
diff --git a/arch/arm/mach-tegra/include/mach/tegra2_i2s.h b/arch/arm/mach-tegra/include/mach/tegra2_i2s.h
index e48ccacd1422..44a416d7acbf 100644
--- a/arch/arm/mach-tegra/include/mach/tegra2_i2s.h
+++ b/arch/arm/mach-tegra/include/mach/tegra2_i2s.h
@@ -35,8 +35,8 @@
#define I2S_I2S_FIFO_SCR_0 0x0c
#define I2S_I2S_PCM_CTRL_0 0x10
#define I2S_I2S_NW_CTRL_0 0x14
-#define I2S_I2S_TDM_CTRL_0 0x20
-#define I2S_I2S_TDM_TX_RX_CTRL_0 0x24
+#define I2S_TDM_CTRL_0 0x20
+#define I2S_TDM_TX_RX_CTRL_0 0x24
#define I2S_I2S_FIFO1_0 0x40
#define I2S_I2S_FIFO2_0 0x80
@@ -84,21 +84,21 @@
#define I2S_FIFO_16_LSB 0
#define I2S_FIFO_20_LSB 1
#define I2S_FIFO_24_LSB 2
-#define I2S_FIFO_32 3
+#define I2S_FIFO_32 3
#define I2S_FIFO_PACKED 7
#define I2S_FIFO_SHIFT 4
#define I2S_I2S_CTRL_FIFO_FORMAT_MASK (7<<4)
#define I2S_I2S_CTRL_FIFO_FORMAT_16_LSB \
- (I2S_FIFO_16_LSB << I2S_FIFO_SHIFT)
+ (I2S_FIFO_16_LSB << I2S_FIFO_SHIFT)
#define I2S_I2S_CTRL_FIFO_FORMAT_20_LSB \
- (I2S_FIFO_20_LSB << I2S_FIFO_SHIFT)
+ (I2S_FIFO_20_LSB << I2S_FIFO_SHIFT)
#define I2S_I2S_CTRL_FIFO_FORMAT_24_LSB \
- (I2S_FIFO_24_LSB << I2S_FIFO_SHIFT)
+ (I2S_FIFO_24_LSB << I2S_FIFO_SHIFT)
#define I2S_I2S_CTRL_FIFO_FORMAT_32 \
- (I2S_FIFO_32 << I2S_FIFO_SHIFT)
+ (I2S_FIFO_32 << I2S_FIFO_SHIFT)
#define I2S_I2S_CTRL_FIFO_FORMAT_PACKED \
- (I2S_FIFO_PACKED << I2S_FIFO_SHIFT)
+ (I2S_FIFO_PACKED << I2S_FIFO_SHIFT)
// Left/Right Control Polarity. 0= Left channel when LRCK is low,
// Right channel when LRCK is high, 1= vice versa
@@ -289,6 +289,39 @@
#define I2S_I2S_PCM_CTRL_RCV_MODE (1<<0)
+/*
+ * I2S_TDM_CTRL_0
+ */
+#define I2S_TDM_CTRL_TDM_EN (1<<31)
+#define I2S_TDM_CTRL_TX_MSB_LSB_MASK (1<<25)
+#define I2S_TDM_CTRL_TX_MSB_LSB_SHIFT 25
+#define I2S_TDM_CTRL_RX_MSB_LSB_MASK (1<<24)
+#define I2S_TDM_CTRL_RX_MSB_LSB_SHIFT 24
+#define I2S_TDM_CTRL_TDM_EDGE_CTRL_MASK (1<<22)
+#define I2S_TDM_CTRL_TDM_EDGE_CTRL_SHIFT 22
+#define I2S_TDM_CTRL_TOTAL_SLOTS_MASK (0x7<<18)
+#define I2S_TDM_CTRL_TOTAL_SLOTS_SHIFT 18
+#define I2S_TDM_CTRL_TDM_BIT_SIZE_MASK (0x1f<<12)
+#define I2S_TDM_CTRL_TDM_BIT_SIZE_SHIFT 12
+#define I2S_TDM_CTRL_RX_DATA_OFFSET_MASK (0x3<<8)
+#define I2S_TDM_CTRL_RX_DATA_OFFSET_SHIFT 8
+#define I2S_TDM_CTRL_TX_DATA_OFFSET_MASK (0x3<<6)
+#define I2S_TDM_CTRL_TX_DATA_OFFSET_SHIFT 6
+#define I2S_TDM_CTRL_FSYNC_WIDTH_MASK 0x3f
+#define I2S_TDM_CTRL_FSYNC_WIDTH_SHIFT 0
+
+/*
+ * I2S_TDM_TX_RX_CTRL_0
+ */
+#define I2S_TDM_TX_RX_CTRL_TDM_TX_EN (1<<31)
+#define I2S_TDM_TX_RX_CTRL_TDM_RX_EN (1<<29)
+#define I2S_TDM_TX_RX_CTRL_TDM_RX_SLOT_ENABLES_MASK (0xff<<8)
+#define I2S_TDM_TX_RX_CTRL_TDM_RX_SLOT_ENABLES_SHIFT 8
+#define I2S_TDM_TX_RX_CTRL_TDM_TX_SLOT_ENABLES_MASK (0xff<<0)
+#define I2S_TDM_TX_RX_CTRL_TDM_TX_SLOT_ENABLES_SHIFT 0
+#define I2S_TDM_TX_FIFO_BUSY (1<<30)
+#define I2S_TDM_RX_FIFO_BUSY (1<<28)
+
/*
* API
@@ -300,4 +333,20 @@ int i2s_set_pcm_mask_bits(int ifc, unsigned mask_bits, int tx);
int i2s_set_pcm_fsync_width(int ifc, int fsync_long);
int i2s_enable_pcm_mode(int ifc, int enable);
int i2s_enable_fifos(int ifc, int on);
+
+/* I2S TDM APIs */
+
+int i2s_tdm_set_transfer(int ifc, int mode , int on);
+int i2s_tdm_set_fifo_attention(int ifc, int fifo_mode, int buffersize);
+u32 i2s_tdm_get_status(int ifc, int mode);
+int i2s_tdm_enable(int ifc);
+int i2s_tdm_set_msb_first(int ifc, int mode, int msb_first);
+int i2s_tdm_set_tdm_edge_ctrl_highz(int ifc, int highz);
+int i2s_tdm_set_total_slots(int ifc, int num_slots);
+int i2s_tdm_set_bit_size(int ifc, int bit_size);
+int i2s_tdm_set_data_offset(int ifc, int mode, int data_offset);
+int i2s_tdm_set_fsync_width(int ifc, int fsync_width);
+int i2s_tdm_set_slot_enables(int ifc, int mode, int slot_mask);
+int i2s_tdm_init(int ifc, struct tegra_i2s_property *pi2sprop);
+
#endif /* __ARCH_ARM_MACH_TEGRA_I2S_H */
diff --git a/arch/arm/mach-tegra/include/mach/tegra_i2s.h b/arch/arm/mach-tegra/include/mach/tegra_i2s.h
index ce98c081c53c..aff5e8002a6d 100644
--- a/arch/arm/mach-tegra/include/mach/tegra_i2s.h
+++ b/arch/arm/mach-tegra/include/mach/tegra_i2s.h
@@ -52,6 +52,11 @@ struct tegra_i2s_property {
int fsync_width; /* Fsync width in terms of bit clocks */
int highz_control; /* Highz control */
int edge_control; /* sample data on edge */
+ int rx_bit_offset; /* Data offset to FSync for TDM mode */
+ int tx_bit_offset; /* Data offset to FSync for TDM mode */
+ int tx_slot_enables; /* Number of slots enabled in the Fsync */
+ int rx_slot_enables; /* Number of slots enabled in the Fsync */
+ int tdm_bitsize;
struct clk *i2s_clk;
struct clk *i2s_sync_clk;
@@ -100,4 +105,5 @@ int i2s_clock_enable(int ifc, int fifo_mode);
int i2s_close(int ifc);
int i2s_clock_set_parent(int ifc, int mode, int parent);
int i2s_clock_set_rate(int ifc, int mode, int rate);
+
#endif /* __ARCH_ARM_MACH_TEGRA_I2S_H */
diff --git a/arch/arm/mach-tegra/tegra2_i2s.c b/arch/arm/mach-tegra/tegra2_i2s.c
index 2c323aabf24e..a07b4ae85b3e 100644
--- a/arch/arm/mach-tegra/tegra2_i2s.c
+++ b/arch/arm/mach-tegra/tegra2_i2s.c
@@ -29,7 +29,6 @@
#include <mach/audio.h>
#include <mach/tegra2_i2s.h>
-
#define NR_I2S_IFC 2
#define check_ifc(n, ...) if ((n) > NR_I2S_IFC) { \
@@ -98,12 +97,17 @@ void i2s_dump_registers(int ifc)
i2s_readl(ifc, I2S_I2S_STATUS_0));
pr_info("%s: TIMING %08x\n", __func__,
i2s_readl(ifc, I2S_I2S_TIMING_0));
- pr_info("%s: SCR %08x\n", __func__,
+ pr_info("%s: SCR %08x\n", __func__,
i2s_readl(ifc, I2S_I2S_FIFO_SCR_0));
pr_info("%s: FIFO1 %08x\n", __func__,
i2s_readl(ifc, I2S_I2S_FIFO1_0));
pr_info("%s: FIFO2 %08x\n", __func__,
i2s_readl(ifc, I2S_I2S_FIFO1_0));
+ pr_info("%s: TDM CTRL %08x\n", __func__,
+ i2s_readl(ifc, I2S_TDM_CTRL_0));
+ pr_info("%s: TDM RX TX CTRL %08x\n", __func__,
+ i2s_readl(ifc, I2S_TDM_TX_RX_CTRL_0));
+
}
struct i2s_controller_info * i2s_get_cont_info(int ifc)
@@ -137,8 +141,8 @@ int i2s_suspend(int ifc)
ird->i2s__fifo_scr_0 = i2s_readl(ifc, I2S_I2S_FIFO_SCR_0);
ird->i2s_pcm_ctrl_0 = i2s_readl(ifc, I2S_I2S_PCM_CTRL_0);
ird->i2s_nw_ctrl_0 = i2s_readl(ifc, I2S_I2S_NW_CTRL_0);
- ird->i2s_tdm_ctrl_0 = i2s_readl(ifc, I2S_I2S_TDM_CTRL_0);
- ird->i2s_tdm_tx_rx_ctrl_0 = i2s_readl(ifc, I2S_I2S_TDM_TX_RX_CTRL_0);
+ ird->i2s_tdm_ctrl_0 = i2s_readl(ifc, I2S_TDM_CTRL_0);
+ ird->i2s_tdm_tx_rx_ctrl_0 = i2s_readl(ifc, I2S_TDM_TX_RX_CTRL_0);
ird->i2s_fifo1_0 = i2s_readl(ifc, I2S_I2S_FIFO1_0);
ird->i2s_fifo2_0 = i2s_readl(ifc, I2S_I2S_FIFO2_0);
@@ -159,8 +163,8 @@ int i2s_resume(int ifc)
i2s_writel(ifc, ird->i2s__fifo_scr_0, I2S_I2S_FIFO_SCR_0);
i2s_writel(ifc, ird->i2s_pcm_ctrl_0, I2S_I2S_PCM_CTRL_0);
i2s_writel(ifc, ird->i2s_nw_ctrl_0, I2S_I2S_NW_CTRL_0);
- i2s_writel(ifc, ird->i2s_tdm_ctrl_0, I2S_I2S_TDM_CTRL_0);
- i2s_writel(ifc, ird->i2s_tdm_tx_rx_ctrl_0, I2S_I2S_TDM_TX_RX_CTRL_0);
+ i2s_writel(ifc, ird->i2s_tdm_ctrl_0, I2S_TDM_CTRL_0);
+ i2s_writel(ifc, ird->i2s_tdm_tx_rx_ctrl_0, I2S_TDM_TX_RX_CTRL_0);
i2s_writel(ifc, ird->i2s_fifo1_0, I2S_I2S_FIFO1_0);
i2s_writel(ifc, ird->i2s_fifo2_0, I2S_I2S_FIFO2_0);
return 0;
@@ -285,6 +289,9 @@ int i2s_fifo_enable(int ifc, int fifo, int on)
check_ifc(ifc, -EINVAL);
+ if (info->i2sprop.audio_mode == AUDIO_FRAME_FORMAT_TDM)
+ return i2s_tdm_set_transfer(ifc, fifo, on);
+
val = i2s_readl(ifc, I2S_I2S_CTRL_0);
if (!fifo) {
val &= ~I2S_I2S_CTRL_FIFO1_ENABLE;
@@ -340,6 +347,11 @@ int i2s_set_bit_format(int ifc, unsigned fmt)
check_ifc(ifc, -EINVAL);
+ if (fmt == AUDIO_FRAME_FORMAT_TDM) {
+ i2s_tdm_enable(ifc);
+ return 0;
+ }
+
if (fmt > AUDIO_FRAME_FORMAT_DSP) {
pr_err("%s: invalid bit-format selector %d\n", __func__, fmt);
return -EINVAL;
@@ -533,6 +545,10 @@ int i2s_set_fifo_attention(int ifc, int fifo_mode, int buffersize)
int fifoattn = I2S_FIFO_ATN_LVL_FOUR_SLOTS;
struct i2s_controller_info *info = &i2s_cont_info[ifc];
info->i2s_ch_prop[fifo_mode].fifo_attn = fifoattn;
+
+ if (info->i2sprop.audio_mode == AUDIO_FRAME_FORMAT_TDM)
+ i2s_tdm_set_fifo_attention(ifc, fifo_mode, buffersize);
+
return 0;
}
@@ -545,7 +561,7 @@ int i2s_enable_fifos(int ifc, int on)
val = i2s_readl(ifc, I2S_I2S_CTRL_0);
if (on)
val |= I2S_I2S_QE_FIFO1 | I2S_I2S_QE_FIFO2 |
- I2S_I2S_IE_FIFO1_ERR | I2S_I2S_IE_FIFO2_ERR;
+ I2S_I2S_IE_FIFO1_ERR | I2S_I2S_IE_FIFO2_ERR;
else
val &= ~(I2S_I2S_QE_FIFO1 | I2S_I2S_QE_FIFO2 |
I2S_I2S_IE_FIFO1_ERR | I2S_I2S_IE_FIFO2_ERR);
@@ -570,7 +586,13 @@ u32 i2s_fifo_read(int ifc, int fifo)
u32 i2s_get_status(int ifc, int fifo)
{
int regval = 0;
+ struct i2s_controller_info *info;
check_ifc(ifc, 0);
+
+ info = &i2s_cont_info[ifc];
+ if (info->i2sprop.audio_mode == AUDIO_FRAME_FORMAT_TDM)
+ return i2s_tdm_get_status(ifc, fifo);
+
regval = i2s_readl(ifc, I2S_I2S_STATUS_0);
if (fifo == AUDIO_TX_MODE)
@@ -623,10 +645,184 @@ u32 i2s_get_fifo_full_empty_count(int ifc, int fifo)
return val & I2S_I2S_FIFO_SCR_FIFO_FULL_EMPTY_COUNT_MASK;
}
+/* I2S TDM Mode Register settings */
+
+int i2s_tdm_enable(int ifc)
+{
+ u32 val;
+ check_ifc(ifc, -EINVAL);
+ val = i2s_readl(ifc, I2S_TDM_CTRL_0);
+ val &= ~I2S_TDM_CTRL_TDM_EN;
+ val |= I2S_TDM_CTRL_TDM_EN;
+ i2s_writel(ifc, val, I2S_TDM_CTRL_0);
+ return 0;
+}
+
+int i2s_tdm_set_msb_first(int ifc, int mode, int msb_first)
+{
+ u32 val;
+ check_ifc(ifc, -EINVAL);
+ val = i2s_readl(ifc, I2S_TDM_CTRL_0);
+ if (mode == AUDIO_TX_MODE) {
+ val &= ~I2S_TDM_CTRL_TX_MSB_LSB_MASK;
+ val |= (msb_first) << I2S_TDM_CTRL_TX_MSB_LSB_SHIFT;
+ } else {
+ val &= ~I2S_TDM_CTRL_RX_MSB_LSB_MASK;
+ val |= (msb_first) << I2S_TDM_CTRL_RX_MSB_LSB_SHIFT;
+ }
+ i2s_writel(ifc, val, I2S_TDM_CTRL_0);
+ return 0;
+}
+
+int i2s_tdm_set_tdm_edge_ctrl_highz(int ifc, int highz)
+{
+ u32 val;
+ check_ifc(ifc, -EINVAL);
+ val = i2s_readl(ifc, I2S_TDM_CTRL_0);
+ val &= ~I2S_TDM_CTRL_TDM_EDGE_CTRL_MASK;
+ val |= highz << I2S_TDM_CTRL_TDM_EDGE_CTRL_SHIFT;
+ i2s_writel(ifc, val, I2S_TDM_CTRL_0);
+ return 0;
+}
+
+int i2s_tdm_set_total_slots(int ifc, int total_slots)
+{
+ u32 val;
+ check_ifc(ifc, -EINVAL);
+ if (total_slots > 8 || total_slots < 1)
+ return -EINVAL;
+ val = i2s_readl(ifc, I2S_TDM_CTRL_0);
+ val &= ~I2S_TDM_CTRL_TOTAL_SLOTS_MASK;
+ val |= (total_slots - 1) << I2S_TDM_CTRL_TOTAL_SLOTS_SHIFT;
+ i2s_writel(ifc, val, I2S_TDM_CTRL_0);
+ return 0;
+}
+
+int i2s_tdm_set_tdm_bitsize(int ifc, int tdm_bitsize)
+{
+ u32 val;
+ check_ifc(ifc, -EINVAL);
+ if ((tdm_bitsize) & 3)
+ return -EINVAL;
+ val = i2s_readl(ifc, I2S_TDM_CTRL_0);
+ val &= ~I2S_TDM_CTRL_TDM_BIT_SIZE_MASK;
+ val |= (tdm_bitsize - 1) << I2S_TDM_CTRL_TDM_BIT_SIZE_SHIFT;
+ i2s_writel(ifc, val, I2S_TDM_CTRL_0);
+ return 0;
+}
+
+int i2s_tdm_set_data_offset(int ifc, int mode, int data_offset)
+{
+ u32 val;
+ check_ifc(ifc, -EINVAL);
+ if (data_offset < 0 || data_offset > 3)
+ return -EINVAL;
+ val = i2s_readl(ifc, I2S_TDM_CTRL_0);
+ if (mode == AUDIO_TX_MODE) {
+ val &= ~I2S_TDM_CTRL_TX_DATA_OFFSET_MASK;
+ val |= (data_offset) << I2S_TDM_CTRL_TX_DATA_OFFSET_SHIFT;
+ } else {
+ val &= ~I2S_TDM_CTRL_RX_DATA_OFFSET_MASK;
+ val |= (data_offset) << I2S_TDM_CTRL_RX_DATA_OFFSET_SHIFT;
+ }
+ i2s_writel(ifc, val, I2S_TDM_CTRL_0);
+ return 0;
+}
+
+int i2s_tdm_set_fsync_width(int ifc, int fsync_width)
+{
+ u32 val;
+ check_ifc(ifc, -EINVAL);
+ val = i2s_readl(ifc, I2S_TDM_CTRL_0);
+ val &= ~I2S_TDM_CTRL_FSYNC_WIDTH_MASK;
+ val |= (fsync_width - 1) << I2S_TDM_CTRL_FSYNC_WIDTH_SHIFT;
+ i2s_writel(ifc, val, I2S_TDM_CTRL_0);
+ return 0;
+}
+
+int i2s_tdm_set_transfer(int ifc, int mode , int on)
+{
+ u32 val;
+ struct i2s_controller_info *info;
+ check_ifc(ifc, -EINVAL);
+
+ info = &i2s_cont_info[ifc];
+ if (on)
+ i2s_fifo_set_attention_level(ifc, mode ,
+ info->i2s_ch_prop[mode].fifo_attn);
+
+ val = i2s_readl(ifc, I2S_TDM_TX_RX_CTRL_0);
+
+ if (mode == AUDIO_TX_MODE) {
+ val &= ~I2S_TDM_TX_RX_CTRL_TDM_TX_EN;
+ val |= on ? I2S_TDM_TX_RX_CTRL_TDM_TX_EN : 0;
+ } else {
+ val &= ~I2S_TDM_TX_RX_CTRL_TDM_RX_EN;
+ val |= on ? I2S_TDM_TX_RX_CTRL_TDM_RX_EN : 0;
+ }
+ i2s_writel(ifc, val, I2S_TDM_TX_RX_CTRL_0);
+
+ return 0;
+}
+
+int i2s_tdm_set_slot_enables(int ifc, int mode, int slot_mask)
+{
+ u32 val;
+ check_ifc(ifc, -EINVAL);
+ val = i2s_readl(ifc, I2S_TDM_TX_RX_CTRL_0);
+
+ if (mode == AUDIO_TX_MODE) {
+ val &= ~I2S_TDM_TX_RX_CTRL_TDM_RX_SLOT_ENABLES_MASK;
+ val |= (slot_mask) << \
+ I2S_TDM_TX_RX_CTRL_TDM_RX_SLOT_ENABLES_SHIFT;
+ } else {
+ val &= ~I2S_TDM_TX_RX_CTRL_TDM_TX_SLOT_ENABLES_MASK;
+ val |= (slot_mask) << \
+ I2S_TDM_TX_RX_CTRL_TDM_TX_SLOT_ENABLES_SHIFT;
+ }
+ i2s_writel(ifc, val, I2S_TDM_TX_RX_CTRL_0);
+ return 0;
+}
+
+u32 i2s_tdm_get_status(int ifc , int mode)
+{
+ u32 val;
+ check_ifc(ifc, 0);
+ val = i2s_readl(ifc, I2S_TDM_TX_RX_CTRL_0);
+
+ if (mode == AUDIO_TX_MODE)
+ val &= I2S_TDM_TX_FIFO_BUSY;
+ else
+ val &= I2S_TDM_RX_FIFO_BUSY;
+
+ return val;
+}
+
+int i2s_tdm_set_fifo_attention(int ifc, int fifo_mode, int bitsize)
+{
+ int fifoattn;
+ struct i2s_controller_info *info = &i2s_cont_info[ifc];
+
+ switch (info->i2sprop.total_slots) {
+ case 1:
+ fifoattn = I2S_FIFO_ATN_LVL_ONE_SLOT;
+ break;
+ case 4:
+ fifoattn = I2S_FIFO_ATN_LVL_FOUR_SLOTS;
+ break;
+ case 8:
+ fifoattn = I2S_FIFO_ATN_LVL_EIGHT_SLOTS;
+ break;
+ default:
+ fifoattn = I2S_FIFO_ATN_LVL_FOUR_SLOTS;
+ }
+ info->i2s_ch_prop[fifo_mode].fifo_attn = fifoattn;
+ return 0;
+}
struct clk *i2s_get_clock_by_name(const char *name)
{
- return tegra_get_clock_by_name(name);
+ return tegra_get_clock_by_name(name);
}
int i2s_free_dma_requestor(int ifc, int fifo)
@@ -707,11 +903,32 @@ int i2s_init(int ifc, struct tegra_i2s_property* pi2sprop)
i2s_set_bit_size(ifc, pi2sprop->bit_size);
i2s_set_fifo_format(ifc, pi2sprop->fifo_fmt);
+ if (info->i2sprop.audio_mode == AUDIO_FRAME_FORMAT_TDM)
+ i2s_tdm_init(ifc, pi2sprop);
+
i2s_clock_disable(ifc, 0);
return 0;
}
+int i2s_tdm_init(int ifc, struct tegra_i2s_property *pi2sprop)
+{
+
+ /* Set the TDM controller specific registers */
+ i2s_tdm_enable(ifc);
+ i2s_tdm_set_msb_first(ifc, AUDIO_TX_MODE, 0); /* MSB_FIRST */
+ i2s_tdm_set_msb_first(ifc, AUDIO_RX_MODE, 0); /* MSB_FIRST */
+ i2s_tdm_set_tdm_edge_ctrl_highz(ifc, 0); /* NO_HIGHZ */
+ i2s_tdm_set_total_slots(ifc, pi2sprop->total_slots);
+ i2s_tdm_set_tdm_bitsize(ifc, pi2sprop->tdm_bitsize);
+ i2s_tdm_set_data_offset(ifc, AUDIO_TX_MODE, pi2sprop->rx_bit_offset);
+ i2s_tdm_set_data_offset(ifc, AUDIO_RX_MODE, pi2sprop->tx_bit_offset);
+ i2s_tdm_set_fsync_width(ifc, pi2sprop->fsync_width);
+ i2s_tdm_set_slot_enables(ifc, AUDIO_TX_MODE, pi2sprop->tx_slot_enables);
+ i2s_tdm_set_slot_enables(ifc, AUDIO_RX_MODE, pi2sprop->rx_slot_enables);
+
+ return 0;
+}
int i2s_clock_enable(int ifc, int fifo_mode)
{