mirror of https://gitee.com/openkylin/linux.git
Merge branch 'for-3.1' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound-2.6 into topic/asoc
This commit is contained in:
commit
e320bc42be
|
@ -447,6 +447,7 @@ struct snd_soc_dapm_widget {
|
|||
char *name; /* widget name */
|
||||
char *sname; /* stream name */
|
||||
struct snd_soc_codec *codec;
|
||||
struct snd_soc_platform *platform;
|
||||
struct list_head list;
|
||||
struct snd_soc_dapm_context *dapm;
|
||||
|
||||
|
@ -510,6 +511,7 @@ struct snd_soc_dapm_context {
|
|||
|
||||
struct device *dev; /* from parent - for debug */
|
||||
struct snd_soc_codec *codec; /* parent codec */
|
||||
struct snd_soc_platform *platform; /* parent platform */
|
||||
struct snd_soc_card *card; /* parent card */
|
||||
|
||||
/* used during DAPM updates */
|
||||
|
|
|
@ -368,6 +368,8 @@ struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template,
|
|||
const char *prefix);
|
||||
int snd_soc_add_controls(struct snd_soc_codec *codec,
|
||||
const struct snd_kcontrol_new *controls, int num_controls);
|
||||
int snd_soc_add_platform_controls(struct snd_soc_platform *platform,
|
||||
const struct snd_kcontrol_new *controls, int num_controls);
|
||||
int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo);
|
||||
int snd_soc_info_enum_ext(struct snd_kcontrol *kcontrol,
|
||||
|
@ -649,6 +651,14 @@ struct snd_soc_platform_driver {
|
|||
int (*pcm_new)(struct snd_soc_pcm_runtime *);
|
||||
void (*pcm_free)(struct snd_pcm *);
|
||||
|
||||
/* Default control and setup, added after probe() is run */
|
||||
const struct snd_kcontrol_new *controls;
|
||||
int num_controls;
|
||||
const struct snd_soc_dapm_widget *dapm_widgets;
|
||||
int num_dapm_widgets;
|
||||
const struct snd_soc_dapm_route *dapm_routes;
|
||||
int num_dapm_routes;
|
||||
|
||||
/*
|
||||
* For platform caused delay reporting.
|
||||
* Optional.
|
||||
|
@ -680,6 +690,8 @@ struct snd_soc_platform {
|
|||
struct snd_soc_card *card;
|
||||
struct list_head list;
|
||||
struct list_head card_list;
|
||||
|
||||
struct snd_soc_dapm_context dapm;
|
||||
};
|
||||
|
||||
struct snd_soc_dai_link {
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
struct snd_soc_jack;
|
||||
struct snd_soc_codec;
|
||||
struct snd_soc_platform;
|
||||
struct snd_soc_card;
|
||||
struct snd_soc_dapm_widget;
|
||||
|
||||
|
@ -59,6 +60,50 @@ DEFINE_EVENT(snd_soc_reg, snd_soc_reg_read,
|
|||
|
||||
);
|
||||
|
||||
DECLARE_EVENT_CLASS(snd_soc_preg,
|
||||
|
||||
TP_PROTO(struct snd_soc_platform *platform, unsigned int reg,
|
||||
unsigned int val),
|
||||
|
||||
TP_ARGS(platform, reg, val),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__string( name, platform->name )
|
||||
__field( int, id )
|
||||
__field( unsigned int, reg )
|
||||
__field( unsigned int, val )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__assign_str(name, platform->name);
|
||||
__entry->id = platform->id;
|
||||
__entry->reg = reg;
|
||||
__entry->val = val;
|
||||
),
|
||||
|
||||
TP_printk("platform=%s.%d reg=%x val=%x", __get_str(name),
|
||||
(int)__entry->id, (unsigned int)__entry->reg,
|
||||
(unsigned int)__entry->val)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(snd_soc_preg, snd_soc_preg_write,
|
||||
|
||||
TP_PROTO(struct snd_soc_platform *platform, unsigned int reg,
|
||||
unsigned int val),
|
||||
|
||||
TP_ARGS(platform, reg, val)
|
||||
|
||||
);
|
||||
|
||||
DEFINE_EVENT(snd_soc_preg, snd_soc_preg_read,
|
||||
|
||||
TP_PROTO(struct snd_soc_platform *platform, unsigned int reg,
|
||||
unsigned int val),
|
||||
|
||||
TP_ARGS(platform, reg, val)
|
||||
|
||||
);
|
||||
|
||||
DECLARE_EVENT_CLASS(snd_soc_card,
|
||||
|
||||
TP_PROTO(struct snd_soc_card *card, int val),
|
||||
|
|
|
@ -357,7 +357,7 @@ static int ak4642_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
|
|||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
snd_soc_update_bits(codec, PW_MGMT2, MS, data);
|
||||
snd_soc_update_bits(codec, PW_MGMT2, MS | MCKO | PMPLL, data);
|
||||
snd_soc_update_bits(codec, MD_CTL1, BCKO_MASK, bcko);
|
||||
|
||||
/* format type */
|
||||
|
|
|
@ -175,6 +175,7 @@ static const struct snd_kcontrol_new wm8731_input_mux_controls =
|
|||
SOC_DAPM_ENUM("Input Select", wm8731_insel_enum);
|
||||
|
||||
static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_SUPPLY("ACTIVE",WM8731_ACTIVE, 0, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("OSC", WM8731_PWR, 5, 1, NULL, 0),
|
||||
SND_SOC_DAPM_MIXER("Output Mixer", WM8731_PWR, 4, 1,
|
||||
&wm8731_output_mixer_controls[0],
|
||||
|
@ -204,6 +205,8 @@ static int wm8731_check_osc(struct snd_soc_dapm_widget *source,
|
|||
static const struct snd_soc_dapm_route wm8731_intercon[] = {
|
||||
{"DAC", NULL, "OSC", wm8731_check_osc},
|
||||
{"ADC", NULL, "OSC", wm8731_check_osc},
|
||||
{"DAC", NULL, "ACTIVE"},
|
||||
{"ADC", NULL, "ACTIVE"},
|
||||
|
||||
/* output mixer */
|
||||
{"Output Mixer", "Line Bypass Switch", "Line Input"},
|
||||
|
@ -315,29 +318,6 @@ static int wm8731_hw_params(struct snd_pcm_substream *substream,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int wm8731_pcm_prepare(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
|
||||
/* set active */
|
||||
snd_soc_write(codec, WM8731_ACTIVE, 0x0001);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void wm8731_shutdown(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
|
||||
/* deactivate */
|
||||
if (!codec->active) {
|
||||
udelay(50);
|
||||
snd_soc_write(codec, WM8731_ACTIVE, 0x0);
|
||||
}
|
||||
}
|
||||
|
||||
static int wm8731_mute(struct snd_soc_dai *dai, int mute)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
|
@ -480,7 +460,6 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec,
|
|||
snd_soc_write(codec, WM8731_PWR, reg | 0x0040);
|
||||
break;
|
||||
case SND_SOC_BIAS_OFF:
|
||||
snd_soc_write(codec, WM8731_ACTIVE, 0x0);
|
||||
snd_soc_write(codec, WM8731_PWR, 0xffff);
|
||||
regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies),
|
||||
wm8731->supplies);
|
||||
|
@ -496,9 +475,7 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec,
|
|||
SNDRV_PCM_FMTBIT_S24_LE)
|
||||
|
||||
static struct snd_soc_dai_ops wm8731_dai_ops = {
|
||||
.prepare = wm8731_pcm_prepare,
|
||||
.hw_params = wm8731_hw_params,
|
||||
.shutdown = wm8731_shutdown,
|
||||
.digital_mute = wm8731_mute,
|
||||
.set_sysclk = wm8731_set_dai_sysclk,
|
||||
.set_fmt = wm8731_set_dai_fmt,
|
||||
|
|
|
@ -88,7 +88,6 @@ static u64 pxa2xx_pcm_dmamask = DMA_BIT_MASK(32);
|
|||
static int pxa2xx_soc_pcm_new(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_card *card = rtd->card->snd_card;
|
||||
struct snd_soc_dai *dai = rtd->cpu_dai;
|
||||
struct snd_pcm *pcm = rtd->pcm;
|
||||
int ret = 0;
|
||||
|
||||
|
|
|
@ -993,10 +993,15 @@ static int soc_probe_platform(struct snd_soc_card *card,
|
|||
const struct snd_soc_platform_driver *driver = platform->driver;
|
||||
|
||||
platform->card = card;
|
||||
platform->dapm.card = card;
|
||||
|
||||
if (!try_module_get(platform->dev->driver->owner))
|
||||
return -ENODEV;
|
||||
|
||||
if (driver->dapm_widgets)
|
||||
snd_soc_dapm_new_controls(&platform->dapm,
|
||||
driver->dapm_widgets, driver->num_dapm_widgets);
|
||||
|
||||
if (driver->probe) {
|
||||
ret = driver->probe(platform);
|
||||
if (ret < 0) {
|
||||
|
@ -1007,9 +1012,17 @@ static int soc_probe_platform(struct snd_soc_card *card,
|
|||
}
|
||||
}
|
||||
|
||||
if (driver->controls)
|
||||
snd_soc_add_platform_controls(platform, driver->controls,
|
||||
driver->num_controls);
|
||||
if (driver->dapm_routes)
|
||||
snd_soc_dapm_add_routes(&platform->dapm, driver->dapm_routes,
|
||||
driver->num_dapm_routes);
|
||||
|
||||
/* mark platform as probed and add to card platform list */
|
||||
platform->probed = 1;
|
||||
list_add(&platform->card_list, &card->platform_dev_list);
|
||||
list_add(&platform->dapm.list, &card->dapm_list);
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -1652,6 +1665,7 @@ int snd_soc_platform_read(struct snd_soc_platform *platform,
|
|||
|
||||
ret = platform->driver->read(platform, reg);
|
||||
dev_dbg(platform->dev, "read %x => %x\n", reg, ret);
|
||||
trace_snd_soc_preg_read(platform, reg, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -1666,6 +1680,7 @@ int snd_soc_platform_write(struct snd_soc_platform *platform,
|
|||
}
|
||||
|
||||
dev_dbg(platform->dev, "write %x = %x\n", reg, val);
|
||||
trace_snd_soc_preg_write(platform, reg, val);
|
||||
return platform->driver->write(platform, reg, val);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_soc_platform_write);
|
||||
|
@ -1948,6 +1963,36 @@ int snd_soc_add_controls(struct snd_soc_codec *codec,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(snd_soc_add_controls);
|
||||
|
||||
/**
|
||||
* snd_soc_add_platform_controls - add an array of controls to a platform.
|
||||
* Convienience function to add a list of controls.
|
||||
*
|
||||
* @platform: platform to add controls to
|
||||
* @controls: array of controls to add
|
||||
* @num_controls: number of elements in the array
|
||||
*
|
||||
* Return 0 for success, else error.
|
||||
*/
|
||||
int snd_soc_add_platform_controls(struct snd_soc_platform *platform,
|
||||
const struct snd_kcontrol_new *controls, int num_controls)
|
||||
{
|
||||
struct snd_card *card = platform->card->snd_card;
|
||||
int err, i;
|
||||
|
||||
for (i = 0; i < num_controls; i++) {
|
||||
const struct snd_kcontrol_new *control = &controls[i];
|
||||
err = snd_ctl_add(card, snd_soc_cnew(control, platform,
|
||||
control->name, NULL));
|
||||
if (err < 0) {
|
||||
dev_err(platform->dev, "Failed to add %s %d\n",control->name, err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_soc_add_platform_controls);
|
||||
|
||||
/**
|
||||
* snd_soc_info_enum_double - enumerated double mixer info callback
|
||||
* @kcontrol: mixer control
|
||||
|
@ -3092,6 +3137,8 @@ int snd_soc_register_platform(struct device *dev,
|
|||
|
||||
platform->dev = dev;
|
||||
platform->driver = platform_drv;
|
||||
platform->dapm.dev = dev;
|
||||
platform->dapm.platform = platform;
|
||||
|
||||
mutex_lock(&client_mutex);
|
||||
list_add(&platform->list, &platform_list);
|
||||
|
|
|
@ -128,14 +128,22 @@ static int soc_widget_read(struct snd_soc_dapm_widget *w, int reg)
|
|||
{
|
||||
if (w->codec)
|
||||
return snd_soc_read(w->codec, reg);
|
||||
return 0;
|
||||
else if (w->platform)
|
||||
return snd_soc_platform_read(w->platform, reg);
|
||||
|
||||
dev_err(w->dapm->dev, "no valid widget read method\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int soc_widget_write(struct snd_soc_dapm_widget *w, int reg, int val)
|
||||
{
|
||||
if (w->codec)
|
||||
return snd_soc_write(w->codec, reg, val);
|
||||
return 0;
|
||||
else if (w->platform)
|
||||
return snd_soc_platform_write(w->platform, reg, val);
|
||||
|
||||
dev_err(w->dapm->dev, "no valid widget write method\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int soc_widget_update_bits(struct snd_soc_dapm_widget *w,
|
||||
|
@ -2495,6 +2503,7 @@ int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
|
|||
dapm->n_widgets++;
|
||||
w->dapm = dapm;
|
||||
w->codec = dapm->codec;
|
||||
w->platform = dapm->platform;
|
||||
INIT_LIST_HEAD(&w->sources);
|
||||
INIT_LIST_HEAD(&w->sinks);
|
||||
INIT_LIST_HEAD(&w->list);
|
||||
|
|
|
@ -12,6 +12,15 @@ config SND_SOC_TEGRA_I2S
|
|||
Tegra I2S interface. You will also need to select the individual
|
||||
machine drivers to support below.
|
||||
|
||||
config SND_SOC_TEGRA_SPDIF
|
||||
tristate
|
||||
depends on SND_SOC_TEGRA
|
||||
default m
|
||||
help
|
||||
Say Y or M if you want to add support for the SPDIF interface.
|
||||
You will also need to select the individual machine drivers to support
|
||||
below.
|
||||
|
||||
config MACH_HAS_SND_SOC_TEGRA_WM8903
|
||||
bool
|
||||
help
|
||||
|
|
|
@ -2,12 +2,14 @@
|
|||
snd-soc-tegra-das-objs := tegra_das.o
|
||||
snd-soc-tegra-pcm-objs := tegra_pcm.o
|
||||
snd-soc-tegra-i2s-objs := tegra_i2s.o
|
||||
snd-soc-tegra-spdif-objs := tegra_spdif.o
|
||||
snd-soc-tegra-utils-objs += tegra_asoc_utils.o
|
||||
|
||||
obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-utils.o
|
||||
obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-das.o
|
||||
obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-pcm.o
|
||||
obj-$(CONFIG_SND_SOC_TEGRA_I2S) += snd-soc-tegra-i2s.o
|
||||
obj-$(CONFIG_SND_SOC_TEGRA_SPDIF) += snd-soc-tegra-spdif.o
|
||||
|
||||
# Tegra machine Support
|
||||
snd-soc-tegra-wm8903-objs := tegra_wm8903.o
|
||||
|
|
|
@ -0,0 +1,371 @@
|
|||
/*
|
||||
* tegra_spdif.c - Tegra SPDIF driver
|
||||
*
|
||||
* Author: Stephen Warren <swarren@nvidia.com>
|
||||
* Copyright (C) 2011 - NVIDIA, Inc.
|
||||
*
|
||||
* 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/clk.h>
|
||||
#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_spdif.h"
|
||||
|
||||
#define DRV_NAME "tegra-spdif"
|
||||
|
||||
static inline void tegra_spdif_write(struct tegra_spdif *spdif, u32 reg,
|
||||
u32 val)
|
||||
{
|
||||
__raw_writel(val, spdif->regs + reg);
|
||||
}
|
||||
|
||||
static inline u32 tegra_spdif_read(struct tegra_spdif *spdif, u32 reg)
|
||||
{
|
||||
return __raw_readl(spdif->regs + reg);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
static int tegra_spdif_show(struct seq_file *s, void *unused)
|
||||
{
|
||||
#define REG(r) { r, #r }
|
||||
static const struct {
|
||||
int offset;
|
||||
const char *name;
|
||||
} regs[] = {
|
||||
REG(TEGRA_SPDIF_CTRL),
|
||||
REG(TEGRA_SPDIF_STATUS),
|
||||
REG(TEGRA_SPDIF_STROBE_CTRL),
|
||||
REG(TEGRA_SPDIF_DATA_FIFO_CSR),
|
||||
REG(TEGRA_SPDIF_CH_STA_RX_A),
|
||||
REG(TEGRA_SPDIF_CH_STA_RX_B),
|
||||
REG(TEGRA_SPDIF_CH_STA_RX_C),
|
||||
REG(TEGRA_SPDIF_CH_STA_RX_D),
|
||||
REG(TEGRA_SPDIF_CH_STA_RX_E),
|
||||
REG(TEGRA_SPDIF_CH_STA_RX_F),
|
||||
REG(TEGRA_SPDIF_CH_STA_TX_A),
|
||||
REG(TEGRA_SPDIF_CH_STA_TX_B),
|
||||
REG(TEGRA_SPDIF_CH_STA_TX_C),
|
||||
REG(TEGRA_SPDIF_CH_STA_TX_D),
|
||||
REG(TEGRA_SPDIF_CH_STA_TX_E),
|
||||
REG(TEGRA_SPDIF_CH_STA_TX_F),
|
||||
};
|
||||
#undef REG
|
||||
|
||||
struct tegra_spdif *spdif = s->private;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(regs); i++) {
|
||||
u32 val = tegra_spdif_read(spdif, regs[i].offset);
|
||||
seq_printf(s, "%s = %08x\n", regs[i].name, val);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_spdif_debug_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, tegra_spdif_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations tegra_spdif_debug_fops = {
|
||||
.open = tegra_spdif_debug_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
static void tegra_spdif_debug_add(struct tegra_spdif *spdif)
|
||||
{
|
||||
spdif->debug = debugfs_create_file(DRV_NAME, S_IRUGO,
|
||||
snd_soc_debugfs_root, spdif,
|
||||
&tegra_spdif_debug_fops);
|
||||
}
|
||||
|
||||
static void tegra_spdif_debug_remove(struct tegra_spdif *spdif)
|
||||
{
|
||||
if (spdif->debug)
|
||||
debugfs_remove(spdif->debug);
|
||||
}
|
||||
#else
|
||||
static inline void tegra_spdif_debug_add(struct tegra_spdif *spdif)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void tegra_spdif_debug_remove(struct tegra_spdif *spdif)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
static int tegra_spdif_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 tegra_spdif *spdif = snd_soc_dai_get_drvdata(dai);
|
||||
int ret, srate, spdifclock;
|
||||
|
||||
spdif->reg_ctrl &= ~TEGRA_SPDIF_CTRL_PACK;
|
||||
spdif->reg_ctrl &= ~TEGRA_SPDIF_CTRL_BIT_MODE_MASK;
|
||||
switch (params_format(params)) {
|
||||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
spdif->reg_ctrl |= TEGRA_SPDIF_CTRL_PACK;
|
||||
spdif->reg_ctrl |= TEGRA_SPDIF_CTRL_BIT_MODE_16BIT;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
srate = params_rate(params);
|
||||
switch (params_rate(params)) {
|
||||
case 32000:
|
||||
spdifclock = 4096000;
|
||||
break;
|
||||
case 44100:
|
||||
spdifclock = 5644800;
|
||||
break;
|
||||
case 48000:
|
||||
spdifclock = 6144000;
|
||||
break;
|
||||
case 88200:
|
||||
spdifclock = 11289600;
|
||||
break;
|
||||
case 96000:
|
||||
spdifclock = 12288000;
|
||||
break;
|
||||
case 176400:
|
||||
spdifclock = 22579200;
|
||||
break;
|
||||
case 192000:
|
||||
spdifclock = 24576000;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = clk_set_rate(spdif->clk_spdif_out, spdifclock);
|
||||
if (ret) {
|
||||
dev_err(dev, "Can't set SPDIF clock rate: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tegra_spdif_start_playback(struct tegra_spdif *spdif)
|
||||
{
|
||||
spdif->reg_ctrl |= TEGRA_SPDIF_CTRL_TX_EN;
|
||||
tegra_spdif_write(spdif, TEGRA_SPDIF_CTRL, spdif->reg_ctrl);
|
||||
}
|
||||
|
||||
static void tegra_spdif_stop_playback(struct tegra_spdif *spdif)
|
||||
{
|
||||
spdif->reg_ctrl &= ~TEGRA_SPDIF_CTRL_TX_EN;
|
||||
tegra_spdif_write(spdif, TEGRA_SPDIF_CTRL, spdif->reg_ctrl);
|
||||
}
|
||||
|
||||
static int tegra_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct tegra_spdif *spdif = snd_soc_dai_get_drvdata(dai);
|
||||
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
case SNDRV_PCM_TRIGGER_RESUME:
|
||||
if (!spdif->clk_refs)
|
||||
clk_enable(spdif->clk_spdif_out);
|
||||
spdif->clk_refs++;
|
||||
tegra_spdif_start_playback(spdif);
|
||||
break;
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
tegra_spdif_stop_playback(spdif);
|
||||
spdif->clk_refs--;
|
||||
if (!spdif->clk_refs)
|
||||
clk_disable(spdif->clk_spdif_out);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_spdif_probe(struct snd_soc_dai *dai)
|
||||
{
|
||||
struct tegra_spdif *spdif = snd_soc_dai_get_drvdata(dai);
|
||||
|
||||
dai->capture_dma_data = NULL;
|
||||
dai->playback_dma_data = &spdif->playback_dma_data;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_dai_ops tegra_spdif_dai_ops = {
|
||||
.hw_params = tegra_spdif_hw_params,
|
||||
.trigger = tegra_spdif_trigger,
|
||||
};
|
||||
|
||||
struct snd_soc_dai_driver tegra_spdif_dai = {
|
||||
.name = DRV_NAME,
|
||||
.probe = tegra_spdif_probe,
|
||||
.playback = {
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
|
||||
SNDRV_PCM_RATE_48000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
},
|
||||
.ops = &tegra_spdif_dai_ops,
|
||||
};
|
||||
|
||||
static __devinit int tegra_spdif_platform_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct tegra_spdif *spdif;
|
||||
struct resource *mem, *memregion, *dmareq;
|
||||
int ret;
|
||||
|
||||
spdif = kzalloc(sizeof(struct tegra_spdif), GFP_KERNEL);
|
||||
if (!spdif) {
|
||||
dev_err(&pdev->dev, "Can't allocate tegra_spdif\n");
|
||||
ret = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
dev_set_drvdata(&pdev->dev, spdif);
|
||||
|
||||
spdif->clk_spdif_out = clk_get(&pdev->dev, "spdif_out");
|
||||
if (IS_ERR(spdif->clk_spdif_out)) {
|
||||
pr_err("Can't retrieve spdif clock\n");
|
||||
ret = PTR_ERR(spdif->clk_spdif_out);
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!mem) {
|
||||
dev_err(&pdev->dev, "No memory resource\n");
|
||||
ret = -ENODEV;
|
||||
goto err_clk_put;
|
||||
}
|
||||
|
||||
dmareq = platform_get_resource(pdev, IORESOURCE_DMA, 0);
|
||||
if (!dmareq) {
|
||||
dev_err(&pdev->dev, "No DMA resource\n");
|
||||
ret = -ENODEV;
|
||||
goto err_clk_put;
|
||||
}
|
||||
|
||||
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_clk_put;
|
||||
}
|
||||
|
||||
spdif->regs = ioremap(mem->start, resource_size(mem));
|
||||
if (!spdif->regs) {
|
||||
dev_err(&pdev->dev, "ioremap failed\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_release;
|
||||
}
|
||||
|
||||
spdif->playback_dma_data.addr = mem->start + TEGRA_SPDIF_DATA_OUT;
|
||||
spdif->playback_dma_data.wrap = 4;
|
||||
spdif->playback_dma_data.width = 32;
|
||||
spdif->playback_dma_data.req_sel = dmareq->start;
|
||||
|
||||
ret = snd_soc_register_dai(&pdev->dev, &tegra_spdif_dai);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
|
||||
ret = -ENOMEM;
|
||||
goto err_unmap;
|
||||
}
|
||||
|
||||
tegra_spdif_debug_add(spdif);
|
||||
|
||||
return 0;
|
||||
|
||||
err_unmap:
|
||||
iounmap(spdif->regs);
|
||||
err_release:
|
||||
release_mem_region(mem->start, resource_size(mem));
|
||||
err_clk_put:
|
||||
clk_put(spdif->clk_spdif_out);
|
||||
err_free:
|
||||
kfree(spdif);
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit tegra_spdif_platform_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct tegra_spdif *spdif = dev_get_drvdata(&pdev->dev);
|
||||
struct resource *res;
|
||||
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
|
||||
tegra_spdif_debug_remove(spdif);
|
||||
|
||||
iounmap(spdif->regs);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
|
||||
clk_put(spdif->clk_spdif_out);
|
||||
|
||||
kfree(spdif);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver tegra_spdif_driver = {
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = tegra_spdif_platform_probe,
|
||||
.remove = __devexit_p(tegra_spdif_platform_remove),
|
||||
};
|
||||
|
||||
static int __init snd_tegra_spdif_init(void)
|
||||
{
|
||||
return platform_driver_register(&tegra_spdif_driver);
|
||||
}
|
||||
module_init(snd_tegra_spdif_init);
|
||||
|
||||
static void __exit snd_tegra_spdif_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&tegra_spdif_driver);
|
||||
}
|
||||
module_exit(snd_tegra_spdif_exit);
|
||||
|
||||
MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
|
||||
MODULE_DESCRIPTION("Tegra SPDIF ASoC driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:" DRV_NAME);
|
|
@ -0,0 +1,473 @@
|
|||
/*
|
||||
* tegra_spdif.h - Definitions for Tegra SPDIF driver
|
||||
*
|
||||
* Author: Stephen Warren <swarren@nvidia.com>
|
||||
* Copyright (C) 2011 - NVIDIA, Inc.
|
||||
*
|
||||
* Based on code copyright/by:
|
||||
* Copyright (c) 2008-2009, NVIDIA Corporation
|
||||
*
|
||||
* 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_SPDIF_H__
|
||||
#define __TEGRA_SPDIF_H__
|
||||
|
||||
#include "tegra_pcm.h"
|
||||
|
||||
/* Offsets from TEGRA_SPDIF_BASE */
|
||||
|
||||
#define TEGRA_SPDIF_CTRL 0x0
|
||||
#define TEGRA_SPDIF_STATUS 0x4
|
||||
#define TEGRA_SPDIF_STROBE_CTRL 0x8
|
||||
#define TEGRA_SPDIF_DATA_FIFO_CSR 0x0C
|
||||
#define TEGRA_SPDIF_DATA_OUT 0x40
|
||||
#define TEGRA_SPDIF_DATA_IN 0x80
|
||||
#define TEGRA_SPDIF_CH_STA_RX_A 0x100
|
||||
#define TEGRA_SPDIF_CH_STA_RX_B 0x104
|
||||
#define TEGRA_SPDIF_CH_STA_RX_C 0x108
|
||||
#define TEGRA_SPDIF_CH_STA_RX_D 0x10C
|
||||
#define TEGRA_SPDIF_CH_STA_RX_E 0x110
|
||||
#define TEGRA_SPDIF_CH_STA_RX_F 0x114
|
||||
#define TEGRA_SPDIF_CH_STA_TX_A 0x140
|
||||
#define TEGRA_SPDIF_CH_STA_TX_B 0x144
|
||||
#define TEGRA_SPDIF_CH_STA_TX_C 0x148
|
||||
#define TEGRA_SPDIF_CH_STA_TX_D 0x14C
|
||||
#define TEGRA_SPDIF_CH_STA_TX_E 0x150
|
||||
#define TEGRA_SPDIF_CH_STA_TX_F 0x154
|
||||
#define TEGRA_SPDIF_USR_STA_RX_A 0x180
|
||||
#define TEGRA_SPDIF_USR_DAT_TX_A 0x1C0
|
||||
|
||||
/* Fields in TEGRA_SPDIF_CTRL */
|
||||
|
||||
/* Start capturing from 0=right, 1=left channel */
|
||||
#define TEGRA_SPDIF_CTRL_CAP_LC (1 << 30)
|
||||
|
||||
/* SPDIF receiver(RX) enable */
|
||||
#define TEGRA_SPDIF_CTRL_RX_EN (1 << 29)
|
||||
|
||||
/* SPDIF Transmitter(TX) enable */
|
||||
#define TEGRA_SPDIF_CTRL_TX_EN (1 << 28)
|
||||
|
||||
/* Transmit Channel status */
|
||||
#define TEGRA_SPDIF_CTRL_TC_EN (1 << 27)
|
||||
|
||||
/* Transmit user Data */
|
||||
#define TEGRA_SPDIF_CTRL_TU_EN (1 << 26)
|
||||
|
||||
/* Interrupt on transmit error */
|
||||
#define TEGRA_SPDIF_CTRL_IE_TXE (1 << 25)
|
||||
|
||||
/* Interrupt on receive error */
|
||||
#define TEGRA_SPDIF_CTRL_IE_RXE (1 << 24)
|
||||
|
||||
/* Interrupt on invalid preamble */
|
||||
#define TEGRA_SPDIF_CTRL_IE_P (1 << 23)
|
||||
|
||||
/* Interrupt on "B" preamble */
|
||||
#define TEGRA_SPDIF_CTRL_IE_B (1 << 22)
|
||||
|
||||
/* Interrupt when block of channel status received */
|
||||
#define TEGRA_SPDIF_CTRL_IE_C (1 << 21)
|
||||
|
||||
/* Interrupt when a valid information unit (IU) is received */
|
||||
#define TEGRA_SPDIF_CTRL_IE_U (1 << 20)
|
||||
|
||||
/* Interrupt when RX user FIFO attention level is reached */
|
||||
#define TEGRA_SPDIF_CTRL_QE_RU (1 << 19)
|
||||
|
||||
/* Interrupt when TX user FIFO attention level is reached */
|
||||
#define TEGRA_SPDIF_CTRL_QE_TU (1 << 18)
|
||||
|
||||
/* Interrupt when RX data FIFO attention level is reached */
|
||||
#define TEGRA_SPDIF_CTRL_QE_RX (1 << 17)
|
||||
|
||||
/* Interrupt when TX data FIFO attention level is reached */
|
||||
#define TEGRA_SPDIF_CTRL_QE_TX (1 << 16)
|
||||
|
||||
/* Loopback test mode enable */
|
||||
#define TEGRA_SPDIF_CTRL_LBK_EN (1 << 15)
|
||||
|
||||
/*
|
||||
* Pack data mode:
|
||||
* 0 = Single data (16 bit needs to be padded to match the
|
||||
* interface data bit size).
|
||||
* 1 = Packeted left/right channel data into a single word.
|
||||
*/
|
||||
#define TEGRA_SPDIF_CTRL_PACK (1 << 14)
|
||||
|
||||
/*
|
||||
* 00 = 16bit data
|
||||
* 01 = 20bit data
|
||||
* 10 = 24bit data
|
||||
* 11 = raw data
|
||||
*/
|
||||
#define TEGRA_SPDIF_BIT_MODE_16BIT 0
|
||||
#define TEGRA_SPDIF_BIT_MODE_20BIT 1
|
||||
#define TEGRA_SPDIF_BIT_MODE_24BIT 2
|
||||
#define TEGRA_SPDIF_BIT_MODE_RAW 3
|
||||
|
||||
#define TEGRA_SPDIF_CTRL_BIT_MODE_SHIFT 12
|
||||
#define TEGRA_SPDIF_CTRL_BIT_MODE_MASK (3 << TEGRA_SPDIF_CTRL_BIT_MODE_SHIFT)
|
||||
#define TEGRA_SPDIF_CTRL_BIT_MODE_16BIT (TEGRA_SPDIF_BIT_MODE_16BIT << TEGRA_SPDIF_CTRL_BIT_MODE_SHIFT)
|
||||
#define TEGRA_SPDIF_CTRL_BIT_MODE_20BIT (TEGRA_SPDIF_BIT_MODE_20BIT << TEGRA_SPDIF_CTRL_BIT_MODE_SHIFT)
|
||||
#define TEGRA_SPDIF_CTRL_BIT_MODE_24BIT (TEGRA_SPDIF_BIT_MODE_24BIT << TEGRA_SPDIF_CTRL_BIT_MODE_SHIFT)
|
||||
#define TEGRA_SPDIF_CTRL_BIT_MODE_RAW (TEGRA_SPDIF_BIT_MODE_RAW << TEGRA_SPDIF_CTRL_BIT_MODE_SHIFT)
|
||||
|
||||
/* Fields in TEGRA_SPDIF_STATUS */
|
||||
|
||||
/*
|
||||
* Note: IS_P, IS_B, IS_C, and IS_U are sticky bits. Software must
|
||||
* write a 1 to the corresponding bit location to clear the status.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Receiver(RX) shifter is busy receiving data.
|
||||
* This bit is asserted when the receiver first locked onto the
|
||||
* preamble of the data stream after RX_EN is asserted. This bit is
|
||||
* deasserted when either,
|
||||
* (a) the end of a frame is reached after RX_EN is deeasserted, or
|
||||
* (b) the SPDIF data stream becomes inactive.
|
||||
*/
|
||||
#define TEGRA_SPDIF_STATUS_RX_BSY (1 << 29)
|
||||
|
||||
/*
|
||||
* Transmitter(TX) shifter is busy transmitting data.
|
||||
* This bit is asserted when TX_EN is asserted.
|
||||
* This bit is deasserted when the end of a frame is reached after
|
||||
* TX_EN is deasserted.
|
||||
*/
|
||||
#define TEGRA_SPDIF_STATUS_TX_BSY (1 << 28)
|
||||
|
||||
/*
|
||||
* TX is busy shifting out channel status.
|
||||
* This bit is asserted when both TX_EN and TC_EN are asserted and
|
||||
* data from CH_STA_TX_A register is loaded into the internal shifter.
|
||||
* This bit is deasserted when either,
|
||||
* (a) the end of a frame is reached after TX_EN is deasserted, or
|
||||
* (b) CH_STA_TX_F register is loaded into the internal shifter.
|
||||
*/
|
||||
#define TEGRA_SPDIF_STATUS_TC_BSY (1 << 27)
|
||||
|
||||
/*
|
||||
* TX User data FIFO busy.
|
||||
* This bit is asserted when TX_EN and TXU_EN are asserted and
|
||||
* there's data in the TX user FIFO. This bit is deassert when either,
|
||||
* (a) the end of a frame is reached after TX_EN is deasserted, or
|
||||
* (b) there's no data left in the TX user FIFO.
|
||||
*/
|
||||
#define TEGRA_SPDIF_STATUS_TU_BSY (1 << 26)
|
||||
|
||||
/* TX FIFO Underrun error status */
|
||||
#define TEGRA_SPDIF_STATUS_TX_ERR (1 << 25)
|
||||
|
||||
/* RX FIFO Overrun error status */
|
||||
#define TEGRA_SPDIF_STATUS_RX_ERR (1 << 24)
|
||||
|
||||
/* Preamble status: 0=Preamble OK, 1=bad/missing preamble */
|
||||
#define TEGRA_SPDIF_STATUS_IS_P (1 << 23)
|
||||
|
||||
/* B-preamble detection status: 0=not detected, 1=B-preamble detected */
|
||||
#define TEGRA_SPDIF_STATUS_IS_B (1 << 22)
|
||||
|
||||
/*
|
||||
* RX channel block data receive status:
|
||||
* 0=entire block not recieved yet.
|
||||
* 1=received entire block of channel status,
|
||||
*/
|
||||
#define TEGRA_SPDIF_STATUS_IS_C (1 << 21)
|
||||
|
||||
/* RX User Data Valid flag: 1=valid IU detected, 0 = no IU detected. */
|
||||
#define TEGRA_SPDIF_STATUS_IS_U (1 << 20)
|
||||
|
||||
/*
|
||||
* RX User FIFO Status:
|
||||
* 1=attention level reached, 0=attention level not reached.
|
||||
*/
|
||||
#define TEGRA_SPDIF_STATUS_QS_RU (1 << 19)
|
||||
|
||||
/*
|
||||
* TX User FIFO Status:
|
||||
* 1=attention level reached, 0=attention level not reached.
|
||||
*/
|
||||
#define TEGRA_SPDIF_STATUS_QS_TU (1 << 18)
|
||||
|
||||
/*
|
||||
* RX Data FIFO Status:
|
||||
* 1=attention level reached, 0=attention level not reached.
|
||||
*/
|
||||
#define TEGRA_SPDIF_STATUS_QS_RX (1 << 17)
|
||||
|
||||
/*
|
||||
* TX Data FIFO Status:
|
||||
* 1=attention level reached, 0=attention level not reached.
|
||||
*/
|
||||
#define TEGRA_SPDIF_STATUS_QS_TX (1 << 16)
|
||||
|
||||
/* Fields in TEGRA_SPDIF_STROBE_CTRL */
|
||||
|
||||
/*
|
||||
* Indicates the approximate number of detected SPDIFIN clocks within a
|
||||
* bi-phase period.
|
||||
*/
|
||||
#define TEGRA_SPDIF_STROBE_CTRL_PERIOD_SHIFT 16
|
||||
#define TEGRA_SPDIF_STROBE_CTRL_PERIOD_MASK (0xff << TEGRA_SPDIF_STROBE_CTRL_PERIOD_SHIFT)
|
||||
|
||||
/* Data strobe mode: 0=Auto-locked 1=Manual locked */
|
||||
#define TEGRA_SPDIF_STROBE_CTRL_STROBE (1 << 15)
|
||||
|
||||
/*
|
||||
* Manual data strobe time within the bi-phase clock period (in terms of
|
||||
* the number of over-sampling clocks).
|
||||
*/
|
||||
#define TEGRA_SPDIF_STROBE_CTRL_DATA_STROBES_SHIFT 8
|
||||
#define TEGRA_SPDIF_STROBE_CTRL_DATA_STROBES_MASK (0x1f << TEGRA_SPDIF_STROBE_CTRL_DATA_STROBES_SHIFT)
|
||||
|
||||
/*
|
||||
* Manual SPDIFIN bi-phase clock period (in terms of the number of
|
||||
* over-sampling clocks).
|
||||
*/
|
||||
#define TEGRA_SPDIF_STROBE_CTRL_CLOCK_PERIOD_SHIFT 0
|
||||
#define TEGRA_SPDIF_STROBE_CTRL_CLOCK_PERIOD_MASK (0x3f << TEGRA_SPDIF_STROBE_CTRL_CLOCK_PERIOD_SHIFT)
|
||||
|
||||
/* Fields in SPDIF_DATA_FIFO_CSR */
|
||||
|
||||
/* Clear Receiver User FIFO (RX USR.FIFO) */
|
||||
#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_CLR (1 << 31)
|
||||
|
||||
#define TEGRA_SPDIF_FIFO_ATN_LVL_U_ONE_SLOT 0
|
||||
#define TEGRA_SPDIF_FIFO_ATN_LVL_U_TWO_SLOTS 1
|
||||
#define TEGRA_SPDIF_FIFO_ATN_LVL_U_THREE_SLOTS 2
|
||||
#define TEGRA_SPDIF_FIFO_ATN_LVL_U_FOUR_SLOTS 3
|
||||
|
||||
/* RU FIFO attention level */
|
||||
#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT 29
|
||||
#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_MASK \
|
||||
(0x3 << TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT)
|
||||
#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_RU1_WORD_FULL \
|
||||
(TEGRA_SPDIF_FIFO_ATN_LVL_U_ONE_SLOT << TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT)
|
||||
#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_RU2_WORD_FULL \
|
||||
(TEGRA_SPDIF_FIFO_ATN_LVL_U_TWO_SLOTS << TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT)
|
||||
#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_RU3_WORD_FULL \
|
||||
(TEGRA_SPDIF_FIFO_ATN_LVL_U_THREE_SLOTS << TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT)
|
||||
#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_RU4_WORD_FULL \
|
||||
(TEGRA_SPDIF_FIFO_ATN_LVL_U_FOUR_SLOTS << TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT)
|
||||
|
||||
/* Number of RX USR.FIFO levels with valid data. */
|
||||
#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_FULL_COUNT_SHIFT 24
|
||||
#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_FULL_COUNT_MASK (0x1f << TEGRA_SPDIF_DATA_FIFO_CSR_RU_FULL_COUNT_SHIFT)
|
||||
|
||||
/* Clear Transmitter User FIFO (TX USR.FIFO) */
|
||||
#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_CLR (1 << 23)
|
||||
|
||||
/* TU FIFO attention level */
|
||||
#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT 21
|
||||
#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_MASK \
|
||||
(0x3 << TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT)
|
||||
#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_TU1_WORD_FULL \
|
||||
(TEGRA_SPDIF_FIFO_ATN_LVL_U_ONE_SLOT << TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT)
|
||||
#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_TU2_WORD_FULL \
|
||||
(TEGRA_SPDIF_FIFO_ATN_LVL_U_TWO_SLOTS << TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT)
|
||||
#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_TU3_WORD_FULL \
|
||||
(TEGRA_SPDIF_FIFO_ATN_LVL_U_THREE_SLOTS << TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT)
|
||||
#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_TU4_WORD_FULL \
|
||||
(TEGRA_SPDIF_FIFO_ATN_LVL_U_FOUR_SLOTS << TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT)
|
||||
|
||||
/* Number of TX USR.FIFO levels that could be filled. */
|
||||
#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_EMPTY_COUNT_SHIFT 16
|
||||
#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_EMPTY_COUNT_MASK (0x1f << SPDIF_DATA_FIFO_CSR_TU_EMPTY_COUNT_SHIFT)
|
||||
|
||||
/* Clear Receiver Data FIFO (RX DATA.FIFO) */
|
||||
#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_CLR (1 << 15)
|
||||
|
||||
#define TEGRA_SPDIF_FIFO_ATN_LVL_D_ONE_SLOT 0
|
||||
#define TEGRA_SPDIF_FIFO_ATN_LVL_D_FOUR_SLOTS 1
|
||||
#define TEGRA_SPDIF_FIFO_ATN_LVL_D_EIGHT_SLOTS 2
|
||||
#define TEGRA_SPDIF_FIFO_ATN_LVL_D_TWELVE_SLOTS 3
|
||||
|
||||
/* RU FIFO attention level */
|
||||
#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT 13
|
||||
#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_MASK \
|
||||
(0x3 << TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT)
|
||||
#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_RU1_WORD_FULL \
|
||||
(TEGRA_SPDIF_FIFO_ATN_LVL_D_ONE_SLOT << TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT)
|
||||
#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_RU4_WORD_FULL \
|
||||
(TEGRA_SPDIF_FIFO_ATN_LVL_D_FOUR_SLOTS << TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT)
|
||||
#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_RU8_WORD_FULL \
|
||||
(TEGRA_SPDIF_FIFO_ATN_LVL_D_EIGHT_SLOTS << TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT)
|
||||
#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_RU12_WORD_FULL \
|
||||
(TEGRA_SPDIF_FIFO_ATN_LVL_D_TWELVE_SLOTS << TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT)
|
||||
|
||||
/* Number of RX DATA.FIFO levels with valid data. */
|
||||
#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_FULL_COUNT_SHIFT 8
|
||||
#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_FULL_COUNT_MASK (0x1f << TEGRA_SPDIF_DATA_FIFO_CSR_RX_FULL_COUNT_SHIFT)
|
||||
|
||||
/* Clear Transmitter Data FIFO (TX DATA.FIFO) */
|
||||
#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_CLR (1 << 7)
|
||||
|
||||
/* TU FIFO attention level */
|
||||
#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT 5
|
||||
#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_MASK \
|
||||
(0x3 << TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT)
|
||||
#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU1_WORD_FULL \
|
||||
(TEGRA_SPDIF_FIFO_ATN_LVL_D_ONE_SLOT << TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT)
|
||||
#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU4_WORD_FULL \
|
||||
(TEGRA_SPDIF_FIFO_ATN_LVL_D_FOUR_SLOTS << TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT)
|
||||
#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU8_WORD_FULL \
|
||||
(TEGRA_SPDIF_FIFO_ATN_LVL_D_EIGHT_SLOTS << TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT)
|
||||
#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU12_WORD_FULL \
|
||||
(TEGRA_SPDIF_FIFO_ATN_LVL_D_TWELVE_SLOTS << TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT)
|
||||
|
||||
/* Number of TX DATA.FIFO levels that could be filled. */
|
||||
#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_EMPTY_COUNT_SHIFT 0
|
||||
#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_EMPTY_COUNT_MASK (0x1f << SPDIF_DATA_FIFO_CSR_TX_EMPTY_COUNT_SHIFT)
|
||||
|
||||
/* Fields in TEGRA_SPDIF_DATA_OUT */
|
||||
|
||||
/*
|
||||
* This register has 5 different formats:
|
||||
* 16-bit (BIT_MODE=00, PACK=0)
|
||||
* 20-bit (BIT_MODE=01, PACK=0)
|
||||
* 24-bit (BIT_MODE=10, PACK=0)
|
||||
* raw (BIT_MODE=11, PACK=0)
|
||||
* 16-bit packed (BIT_MODE=00, PACK=1)
|
||||
*/
|
||||
|
||||
#define TEGRA_SPDIF_DATA_OUT_DATA_16_SHIFT 0
|
||||
#define TEGRA_SPDIF_DATA_OUT_DATA_16_MASK (0xffff << TEGRA_SPDIF_DATA_OUT_DATA_16_SHIFT)
|
||||
|
||||
#define TEGRA_SPDIF_DATA_OUT_DATA_20_SHIFT 0
|
||||
#define TEGRA_SPDIF_DATA_OUT_DATA_20_MASK (0xfffff << TEGRA_SPDIF_DATA_OUT_DATA_20_SHIFT)
|
||||
|
||||
#define TEGRA_SPDIF_DATA_OUT_DATA_24_SHIFT 0
|
||||
#define TEGRA_SPDIF_DATA_OUT_DATA_24_MASK (0xffffff << TEGRA_SPDIF_DATA_OUT_DATA_24_SHIFT)
|
||||
|
||||
#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_P (1 << 31)
|
||||
#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_C (1 << 30)
|
||||
#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_U (1 << 29)
|
||||
#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_V (1 << 28)
|
||||
|
||||
#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_DATA_SHIFT 8
|
||||
#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_DATA_MASK (0xfffff << TEGRA_SPDIF_DATA_OUT_DATA_RAW_DATA_SHIFT)
|
||||
|
||||
#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_AUX_SHIFT 4
|
||||
#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_AUX_MASK (0xf << TEGRA_SPDIF_DATA_OUT_DATA_RAW_AUX_SHIFT)
|
||||
|
||||
#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_PREAMBLE_SHIFT 0
|
||||
#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_PREAMBLE_MASK (0xf << TEGRA_SPDIF_DATA_OUT_DATA_RAW_PREAMBLE_SHIFT)
|
||||
|
||||
#define TEGRA_SPDIF_DATA_OUT_DATA_16_PACKED_RIGHT_SHIFT 16
|
||||
#define TEGRA_SPDIF_DATA_OUT_DATA_16_PACKED_RIGHT_MASK (0xffff << TEGRA_SPDIF_DATA_OUT_DATA_16_PACKED_RIGHT_SHIFT)
|
||||
|
||||
#define TEGRA_SPDIF_DATA_OUT_DATA_16_PACKED_LEFT_SHIFT 0
|
||||
#define TEGRA_SPDIF_DATA_OUT_DATA_16_PACKED_LEFT_MASK (0xffff << TEGRA_SPDIF_DATA_OUT_DATA_16_PACKED_LEFT_SHIFT)
|
||||
|
||||
/* Fields in TEGRA_SPDIF_DATA_IN */
|
||||
|
||||
/*
|
||||
* This register has 5 different formats:
|
||||
* 16-bit (BIT_MODE=00, PACK=0)
|
||||
* 20-bit (BIT_MODE=01, PACK=0)
|
||||
* 24-bit (BIT_MODE=10, PACK=0)
|
||||
* raw (BIT_MODE=11, PACK=0)
|
||||
* 16-bit packed (BIT_MODE=00, PACK=1)
|
||||
*
|
||||
* Bits 31:24 are common to all modes except 16-bit packed
|
||||
*/
|
||||
|
||||
#define TEGRA_SPDIF_DATA_IN_DATA_P (1 << 31)
|
||||
#define TEGRA_SPDIF_DATA_IN_DATA_C (1 << 30)
|
||||
#define TEGRA_SPDIF_DATA_IN_DATA_U (1 << 29)
|
||||
#define TEGRA_SPDIF_DATA_IN_DATA_V (1 << 28)
|
||||
|
||||
#define TEGRA_SPDIF_DATA_IN_DATA_PREAMBLE_SHIFT 24
|
||||
#define TEGRA_SPDIF_DATA_IN_DATA_PREAMBLE_MASK (0xf << TEGRA_SPDIF_DATA_IN_DATA_PREAMBLE_SHIFT)
|
||||
|
||||
#define TEGRA_SPDIF_DATA_IN_DATA_16_SHIFT 0
|
||||
#define TEGRA_SPDIF_DATA_IN_DATA_16_MASK (0xffff << TEGRA_SPDIF_DATA_IN_DATA_16_SHIFT)
|
||||
|
||||
#define TEGRA_SPDIF_DATA_IN_DATA_20_SHIFT 0
|
||||
#define TEGRA_SPDIF_DATA_IN_DATA_20_MASK (0xfffff << TEGRA_SPDIF_DATA_IN_DATA_20_SHIFT)
|
||||
|
||||
#define TEGRA_SPDIF_DATA_IN_DATA_24_SHIFT 0
|
||||
#define TEGRA_SPDIF_DATA_IN_DATA_24_MASK (0xffffff << TEGRA_SPDIF_DATA_IN_DATA_24_SHIFT)
|
||||
|
||||
#define TEGRA_SPDIF_DATA_IN_DATA_RAW_DATA_SHIFT 8
|
||||
#define TEGRA_SPDIF_DATA_IN_DATA_RAW_DATA_MASK (0xfffff << TEGRA_SPDIF_DATA_IN_DATA_RAW_DATA_SHIFT)
|
||||
|
||||
#define TEGRA_SPDIF_DATA_IN_DATA_RAW_AUX_SHIFT 4
|
||||
#define TEGRA_SPDIF_DATA_IN_DATA_RAW_AUX_MASK (0xf << TEGRA_SPDIF_DATA_IN_DATA_RAW_AUX_SHIFT)
|
||||
|
||||
#define TEGRA_SPDIF_DATA_IN_DATA_RAW_PREAMBLE_SHIFT 0
|
||||
#define TEGRA_SPDIF_DATA_IN_DATA_RAW_PREAMBLE_MASK (0xf << TEGRA_SPDIF_DATA_IN_DATA_RAW_PREAMBLE_SHIFT)
|
||||
|
||||
#define TEGRA_SPDIF_DATA_IN_DATA_16_PACKED_RIGHT_SHIFT 16
|
||||
#define TEGRA_SPDIF_DATA_IN_DATA_16_PACKED_RIGHT_MASK (0xffff << TEGRA_SPDIF_DATA_IN_DATA_16_PACKED_RIGHT_SHIFT)
|
||||
|
||||
#define TEGRA_SPDIF_DATA_IN_DATA_16_PACKED_LEFT_SHIFT 0
|
||||
#define TEGRA_SPDIF_DATA_IN_DATA_16_PACKED_LEFT_MASK (0xffff << TEGRA_SPDIF_DATA_IN_DATA_16_PACKED_LEFT_SHIFT)
|
||||
|
||||
/* Fields in TEGRA_SPDIF_CH_STA_RX_A */
|
||||
/* Fields in TEGRA_SPDIF_CH_STA_RX_B */
|
||||
/* Fields in TEGRA_SPDIF_CH_STA_RX_C */
|
||||
/* Fields in TEGRA_SPDIF_CH_STA_RX_D */
|
||||
/* Fields in TEGRA_SPDIF_CH_STA_RX_E */
|
||||
/* Fields in TEGRA_SPDIF_CH_STA_RX_F */
|
||||
|
||||
/*
|
||||
* The 6-word receive channel data page buffer holds a block (192 frames) of
|
||||
* channel status information. The order of receive is from LSB to MSB
|
||||
* bit, and from CH_STA_RX_A to CH_STA_RX_F then back to CH_STA_RX_A.
|
||||
*/
|
||||
|
||||
/* Fields in TEGRA_SPDIF_CH_STA_TX_A */
|
||||
/* Fields in TEGRA_SPDIF_CH_STA_TX_B */
|
||||
/* Fields in TEGRA_SPDIF_CH_STA_TX_C */
|
||||
/* Fields in TEGRA_SPDIF_CH_STA_TX_D */
|
||||
/* Fields in TEGRA_SPDIF_CH_STA_TX_E */
|
||||
/* Fields in TEGRA_SPDIF_CH_STA_TX_F */
|
||||
|
||||
/*
|
||||
* The 6-word transmit channel data page buffer holds a block (192 frames) of
|
||||
* channel status information. The order of transmission is from LSB to MSB
|
||||
* bit, and from CH_STA_TX_A to CH_STA_TX_F then back to CH_STA_TX_A.
|
||||
*/
|
||||
|
||||
/* Fields in TEGRA_SPDIF_USR_STA_RX_A */
|
||||
|
||||
/*
|
||||
* This 4-word deep FIFO receives user FIFO field information. The order of
|
||||
* receive is from LSB to MSB bit.
|
||||
*/
|
||||
|
||||
/* Fields in TEGRA_SPDIF_USR_DAT_TX_A */
|
||||
|
||||
/*
|
||||
* This 4-word deep FIFO transmits user FIFO field information. The order of
|
||||
* transmission is from LSB to MSB bit.
|
||||
*/
|
||||
|
||||
struct tegra_spdif {
|
||||
struct clk *clk_spdif_out;
|
||||
int clk_refs;
|
||||
struct tegra_pcm_dma_params capture_dma_data;
|
||||
struct tegra_pcm_dma_params playback_dma_data;
|
||||
void __iomem *regs;
|
||||
struct dentry *debug;
|
||||
u32 reg_ctrl;
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue