diff options
author | Sumit Bhattacharya <sumitb@nvidia.com> | 2011-03-10 04:14:03 +0530 |
---|---|---|
committer | Varun Colbert <vcolbert@nvidia.com> | 2011-03-17 21:40:28 -0800 |
commit | e0677a9398abde4739071e1092f577bdc97efae6 (patch) | |
tree | b4f5ffcbec07b254e0bfea42594dc3a9ff03fd08 /arch | |
parent | 769ff2f06c1747487e51a8e878ed08bf9226bfca (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/Makefile | 3 | ||||
-rw-r--r-- | arch/arm/mach-tegra/board-ventana.c | 6 | ||||
-rw-r--r-- | arch/arm/mach-tegra/board-whistler.c | 8 | ||||
-rw-r--r-- | arch/arm/mach-tegra/include/mach/audio.h | 4 | ||||
-rw-r--r-- | arch/arm/mach-tegra/include/mach/spdif.h | 41 | ||||
-rw-r--r-- | arch/arm/mach-tegra/spdif.c | 286 | ||||
-rw-r--r-- | arch/arm/mach-tegra/tegra_spdif_audio.c | 201 |
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; |