This provides an ASoC DAI interface for Tegra's I2S controller. Signed-off-by: Stephen Warren <swarren@xxxxxxxxxx> --- arch/arm/mach-tegra/Kconfig | 2 + sound/soc/tegra/Kconfig | 13 ++ sound/soc/tegra/Makefile | 2 + sound/soc/tegra/tegra_i2s.c | 468 +++++++++++++++++++++++++++++++++++++++++++ sound/soc/tegra/tegra_i2s.h | 166 +++++++++++++++ 5 files changed, 651 insertions(+), 0 deletions(-) create mode 100644 sound/soc/tegra/tegra_i2s.c create mode 100644 sound/soc/tegra/tegra_i2s.h diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig index d89d9b3..dedac6c 100644 --- a/arch/arm/mach-tegra/Kconfig +++ b/arch/arm/mach-tegra/Kconfig @@ -102,3 +102,5 @@ config TEGRA_I2S_AUDIO default n help Say Y if you want to add support for i2s audio on tegra. + + This option conflicts with SND_TEGRA_SOC_I2S. diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig index f568b2a..d6b0444 100644 --- a/sound/soc/tegra/Kconfig +++ b/sound/soc/tegra/Kconfig @@ -4,3 +4,16 @@ config SND_TEGRA_SOC default m help Say Y or M here if you want support for SoC audio on Tegra. + +config SND_TEGRA_SOC_I2S + tristate + depends on SND_TEGRA_SOC + depends on !TEGRA_I2S_AUDIO + default m + help + Say Y or M if you want to add support for codecs attached to the + Tegra I2S interface. You will also need to select the individual + machine drivers to support below. + + This option conflicts with TEGRA_I2S_AUDIO. + diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile index 3c90e79..d7712a2 100644 --- a/sound/soc/tegra/Makefile +++ b/sound/soc/tegra/Makefile @@ -1,7 +1,9 @@ # Tegra platform Support snd-soc-tegra-das-objs := tegra_das.o snd-soc-tegra-pcm-objs := tegra_pcm.o +snd-soc-tegra-i2s-objs := tegra_i2s.o obj-$(CONFIG_SND_TEGRA_SOC) += snd-soc-tegra-das.o obj-$(CONFIG_SND_TEGRA_SOC) += snd-soc-tegra-pcm.o +obj-$(CONFIG_SND_TEGRA_SOC_I2S) += snd-soc-tegra-i2s.o diff --git a/sound/soc/tegra/tegra_i2s.c b/sound/soc/tegra/tegra_i2s.c new file mode 100644 index 0000000..dd6547f --- /dev/null +++ b/sound/soc/tegra/tegra_i2s.c @@ -0,0 +1,468 @@ +/* + * tegra_i2s.c - Tegra I2S driver + * + * Author: Stephen Warren <swarren@xxxxxxxxxx> + * Copyright (C) 2010 - NVIDIA, Inc. + * + * Based on code copyright/by: + * + * Copyright (c) 2009-2010, NVIDIA Corporation. + * Scott Peterson <speterson@xxxxxxxxxx> + * + * Copyright (C) 2010 Google, Inc. + * Iliyan Malchev <malchev@xxxxxxxxxx> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * 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 St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include <linux/module.h> +#include <linux/debugfs.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/seq_file.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <mach/iomap.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> + +#include "tegra_i2s.h" + +#define DRV_NAME "tegra-i2s" + +static inline void tegra_i2s_write(struct tegra_i2s *i2s, u32 reg, u32 val) +{ + __raw_writel(val, i2s->regs + reg); +} + +static inline u32 tegra_i2s_read(struct tegra_i2s *i2s, u32 reg) +{ + return __raw_readl(i2s->regs + reg); +} + +#ifdef CONFIG_DEBUG_FS +static int tegra_i2s_show(struct seq_file *s, void *unused) +{ +#define REG(r) { r, #r } + static const struct { + int offset; + const char *name; + } regs[] = { + REG(TEGRA_I2S_CTRL), + REG(TEGRA_I2S_STATUS), + REG(TEGRA_I2S_TIMING), + REG(TEGRA_I2S_FIFO_SCR), + REG(TEGRA_I2S_PCM_CTRL), + REG(TEGRA_I2S_NW_CTRL), + REG(TEGRA_I2S_TDM_CTRL), + REG(TEGRA_I2S_TDM_TX_RX_CTRL), + }; +#undef REG + + struct tegra_i2s *i2s = s->private; + int i; + + for (i = 0; i < ARRAY_SIZE(regs); i++) { + u32 val = tegra_i2s_read(i2s, regs[i].offset); + seq_printf(s, "%s = %08x\n", regs[i].name, val); + } + + return 0; +} + +static int tegra_i2s_debug_open(struct inode *inode, struct file *file) +{ + return single_open(file, tegra_i2s_show, inode->i_private); +} + +static const struct file_operations tegra_i2s_debug_fops = { + .open = tegra_i2s_debug_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static void tegra_i2s_debug_add(struct tegra_i2s *i2s) +{ + char name[] = DRV_NAME ".0"; + + snprintf(name, sizeof(name), DRV_NAME".%1d", i2s->pdev->id); + i2s->debug = debugfs_create_file(name, S_IRUGO, NULL, i2s, + &tegra_i2s_debug_fops); +} + +static void tegra_i2s_debug_remove(struct tegra_i2s *i2s) +{ + if (i2s->debug) + debugfs_remove(i2s->debug); +} +#else +static inline void tegra_i2s_debug_add(struct tegra_i2s *i2s) +{ +} + +static inline void tegra_i2s_debug_remove(struct tegra_i2s *i2s) +{ +} +#endif + +static int tegra_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, + unsigned int freq, int dir) +{ + struct tegra_i2s *i2s = dai->private_data; + + i2s->sysclk = freq; + + return 0; +} + +static int tegra_i2s_set_fmt(struct snd_soc_dai *dai, + unsigned int fmt) +{ + struct tegra_i2s *i2s = dai->private_data; + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_IF: + case SND_SOC_DAIFMT_IB_NF: + case SND_SOC_DAIFMT_NB_IF: + /* + * Tegra does not support bit/frame clock inversion. + */ + default: + return -EINVAL; + } + + i2s->reg_ctrl &= ~TEGRA_I2S_CTRL_MASTER_ENABLE; + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + i2s->reg_ctrl |= TEGRA_I2S_CTRL_MASTER_ENABLE; + break; + case SND_SOC_DAIFMT_CBM_CFM: + break; + case SND_SOC_DAIFMT_CBS_CFM: + case SND_SOC_DAIFMT_CBM_CFS: + /* + * Tegra does not support different combinations of + * master and slave for FSYNC and BCLK + */ + default: + return -EINVAL; + } + + i2s->reg_ctrl &= ~(TEGRA_I2S_CTRL_BIT_FORMAT_MASK | + TEGRA_I2S_CTRL_LRCK_MASK); + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_FORMAT_DSP; + i2s->reg_ctrl |= TEGRA_I2S_CTRL_LRCK_L_LOW; + break; + case SND_SOC_DAIFMT_DSP_B: + i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_FORMAT_DSP; + i2s->reg_ctrl |= TEGRA_I2S_CTRL_LRCK_R_LOW; + break; + case SND_SOC_DAIFMT_I2S: + i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_FORMAT_I2S; + i2s->reg_ctrl |= TEGRA_I2S_CTRL_LRCK_L_LOW; + break; + case SND_SOC_DAIFMT_RIGHT_J: + i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_FORMAT_RJM; + i2s->reg_ctrl |= TEGRA_I2S_CTRL_LRCK_L_LOW; + break; + case SND_SOC_DAIFMT_LEFT_J: + i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_FORMAT_LJM; + i2s->reg_ctrl |= TEGRA_I2S_CTRL_LRCK_L_LOW; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int tegra_i2s_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct tegra_i2s *i2s = dai->private_data; + u32 reg; + int srate; + int bitcnt; + + i2s->reg_ctrl &= ~TEGRA_I2S_CTRL_BIT_SIZE_MASK; + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_SIZE_16; + break; + case SNDRV_PCM_FORMAT_S24_LE: + i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_SIZE_24; + break; + case SNDRV_PCM_FORMAT_S32_LE: + i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_SIZE_32; + break; + default: + return -EINVAL; + } + + srate = params_rate(params); + bitcnt = (i2s->sysclk / (2 * srate)) - 1; + if (bitcnt < 0 || bitcnt > TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US) + return -EINVAL; + reg = bitcnt << TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT; + + if (i2s->sysclk % (2 * srate)) + reg |= TEGRA_I2S_TIMING_NON_SYM_ENABLE; + + tegra_i2s_write(i2s, TEGRA_I2S_TIMING, reg); + + tegra_i2s_write(i2s, TEGRA_I2S_FIFO_SCR, + TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_FOUR_SLOTS | + TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_FOUR_SLOTS); + + return 0; +} + +static void tegra_i2s_start_playback(struct tegra_i2s *i2s) +{ + i2s->reg_ctrl |= TEGRA_I2S_CTRL_FIFO1_ENABLE; + tegra_i2s_write(i2s, TEGRA_I2S_CTRL, i2s->reg_ctrl); +} + +static void tegra_i2s_stop_playback(struct tegra_i2s *i2s) +{ + i2s->reg_ctrl &= ~TEGRA_I2S_CTRL_FIFO1_ENABLE; + tegra_i2s_write(i2s, TEGRA_I2S_CTRL, i2s->reg_ctrl); +} + +static void tegra_i2s_start_capture(struct tegra_i2s *i2s) +{ + i2s->reg_ctrl |= TEGRA_I2S_CTRL_FIFO2_ENABLE; + tegra_i2s_write(i2s, TEGRA_I2S_CTRL, i2s->reg_ctrl); +} + +static void tegra_i2s_stop_capture(struct tegra_i2s *i2s) +{ + i2s->reg_ctrl &= ~TEGRA_I2S_CTRL_FIFO2_ENABLE; + tegra_i2s_write(i2s, TEGRA_I2S_CTRL, i2s->reg_ctrl); +} + +static int tegra_i2s_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct tegra_i2s *i2s = dai->private_data; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + case SNDRV_PCM_TRIGGER_RESUME: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + tegra_i2s_start_playback(i2s); + else + tegra_i2s_start_capture(i2s); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_SUSPEND: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + tegra_i2s_stop_playback(i2s); + else + tegra_i2s_stop_capture(i2s); + break; + default: + return -EINVAL; + } + + return 0; +} + +static struct snd_soc_dai_ops tegra_i2s_dai_ops = { + .set_sysclk = tegra_i2s_set_sysclk, + .set_fmt = tegra_i2s_set_fmt, + .hw_params = tegra_i2s_hw_params, + .trigger = tegra_i2s_trigger, +}; + +struct snd_soc_dai tegra_i2s_dai[] = { + { + .name = DRV_NAME ".0", + .id = 0, + .playback = { + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .capture = { + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .ops = &tegra_i2s_dai_ops, + .symmetric_rates = 1, + }, + { + .name = DRV_NAME ".1", + .id = 1, + .playback = { + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .capture = { + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .ops = &tegra_i2s_dai_ops, + .symmetric_rates = 1, + }, +}; +EXPORT_SYMBOL_GPL(tegra_i2s_dai); + +static int tegra_i2s_probe(struct platform_device *pdev) +{ + static struct tegra_i2s * i2s; + struct resource *mem, *memregion, *dmareq; + int ret = 0; + + i2s = kzalloc(sizeof(struct tegra_i2s), GFP_KERNEL); + if (!i2s) { + dev_err(&pdev->dev, "Can't allocate tegra_i2s\n"); + ret = -ENOMEM; + goto exit; + } + i2s->pdev = pdev; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) { + dev_err(&pdev->dev, "No memory resource\n"); + ret = -ENODEV; + goto err_free; + } + + dmareq = platform_get_resource(pdev, IORESOURCE_DMA, 0); + if (!dmareq) { + dev_err(&pdev->dev, "No DMA resource\n"); + ret = -ENODEV; + goto err_free; + } + + memregion = request_mem_region(mem->start, resource_size(mem), + DRV_NAME); + if (!memregion) { + dev_err(&pdev->dev, "Memory region already claimed\n"); + ret = -EBUSY; + goto err_free; + } + + i2s->regs = ioremap(mem->start, resource_size(mem)); + if (!i2s->regs) { + dev_err(&pdev->dev, "ioremap failed\n"); + ret = -ENOMEM; + goto err_release; + } + + i2s->dma_params[0].addr = mem->start + TEGRA_I2S_FIFO2; + i2s->dma_params[0].wrap = 4; + i2s->dma_params[0].width = 32; + i2s->dma_params[0].req_sel = dmareq->start; + + i2s->dma_params[1].addr = mem->start + TEGRA_I2S_FIFO1; + i2s->dma_params[1].wrap = 4; + i2s->dma_params[1].width = 32; + i2s->dma_params[1].req_sel = dmareq->start; + + tegra_i2s_dai[pdev->id].private_data = i2s; + tegra_i2s_dai[pdev->id].capture.dma_data = &i2s->dma_params[0]; + tegra_i2s_dai[pdev->id].playback.dma_data = &i2s->dma_params[1]; + tegra_i2s_dai[pdev->id].dev = &pdev->dev; + + ret = snd_soc_register_dai(&tegra_i2s_dai[pdev->id]); + if (ret != 0) { + dev_err(&pdev->dev, "Could not register DAI: %d\n", ret); + ret = -ENOMEM; + goto err_unmap; + } + + tegra_i2s_debug_add(i2s); + + platform_set_drvdata(pdev, i2s); + + i2s->reg_ctrl = TEGRA_I2S_CTRL_FIFO_FORMAT_PACKED; + + return 0; + +err_unmap: + iounmap(i2s->regs); +err_release: + release_mem_region(mem->start, resource_size(mem)); +err_free: + kfree(i2s); +exit: + return ret; +} + +static int tegra_i2s_remove(struct platform_device *pdev) +{ + struct tegra_i2s *i2s = platform_get_drvdata(pdev); + struct resource *res; + + platform_set_drvdata(pdev, NULL); + + tegra_i2s_debug_remove(i2s); + + snd_soc_unregister_dai(&tegra_i2s_dai[pdev->id]); + + iounmap(i2s->regs); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(res->start, resource_size(res)); + + kfree(i2s); + + return 0; +} + +static struct platform_driver tegra_i2s_driver = { + .probe = tegra_i2s_probe, + .remove = tegra_i2s_remove, + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init tegra_i2s_modinit(void) +{ + return platform_driver_register(&tegra_i2s_driver); +} +module_init(tegra_i2s_modinit); + +static void __exit tegra_i2s_modexit(void) +{ + platform_driver_unregister(&tegra_i2s_driver); +} +module_exit(tegra_i2s_modexit); + +MODULE_AUTHOR("Stephen Warren <swarren@xxxxxxxxxx>"); +MODULE_DESCRIPTION("Tegra I2S ASoC driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/tegra/tegra_i2s.h b/sound/soc/tegra/tegra_i2s.h new file mode 100644 index 0000000..2396221 --- /dev/null +++ b/sound/soc/tegra/tegra_i2s.h @@ -0,0 +1,166 @@ +/* + * tegra_i2s.h - Definitions for Tegra I2S driver + * + * Author: Stephen Warren <swarren@xxxxxxxxxx> + * Copyright (C) 2010 - NVIDIA, Inc. + * + * Based on code copyright/by: + * + * Copyright (c) 2009-2010, NVIDIA Corporation. + * Scott Peterson <speterson@xxxxxxxxxx> + * + * Copyright (C) 2010 Google, Inc. + * Iliyan Malchev <malchev@xxxxxxxxxx> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * 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 St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __TEGRA_I2S_H__ +#define __TEGRA_I2S_H__ + +#include "tegra_pcm.h" + +/* Register offsets from TEGRA_I2S1_BASE and TEGRA_I2S2_BASE */ + +#define TEGRA_I2S_CTRL 0x00 +#define TEGRA_I2S_STATUS 0x04 +#define TEGRA_I2S_TIMING 0x08 +#define TEGRA_I2S_FIFO_SCR 0x0c +#define TEGRA_I2S_PCM_CTRL 0x10 +#define TEGRA_I2S_NW_CTRL 0x14 +#define TEGRA_I2S_TDM_CTRL 0x20 +#define TEGRA_I2S_TDM_TX_RX_CTRL 0x24 +#define TEGRA_I2S_FIFO1 0x40 +#define TEGRA_I2S_FIFO2 0x80 + +/* Fields in TEGRA_I2S_CTRL */ + +#define TEGRA_I2S_CTRL_FIFO2_TX_ENABLE (1 << 30) +#define TEGRA_I2S_CTRL_FIFO1_ENABLE (1 << 29) +#define TEGRA_I2S_CTRL_FIFO2_ENABLE (1 << 28) +#define TEGRA_I2S_CTRL_FIFO1_RX_ENABLE (1 << 27) +#define TEGRA_I2S_CTRL_FIFO_LPBK_ENABLE (1 << 26) +#define TEGRA_I2S_CTRL_MASTER_ENABLE (1 << 25) + +#define I2S_LRCK_LEFT_LOW 0 +#define I2S_LRCK_RIGHT_LOW 1 +#define I2S_LRCK_SHIFT 24 + +#define TEGRA_I2S_CTRL_LRCK_MASK (1 << I2S_LRCK_SHIFT) +#define TEGRA_I2S_CTRL_LRCK_L_LOW (I2S_LRCK_LEFT_LOW << I2S_LRCK_SHIFT) +#define TEGRA_I2S_CTRL_LRCK_R_LOW (I2S_LRCK_RIGHT_LOW << I2S_LRCK_SHIFT) + +#define I2S_BIT_FORMAT_I2S 0 +#define I2S_BIT_FORMAT_RJM 1 +#define I2S_BIT_FORMAT_LJM 2 +#define I2S_BIT_FORMAT_DSP 3 +#define I2S_BIT_FORMAT_SHIFT 10 + +#define TEGRA_I2S_CTRL_BIT_FORMAT_MASK (3 << I2S_BIT_FORMAT_SHIFT) +#define TEGRA_I2S_CTRL_BIT_FORMAT_I2S (I2S_BIT_FORMAT_I2S << 10) +#define TEGRA_I2S_CTRL_BIT_FORMAT_RJM (I2S_BIT_FORMAT_RJM << 10) +#define TEGRA_I2S_CTRL_BIT_FORMAT_LJM (I2S_BIT_FORMAT_LJM << 10) +#define TEGRA_I2S_CTRL_BIT_FORMAT_DSP (I2S_BIT_FORMAT_DSP << 10) + +#define I2S_BIT_SIZE_16 0 +#define I2S_BIT_SIZE_20 1 +#define I2S_BIT_SIZE_24 2 +#define I2S_BIT_SIZE_32 3 +#define I2S_BIT_SIZE_SHIFT 8 + +#define TEGRA_I2S_CTRL_BIT_SIZE_MASK (3 << I2S_BIT_SIZE_SHIFT) +#define TEGRA_I2S_CTRL_BIT_SIZE_16 (I2S_BIT_SIZE_16 << I2S_BIT_SIZE_SHIFT) +#define TEGRA_I2S_CTRL_BIT_SIZE_20 (I2S_BIT_SIZE_20 << I2S_BIT_SIZE_SHIFT) +#define TEGRA_I2S_CTRL_BIT_SIZE_24 (I2S_BIT_SIZE_24 << I2S_BIT_SIZE_SHIFT) +#define TEGRA_I2S_CTRL_BIT_SIZE_32 (I2S_BIT_SIZE_32 << I2S_BIT_SIZE_SHIFT) + +#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_PACKED 7 +#define I2S_FIFO_SHIFT 4 + +#define TEGRA_I2S_CTRL_FIFO_FORMAT_MASK (7 << I2S_FIFO_SHIFT) +#define TEGRA_I2S_CTRL_FIFO_FORMAT_16_LSB (I2S_FIFO_16_LSB << I2S_FIFO_SHIFT) +#define TEGRA_I2S_CTRL_FIFO_FORMAT_20_LSB (I2S_FIFO_20_LSB << I2S_FIFO_SHIFT) +#define TEGRA_I2S_CTRL_FIFO_FORMAT_24_LSB (I2S_FIFO_24_LSB << I2S_FIFO_SHIFT) +#define TEGRA_I2S_CTRL_FIFO_FORMAT_32 (I2S_FIFO_32 << I2S_FIFO_SHIFT) +#define TEGRA_I2S_CTRL_FIFO_FORMAT_PACKED (I2S_FIFO_PACKED << I2S_FIFO_SHIFT) + +#define TEGRA_I2S_CTRL_IE_FIFO1_ERR (1 << 3) +#define TEGRA_I2S_CTRL_IE_FIFO2_ERR (1 << 2) +#define TEGRA_I2S_CTRL_QE_FIFO1 (1 << 1) +#define TEGRA_I2S_CTRL_QE_FIFO2 (1 << 0) + +/* Fields in TEGRA_I2S_STATUS */ + +#define TEGRA_I2S_STATUS_FIFO1_RDY (1 << 31) +#define TEGRA_I2S_STATUS_FIFO2_RDY (1 << 30) +#define TEGRA_I2S_STATUS_FIFO1_BSY (1 << 29) +#define TEGRA_I2S_STATUS_FIFO2_BSY (1 << 28) +#define TEGRA_I2S_STATUS_FIFO1_ERR (1 << 3) +#define TEGRA_I2S_STATUS_FIFO2_ERR (1 << 2) +#define TEGRA_I2S_STATUS_QS_FIFO1 (1 << 1) +#define TEGRA_I2S_STATUS_QS_FIFO2 (1 << 0) + +/* Fields in TEGRA_I2S_TIMING */ + +#define TEGRA_I2S_TIMING_NON_SYM_ENABLE (1 << 12) +#define TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT 0 +#define TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US 0x7fff +#define TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_MASK (TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US << TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT) + +/* Fields in TEGRA_I2S_FIFO_SCR */ + +#define TEGRA_I2S_FIFO_SCR_FIFO2_FULL_EMPTY_COUNT_SHIFT 24 +#define TEGRA_I2S_FIFO_SCR_FIFO1_FULL_EMPTY_COUNT_SHIFT 16 +#define TEGRA_I2S_FIFO_SCR_FIFO_FULL_EMPTY_COUNT_MASK 0x3f + +#define TEGRA_I2S_FIFO_SCR_FIFO2_CLR (1 << 12) +#define TEGRA_I2S_FIFO_SCR_FIFO1_CLR (1 << 8) + +#define I2S_FIFO_ATN_LVL_ONE_SLOT 0 +#define I2S_FIFO_ATN_LVL_FOUR_SLOTS 1 +#define I2S_FIFO_ATN_LVL_EIGHT_SLOTS 2 +#define I2S_FIFO_ATN_LVL_TWELVE_SLOTS 3 +#define I2S_FIFO2_ATN_LVL_SHIFT 4 +#define I2S_FIFO1_ATN_LVL_SHIFT 0 + +#define TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_MASK (3 << I2S_FIFO2_ATN_LVL_SHIFT) +#define TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_ONE_SLOT (I2S_FIFO_ATN_LVL_ONE_SLOT << I2S_FIFO2_ATN_LVL_SHIFT) +#define TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_FOUR_SLOTS (I2S_FIFO_ATN_LVL_FOUR_SLOTS << I2S_FIFO2_ATN_LVL_SHIFT) +#define TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_EIGHT_SLOTS (I2S_FIFO_ATN_LVL_EIGHT_SLOTS << I2S_FIFO2_ATN_LVL_SHIFT) +#define TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_TWELVE_SLOTS (I2S_FIFO_ATN_LVL_TWELVE_SLOTS << I2S_FIFO2_ATN_LVL_SHIFT) + +#define TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_MASK (3 << I2S_FIFO1_ATN_LVL_SHIFT) +#define TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_ONE_SLOT (I2S_FIFO_ATN_LVL_ONE_SLOT << I2S_FIFO1_ATN_LVL_SHIFT) +#define TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_FOUR_SLOTS (I2S_FIFO_ATN_LVL_FOUR_SLOTS << I2S_FIFO1_ATN_LVL_SHIFT) +#define TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_EIGHT_SLOTS (I2S_FIFO_ATN_LVL_EIGHT_SLOTS << I2S_FIFO1_ATN_LVL_SHIFT) +#define TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_TWELVE_SLOTS (I2S_FIFO_ATN_LVL_TWELVE_SLOTS << I2S_FIFO1_ATN_LVL_SHIFT) + +struct tegra_i2s { + struct platform_device *pdev; + struct tegra_pcm_dma_params dma_params[2]; + void __iomem *regs; + struct dentry *debug; + unsigned int sysclk; + u32 reg_ctrl; +}; + +extern struct snd_soc_dai tegra_i2s_dai[]; + +#endif -- 1.7.0.4 nvpublic -- To unsubscribe from this list: send the line "unsubscribe linux-tegra" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html