summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorSumit Bhattacharya <sumitb@nvidia.com>2011-03-10 04:14:03 +0530
committerVarun Colbert <vcolbert@nvidia.com>2011-03-17 21:40:28 -0800
commite0677a9398abde4739071e1092f577bdc97efae6 (patch)
treeb4f5ffcbec07b254e0bfea42594dc3a9ff03fd08 /arch
parent769ff2f06c1747487e51a8e878ed08bf9226bfca (diff)
[ARM] tegra: Integrate spdif driver with ALSA
Bug 783013 Bug 788021 Change-Id: Ib49c50be4db1ad8266dbb7f456d700d9e6328ae9 Reviewed-on: http://git-master/r/22328 Tested-by: Sumit Bhattacharya <sumitb@nvidia.com> Reviewed-by: Scott Peterson <speterson@nvidia.com> Reviewed-by: Vijay Mali <vmali@nvidia.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-tegra/Makefile3
-rw-r--r--arch/arm/mach-tegra/board-ventana.c6
-rw-r--r--arch/arm/mach-tegra/board-whistler.c8
-rw-r--r--arch/arm/mach-tegra/include/mach/audio.h4
-rw-r--r--arch/arm/mach-tegra/include/mach/spdif.h41
-rw-r--r--arch/arm/mach-tegra/spdif.c286
-rw-r--r--arch/arm/mach-tegra/tegra_spdif_audio.c201
7 files changed, 352 insertions, 197 deletions
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
index 621f7493ebb3..970c431da188 100644
--- a/arch/arm/mach-tegra/Makefile
+++ b/arch/arm/mach-tegra/Makefile
@@ -18,8 +18,9 @@ ifeq ($(CONFIG_TEGRA_ALSA),y)
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_i2s.o
else
obj-y += tegra_i2s_audio.o
-endif
obj-y += tegra_spdif_audio.o
+endif
+obj-y += spdif.o
obj-y += tegra_das.o
obj-y += mc.o
obj-$(CONFIG_USB_SUPPORT) += usb_phy.o
diff --git a/arch/arm/mach-tegra/board-ventana.c b/arch/arm/mach-tegra/board-ventana.c
index fbd7c205fb2e..c2729f2b4567 100644
--- a/arch/arm/mach-tegra/board-ventana.c
+++ b/arch/arm/mach-tegra/board-ventana.c
@@ -108,9 +108,7 @@ static struct platform_device debug_uart = {
static struct tegra_audio_platform_data tegra_spdif_pdata = {
.dma_on = true, /* use dma by default */
- .i2s_clk_rate = 5644800,
- .mode = SPDIF_BIT_MODE_MODE16BIT,
- .fifo_fmt = 0,
+ .spdif_clk_rate = 5644800,
};
static struct tegra_utmip_config utmi_phy_config[] = {
@@ -408,7 +406,7 @@ static struct tegra_audio_platform_data tegra_audio_pdata[] = {
.i2s_master = true,
.dma_on = true, /* use dma by default */
.i2s_master_clk = 44100,
- .i2s_clk_rate = 240000000,
+ .i2s_clk_rate = 11289600,
.dap_clk = "clk_dev1",
.audio_sync_clk = "audio_2x",
.mode = I2S_BIT_FORMAT_I2S,
diff --git a/arch/arm/mach-tegra/board-whistler.c b/arch/arm/mach-tegra/board-whistler.c
index 464fe2afdb9d..748d6e50788e 100644
--- a/arch/arm/mach-tegra/board-whistler.c
+++ b/arch/arm/mach-tegra/board-whistler.c
@@ -45,6 +45,7 @@
#include <mach/iomap.h>
#include <mach/io.h>
#include <mach/i2s.h>
+#include <mach/spdif.h>
#include <mach/audio.h>
#include <asm/mach-types.h>
@@ -147,6 +148,7 @@ static __initdata struct tegra_clk_init_table whistler_clk_init_table[] = {
{ "i2s2", "pll_a_out0", 11289600, true},
{ "audio", "pll_a_out0", 11289600, true},
{ "audio_2x", "audio", 22579200, true},
+ { "spdif_out", "pll_a_out0", 5644800, false},
{ "sdmmc2", "pll_p", 25000000, false},
{ NULL, NULL, 0, 0},
};
@@ -307,6 +309,10 @@ static void whistler_i2c_init(void)
platform_device_register(&tegra_i2c_device1);
}
+static struct tegra_audio_platform_data tegra_spdif_pdata = {
+ .dma_on = true, /* use dma by default */
+ .spdif_clk_rate = 5644800,
+};
static struct tegra_audio_platform_data tegra_audio_pdata[] = {
/* For I2S1 */
@@ -391,6 +397,7 @@ static struct platform_device *whistler_devices[] __initdata = {
&tegra_camera,
&tegra_i2s_device1,
&tegra_i2s_device2,
+ &tegra_spdif_device,
&tegra_das_device,
};
@@ -549,6 +556,7 @@ static void __init tegra_whistler_init(void)
andusb_plat.serial_number = kstrdup(serial, GFP_KERNEL);
tegra_i2s_device1.dev.platform_data = &tegra_audio_pdata[0];
tegra_i2s_device2.dev.platform_data = &tegra_audio_pdata[1];
+ tegra_spdif_device.dev.platform_data = &tegra_spdif_pdata;
platform_add_devices(whistler_devices, ARRAY_SIZE(whistler_devices));
tegra_das_device.dev.platform_data = &tegra_das_pdata;
diff --git a/arch/arm/mach-tegra/include/mach/audio.h b/arch/arm/mach-tegra/include/mach/audio.h
index 67951fe26379..05c849f7628a 100644
--- a/arch/arm/mach-tegra/include/mach/audio.h
+++ b/arch/arm/mach-tegra/include/mach/audio.h
@@ -34,6 +34,9 @@
#define TEGRA_AUDIO_ENABLE_TX 1
#define TEGRA_AUDIO_ENABLE_RX 2
+#define AUDIO_TX_MODE 1
+#define AUDIO_RX_MODE 2
+
struct tegra_audio_platform_data {
bool i2s_master;
bool dsp_master;
@@ -41,6 +44,7 @@ struct tegra_audio_platform_data {
int dsp_master_clk; /* When DSP mode and master, the framesync rate. */
bool dma_on;
unsigned long i2s_clk_rate;
+ unsigned long spdif_clk_rate;
const char *dap_clk;
const char *audio_sync_clk;
diff --git a/arch/arm/mach-tegra/include/mach/spdif.h b/arch/arm/mach-tegra/include/mach/spdif.h
index 96103fae91b1..2ccfc9f861f6 100644
--- a/arch/arm/mach-tegra/include/mach/spdif.h
+++ b/arch/arm/mach-tegra/include/mach/spdif.h
@@ -389,4 +389,45 @@
((0x1f) << SPDIF_DATA_FIFO_CSR_0_TD_EMPTY_COUNT_SHIFT)
+struct spdif_regs_cache {
+ int spdif_ctrl_0;
+ int spdif_status_0;
+ int spdif_strobe_ctrl_0;
+ int spdif_data_fifo_scr_0;
+ int spdif_ch_sta_rx_a_0;
+ int spdif_ch_sta_rx_b_0;
+ int spdif_ch_sta_rx_c_0;
+ int spdif_ch_sta_rx_d_0;
+ int spdif_ch_sta_rx_e_0;
+ int spdif_ch_sta_rx_f_0;
+ int spdif_ch_sta_tx_a_0;
+ int spdif_ch_sta_tx_b_0;
+ int spdif_ch_sta_tx_c_0;
+ int spdif_ch_sta_tx_d_0;
+ int spdif_ch_sta_tx_e_0;
+ int spdif_ch_sta_tx_f_0;
+ int spdif_usr_sta_rx_a_0;
+ int spdif_usr_dat_tx_a_0;
+};
+
+/* spdif apis */
+void spdif_fifo_enable(unsigned long base, int mode, int on);
+int spdif_set_bit_mode(unsigned long base, unsigned mode);
+int spdif_set_fifo_packed(unsigned long base, unsigned on);
+int spdif_set_sample_rate(unsigned long base, unsigned int sample_rate);
+void spdif_fifo_write(unsigned long base, int mode, u32 data);
+int spdif_fifo_set_attention_level(unsigned long base,
+ int mode,
+ unsigned int level);
+void spdif_fifo_clear(unsigned long base, int mode);
+u32 spdif_get_status(unsigned long base);
+u32 spdif_get_control(unsigned long base);
+void spdif_ack_status(unsigned long base);
+u32 spdif_get_fifo_scr(unsigned long base);
+phys_addr_t spdif_get_fifo_phy_base(phys_addr_t phy_base, int mode);
+u32 spdif_get_fifo_full_empty_count(unsigned long base, int mode);
+int spdif_initialize(unsigned long base, int mode);
+void spdif_get_all_regs(unsigned long base, struct spdif_regs_cache* regs);
+void spdif_set_all_regs(unsigned long base, struct spdif_regs_cache* regs);
+
#endif /* __ARCH_ARM_MACH_TEGRA_SPDIF_H */
diff --git a/arch/arm/mach-tegra/spdif.c b/arch/arm/mach-tegra/spdif.c
new file mode 100644
index 000000000000..c01829e708de
--- /dev/null
+++ b/arch/arm/mach-tegra/spdif.c
@@ -0,0 +1,286 @@
+/*
+ * arch/arm/mach-tegra/spdif.c
+ *
+ * S/PDIF audio driver
+ *
+ * Copyright (c) 2011, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <mach/iomap.h>
+#include <mach/spdif.h>
+#include <mach/audio.h>
+#include <mach/dma.h>
+
+#define ENABLE_SPDIF_DEBUG_PRINT 0
+#if ENABLE_SPDIF_DEBUG_PRINT
+#define SPDIF_DEBUG_PRINT(fmt, arg...) printk(fmt, ## arg)
+#else
+#define SPDIF_DEBUG_PRINT(fmt, arg...) do {} while (0)
+#endif
+
+static inline void spdif_writel(unsigned long base, u32 val, u32 reg)
+{
+ SPDIF_DEBUG_PRINT("Spdif Write 0x%lx : %08x\n",base + reg, val);
+ writel(val, base + reg);
+}
+
+static inline u32 spdif_readl(unsigned long base, u32 reg)
+{
+ u32 val = readl(base + reg);
+ SPDIF_DEBUG_PRINT("Spdif Read 0x%lx : %08x\n",base + reg, val);
+ return val;
+}
+
+void spdif_fifo_enable(unsigned long base, int mode, int on)
+{
+ u32 val = spdif_readl(base, SPDIF_CTRL_0);
+
+ if (mode == AUDIO_TX_MODE)
+ {
+ val &= ~(SPDIF_CTRL_0_TU_EN | SPDIF_CTRL_0_TC_EN | SPDIF_CTRL_0_TX_EN);
+ val |= on ? (SPDIF_CTRL_0_TX_EN) : 0;
+ val |= on ? (SPDIF_CTRL_0_TC_EN) : 0;
+ }
+ if (mode == AUDIO_RX_MODE)
+ {
+ val &= ~SPDIF_CTRL_0_RX_EN;
+ val |= on ? (SPDIF_CTRL_0_RX_EN) : 0;
+ }
+
+ spdif_writel(base, val, SPDIF_CTRL_0);
+}
+
+int spdif_set_bit_mode(unsigned long base, unsigned mode)
+{
+ u32 val = spdif_readl(base, SPDIF_CTRL_0);
+ val &= ~SPDIF_CTRL_0_BIT_MODE_MASK;
+
+ if (mode > SPDIF_BIT_MODE_MODERAW) {
+ pr_err("%s: invalid bit_size selector %d\n", __func__,
+ mode);
+ return -EINVAL;
+ }
+
+ val |= mode << SPDIF_CTRL_0_BIT_MODE_SHIFT;
+
+ spdif_writel(base, val, SPDIF_CTRL_0);
+ return 0;
+}
+
+int spdif_set_sample_rate(unsigned long base, unsigned int sample_rate)
+{
+ unsigned int ch_sta[] = {
+ 0x0, /* 44.1, default values */
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ };
+
+ switch (sample_rate) {
+ case 32000:
+ ch_sta[0] = 0x3 << 24;
+ ch_sta[1] = 0xC << 4;
+ break;
+ case 44100:
+ ch_sta[0] = 0x0;
+ ch_sta[1] = 0xF << 4;
+ break;
+ case 48000:
+ ch_sta[0] = 0x2 << 24;
+ ch_sta[1] = 0xD << 4;
+ break;
+ case 88200:
+ case 96000:
+ case 176400:
+ case 192000:
+ break;
+ default:
+ return -1;
+ }
+
+ spdif_writel(base, ch_sta[0], SPDIF_CH_STA_TX_A_0);
+ spdif_writel(base, ch_sta[1], SPDIF_CH_STA_TX_B_0);
+ spdif_writel(base, ch_sta[2], SPDIF_CH_STA_TX_C_0);
+ spdif_writel(base, ch_sta[3], SPDIF_CH_STA_TX_D_0);
+ spdif_writel(base, ch_sta[4], SPDIF_CH_STA_TX_E_0);
+ spdif_writel(base, ch_sta[5], SPDIF_CH_STA_TX_F_0);
+
+ return 0;
+}
+
+u32 spdif_get_control(unsigned long base)
+{
+ return spdif_readl(base, SPDIF_CTRL_0);
+}
+
+void spdif_fifo_write(unsigned long base, int mode, u32 data)
+{
+ if (mode == AUDIO_TX_MODE)
+ {
+ spdif_writel(base, data, SPDIF_DATA_OUT_0);
+ }
+ if (mode == AUDIO_RX_MODE)
+ {
+ spdif_writel(base, data, SPDIF_DATA_IN_0);
+ }
+}
+
+int spdif_fifo_set_attention_level(unsigned long base, int mode,
+ unsigned level)
+{
+ u32 val;
+
+ if (level > SPDIF_FIFO_ATN_LVL_TWELVE_SLOTS) {
+ pr_err("%s: invalid fifo level selector %d\n", __func__,
+ level);
+ return -EINVAL;
+ }
+
+ val = spdif_readl(base, SPDIF_DATA_FIFO_CSR_0);
+
+ if (mode == AUDIO_TX_MODE)
+ {
+ val &= ~SPDIF_DATA_FIFO_CSR_0_TX_ATN_LVL_MASK;
+ val |= level << SPDIF_DATA_FIFO_CSR_0_TX_ATN_LVL_SHIFT;
+ }
+
+ spdif_writel(base, val, SPDIF_DATA_FIFO_CSR_0);
+ return 0;
+}
+
+void spdif_fifo_clear(unsigned long base, int mode)
+{
+ u32 val = spdif_readl(base, SPDIF_DATA_FIFO_CSR_0);
+ if (mode == AUDIO_TX_MODE)
+ {
+ val &= ~(SPDIF_DATA_FIFO_CSR_0_TX_CLR | SPDIF_DATA_FIFO_CSR_0_TU_CLR);
+ val |= SPDIF_DATA_FIFO_CSR_0_TX_CLR | SPDIF_DATA_FIFO_CSR_0_TU_CLR;
+ }
+ spdif_writel(base, val, SPDIF_DATA_FIFO_CSR_0);
+}
+
+int spdif_set_fifo_packed(unsigned long base, unsigned on)
+{
+ u32 val = spdif_readl(base, SPDIF_CTRL_0);
+
+ val &= ~SPDIF_CTRL_0_PACK;
+ val |= on ? (SPDIF_CTRL_0_PACK) : 0;
+ spdif_writel(base, val, SPDIF_CTRL_0);
+ return 0;
+}
+
+u32 spdif_get_status(unsigned long base)
+{
+ return spdif_readl(base, SPDIF_STATUS_0);
+}
+
+void spdif_ack_status(unsigned long base)
+{
+ return spdif_writel(base, spdif_readl(base, SPDIF_STATUS_0),
+ SPDIF_STATUS_0);
+}
+
+u32 spdif_get_fifo_scr(unsigned long base)
+{
+ return spdif_readl(base, SPDIF_DATA_FIFO_CSR_0);
+}
+
+phys_addr_t spdif_get_fifo_phy_base(phys_addr_t phy_base, int mode)
+{
+ if (mode == AUDIO_TX_MODE)
+ return phy_base + SPDIF_DATA_OUT_0;
+ else
+ return phy_base + SPDIF_DATA_IN_0;
+}
+
+u32 spdif_get_fifo_full_empty_count(unsigned long base, int mode)
+{
+ u32 val = spdif_readl(base, SPDIF_DATA_FIFO_CSR_0);
+
+ if (mode == AUDIO_TX_MODE)
+ {
+ val = val >> SPDIF_DATA_FIFO_CSR_0_TD_EMPTY_COUNT_SHIFT;
+ return val & SPDIF_DATA_FIFO_CSR_0_TD_EMPTY_COUNT_MASK;
+ }
+
+ return 0;
+}
+
+int spdif_initialize(unsigned long base, int mode)
+{
+ /* disable interrupts from SPDIF */
+ spdif_writel(base, 0x0, SPDIF_CTRL_0);
+ spdif_fifo_clear(base, mode);
+ spdif_fifo_enable(base, mode, 0);
+
+ spdif_set_bit_mode(base, SPDIF_BIT_MODE_MODE16BIT);
+ spdif_set_fifo_packed(base, 1);
+
+ spdif_set_sample_rate(base, 44100);
+
+ return 0;
+}
+
+void spdif_get_all_regs(unsigned long base, struct spdif_regs_cache* regs)
+{
+ regs->spdif_ctrl_0 = spdif_readl(base, SPDIF_CTRL_0);
+ regs->spdif_status_0 = spdif_readl(base, SPDIF_STATUS_0);
+ regs->spdif_strobe_ctrl_0 = spdif_readl(base, SPDIF_STROBE_CTRL_0);
+ regs->spdif_data_fifo_scr_0 = spdif_readl(base, SPDIF_DATA_FIFO_CSR_0);
+ regs->spdif_ch_sta_rx_a_0 = spdif_readl(base, SPDIF_CH_STA_RX_A_0);
+ regs->spdif_ch_sta_rx_b_0 = spdif_readl(base, SPDIF_CH_STA_RX_B_0);
+ regs->spdif_ch_sta_rx_c_0 = spdif_readl(base, SPDIF_CH_STA_RX_C_0);
+ regs->spdif_ch_sta_rx_d_0 = spdif_readl(base, SPDIF_CH_STA_RX_D_0);
+ regs->spdif_ch_sta_rx_e_0 = spdif_readl(base, SPDIF_CH_STA_RX_E_0);
+ regs->spdif_ch_sta_rx_f_0 = spdif_readl(base, SPDIF_CH_STA_RX_F_0);
+ regs->spdif_ch_sta_tx_a_0 = spdif_readl(base, SPDIF_CH_STA_TX_A_0);
+ regs->spdif_ch_sta_tx_b_0 = spdif_readl(base, SPDIF_CH_STA_TX_B_0);
+ regs->spdif_ch_sta_tx_c_0 = spdif_readl(base, SPDIF_CH_STA_TX_C_0);
+ regs->spdif_ch_sta_tx_d_0 = spdif_readl(base, SPDIF_CH_STA_TX_D_0);
+ regs->spdif_ch_sta_tx_e_0 = spdif_readl(base, SPDIF_CH_STA_TX_E_0);
+ regs->spdif_ch_sta_tx_f_0 = spdif_readl(base, SPDIF_CH_STA_TX_F_0);
+ regs->spdif_usr_sta_rx_a_0 = spdif_readl(base, SPDIF_USR_STA_RX_A_0);
+ regs->spdif_usr_dat_tx_a_0 = spdif_readl(base, SPDIF_USR_DAT_TX_A_0);
+}
+
+void spdif_set_all_regs(unsigned long base, struct spdif_regs_cache* regs)
+{
+ spdif_writel(base, regs->spdif_ctrl_0, SPDIF_CTRL_0);
+ spdif_writel(base, regs->spdif_status_0, SPDIF_STATUS_0);
+ spdif_writel(base, regs->spdif_strobe_ctrl_0, SPDIF_STROBE_CTRL_0);
+ spdif_writel(base, regs->spdif_data_fifo_scr_0, SPDIF_DATA_FIFO_CSR_0);
+ spdif_writel(base, regs->spdif_ch_sta_rx_a_0, SPDIF_CH_STA_RX_A_0);
+ spdif_writel(base, regs->spdif_ch_sta_rx_b_0, SPDIF_CH_STA_RX_B_0);
+ spdif_writel(base, regs->spdif_ch_sta_rx_c_0, SPDIF_CH_STA_RX_C_0);
+ spdif_writel(base, regs->spdif_ch_sta_rx_d_0, SPDIF_CH_STA_RX_D_0);
+ spdif_writel(base, regs->spdif_ch_sta_rx_e_0, SPDIF_CH_STA_RX_E_0);
+ spdif_writel(base, regs->spdif_ch_sta_rx_f_0, SPDIF_CH_STA_RX_F_0);
+ spdif_writel(base, regs->spdif_ch_sta_tx_a_0, SPDIF_CH_STA_TX_A_0);
+ spdif_writel(base, regs->spdif_ch_sta_tx_b_0, SPDIF_CH_STA_TX_B_0);
+ spdif_writel(base, regs->spdif_ch_sta_tx_c_0, SPDIF_CH_STA_TX_C_0);
+ spdif_writel(base, regs->spdif_ch_sta_tx_d_0, SPDIF_CH_STA_TX_D_0);
+ spdif_writel(base, regs->spdif_ch_sta_tx_e_0, SPDIF_CH_STA_TX_E_0);
+ spdif_writel(base, regs->spdif_ch_sta_tx_f_0, SPDIF_CH_STA_TX_F_0);
+ spdif_writel(base, regs->spdif_usr_sta_rx_a_0, SPDIF_USR_STA_RX_A_0);
+ spdif_writel(base, regs->spdif_usr_dat_tx_a_0, SPDIF_USR_DAT_TX_A_0);
+}
diff --git a/arch/arm/mach-tegra/tegra_spdif_audio.c b/arch/arm/mach-tegra/tegra_spdif_audio.c
index 6613d3d5edeb..d2bbc03a0a9e 100644
--- a/arch/arm/mach-tegra/tegra_spdif_audio.c
+++ b/arch/arm/mach-tegra/tegra_spdif_audio.c
@@ -166,193 +166,21 @@ static inline void allow_suspend(struct audio_stream *as)
schedule_work(&as->allow_suspend_work);
}
-#define I2S_I2S_FIFO_TX_BUSY I2S_I2S_STATUS_FIFO1_BSY
-#define I2S_I2S_FIFO_TX_QS I2S_I2S_STATUS_QS_FIFO1
-#define I2S_I2S_FIFO_TX_ERR I2S_I2S_STATUS_FIFO1_ERR
-
-#define I2S_I2S_FIFO_RX_BUSY I2S_I2S_STATUS_FIFO2_BSY
-#define I2S_I2S_FIFO_RX_QS I2S_I2S_STATUS_QS_FIFO2
-#define I2S_I2S_FIFO_RX_ERR I2S_I2S_STATUS_FIFO2_ERR
-
-#define I2S_FIFO_ERR (I2S_I2S_STATUS_FIFO1_ERR | I2S_I2S_STATUS_FIFO2_ERR)
-
-
-static inline void spdif_writel(unsigned long base, u32 val, u32 reg)
-{
- writel(val, base + reg);
-}
-
-static inline u32 spdif_readl(unsigned long base, u32 reg)
-{
- return readl(base + reg);
-}
-
-static inline void spdif_fifo_write(unsigned long base, u32 data)
-{
- spdif_writel(base, data, SPDIF_DATA_OUT_0);
-}
-
-static int spdif_fifo_set_attention_level(unsigned long base,
- unsigned level)
-{
- u32 val;
-
- if (level > SPDIF_FIFO_ATN_LVL_TWELVE_SLOTS) {
- pr_err("%s: invalid fifo level selector %d\n", __func__,
- level);
- return -EINVAL;
- }
-
- val = spdif_readl(base, SPDIF_DATA_FIFO_CSR_0);
-
- val &= ~SPDIF_DATA_FIFO_CSR_0_TX_ATN_LVL_MASK;
- val |= level << SPDIF_DATA_FIFO_CSR_0_TX_ATN_LVL_SHIFT;
-
-
- spdif_writel(base, val, SPDIF_DATA_FIFO_CSR_0);
- return 0;
-}
-
-static void spdif_fifo_enable(unsigned long base, int on)
-{
- u32 val = spdif_readl(base, SPDIF_CTRL_0);
- val &= ~(SPDIF_CTRL_0_TX_EN | SPDIF_CTRL_0_TC_EN | SPDIF_CTRL_0_TU_EN);
- val |= on ? (SPDIF_CTRL_0_TX_EN) : 0;
- val |= on ? (SPDIF_CTRL_0_TC_EN) : 0;
-
- spdif_writel(base, val, SPDIF_CTRL_0);
-}
-#if 0
-static bool spdif_is_fifo_enabled(unsigned long base)
-{
- u32 val = spdif_readl(base, SPDIF_CTRL_0);
- return !!(val & SPDIF_CTRL_0_TX_EN);
-}
-#endif
-
-static void spdif_fifo_clear(unsigned long base)
-{
- u32 val = spdif_readl(base, SPDIF_DATA_FIFO_CSR_0);
- val &= ~(SPDIF_DATA_FIFO_CSR_0_TX_CLR | SPDIF_DATA_FIFO_CSR_0_TU_CLR);
- val |= SPDIF_DATA_FIFO_CSR_0_TX_CLR | SPDIF_DATA_FIFO_CSR_0_TU_CLR;
- spdif_writel(base, val, SPDIF_DATA_FIFO_CSR_0);
-}
-
-
-static int spdif_set_bit_mode(unsigned long base, unsigned mode)
-{
- u32 val = spdif_readl(base, SPDIF_CTRL_0);
- val &= ~SPDIF_CTRL_0_BIT_MODE_MASK;
-
- if (mode > SPDIF_BIT_MODE_MODERAW) {
- pr_err("%s: invalid bit_size selector %d\n", __func__,
- mode);
- return -EINVAL;
- }
-
- val |= mode << SPDIF_CTRL_0_BIT_MODE_SHIFT;
-
- spdif_writel(base, val, SPDIF_CTRL_0);
- return 0;
-}
-
-static int spdif_set_fifo_packed(unsigned long base, unsigned on)
-{
- u32 val = spdif_readl(base, SPDIF_CTRL_0);
- val &= ~SPDIF_CTRL_0_PACK;
- val |= on ? SPDIF_CTRL_0_PACK : 0;
- spdif_writel(base, val, SPDIF_CTRL_0);
- return 0;
-}
-
-#if 0
-static void spdif_set_fifo_irq_on_err(unsigned long base, int on)
-{
- u32 val = spdif_readl(base, SPDIF_CTRL_0);
- val &= ~SPDIF_CTRL_0_IE_TXE;
- val |= on ? SPDIF_CTRL_0_IE_TXE : 0;
- spdif_writel(base, val, SPDIF_CTRL_0);
-}
-#endif
-
-
-static void spdif_enable_fifos(unsigned long base, int on)
-{
- u32 val = spdif_readl(base, SPDIF_CTRL_0);
- if (on)
- val |= SPDIF_CTRL_0_TX_EN | SPDIF_CTRL_0_TC_EN |
- SPDIF_CTRL_0_IE_TXE;
- else
- val &= ~(SPDIF_CTRL_0_TX_EN | SPDIF_CTRL_0_TC_EN |
- SPDIF_CTRL_0_IE_TXE);
-
- spdif_writel(base, val, SPDIF_CTRL_0);
-}
-
-static inline u32 spdif_get_status(unsigned long base)
-{
- return spdif_readl(base, SPDIF_STATUS_0);
-}
-
-static inline u32 spdif_get_control(unsigned long base)
-{
- return spdif_readl(base, SPDIF_CTRL_0);
-}
-
-static inline void spdif_ack_status(unsigned long base)
-{
- return spdif_writel(base, spdif_readl(base, SPDIF_STATUS_0),
- SPDIF_STATUS_0);
-}
-
-static inline u32 spdif_get_fifo_scr(unsigned long base)
-{
- return spdif_readl(base, SPDIF_DATA_FIFO_CSR_0);
-}
-
-static inline phys_addr_t spdif_get_fifo_phy_base(unsigned long phy_base)
-{
- return phy_base + SPDIF_DATA_OUT_0;
-}
-
-static inline u32 spdif_get_fifo_full_empty_count(unsigned long base)
-{
- u32 val = spdif_readl(base, SPDIF_DATA_FIFO_CSR_0);
- val = val >> SPDIF_DATA_FIFO_CSR_0_TD_EMPTY_COUNT_SHIFT;
- return val & SPDIF_DATA_FIFO_CSR_0_TD_EMPTY_COUNT_MASK;
-}
-
-
-static int spdif_set_sample_rate(struct audio_driver_state *state,
+static int set_spdif_clock(struct audio_driver_state *state,
unsigned int sample_rate)
{
unsigned int clock_freq = 0;
struct clk *spdif_clk;
- unsigned int ch_sta[] = {
- 0x0, /* 44.1, default values */
- 0x0,
- 0x0,
- 0x0,
- 0x0,
- 0x0,
- };
-
switch (sample_rate) {
case 32000:
clock_freq = 4096000; /* 4.0960 MHz */
- ch_sta[0] = 0x3 << 24;
- ch_sta[1] = 0xC << 4;
break;
case 44100:
clock_freq = 5644800; /* 5.6448 MHz */
- ch_sta[0] = 0x0;
- ch_sta[1] = 0xF << 4;
break;
case 48000:
clock_freq = 6144000; /* 6.1440MHz */
- ch_sta[0] = 0x2 << 24;
- ch_sta[1] = 0xD << 4;
break;
case 88200:
clock_freq = 11289600; /* 11.2896 MHz */
@@ -385,13 +213,6 @@ static int spdif_set_sample_rate(struct audio_driver_state *state,
}
pr_info("%s: spdif_clk rate %ld\n", __func__, clk_get_rate(spdif_clk));
- spdif_writel(state->spdif_base, ch_sta[0], SPDIF_CH_STA_TX_A_0);
- spdif_writel(state->spdif_base, ch_sta[1], SPDIF_CH_STA_TX_B_0);
- spdif_writel(state->spdif_base, ch_sta[2], SPDIF_CH_STA_TX_C_0);
- spdif_writel(state->spdif_base, ch_sta[3], SPDIF_CH_STA_TX_D_0);
- spdif_writel(state->spdif_base, ch_sta[4], SPDIF_CH_STA_TX_E_0);
- spdif_writel(state->spdif_base, ch_sta[5], SPDIF_CH_STA_TX_F_0);
-
return 0;
}
@@ -565,7 +386,7 @@ static void setup_dma_tx_request(struct tegra_dma_req *req,
req->complete = dma_tx_complete_callback;
req->dev = aos;
req->to_memory = false;
- req->dest_addr = spdif_get_fifo_phy_base(ads->spdif_phys);
+ req->dest_addr = spdif_get_fifo_phy_base(ads->spdif_phys, AUDIO_TX_MODE);
req->dest_bus_width = 32;
req->dest_wrap = 4;
req->source_wrap = 0;
@@ -590,6 +411,7 @@ static int start_playback(struct audio_stream *aos,
#endif
spdif_fifo_set_attention_level(ads->spdif_base,
+ AUDIO_TX_MODE,
ads->out.spdif_fifo_atn_level);
if (ads->fifo_init) {
@@ -598,7 +420,7 @@ static int start_playback(struct audio_stream *aos,
ads->fifo_init = false;
}
- spdif_fifo_enable(ads->spdif_base, 1);
+ spdif_fifo_enable(ads->spdif_base, AUDIO_TX_MODE, 1);
rc = tegra_dma_enqueue_req(aos->dma_chan, req);
spin_unlock_irqrestore(&aos->dma_req_lock, flags);
@@ -614,7 +436,7 @@ static void stop_dma_playback(struct audio_stream *aos)
int spin = 0;
struct audio_driver_state *ads = ads_from_out(aos);
pr_debug("%s\n", __func__);
- spdif_fifo_enable(ads->spdif_base, 0);
+ spdif_fifo_enable(ads->spdif_base, AUDIO_TX_MODE, 0);
while ((spdif_get_status(ads->spdif_base) & SPDIF_STATUS_0_TX_BSY) &&
spin < 100) {
udelay(10);
@@ -627,7 +449,6 @@ static void stop_dma_playback(struct audio_stream *aos)
}
-
static irqreturn_t spdif_interrupt(int irq, void *data)
{
struct audio_driver_state *ads = data;
@@ -1017,18 +838,14 @@ static int spdif_configure(struct platform_device *pdev)
if (!state)
return -ENOMEM;
- /* disable interrupts from SPDIF */
- spdif_writel(state->spdif_base, 0x0, SPDIF_CTRL_0);
- spdif_fifo_clear(state->spdif_base);
- spdif_enable_fifos(state->spdif_base, 0);
+ set_spdif_clock(state, 44100);
- spdif_set_bit_mode(state->spdif_base, SPDIF_BIT_MODE_MODE16BIT);
- spdif_set_fifo_packed(state->spdif_base, 1);
+ spdif_initialize(state->spdif_base, AUDIO_TX_MODE);
- spdif_fifo_set_attention_level(state->spdif_base,
+ spdif_fifo_set_attention_level(state->spdif_base, AUDIO_TX_MODE,
state->out.spdif_fifo_atn_level);
- spdif_set_sample_rate(state, 44100);
+ spdif_set_sample_rate(state->spdif_base, 44100);
state->fifo_init = true;
return 0;