diff options
Diffstat (limited to 'sound')
89 files changed, 39125 insertions, 1608 deletions
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 3388442..cd69b38 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -1961,6 +1961,9 @@ static int pcm_sanity_check(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime; if (PCM_RUNTIME_CHECK(substream)) return -ENXIO; + /* TODO: consider and -EINVAL here */ + if (substream->hw_no_buffer) + snd_printd("%s: warning this PCM is host less\n", __func__); runtime = substream->runtime; if (snd_BUG_ON(!substream->ops->copy && !runtime->dma_area)) return -EINVAL; diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 7393551..4e9ebae 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -850,6 +850,7 @@ static int snd_pcm_pre_start(struct snd_pcm_substream *substream, int state) if (runtime->status->state != SNDRV_PCM_STATE_PREPARED) return -EBADFD; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && + !substream->hw_no_buffer && !snd_pcm_playback_data(substream)) return -EPIPE; runtime->trigger_master = substream; @@ -2048,6 +2049,12 @@ int snd_pcm_open_substream(struct snd_pcm *pcm, int stream, goto error; } + if (substream->ops == NULL) { + snd_printd("cannot open back end PCMs directly\n"); + err = -ENODEV; + goto error; + } + if ((err = substream->ops->open(substream)) < 0) goto error; diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 1ed61c5..0af7016 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -1,4 +1,4 @@ -snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o +snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o soc-dsp.o obj-$(CONFIG_SND_SOC) += snd-soc-core.o obj-$(CONFIG_SND_SOC) += codecs/ diff --git a/sound/soc/atmel/atmel-pcm.c b/sound/soc/atmel/atmel-pcm.c index d0e7532..42f699c 100644 --- a/sound/soc/atmel/atmel-pcm.c +++ b/sound/soc/atmel/atmel-pcm.c @@ -364,9 +364,11 @@ static struct snd_pcm_ops atmel_pcm_ops = { \*--------------------------------------------------------------------------*/ static u64 atmel_pcm_dmamask = 0xffffffff; -static int atmel_pcm_new(struct snd_card *card, - struct snd_soc_dai *dai, struct snd_pcm *pcm) +static int atmel_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; if (!card->dev->dma_mask) diff --git a/sound/soc/au1x/dbdma2.c b/sound/soc/au1x/dbdma2.c index 10fdd28..20bb53a 100644 --- a/sound/soc/au1x/dbdma2.c +++ b/sound/soc/au1x/dbdma2.c @@ -319,10 +319,11 @@ static void au1xpsc_pcm_free_dma_buffers(struct snd_pcm *pcm) snd_pcm_lib_preallocate_free_for_all(pcm); } -static int au1xpsc_pcm_new(struct snd_card *card, - struct snd_soc_dai *dai, - struct snd_pcm *pcm) +static int au1xpsc_pcm_new(struct snd_soc_pcm_runtime *rtd) { + struct snd_card *card = rtd->card->snd_card; + struct snd_pcm *pcm = rtd->pcm; + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, card->dev, AU1XPSC_BUFFER_MIN_BYTES, (4096 * 1024) - 1); diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.c b/sound/soc/blackfin/bf5xx-ac97-pcm.c index 98b44b3..9e59f68 100644 --- a/sound/soc/blackfin/bf5xx-ac97-pcm.c +++ b/sound/soc/blackfin/bf5xx-ac97-pcm.c @@ -418,9 +418,11 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm) static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32); -int bf5xx_pcm_ac97_new(struct snd_card *card, struct snd_soc_dai *dai, - struct snd_pcm *pcm) +int bf5xx_pcm_ac97_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; pr_debug("%s enter\n", __func__); diff --git a/sound/soc/blackfin/bf5xx-i2s-pcm.c b/sound/soc/blackfin/bf5xx-i2s-pcm.c index f1fd95b..c42fb73 100644 --- a/sound/soc/blackfin/bf5xx-i2s-pcm.c +++ b/sound/soc/blackfin/bf5xx-i2s-pcm.c @@ -257,9 +257,11 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm) static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32); -int bf5xx_pcm_i2s_new(struct snd_card *card, struct snd_soc_dai *dai, - struct snd_pcm *pcm) +int bf5xx_pcm_i2s_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; pr_debug("%s enter\n", __func__); diff --git a/sound/soc/blackfin/bf5xx-tdm-pcm.c b/sound/soc/blackfin/bf5xx-tdm-pcm.c index 07cfc7a..c95cc03 100644 --- a/sound/soc/blackfin/bf5xx-tdm-pcm.c +++ b/sound/soc/blackfin/bf5xx-tdm-pcm.c @@ -283,9 +283,11 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm) static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32); -static int bf5xx_pcm_tdm_new(struct snd_card *card, struct snd_soc_dai *dai, - struct snd_pcm *pcm) +static int bf5xx_pcm_tdm_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; if (!card->dev->dma_mask) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 98175a0..40e3a82 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -240,6 +240,10 @@ config SND_SOC_TWL4030 tristate config SND_SOC_TWL6040 + select TWL6040_CODEC + tristate + +config SND_SOC_OMAP_HDMI_CODEC tristate config SND_SOC_UDA134X diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index fd85584..04e7b26 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -36,6 +36,7 @@ snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o snd-soc-tlv320dac33-objs := tlv320dac33.o snd-soc-twl4030-objs := twl4030.o snd-soc-twl6040-objs := twl6040.o +snd-soc-omap-hdmi-codec-objs := omap-hdmi-codec.o snd-soc-uda134x-objs := uda134x.o snd-soc-uda1380-objs := uda1380.o snd-soc-wl1273-objs := wl1273.o @@ -128,6 +129,7 @@ obj-$(CONFIG_SND_SOC_TVL320AIC32X4) += snd-soc-tlv320aic32x4.o obj-$(CONFIG_SND_SOC_TLV320DAC33) += snd-soc-tlv320dac33.o obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o obj-$(CONFIG_SND_SOC_TWL6040) += snd-soc-twl6040.o +obj-$(CONFIG_SND_SOC_OMAP_HDMI_CODEC) += snd-soc-omap-hdmi-codec.o obj-$(CONFIG_SND_SOC_UDA134X) += snd-soc-uda134x.o obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o obj-$(CONFIG_SND_SOC_WL1273) += snd-soc-wl1273.o diff --git a/sound/soc/codecs/omap-hdmi-codec.c b/sound/soc/codecs/omap-hdmi-codec.c new file mode 100644 index 0000000..b1f3c72 --- /dev/null +++ b/sound/soc/codecs/omap-hdmi-codec.c @@ -0,0 +1,492 @@ +/* + * ALSA SoC HMDI codec driver + * + * Author: Ricardo Neri <ricardo.neri@ti.com> + * + * 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/moduleparam.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/gpio.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/initval.h> +#include <sound/tlv.h> + +#include <plat/omap_hwmod.h> +#include <video/omapdss.h> +#include <video/hdmi_ti_4xxx_ip.h> + +#include "../../../drivers/video/omap2/dss/dss_features.h" +#include "../../../drivers/video/omap2/dss/dss.h" + +#define HDMI_WP 0x0 +#define HDMI_CORE_SYS 0x400 +#define HDMI_CORE_AV 0x900 +#define HDMI_PLLCTRL 0x200 +#define HDMI_PHY 0x300 + +/* hdmi configuration params */ +struct hdmi_params { + int format; + int sample_freq; + int channels_nr; +}; + + +/* codec private data */ +struct hdmi_codec_data { + struct hdmi_audio_format audio_fmt; + struct hdmi_audio_dma audio_dma; + struct hdmi_core_audio_config audio_core_cfg; + struct hdmi_core_infoframe_audio aud_if_cfg; + struct hdmi_ip_data ip_data; + struct omap_hwmod *oh; + struct omap_dss_device *dssdev; + struct notifier_block notifier; + struct hdmi_params params; + struct delayed_work delayed_work; + struct workqueue_struct *workqueue; + int active; +} hdmi_data; + + +static int hdmi_audio_set_configuration(struct hdmi_codec_data *priv) +{ + struct hdmi_audio_format *audio_format = &priv->audio_fmt; + struct hdmi_audio_dma *audio_dma = &priv->audio_dma; + struct hdmi_core_audio_config *core_cfg = &priv->audio_core_cfg; + struct hdmi_core_infoframe_audio *aud_if_cfg = &priv->aud_if_cfg; + int err, n, cts, channel_alloc; + enum hdmi_core_audio_sample_freq sample_freq; + u32 pclk = omapdss_hdmi_get_pixel_clock(); + + switch (priv->params.format) { + case SNDRV_PCM_FORMAT_S16_LE: + core_cfg->i2s_cfg.word_max_length = + HDMI_AUDIO_I2S_MAX_WORD_20BITS; + core_cfg->i2s_cfg.word_length = + HDMI_AUDIO_I2S_CHST_WORD_16_BITS; + core_cfg->i2s_cfg.in_length_bits = + HDMI_AUDIO_I2S_INPUT_LENGTH_16; + core_cfg->i2s_cfg.justification = HDMI_AUDIO_JUSTIFY_LEFT; + audio_format->samples_per_word = HDMI_AUDIO_ONEWORD_TWOSAMPLES; + audio_format->sample_size = HDMI_AUDIO_SAMPLE_16BITS; + audio_format->justification = HDMI_AUDIO_JUSTIFY_LEFT; + audio_dma->transfer_size = 0x10; + break; + case SNDRV_PCM_FORMAT_S24_LE: + core_cfg->i2s_cfg.word_max_length = + HDMI_AUDIO_I2S_MAX_WORD_24BITS; + core_cfg->i2s_cfg.word_length = + HDMI_AUDIO_I2S_CHST_WORD_24_BITS; + core_cfg->i2s_cfg.in_length_bits = + HDMI_AUDIO_I2S_INPUT_LENGTH_24; + audio_format->samples_per_word = HDMI_AUDIO_ONEWORD_ONESAMPLE; + audio_format->sample_size = HDMI_AUDIO_SAMPLE_24BITS; + audio_format->justification = HDMI_AUDIO_JUSTIFY_RIGHT; + core_cfg->i2s_cfg.justification = HDMI_AUDIO_JUSTIFY_RIGHT; + audio_dma->transfer_size = 0x20; + break; + default: + return -EINVAL; + } + + + switch (priv->params.sample_freq) { + case 32000: + sample_freq = HDMI_AUDIO_FS_32000; + break; + case 44100: + sample_freq = HDMI_AUDIO_FS_44100; + break; + case 48000: + sample_freq = HDMI_AUDIO_FS_48000; + break; + default: + return -EINVAL; + } + + err = hdmi_ti_4xxx_config_audio_acr(&priv->ip_data, + priv->params.sample_freq, &n, &cts, pclk); + if (err < 0) + return err; + + /* Audio wrapper config */ + audio_format->type = HDMI_AUDIO_TYPE_LPCM; + audio_format->sample_order = HDMI_AUDIO_SAMPLE_LEFT_FIRST; + /* Disable start/stop signals of IEC 60958 blocks */ + audio_format->en_sig_blk_strt_end = HDMI_AUDIO_BLOCK_SIG_STARTEND_OFF; + + audio_dma->block_size = 0xC0; + audio_dma->mode = HDMI_AUDIO_TRANSF_DMA; + audio_dma->fifo_threshold = 0x20; /* in number of samples */ + + hdmi_ti_4xxx_wp_audio_config_dma(&priv->ip_data, audio_dma); + hdmi_ti_4xxx_wp_audio_config_format(&priv->ip_data, audio_format); + + /* + * I2S config + */ + core_cfg->i2s_cfg.en_high_bitrate_aud = false; + /* Only used with high bitrate audio */ + core_cfg->i2s_cfg.cbit_order = false; + /* Serial data and word select should change on sck rising edge */ + core_cfg->i2s_cfg.sck_edge_mode = HDMI_AUDIO_I2S_SCK_EDGE_RISING; + core_cfg->i2s_cfg.vbit = HDMI_AUDIO_I2S_VBIT_FOR_PCM; + /* Set I2S word select polarity */ + core_cfg->i2s_cfg.ws_polarity = HDMI_AUDIO_I2S_WS_POLARITY_LOW_IS_LEFT; + core_cfg->i2s_cfg.direction = HDMI_AUDIO_I2S_MSB_SHIFTED_FIRST; + /* Set serial data to word select shift. See Phillips spec. */ + core_cfg->i2s_cfg.shift = HDMI_AUDIO_I2S_FIRST_BIT_SHIFT; + + /* Core audio config */ + core_cfg->freq_sample = sample_freq; + core_cfg->n = n; + core_cfg->cts = cts; + if (dss_has_feature(FEAT_HDMI_CTS_SWMODE)) { + core_cfg->aud_par_busclk = 0; + core_cfg->cts_mode = HDMI_AUDIO_CTS_MODE_SW; + core_cfg->use_mclk = cpu_is_omap446x(); + } else { + core_cfg->aud_par_busclk = (((128 * 31) - 1) << 8); + core_cfg->cts_mode = HDMI_AUDIO_CTS_MODE_HW; + core_cfg->use_mclk = true; + core_cfg->mclk_mode = HDMI_AUDIO_MCLK_128FS; + } + core_cfg->en_spdif = false; + /* Use sample frequency from channel status word */ + core_cfg->fs_override = true; + /* Enable ACR packets */ + core_cfg->en_acr_pkt = true; + /* Disable direct streaming digital audio */ + core_cfg->en_dsd_audio = false; + /* Use parallel audio interface */ + core_cfg->en_parallel_aud_input = true; + + /* Number of channels */ + + switch (priv->params.channels_nr) { + case 2: + core_cfg->layout = HDMI_AUDIO_LAYOUT_2CH; + channel_alloc = 0x0; + audio_format->stereo_channels = HDMI_AUDIO_STEREO_ONECHANNEL; + audio_format->active_chnnls_msk = 0x03; + /* Enable one of the four available serial data channels */ + core_cfg->i2s_cfg.active_sds = HDMI_AUDIO_I2S_SD0_EN; + break; + case 6: + core_cfg->layout = HDMI_AUDIO_LAYOUT_8CH; + channel_alloc = 0xB; + audio_format->stereo_channels = HDMI_AUDIO_STEREO_FOURCHANNELS; + audio_format->active_chnnls_msk = 0x3f; + /* Enable all of the four available serial data channels */ + core_cfg->i2s_cfg.active_sds = HDMI_AUDIO_I2S_SD0_EN | + HDMI_AUDIO_I2S_SD1_EN | HDMI_AUDIO_I2S_SD2_EN | + HDMI_AUDIO_I2S_SD3_EN; + break; + case 8: + core_cfg->layout = HDMI_AUDIO_LAYOUT_8CH; + channel_alloc = 0x13; + audio_format->stereo_channels = HDMI_AUDIO_STEREO_FOURCHANNELS; + audio_format->active_chnnls_msk = 0xff; + /* Enable all of the four available serial data channels */ + core_cfg->i2s_cfg.active_sds = HDMI_AUDIO_I2S_SD0_EN | + HDMI_AUDIO_I2S_SD1_EN | HDMI_AUDIO_I2S_SD2_EN | + HDMI_AUDIO_I2S_SD3_EN; + break; + default: + pr_err("Unsupported number of channels\n"); + return -EINVAL; + } + + hdmi_ti_4xxx_core_audio_config(&priv->ip_data, core_cfg); + hdmi_ti_4xxx_wp_audio_config_format(&priv->ip_data, audio_format); + + /* + * Configure packet + * info frame audio see doc CEA861-D page 74 + */ + aud_if_cfg->db1_coding_type = HDMI_INFOFRAME_AUDIO_DB1CT_FROM_STREAM; + aud_if_cfg->db1_channel_count = priv->params.channels_nr; + aud_if_cfg->db2_sample_freq = HDMI_INFOFRAME_AUDIO_DB2SF_FROM_STREAM; + aud_if_cfg->db2_sample_size = HDMI_INFOFRAME_AUDIO_DB2SS_FROM_STREAM; + aud_if_cfg->db4_channel_alloc = channel_alloc; + aud_if_cfg->db5_downmix_inh = false; + aud_if_cfg->db5_lsv = 0; + + hdmi_ti_4xxx_core_audio_infoframe_config(&priv->ip_data, aud_if_cfg); + return 0; + +} + +int hdmi_audio_notifier_callback(struct notifier_block *nb, + unsigned long arg, void *ptr) +{ + enum omap_dss_display_state state = arg; + + if (state == OMAP_DSS_DISPLAY_ACTIVE) { + /* this happens just after hdmi_power_on */ + hdmi_audio_set_configuration(&hdmi_data); + if (hdmi_data.active) { + omap_hwmod_set_slave_idlemode(hdmi_data.oh, + HWMOD_IDLEMODE_NO); + hdmi_ti_4xxx_wp_audio_enable(&hdmi_data.ip_data, 1); + queue_delayed_work(hdmi_data.workqueue, + &hdmi_data.delayed_work, + msecs_to_jiffies(1)); + } + } else { + cancel_delayed_work(&hdmi_data.delayed_work); + } + return 0; +} + +static void hdmi_audio_work(struct work_struct *work) +{ + hdmi_ti_4xxx_audio_transfer_en(&hdmi_data.ip_data, 1); +} + +int hdmi_audio_match(struct omap_dss_device *dssdev, void *arg) +{ + return sysfs_streq(dssdev->name , "hdmi"); +} + +static int hdmi_audio_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec *codec = rtd->codec; + struct hdmi_codec_data *priv = snd_soc_codec_get_drvdata(codec); + + priv->params.format = params_format(params); + priv->params.sample_freq = params_rate(params); + priv->params.channels_nr = params_channels(params); + return hdmi_audio_set_configuration(priv); +} + +static int hdmi_audio_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec *codec = rtd->codec; + struct hdmi_codec_data *priv = snd_soc_codec_get_drvdata(codec); + int err = 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + /* + * switch to no-idle to avoid DSS_L3_ICLK clock + * to be shutdown during audio activity (as per TRM) + */ + omap_hwmod_set_slave_idlemode(priv->oh, + HWMOD_IDLEMODE_NO); + hdmi_ti_4xxx_wp_audio_enable(&priv->ip_data, 1); + queue_delayed_work(priv->workqueue, &priv->delayed_work, + msecs_to_jiffies(1)); + + priv->active = 1; + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + cancel_delayed_work(&hdmi_data.delayed_work); + priv->active = 0; + hdmi_ti_4xxx_audio_transfer_en(&priv->ip_data, 0); + hdmi_ti_4xxx_wp_audio_enable(&priv->ip_data, 0); + /* + * switch back to smart-idle & wakeup capable + * after audio activity stops + */ + omap_hwmod_set_slave_idlemode(priv->oh, + HWMOD_IDLEMODE_SMART_WKUP); + break; + default: + err = -EINVAL; + } + return err; +} + +static int hdmi_audio_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + if (!omapdss_hdmi_get_mode()) { + pr_err("Current video settings do not support audio.\n"); + return -EIO; + } + return 0; +} +static int hdmi_probe(struct snd_soc_codec *codec) +{ + struct platform_device *pdev = to_platform_device(codec->dev); + struct resource *hdmi_rsrc; + int ret = 0; + + snd_soc_codec_set_drvdata(codec, &hdmi_data); + + hdmi_rsrc = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + if (!hdmi_rsrc) { + dev_err(&pdev->dev, "Cannot obtain IORESOURCE_MEM HDMI\n"); + ret = -EINVAL; + goto res_err; + } + + + hdmi_data.oh = omap_hwmod_lookup("dss_hdmi"); + + if (!hdmi_data.oh) { + dev_err(&pdev->dev, "can't find omap_hwmod for hdmi\n"); + ret = -ENODEV; + goto res_err; + } + + /* Base address taken from platform */ + hdmi_data.ip_data.base_wp = ioremap(hdmi_rsrc->start, + resource_size(hdmi_rsrc)); + + if (!hdmi_data.ip_data.base_wp) { + dev_err(&pdev->dev, "can't ioremap WP\n"); + ret = -ENOMEM; + goto res_err; + } + + hdmi_data.ip_data.hdmi_core_sys_offset = HDMI_CORE_SYS; + hdmi_data.ip_data.hdmi_core_av_offset = HDMI_CORE_AV; + hdmi_data.ip_data.hdmi_pll_offset = HDMI_PLLCTRL; + hdmi_data.ip_data.hdmi_phy_offset = HDMI_PHY; + + hdmi_data.dssdev = omap_dss_find_device(NULL, hdmi_audio_match); + + if (!hdmi_data.dssdev) { + dev_err(&pdev->dev, "can't find HDMI device\n"); + ret = -ENODEV; + goto dssdev_err; + } + + hdmi_data.notifier.notifier_call = hdmi_audio_notifier_callback; + blocking_notifier_chain_register(&hdmi_data.dssdev->state_notifiers, + &hdmi_data.notifier); + + hdmi_data.workqueue = create_singlethread_workqueue("hdmi-codec"); + + INIT_DELAYED_WORK(&hdmi_data.delayed_work, hdmi_audio_work); + + return 0; + +dssdev_err: + iounmap(hdmi_data.ip_data.base_wp); +res_err: + return ret; + +} + +static int hdmi_remove(struct snd_soc_codec *codec) +{ + struct hdmi_codec_data *priv = snd_soc_codec_get_drvdata(codec); + + blocking_notifier_chain_unregister(&priv->dssdev->state_notifiers, + &priv->notifier); + iounmap(priv->ip_data.base_wp); + kfree(priv); + return 0; +} + + +static struct snd_soc_codec_driver hdmi_audio_codec_drv = { + .probe = hdmi_probe, + .remove = hdmi_remove, +}; + +static struct snd_soc_dai_ops hdmi_audio_codec_ops = { + .hw_params = hdmi_audio_hw_params, + .trigger = hdmi_audio_trigger, + .startup = hdmi_audio_startup, +}; + +static struct snd_soc_dai_driver hdmi_codec_dai_drv = { + .name = "hdmi-audio-codec", + .playback = { + .channels_min = 2, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE, + }, + .ops = &hdmi_audio_codec_ops, +}; + +static __devinit int hdmi_codec_probe(struct platform_device *pdev) +{ + int r; + + /* Register ASoC codec DAI */ + r = snd_soc_register_codec(&pdev->dev, &hdmi_audio_codec_drv, + &hdmi_codec_dai_drv, 1); + if (r) { + dev_err(&pdev->dev, "can't register ASoC HDMI audio codec\n"); + return r; + } + + return 0; +} + +static int __devexit hdmi_codec_remove(struct platform_device *pdev) +{ + snd_soc_unregister_codec(&pdev->dev); + return 0; +} + + +static struct platform_driver hdmi_codec_driver = { + .probe = hdmi_codec_probe, + .remove = __devexit_p(hdmi_codec_remove), + .driver = { + .name = "omap-hdmi-codec", + .owner = THIS_MODULE, + }, +}; + + +static int __init hdmi_codec_init(void) +{ + return platform_driver_register(&hdmi_codec_driver); +} +module_init(hdmi_codec_init); + +static void __exit hdmi_codec_exit(void) +{ + platform_driver_unregister(&hdmi_codec_driver); +} +module_exit(hdmi_codec_exit); + + +MODULE_AUTHOR("Ricardo Neri <ricardo.neri@ti.com>"); +MODULE_DESCRIPTION("ASoC HDMI codec driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c index 4c33663..b23fb26 100644 --- a/sound/soc/codecs/twl6040.c +++ b/sound/soc/codecs/twl6040.c @@ -29,6 +29,7 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/i2c/twl.h> +#include <linux/mfd/twl6040-codec.h> #include <sound/core.h> #include <sound/pcm.h> @@ -57,6 +58,8 @@ #define TWL6040_HSR_VOL_SHIFT 4 #define TWL6040_HF_VOL_MASK 0x1F #define TWL6040_HF_VOL_SHIFT 0 +#define TWL6040_EP_VOL_MASK 0x1E +#define TWL6040_EP_VOL_SHIFT 1 struct twl6040_output { u16 active; @@ -77,25 +80,32 @@ struct twl6040_jack_data { /* codec private data */ struct twl6040_data { - int audpwron; - int naudint; int codec_powered; int pll; - int non_lp; + int power_mode_forced; + int headset_mode; + unsigned int clk_in; unsigned int sysclk; + u16 hs_left_step; + u16 hs_right_step; + u16 hf_left_step; + u16 hf_right_step; + u16 ep_step; struct snd_pcm_hw_constraint_list *sysclk_constraints; - struct completion ready; struct twl6040_jack_data hs_jack; struct snd_soc_codec *codec; struct workqueue_struct *workqueue; struct delayed_work delayed_work; struct mutex mutex; struct twl6040_output headset; + struct twl6040_output earphone; struct twl6040_output handsfree; struct workqueue_struct *hf_workqueue; struct workqueue_struct *hs_workqueue; + struct workqueue_struct *ep_workqueue; struct delayed_work hs_delayed_work; struct delayed_work hf_delayed_work; + struct delayed_work ep_delayed_work; }; /* @@ -120,12 +130,12 @@ static const u8 twl6040_reg[TWL6040_CACHEREGNUM] = { 0x1B, /* TWL6040_LINEGAIN 0x0F */ 0x00, /* TWL6040_HSLCTL 0x10 */ 0x00, /* TWL6040_HSRCTL 0x11 */ - 0x00, /* TWL6040_HSGAIN 0x12 */ - 0x00, /* TWL6040_EARCTL 0x13 */ + 0xFF, /* TWL6040_HSGAIN 0x12 */ + 0x1E, /* TWL6040_EARCTL 0x13 */ 0x00, /* TWL6040_HFLCTL 0x14 */ - 0x00, /* TWL6040_HFLGAIN 0x15 */ + 0x1D, /* TWL6040_HFLGAIN 0x15 */ 0x00, /* TWL6040_HFRCTL 0x16 */ - 0x00, /* TWL6040_HFRGAIN 0x17 */ + 0x1D, /* TWL6040_HFRGAIN 0x17 */ 0x00, /* TWL6040_VIBCTLL 0x18 */ 0x00, /* TWL6040_VIBDATL 0x19 */ 0x00, /* TWL6040_VIBCTLR 0x1A */ @@ -151,59 +161,59 @@ static const u8 twl6040_reg[TWL6040_CACHEREGNUM] = { 0x00, /* TWL6040_STATUS (ro) 0x2E */ }; -/* - * twl6040 vio/gnd registers: - * registers under vio/gnd supply can be accessed - * before the power-up sequence, after NRESPWRON goes high - */ -static const int twl6040_vio_reg[TWL6040_VIOREGNUM] = { - TWL6040_REG_ASICID, - TWL6040_REG_ASICREV, - TWL6040_REG_INTID, - TWL6040_REG_INTMR, - TWL6040_REG_NCPCTL, - TWL6040_REG_LDOCTL, - TWL6040_REG_AMICBCTL, - TWL6040_REG_DMICBCTL, - TWL6040_REG_HKCTL1, - TWL6040_REG_HKCTL2, - TWL6040_REG_GPOCTL, - TWL6040_REG_TRIM1, - TWL6040_REG_TRIM2, - TWL6040_REG_TRIM3, - TWL6040_REG_HSOTRIM, - TWL6040_REG_HFOTRIM, - TWL6040_REG_ACCCTL, - TWL6040_REG_STATUS, -}; -/* - * twl6040 vdd/vss registers: - * registers under vdd/vss supplies can only be accessed - * after the power-up sequence - */ -static const int twl6040_vdd_reg[TWL6040_VDDREGNUM] = { - TWL6040_REG_HPPLLCTL, - TWL6040_REG_LPPLLCTL, - TWL6040_REG_LPPLLDIV, - TWL6040_REG_MICLCTL, - TWL6040_REG_MICRCTL, - TWL6040_REG_MICGAIN, - TWL6040_REG_LINEGAIN, - TWL6040_REG_HSLCTL, - TWL6040_REG_HSRCTL, - TWL6040_REG_HSGAIN, - TWL6040_REG_EARCTL, - TWL6040_REG_HFLCTL, - TWL6040_REG_HFLGAIN, - TWL6040_REG_HFRCTL, - TWL6040_REG_HFRGAIN, - TWL6040_REG_VIBCTLL, - TWL6040_REG_VIBDATL, - TWL6040_REG_VIBCTLR, - TWL6040_REG_VIBDATR, - TWL6040_REG_ALB, - TWL6040_REG_DLB, +/* twl6040 vio/gnd registers: registers under vio/gnd supply can be accessed + * twl6040 vdd/vss registers: registers under vdd/vss supplies can only be + * accessed after the power-up sequence */ + +static const u8 twl6040_reg_supply[TWL6040_CACHEREGNUM] = { + TWL6040_NO_SUPPLY, /* not used */ + TWL6040_VIO_SUPPLY, /* TWL6040_ASICID (ro) */ + TWL6040_VIO_SUPPLY, /* TWL6040_ASICREV (ro) */ + TWL6040_VIO_SUPPLY, /* TWL6040_INTID */ + TWL6040_VIO_SUPPLY, /* TWL6040_INTMR */ + TWL6040_VIO_SUPPLY, /* TWL6040_NCPCTRL */ + TWL6040_VIO_SUPPLY, /* TWL6040_LDOCTL */ + TWL6040_VDD_SUPPLY, /* TWL6040_HPPLLCTL */ + TWL6040_VDD_SUPPLY, /* TWL6040_LPPLLCTL */ + TWL6040_VDD_SUPPLY, /* TWL6040_LPPLLDIV */ + TWL6040_VIO_SUPPLY, /* TWL6040_AMICBCTL */ + TWL6040_VIO_SUPPLY, /* TWL6040_DMICBCTL */ + TWL6040_VDD_SUPPLY, /* TWL6040_MICLCTL */ + TWL6040_VDD_SUPPLY, /* TWL6040_MICRCTL */ + TWL6040_VDD_SUPPLY, /* TWL6040_MICGAIN */ + TWL6040_VDD_SUPPLY, /* TWL6040_LINEGAIN */ + TWL6040_VDD_SUPPLY, /* TWL6040_HSLCTL */ + TWL6040_VDD_SUPPLY, /* TWL6040_HSRCTL */ + TWL6040_VDD_SUPPLY, /* TWL6040_HSGAIN */ + TWL6040_VDD_SUPPLY, /* TWL6040_EARCTL */ + TWL6040_VDD_SUPPLY, /* TWL6040_HFLCTL */ + TWL6040_VDD_SUPPLY, /* TWL6040_HFLGAIN */ + TWL6040_VDD_SUPPLY, /* TWL6040_HFRCTL */ + TWL6040_VDD_SUPPLY, /* TWL6040_HFRGAIN */ + TWL6040_VDD_SUPPLY, /* TWL6040_VIBCTLL */ + TWL6040_VDD_SUPPLY, /* TWL6040_VIBDATL */ + TWL6040_VDD_SUPPLY, /* TWL6040_VIBCTLR */ + TWL6040_VDD_SUPPLY, /* TWL6040_VIBDATR */ + TWL6040_VIO_SUPPLY, /* TWL6040_HKCTL1 */ + TWL6040_VIO_SUPPLY, /* TWL6040_HKCTL2 */ + TWL6040_VIO_SUPPLY, /* TWL6040_GPOCTL */ + TWL6040_VDD_SUPPLY, /* TWL6040_ALB */ + TWL6040_VDD_SUPPLY, /* TWL6040_DLB */ + TWL6040_NO_SUPPLY, /* not used */ + TWL6040_NO_SUPPLY, /* not used */ + TWL6040_NO_SUPPLY, /* not used */ + TWL6040_NO_SUPPLY, /* not used */ + TWL6040_NO_SUPPLY, /* not used */ + TWL6040_NO_SUPPLY, /* not used */ + TWL6040_NO_SUPPLY, /* not used */ + TWL6040_VIO_SUPPLY, /* TWL6040_TRIM1 */ + TWL6040_VIO_SUPPLY, /* TWL6040_TRIM2 */ + TWL6040_VIO_SUPPLY, /* TWL6040_TRIM3 */ + TWL6040_VIO_SUPPLY, /* TWL6040_HSOTRIM */ + TWL6040_VIO_SUPPLY, /* TWL6040_HFOTRIM */ + TWL6040_VIO_SUPPLY, /* TWL6040_ACCCTL */ + TWL6040_VIO_SUPPLY, /* TWL6040_STATUS (ro) */ }; /* @@ -237,14 +247,21 @@ static inline void twl6040_write_reg_cache(struct snd_soc_codec *codec, * read from twl6040 hardware register */ static int twl6040_read_reg_volatile(struct snd_soc_codec *codec, - unsigned int reg) + unsigned int reg) { - u8 value; + struct twl6040 *twl6040 = codec->control_data; + struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); + u8 value = 0; if (reg >= TWL6040_CACHEREGNUM) return -EIO; - twl_i2c_read_u8(TWL_MODULE_AUDIO_VOICE, &value, reg); + /* read access not supported while in sleep state */ + if ((twl6040_reg_supply[reg] == TWL6040_VDD_SUPPLY) && + !priv->codec_powered) + return -EINVAL; + + value = twl6040_reg_read(twl6040, reg); twl6040_write_reg_cache(codec, reg, value); return value; @@ -256,29 +273,52 @@ static int twl6040_read_reg_volatile(struct snd_soc_codec *codec, static int twl6040_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { + struct twl6040 *twl6040 = codec->control_data; + struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); + int ret = 0; + if (reg >= TWL6040_CACHEREGNUM) return -EIO; twl6040_write_reg_cache(codec, reg, value); - return twl_i2c_write_u8(TWL_MODULE_AUDIO_VOICE, value, reg); + + if ((twl6040_reg_supply[reg] == TWL6040_VIO_SUPPLY) || + priv->codec_powered) + ret = twl6040_reg_write(twl6040, reg, value); + else + dev_dbg(codec->dev, "deferring register 0x%02x write: %02x\n", + reg, value); + + return ret; } static void twl6040_init_vio_regs(struct snd_soc_codec *codec) { u8 *cache = codec->reg_cache; - int reg, i; - - /* allow registers to be accessed by i2c */ - twl6040_write(codec, TWL6040_REG_ACCCTL, cache[TWL6040_REG_ACCCTL]); + int reg; - for (i = 0; i < TWL6040_VIOREGNUM; i++) { - reg = twl6040_vio_reg[i]; - /* skip read-only registers (ASICID, ASICREV, STATUS) */ + for (reg = 0; reg < TWL6040_CACHEREGNUM; reg++) { + if (twl6040_reg_supply[reg] != TWL6040_VIO_SUPPLY) + continue; + /* + * skip read-only registers (ASICID, ASICREV, STATUS) + * and registers shared among MFD children + */ switch (reg) { case TWL6040_REG_ASICID: case TWL6040_REG_ASICREV: + case TWL6040_REG_INTID: + case TWL6040_REG_INTMR: + case TWL6040_REG_NCPCTL: + case TWL6040_REG_LDOCTL: + case TWL6040_REG_GPOCTL: + case TWL6040_REG_ACCCTL: case TWL6040_REG_STATUS: continue; + case TWL6040_REG_HSOTRIM: + case TWL6040_REG_HFOTRIM: + twl6040_read_reg_volatile(codec, reg); + continue; default: break; } @@ -289,10 +329,24 @@ static void twl6040_init_vio_regs(struct snd_soc_codec *codec) static void twl6040_init_vdd_regs(struct snd_soc_codec *codec) { u8 *cache = codec->reg_cache; - int reg, i; + int reg; - for (i = 0; i < TWL6040_VDDREGNUM; i++) { - reg = twl6040_vdd_reg[i]; + for (reg = 0; reg < TWL6040_CACHEREGNUM; reg++) { + if (twl6040_reg_supply[reg] != TWL6040_VDD_SUPPLY) + continue; + /* skip vibra and pll registers */ + switch (reg) { + case TWL6040_REG_VIBCTLL: + case TWL6040_REG_VIBDATL: + case TWL6040_REG_VIBCTLR: + case TWL6040_REG_VIBDATR: + case TWL6040_REG_HPPLLCTL: + case TWL6040_REG_LPPLLCTL: + case TWL6040_REG_LPPLLDIV: + continue; + default: + break; + } twl6040_write(codec, reg, cache[reg]); } } @@ -317,7 +371,11 @@ static inline int twl6040_hs_ramp_step(struct snd_soc_codec *codec, if (headset->ramp == TWL6040_RAMP_UP) { /* ramp step up */ if (val < headset->left_vol) { - val += left_step; + if (val + left_step > headset->left_vol) + val = headset->left_vol; + else + val += left_step; + reg &= ~TWL6040_HSL_VOL_MASK; twl6040_write(codec, TWL6040_REG_HSGAIN, (reg | (~val & TWL6040_HSL_VOL_MASK))); @@ -327,7 +385,11 @@ static inline int twl6040_hs_ramp_step(struct snd_soc_codec *codec, } else if (headset->ramp == TWL6040_RAMP_DOWN) { /* ramp step down */ if (val > 0x0) { - val -= left_step; + if ((int)val - (int)left_step < 0) + val = 0; + else + val -= left_step; + reg &= ~TWL6040_HSL_VOL_MASK; twl6040_write(codec, TWL6040_REG_HSGAIN, reg | (~val & TWL6040_HSL_VOL_MASK)); @@ -344,7 +406,11 @@ static inline int twl6040_hs_ramp_step(struct snd_soc_codec *codec, if (headset->ramp == TWL6040_RAMP_UP) { /* ramp step up */ if (val < headset->right_vol) { - val += right_step; + if (val + right_step > headset->right_vol) + val = headset->right_vol; + else + val += right_step; + reg &= ~TWL6040_HSR_VOL_MASK; twl6040_write(codec, TWL6040_REG_HSGAIN, (reg | (~val << TWL6040_HSR_VOL_SHIFT))); @@ -354,7 +420,11 @@ static inline int twl6040_hs_ramp_step(struct snd_soc_codec *codec, } else if (headset->ramp == TWL6040_RAMP_DOWN) { /* ramp step down */ if (val > 0x0) { - val -= right_step; + if ((int)val - (int)right_step < 0) + val = 0; + else + val -= right_step; + reg &= ~TWL6040_HSR_VOL_MASK; twl6040_write(codec, TWL6040_REG_HSGAIN, reg | (~val << TWL6040_HSR_VOL_SHIFT)); @@ -385,7 +455,11 @@ static inline int twl6040_hf_ramp_step(struct snd_soc_codec *codec, if (handsfree->ramp == TWL6040_RAMP_UP) { /* ramp step up */ if (val < handsfree->left_vol) { - val += left_step; + if (val + left_step > handsfree->left_vol) + val = handsfree->left_vol; + else + val += left_step; + reg &= ~TWL6040_HF_VOL_MASK; twl6040_write(codec, TWL6040_REG_HFLGAIN, reg | (0x1D - val)); @@ -395,7 +469,11 @@ static inline int twl6040_hf_ramp_step(struct snd_soc_codec *codec, } else if (handsfree->ramp == TWL6040_RAMP_DOWN) { /* ramp step down */ if (val > 0) { - val -= left_step; + if ((int)val - (int)left_step < 0) + val = 0; + else + val -= left_step; + reg &= ~TWL6040_HF_VOL_MASK; twl6040_write(codec, TWL6040_REG_HFLGAIN, reg | (0x1D - val)); @@ -412,7 +490,11 @@ static inline int twl6040_hf_ramp_step(struct snd_soc_codec *codec, if (handsfree->ramp == TWL6040_RAMP_UP) { /* ramp step up */ if (val < handsfree->right_vol) { - val += right_step; + if (val + right_step > handsfree->right_vol) + val = handsfree->right_vol; + else + val += right_step; + reg &= ~TWL6040_HF_VOL_MASK; twl6040_write(codec, TWL6040_REG_HFRGAIN, reg | (0x1D - val)); @@ -422,10 +504,16 @@ static inline int twl6040_hf_ramp_step(struct snd_soc_codec *codec, } else if (handsfree->ramp == TWL6040_RAMP_DOWN) { /* ramp step down */ if (val > 0) { - val -= right_step; + if ((int)val - (int)right_step < 0) + val = 0; + else + val -= right_step; + reg &= ~TWL6040_HF_VOL_MASK; twl6040_write(codec, TWL6040_REG_HFRGAIN, reg | (0x1D - val)); + } else { + right_complete = 1; } } @@ -433,6 +521,57 @@ static inline int twl6040_hf_ramp_step(struct snd_soc_codec *codec, } /* + * Ramp Earpiece PGA volume to minimise pops at stream startup and shutdown. + */ +static inline int twl6040_ep_ramp_step(struct snd_soc_codec *codec, + unsigned int step) +{ + + struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); + struct twl6040_output *earphone = &priv->earphone; + int complete = 0; + u8 reg, val; + + step = (step > 0xF) ? 0xF : step; + reg = twl6040_read_reg_cache(codec, TWL6040_REG_EARCTL); + val = (~reg & TWL6040_EP_VOL_MASK) >> TWL6040_EP_VOL_SHIFT; + + if (earphone->ramp == TWL6040_RAMP_UP) { + /* ramp step up */ + if (val < earphone->left_vol) { + if (val + step > earphone->left_vol) + val = earphone->left_vol; + else + val += step; + + reg &= ~TWL6040_EP_VOL_MASK; + val = ~val << TWL6040_EP_VOL_SHIFT; + twl6040_write(codec, TWL6040_REG_EARCTL, + reg | (val & TWL6040_EP_VOL_MASK)); + } else { + complete = 1; + } + } else if (earphone->ramp == TWL6040_RAMP_DOWN) { + /* ramp step down */ + if (val > 0x0) { + if ((int)val - (int)step < 0) + val = 0; + else + val -= step; + + reg &= ~TWL6040_EP_VOL_MASK; + val = ~val << TWL6040_EP_VOL_SHIFT; + twl6040_write(codec, TWL6040_REG_EARCTL, + reg | (val & TWL6040_EP_VOL_MASK)); + } else { + complete = 1; + } + } + + return complete; +} + +/* * This work ramps both output PGAs at stream start/stop time to * minimise pop associated with DAPM power switching. */ @@ -451,11 +590,9 @@ static void twl6040_pga_hs_work(struct work_struct *work) /* HS PGA volumes have 4 bits of resolution to ramp */ for (i = 0; i <= 16; i++) { - headset_complete = 1; - if (headset->ramp != TWL6040_RAMP_NONE) - headset_complete = twl6040_hs_ramp_step(codec, - headset->left_step, - headset->right_step); + headset_complete = twl6040_hs_ramp_step(codec, + headset->left_step, + headset->right_step); /* ramp finished ? */ if (headset_complete) @@ -496,11 +633,9 @@ static void twl6040_pga_hf_work(struct work_struct *work) /* HF PGA volumes have 5 bits of resolution to ramp */ for (i = 0; i <= 32; i++) { - handsfree_complete = 1; - if (handsfree->ramp != TWL6040_RAMP_NONE) - handsfree_complete = twl6040_hf_ramp_step(codec, - handsfree->left_step, - handsfree->right_step); + handsfree_complete = twl6040_hf_ramp_step(codec, + handsfree->left_step, + handsfree->right_step); /* ramp finished ? */ if (handsfree_complete) @@ -526,6 +661,48 @@ static void twl6040_pga_hf_work(struct work_struct *work) handsfree->ramp = TWL6040_RAMP_NONE; } +static void twl6040_pga_ep_work(struct work_struct *work) +{ + struct twl6040_data *priv = + container_of(work, struct twl6040_data, ep_delayed_work.work); + struct snd_soc_codec *codec = priv->codec; + struct twl6040_output *earphone = &priv->earphone; + unsigned int delay = earphone->step_delay; + int i, earphone_complete; + + /* do we need to ramp at all ? */ + if (earphone->ramp == TWL6040_RAMP_NONE) + return; + + /* Earpiece PGA volumes have 4 bits of resolution to ramp */ + for (i = 0; i <= 16; i++) { + earphone_complete = twl6040_ep_ramp_step(codec, + earphone->left_step); + + /* ramp finished ? */ + if (earphone_complete) + break; + + /* + * TODO: tune: delay is longer over 0dB + * as increases are larger. + */ + if (i >= 8) + schedule_timeout_interruptible(msecs_to_jiffies(delay + + (delay >> 1))); + else + schedule_timeout_interruptible(msecs_to_jiffies(delay)); + } + + if (earphone->ramp == TWL6040_RAMP_DOWN) { + earphone->active = 0; + complete(&earphone->ramp_done); + } else { + earphone->active = 1; + } + earphone->ramp = TWL6040_RAMP_NONE; +} + static int pga_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -536,22 +713,29 @@ static int pga_event(struct snd_soc_dapm_widget *w, struct workqueue_struct *queue; switch (w->shift) { + case 0: + out = &priv->earphone; + work = &priv->ep_delayed_work; + queue = priv->ep_workqueue; + out->left_step = priv->ep_step; + out->step_delay = 5; /* 5 ms between volume ramp steps */ + break; case 2: case 3: out = &priv->headset; work = &priv->hs_delayed_work; queue = priv->hs_workqueue; + out->left_step = priv->hs_left_step; + out->right_step = priv->hs_right_step; out->step_delay = 5; /* 5 ms between volume ramp steps */ break; case 4: out = &priv->handsfree; work = &priv->hf_delayed_work; queue = priv->hf_workqueue; + out->left_step = priv->hf_left_step; + out->right_step = priv->hf_right_step; out->step_delay = 5; /* 5 ms between volume ramp steps */ - if (SND_SOC_DAPM_EVENT_ON(event)) - priv->non_lp++; - else - priv->non_lp--; break; default: return -1; @@ -579,8 +763,6 @@ static int pga_event(struct snd_soc_dapm_widget *w, if (!delayed_work_pending(work)) { /* use volume ramp for power-down */ - out->left_step = 1; - out->right_step = 1; out->ramp = TWL6040_RAMP_DOWN; INIT_COMPLETION(out->ramp_done); @@ -596,88 +778,6 @@ static int pga_event(struct snd_soc_dapm_widget *w, return 0; } -/* twl6040 codec manual power-up sequence */ -static void twl6040_power_up(struct snd_soc_codec *codec) -{ - u8 ncpctl, ldoctl, lppllctl, accctl; - - ncpctl = twl6040_read_reg_cache(codec, TWL6040_REG_NCPCTL); - ldoctl = twl6040_read_reg_cache(codec, TWL6040_REG_LDOCTL); - lppllctl = twl6040_read_reg_cache(codec, TWL6040_REG_LPPLLCTL); - accctl = twl6040_read_reg_cache(codec, TWL6040_REG_ACCCTL); - - /* enable reference system */ - ldoctl |= TWL6040_REFENA; - twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl); - msleep(10); - /* enable internal oscillator */ - ldoctl |= TWL6040_OSCENA; - twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl); - udelay(10); - /* enable high-side ldo */ - ldoctl |= TWL6040_HSLDOENA; - twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl); - udelay(244); - /* enable negative charge pump */ - ncpctl |= TWL6040_NCPENA | TWL6040_NCPOPEN; - twl6040_write(codec, TWL6040_REG_NCPCTL, ncpctl); - udelay(488); - /* enable low-side ldo */ - ldoctl |= TWL6040_LSLDOENA; - twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl); - udelay(244); - /* enable low-power pll */ - lppllctl |= TWL6040_LPLLENA; - twl6040_write(codec, TWL6040_REG_LPPLLCTL, lppllctl); - /* reset state machine */ - accctl |= TWL6040_RESETSPLIT; - twl6040_write(codec, TWL6040_REG_ACCCTL, accctl); - mdelay(5); - accctl &= ~TWL6040_RESETSPLIT; - twl6040_write(codec, TWL6040_REG_ACCCTL, accctl); - /* disable internal oscillator */ - ldoctl &= ~TWL6040_OSCENA; - twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl); -} - -/* twl6040 codec manual power-down sequence */ -static void twl6040_power_down(struct snd_soc_codec *codec) -{ - u8 ncpctl, ldoctl, lppllctl, accctl; - - ncpctl = twl6040_read_reg_cache(codec, TWL6040_REG_NCPCTL); - ldoctl = twl6040_read_reg_cache(codec, TWL6040_REG_LDOCTL); - lppllctl = twl6040_read_reg_cache(codec, TWL6040_REG_LPPLLCTL); - accctl = twl6040_read_reg_cache(codec, TWL6040_REG_ACCCTL); - - /* enable internal oscillator */ - ldoctl |= TWL6040_OSCENA; - twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl); - udelay(10); - /* disable low-power pll */ - lppllctl &= ~TWL6040_LPLLENA; - twl6040_write(codec, TWL6040_REG_LPPLLCTL, lppllctl); - /* disable low-side ldo */ - ldoctl &= ~TWL6040_LSLDOENA; - twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl); - udelay(244); - /* disable negative charge pump */ - ncpctl &= ~(TWL6040_NCPENA | TWL6040_NCPOPEN); - twl6040_write(codec, TWL6040_REG_NCPCTL, ncpctl); - udelay(488); - /* disable high-side ldo */ - ldoctl &= ~TWL6040_HSLDOENA; - twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl); - udelay(244); - /* disable internal oscillator */ - ldoctl &= ~TWL6040_OSCENA; - twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl); - /* disable reference system */ - ldoctl &= ~TWL6040_REFENA; - twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl); - msleep(10); -} - /* set headset dac and driver power mode */ static int headset_power_mode(struct snd_soc_codec *codec, int high_perf) { @@ -701,27 +801,32 @@ static int headset_power_mode(struct snd_soc_codec *codec, int high_perf) return 0; } -static int twl6040_hs_dac_event(struct snd_soc_dapm_widget *w, +static int twl6040_dac_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { msleep(1); return 0; } -static int twl6040_power_mode_event(struct snd_soc_dapm_widget *w, +static int twl6040_ep_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = w->codec; struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); + int ret = 0; - if (SND_SOC_DAPM_EVENT_ON(event)) - priv->non_lp++; - else - priv->non_lp--; + if (SND_SOC_DAPM_EVENT_ON(event)) { + /* Earphone doesn't support low power mode */ + priv->power_mode_forced = 1; + ret = headset_power_mode(codec, 1); + } else { + priv->power_mode_forced = 0; + ret = headset_power_mode(codec, priv->headset_mode); + } msleep(1); - return 0; + return ret; } static void twl6040_hs_jack_report(struct snd_soc_codec *codec, @@ -766,32 +871,18 @@ static void twl6040_accessory_work(struct work_struct *work) } /* audio interrupt handler */ -static irqreturn_t twl6040_naudint_handler(int irq, void *data) +static irqreturn_t twl6040_audio_handler(int irq, void *data) { struct snd_soc_codec *codec = data; + struct twl6040 *twl6040 = codec->control_data; struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); u8 intid; - twl_i2c_read_u8(TWL_MODULE_AUDIO_VOICE, &intid, TWL6040_REG_INTID); - - if (intid & TWL6040_THINT) - dev_alert(codec->dev, "die temp over-limit detection\n"); + intid = twl6040_reg_read(twl6040, TWL6040_REG_INTID); if ((intid & TWL6040_PLUGINT) || (intid & TWL6040_UNPLUGINT)) queue_delayed_work(priv->workqueue, &priv->delayed_work, - msecs_to_jiffies(200)); - - if (intid & TWL6040_HOOKINT) - dev_info(codec->dev, "hook detection\n"); - - if (intid & TWL6040_HFINT) - dev_alert(codec->dev, "hf drivers over current detection\n"); - - if (intid & TWL6040_VIBINT) - dev_alert(codec->dev, "vib drivers over current detection\n"); - - if (intid & TWL6040_READYINT) - complete(&priv->ready); + msecs_to_jiffies(200)); return IRQ_HANDLED; } @@ -807,13 +898,16 @@ static int twl6040_put_volsw(struct snd_kcontrol *kcontrol, int ret; unsigned int reg = mc->reg; - /* For HS and HF we shadow the values and only actually write + /* For HS and EP we shadow the values and only actually write * them out when active in order to ensure the amplifier comes on * as quietly as possible. */ switch (reg) { case TWL6040_REG_HSGAIN: out = &twl6040_priv->headset; break; + case TWL6040_REG_EARCTL: + out = &twl6040_priv->earphone; + break; default: break; } @@ -848,7 +942,10 @@ static int twl6040_get_volsw(struct snd_kcontrol *kcontrol, ucontrol->value.integer.value[0] = out->left_vol; ucontrol->value.integer.value[1] = out->right_vol; return 0; - + case TWL6040_REG_EARCTL: + out = &twl6040_priv->earphone; + ucontrol->value.integer.value[0] = out->left_vol; + return 0; default: break; } @@ -919,33 +1016,6 @@ static int twl6040_get_volsw_2r(struct snd_kcontrol *kcontrol, return snd_soc_get_volsw_2r(kcontrol, ucontrol); } -/* double control with volume update */ -#define SOC_TWL6040_DOUBLE_TLV(xname, xreg, shift_left, shift_right, xmax,\ - xinvert, tlv_array)\ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ - .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ - SNDRV_CTL_ELEM_ACCESS_READWRITE,\ - .tlv.p = (tlv_array), \ - .info = snd_soc_info_volsw, .get = twl6040_get_volsw, \ - .put = twl6040_put_volsw, \ - .private_value = (unsigned long)&(struct soc_mixer_control) \ - {.reg = xreg, .shift = shift_left, .rshift = shift_right,\ - .max = xmax, .platform_max = xmax, .invert = xinvert} } - -/* double control with volume update */ -#define SOC_TWL6040_DOUBLE_R_TLV(xname, reg_left, reg_right, xshift, xmax,\ - xinvert, tlv_array)\ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ - .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ - SNDRV_CTL_ELEM_ACCESS_READWRITE | \ - SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ - .tlv.p = (tlv_array), \ - .info = snd_soc_info_volsw_2r, \ - .get = twl6040_get_volsw_2r, .put = twl6040_put_volsw_2r_vu, \ - .private_value = (unsigned long)&(struct soc_mixer_control) \ - {.reg = reg_left, .rreg = reg_right, .shift = xshift, \ - .rshift = xshift, .max = xmax, .invert = xinvert}, } - /* * MICATT volume control: * from -6 to 0 dB in 6 dB steps @@ -954,9 +1024,9 @@ static DECLARE_TLV_DB_SCALE(mic_preamp_tlv, -600, 600, 0); /* * MICGAIN volume control: - * from -6 to 30 dB in 6 dB steps + * from 6 to 30 dB in 6 dB steps */ -static DECLARE_TLV_DB_SCALE(mic_amp_tlv, -600, 600, 0); +static DECLARE_TLV_DB_SCALE(mic_amp_tlv, 600, 600, 0); /* * AFMGAIN volume control: @@ -1040,6 +1110,44 @@ static const struct snd_kcontrol_new hfr_mux_controls = static const struct snd_kcontrol_new ep_driver_switch_controls = SOC_DAPM_SINGLE("Switch", TWL6040_REG_EARCTL, 0, 1, 0); +/* Headset power mode */ +static const char *twl6040_headset_power_texts[] = { + "Low-Power", "High-Performance", +}; + +static const struct soc_enum twl6040_headset_power_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(twl6040_headset_power_texts), + twl6040_headset_power_texts); + +static int twl6040_headset_power_get_enum(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.enumerated.item[0] = priv->headset_mode; + + return 0; +} + +static int twl6040_headset_power_put_enum(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); + int high_perf = ucontrol->value.enumerated.item[0]; + int ret; + + if (priv->power_mode_forced) + return -EPERM; + + ret = headset_power_mode(codec, high_perf); + if (!ret) + priv->headset_mode = high_perf; + + return ret; +} + static const struct snd_kcontrol_new twl6040_snd_controls[] = { /* Capture gains */ SOC_DOUBLE_TLV("Capture Preamplifier Volume", @@ -1052,12 +1160,19 @@ static const struct snd_kcontrol_new twl6040_snd_controls[] = { TWL6040_REG_LINEGAIN, 0, 3, 7, 0, afm_amp_tlv), /* Playback gains */ - SOC_TWL6040_DOUBLE_TLV("Headset Playback Volume", - TWL6040_REG_HSGAIN, 0, 4, 0xF, 1, hs_tlv), - SOC_TWL6040_DOUBLE_R_TLV("Handsfree Playback Volume", - TWL6040_REG_HFLGAIN, TWL6040_REG_HFRGAIN, 0, 0x1D, 1, hf_tlv), - SOC_SINGLE_TLV("Earphone Playback Volume", - TWL6040_REG_EARCTL, 1, 0xF, 1, ep_tlv), + SOC_DOUBLE_EXT_TLV("Headset Playback Volume", + TWL6040_REG_HSGAIN, 0, 4, 0xF, 1, + twl6040_get_volsw, twl6040_put_volsw, hs_tlv), + SOC_DOUBLE_R_EXT_TLV("Handsfree Playback Volume", + TWL6040_REG_HFLGAIN, TWL6040_REG_HFRGAIN, 0, 0x1D, 1, + twl6040_get_volsw_2r, twl6040_put_volsw_2r_vu, hf_tlv), + SOC_SINGLE_EXT_TLV("Earphone Playback Volume", + TWL6040_REG_EARCTL, 1, 0xF, 1, + twl6040_get_volsw, twl6040_put_volsw, ep_tlv), + + SOC_ENUM_EXT("Headset Power Mode", twl6040_headset_power_enum, + twl6040_headset_power_get_enum, + twl6040_headset_power_put_enum), }; static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = { @@ -1112,19 +1227,19 @@ static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = { /* DACs */ SND_SOC_DAPM_DAC_E("HSDAC Left", "Headset Playback", TWL6040_REG_HSLCTL, 0, 0, - twl6040_hs_dac_event, + twl6040_dac_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_DAC_E("HSDAC Right", "Headset Playback", TWL6040_REG_HSRCTL, 0, 0, - twl6040_hs_dac_event, + twl6040_dac_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_DAC_E("HFDAC Left", "Handsfree Playback", TWL6040_REG_HFLCTL, 0, 0, - twl6040_power_mode_event, + twl6040_dac_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_DAC_E("HFDAC Right", "Handsfree Playback", TWL6040_REG_HFRCTL, 0, 0, - twl6040_power_mode_event, + twl6040_dac_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_MUX("HF Left Playback", @@ -1154,10 +1269,14 @@ static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = { TWL6040_REG_HSRCTL, 2, 0, NULL, 0, pga_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), - SND_SOC_DAPM_SWITCH_E("Earphone Driver", + SND_SOC_DAPM_SWITCH_E("Earphone Enable", SND_SOC_NOPM, 0, 0, &ep_driver_switch_controls, - twl6040_power_mode_event, + twl6040_ep_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_OUT_DRV_E("Earphone Driver", + SND_SOC_NOPM, 0, 0, NULL, 0, + pga_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), /* Analog playback PGAs */ SND_SOC_DAPM_PGA("HFDAC Left PGA", @@ -1200,7 +1319,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"HSOR", NULL, "Headset Right Driver"}, /* Earphone playback path */ - {"Earphone Driver", "Switch", "HSDAC Left"}, + {"Earphone Enable", "Switch", "HSDAC Left"}, + {"Earphone Driver", NULL, "Earphone Enable"}, {"EP", NULL, "Earphone Driver"}, {"HF Left Playback", "HF DAC", "HFDAC Left"}, @@ -1231,37 +1351,43 @@ static int twl6040_add_widgets(struct snd_soc_codec *codec) return 0; } -static int twl6040_power_up_completion(struct snd_soc_codec *codec, - int naudint) -{ - struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); - int time_left; - u8 intid; +/* set of rates for each pll: low-power and high-performance */ - time_left = wait_for_completion_timeout(&priv->ready, - msecs_to_jiffies(144)); +static unsigned int lp_rates[] = { + 8000, + 11250, + 16000, + 22500, + 32000, + 44100, + 48000, + 88200, + 96000, +}; - if (!time_left) { - twl_i2c_read_u8(TWL_MODULE_AUDIO_VOICE, &intid, - TWL6040_REG_INTID); - if (!(intid & TWL6040_READYINT)) { - dev_err(codec->dev, "timeout waiting for READYINT\n"); - return -ETIMEDOUT; - } - } +static struct snd_pcm_hw_constraint_list lp_constraints = { + .count = ARRAY_SIZE(lp_rates), + .list = lp_rates, +}; - priv->codec_powered = 1; +static unsigned int hp_rates[] = { + 8000, + 16000, + 32000, + 48000, + 96000, +}; - return 0; -} +static struct snd_pcm_hw_constraint_list hp_constraints = { + .count = ARRAY_SIZE(hp_rates), + .list = hp_rates, +}; static int twl6040_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { + struct twl6040 *twl6040 = codec->control_data; struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); - int audpwron = priv->audpwron; - int naudint = priv->naudint; - int ret; switch (level) { case SND_SOC_BIAS_ON: @@ -1272,88 +1398,32 @@ static int twl6040_set_bias_level(struct snd_soc_codec *codec, if (priv->codec_powered) break; - if (gpio_is_valid(audpwron)) { - /* use AUDPWRON line */ - gpio_set_value(audpwron, 1); - - /* wait for power-up completion */ - ret = twl6040_power_up_completion(codec, naudint); - if (ret) - return ret; + twl6040_enable(twl6040); + priv->codec_powered = 1; - /* sync registers updated during power-up sequence */ - twl6040_read_reg_volatile(codec, TWL6040_REG_NCPCTL); - twl6040_read_reg_volatile(codec, TWL6040_REG_LDOCTL); - twl6040_read_reg_volatile(codec, TWL6040_REG_LPPLLCTL); - } else { - /* use manual power-up sequence */ - twl6040_power_up(codec); - priv->codec_powered = 1; - } + priv->sysclk_constraints = &lp_constraints; /* initialize vdd/vss registers with reg_cache */ twl6040_init_vdd_regs(codec); - /* Set external boost GPO */ - twl6040_write(codec, TWL6040_REG_GPOCTL, 0x02); - - /* Set initial minimal gain values */ - twl6040_write(codec, TWL6040_REG_HSGAIN, 0xFF); - twl6040_write(codec, TWL6040_REG_EARCTL, 0x1E); - twl6040_write(codec, TWL6040_REG_HFLGAIN, 0x1D); - twl6040_write(codec, TWL6040_REG_HFRGAIN, 0x1D); break; case SND_SOC_BIAS_OFF: if (!priv->codec_powered) break; - if (gpio_is_valid(audpwron)) { - /* use AUDPWRON line */ - gpio_set_value(audpwron, 0); - - /* power-down sequence latency */ - udelay(500); - - /* sync registers updated during power-down sequence */ - twl6040_read_reg_volatile(codec, TWL6040_REG_NCPCTL); - twl6040_read_reg_volatile(codec, TWL6040_REG_LDOCTL); - twl6040_write_reg_cache(codec, TWL6040_REG_LPPLLCTL, - 0x00); - } else { - /* use manual power-down sequence */ - twl6040_power_down(codec); - } - + twl6040_disable(twl6040); priv->codec_powered = 0; break; } codec->dapm.bias_level = level; + /* get pll and sysclk after power transition */ + priv->pll = twl6040_get_pll(twl6040); + priv->sysclk = twl6040_get_sysclk(twl6040); return 0; } -/* set of rates for each pll: low-power and high-performance */ - -static unsigned int lp_rates[] = { - 88200, - 96000, -}; - -static struct snd_pcm_hw_constraint_list lp_constraints = { - .count = ARRAY_SIZE(lp_rates), - .list = lp_rates, -}; - -static unsigned int hp_rates[] = { - 96000, -}; - -static struct snd_pcm_hw_constraint_list hp_constraints = { - .count = ARRAY_SIZE(hp_rates), - .list = hp_rates, -}; - static int twl6040_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -1374,15 +1444,11 @@ static int twl6040_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_codec *codec = rtd->codec; + struct twl6040 *twl6040 = codec->control_data; struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); - u8 lppllctl; + unsigned int sysclk; int rate; - - /* nothing to do for high-perf pll, it supports only 48 kHz */ - if (priv->pll == TWL6040_HPPLL_ID) - return 0; - - lppllctl = twl6040_read_reg_cache(codec, TWL6040_REG_LPPLLCTL); + int ret; rate = params_rate(params); switch (rate) { @@ -1390,23 +1456,27 @@ static int twl6040_hw_params(struct snd_pcm_substream *substream, case 22500: case 44100: case 88200: - lppllctl |= TWL6040_LPLLFIN; - priv->sysclk = 17640000; + sysclk = 17640000; break; case 8000: case 16000: case 32000: case 48000: case 96000: - lppllctl &= ~TWL6040_LPLLFIN; - priv->sysclk = 19200000; + sysclk = 19200000; break; default: dev_err(codec->dev, "unsupported rate %d\n", rate); return -EINVAL; } - twl6040_write(codec, TWL6040_REG_LPPLLCTL, lppllctl); + ret = twl6040_set_pll(twl6040, priv->pll, priv->clk_in, sysclk); + if (ret) { + dev_err(codec->dev, "failed to configure PLL %d", ret); + return ret; + } + + priv->sysclk = sysclk; return 0; } @@ -1425,23 +1495,19 @@ static int twl6040_prepare(struct snd_pcm_substream *substream, } /* - * capture is not supported at 17.64 MHz, - * it's reserved for headset low-power playback scenario + * In the capture, the Analog path should be turn on and stabilized + * before McPDM prepare itself to avoid pop noises. + * So the codec startup event is sending through dapm in prepare itself + * to ensure that the codec analog path is up before McPDM Uplink FIFO + * is going to be activated. */ - if ((priv->sysclk == 17640000) && - substream->stream == SNDRV_PCM_STREAM_CAPTURE) { - dev_err(codec->dev, - "capture mode is not supported at %dHz\n", - priv->sysclk); - return -EINVAL; + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + snd_soc_dapm_codec_stream_event(dai->codec, + dai->driver->capture.stream_name, + SND_SOC_DAPM_STREAM_START); + msleep(150); } - if ((priv->sysclk == 17640000) && priv->non_lp) { - dev_err(codec->dev, - "some enabled paths aren't supported at %dHz\n", - priv->sysclk); - return -EPERM; - } return 0; } @@ -1450,98 +1516,12 @@ static int twl6040_set_dai_sysclk(struct snd_soc_dai *codec_dai, { struct snd_soc_codec *codec = codec_dai->codec; struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); - u8 hppllctl, lppllctl; - - hppllctl = twl6040_read_reg_cache(codec, TWL6040_REG_HPPLLCTL); - lppllctl = twl6040_read_reg_cache(codec, TWL6040_REG_LPPLLCTL); switch (clk_id) { - case TWL6040_SYSCLK_SEL_LPPLL: - switch (freq) { - case 32768: - /* headset dac and driver must be in low-power mode */ - headset_power_mode(codec, 0); - - /* clk32k input requires low-power pll */ - lppllctl |= TWL6040_LPLLENA; - twl6040_write(codec, TWL6040_REG_LPPLLCTL, lppllctl); - mdelay(5); - lppllctl &= ~TWL6040_HPLLSEL; - twl6040_write(codec, TWL6040_REG_LPPLLCTL, lppllctl); - hppllctl &= ~TWL6040_HPLLENA; - twl6040_write(codec, TWL6040_REG_HPPLLCTL, hppllctl); - break; - default: - dev_err(codec->dev, "unknown mclk freq %d\n", freq); - return -EINVAL; - } - - /* lppll divider */ - switch (priv->sysclk) { - case 17640000: - lppllctl |= TWL6040_LPLLFIN; - break; - case 19200000: - lppllctl &= ~TWL6040_LPLLFIN; - break; - default: - /* sysclk not yet configured */ - lppllctl &= ~TWL6040_LPLLFIN; - priv->sysclk = 19200000; - break; - } - - twl6040_write(codec, TWL6040_REG_LPPLLCTL, lppllctl); - - priv->pll = TWL6040_LPPLL_ID; + case TWL6040_LPPLL_ID: priv->sysclk_constraints = &lp_constraints; break; - case TWL6040_SYSCLK_SEL_HPPLL: - hppllctl &= ~TWL6040_MCLK_MSK; - - switch (freq) { - case 12000000: - /* mclk input, pll enabled */ - hppllctl |= TWL6040_MCLK_12000KHZ | - TWL6040_HPLLSQRBP | - TWL6040_HPLLENA; - break; - case 19200000: - /* mclk input, pll disabled */ - hppllctl |= TWL6040_MCLK_19200KHZ | - TWL6040_HPLLSQRENA | - TWL6040_HPLLBP; - break; - case 26000000: - /* mclk input, pll enabled */ - hppllctl |= TWL6040_MCLK_26000KHZ | - TWL6040_HPLLSQRBP | - TWL6040_HPLLENA; - break; - case 38400000: - /* clk slicer, pll disabled */ - hppllctl |= TWL6040_MCLK_38400KHZ | - TWL6040_HPLLSQRENA | - TWL6040_HPLLBP; - break; - default: - dev_err(codec->dev, "unknown mclk freq %d\n", freq); - return -EINVAL; - } - - /* headset dac and driver must be in high-performance mode */ - headset_power_mode(codec, 1); - - twl6040_write(codec, TWL6040_REG_HPPLLCTL, hppllctl); - udelay(500); - lppllctl |= TWL6040_HPLLSEL; - twl6040_write(codec, TWL6040_REG_LPPLLCTL, lppllctl); - lppllctl &= ~TWL6040_LPLLENA; - twl6040_write(codec, TWL6040_REG_LPPLLCTL, lppllctl); - - /* high-performance pll can provide only 19.2 MHz */ - priv->pll = TWL6040_HPPLL_ID; - priv->sysclk = 19200000; + case TWL6040_HPPLL_ID: priv->sysclk_constraints = &hp_constraints; break; default: @@ -1549,6 +1529,23 @@ static int twl6040_set_dai_sysclk(struct snd_soc_dai *codec_dai, return -EINVAL; } + priv->pll = clk_id; + priv->clk_in = freq; + + return 0; +} + +static int twl6040_digital_mute(struct snd_soc_dai *dai, int mute) +{ + /* + * pop-noise reduction sequence requires to shutdown + * analog side before CPU DAI + */ + if (mute) + snd_soc_dapm_codec_stream_event(dai->codec, + dai->driver->playback.stream_name, + SND_SOC_DAPM_STREAM_STOP); + return 0; } @@ -1557,25 +1554,54 @@ static struct snd_soc_dai_ops twl6040_dai_ops = { .hw_params = twl6040_hw_params, .prepare = twl6040_prepare, .set_sysclk = twl6040_set_dai_sysclk, + .digital_mute = twl6040_digital_mute, }; -static struct snd_soc_dai_driver twl6040_dai = { - .name = "twl6040-hifi", +static struct snd_soc_dai_driver twl6040_dai[] = { +{ + .name = "twl6040-ul", + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = TWL6040_RATES, + .formats = TWL6040_FORMATS, + }, + .ops = &twl6040_dai_ops, +}, +{ + .name = "twl6040-dl1", .playback = { - .stream_name = "Playback", + .stream_name = "Headset Playback", .channels_min = 1, - .channels_max = 4, + .channels_max = 2, .rates = TWL6040_RATES, .formats = TWL6040_FORMATS, }, - .capture = { - .stream_name = "Capture", + .ops = &twl6040_dai_ops, +}, +{ + .name = "twl6040-dl2", + .playback = { + .stream_name = "Handsfree Playback", .channels_min = 1, .channels_max = 2, .rates = TWL6040_RATES, .formats = TWL6040_FORMATS, }, .ops = &twl6040_dai_ops, +}, +{ + .name = "twl6040-vib", + .playback = { + .stream_name = "Vibra Playback", + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .formats = TWL6040_FORMATS, + }, + .ops = &twl6040_dai_ops, +}, }; #ifdef CONFIG_PM @@ -1588,8 +1614,10 @@ static int twl6040_suspend(struct snd_soc_codec *codec, pm_message_t state) static int twl6040_resume(struct snd_soc_codec *codec) { - twl6040_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - twl6040_set_bias_level(codec, codec->dapm.suspend_bias_level); + if (codec->dapm.bias_level != codec->dapm.suspend_bias_level) { + twl6040_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + twl6040_set_bias_level(codec, codec->dapm.suspend_bias_level); + } return 0; } @@ -1600,11 +1628,9 @@ static int twl6040_resume(struct snd_soc_codec *codec) static int twl6040_probe(struct snd_soc_codec *codec) { - struct twl4030_codec_data *twl_codec = codec->dev->platform_data; struct twl6040_data *priv; - int audpwron, naudint; + struct twl4030_codec_audio_data *pdata = dev_get_platdata(codec->dev); int ret = 0; - u8 icrev, intmr = TWL6040_ALLINT_MSK; priv = kzalloc(sizeof(struct twl6040_data), GFP_KERNEL); if (priv == NULL) @@ -1612,21 +1638,33 @@ static int twl6040_probe(struct snd_soc_codec *codec) snd_soc_codec_set_drvdata(codec, priv); priv->codec = codec; + codec->control_data = dev_get_drvdata(codec->dev->parent); + codec->dapm.idle_bias_off = 1; - twl_i2c_read_u8(TWL_MODULE_AUDIO_VOICE, &icrev, TWL6040_REG_ASICREV); + if (pdata && pdata->hs_left_step && pdata->hs_right_step) { + priv->hs_left_step = pdata->hs_left_step; + priv->hs_right_step = pdata->hs_right_step; + } else { + priv->hs_left_step = 1; + priv->hs_right_step = 1; + } - if (twl_codec && (icrev > 0)) - audpwron = twl_codec->audpwron_gpio; - else - audpwron = -EINVAL; + if (pdata && pdata->hf_left_step && pdata->hf_right_step) { + priv->hf_left_step = pdata->hf_left_step; + priv->hf_right_step = pdata->hf_right_step; + } else { + priv->hf_left_step = 1; + priv->hf_right_step = 1; + } - if (twl_codec) - naudint = twl_codec->naudint_irq; + if (pdata && pdata->ep_step) + priv->ep_step = pdata->ep_step; else - naudint = 0; + priv->ep_step = 1; - priv->audpwron = audpwron; - priv->naudint = naudint; + /* default is low-power mode */ + priv->headset_mode = 1; + priv->sysclk_constraints = &lp_constraints; priv->workqueue = create_singlethread_workqueue("twl6040-codec"); if (!priv->workqueue) { @@ -1638,55 +1676,40 @@ static int twl6040_probe(struct snd_soc_codec *codec) mutex_init(&priv->mutex); - init_completion(&priv->ready); init_completion(&priv->headset.ramp_done); init_completion(&priv->handsfree.ramp_done); - - if (gpio_is_valid(audpwron)) { - ret = gpio_request(audpwron, "audpwron"); - if (ret) - goto gpio1_err; - - ret = gpio_direction_output(audpwron, 0); - if (ret) - goto gpio2_err; - - priv->codec_powered = 0; - - /* enable only codec ready interrupt */ - intmr &= ~(TWL6040_READYMSK | TWL6040_PLUGMSK); - - /* reset interrupt status to allow correct power up sequence */ - twl6040_read_reg_volatile(codec, TWL6040_REG_INTID); - } - twl6040_write(codec, TWL6040_REG_INTMR, intmr); - - if (naudint) { - /* audio interrupt */ - ret = request_threaded_irq(naudint, NULL, - twl6040_naudint_handler, - IRQF_TRIGGER_LOW | IRQF_ONESHOT, - "twl6040_codec", codec); - if (ret) - goto gpio2_err; - } - - /* init vio registers */ - twl6040_init_vio_regs(codec); + init_completion(&priv->earphone.ramp_done); priv->hf_workqueue = create_singlethread_workqueue("twl6040-hf"); if (priv->hf_workqueue == NULL) { ret = -ENOMEM; - goto irq_err; + goto hfwork_err; } priv->hs_workqueue = create_singlethread_workqueue("twl6040-hs"); if (priv->hs_workqueue == NULL) { ret = -ENOMEM; - goto wq_err; + goto hswork_err; + } + priv->ep_workqueue = create_singlethread_workqueue("twl6040-ep"); + if (priv->ep_workqueue == NULL) { + ret = -ENOMEM; + goto epwork_err; } INIT_DELAYED_WORK(&priv->hs_delayed_work, twl6040_pga_hs_work); INIT_DELAYED_WORK(&priv->hf_delayed_work, twl6040_pga_hf_work); + INIT_DELAYED_WORK(&priv->ep_delayed_work, twl6040_pga_ep_work); + + ret = twl6040_request_irq(codec->control_data, TWL6040_IRQ_PLUG, + twl6040_audio_handler, "twl6040_irq_plug", + codec); + if (ret) { + dev_err(codec->dev, "PLUG IRQ request failed: %d\n", ret); + goto irq_err; + } + + /* init vio registers */ + twl6040_init_vio_regs(codec); /* power on device */ ret = twl6040_set_bias_level(codec, SND_SOC_BIAS_STANDBY); @@ -1700,16 +1723,14 @@ static int twl6040_probe(struct snd_soc_codec *codec) return 0; bias_err: + twl6040_free_irq(codec->control_data, TWL6040_IRQ_PLUG, codec); +irq_err: + destroy_workqueue(priv->ep_workqueue); +epwork_err: destroy_workqueue(priv->hs_workqueue); -wq_err: +hswork_err: destroy_workqueue(priv->hf_workqueue); -irq_err: - if (naudint) - free_irq(naudint, codec); -gpio2_err: - if (gpio_is_valid(audpwron)) - gpio_free(audpwron); -gpio1_err: +hfwork_err: destroy_workqueue(priv->workqueue); work_err: kfree(priv); @@ -1719,20 +1740,13 @@ work_err: static int twl6040_remove(struct snd_soc_codec *codec) { struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); - int audpwron = priv->audpwron; - int naudint = priv->naudint; twl6040_set_bias_level(codec, SND_SOC_BIAS_OFF); - - if (gpio_is_valid(audpwron)) - gpio_free(audpwron); - - if (naudint) - free_irq(naudint, codec); - + twl6040_free_irq(codec->control_data, TWL6040_IRQ_PLUG, codec); destroy_workqueue(priv->workqueue); destroy_workqueue(priv->hf_workqueue); destroy_workqueue(priv->hs_workqueue); + destroy_workqueue(priv->ep_workqueue); kfree(priv); return 0; @@ -1754,7 +1768,7 @@ static struct snd_soc_codec_driver soc_codec_dev_twl6040 = { static int __devinit twl6040_codec_probe(struct platform_device *pdev) { return snd_soc_register_codec(&pdev->dev, - &soc_codec_dev_twl6040, &twl6040_dai, 1); + &soc_codec_dev_twl6040, twl6040_dai, ARRAY_SIZE(twl6040_dai)); } static int __devexit twl6040_codec_remove(struct platform_device *pdev) diff --git a/sound/soc/codecs/twl6040.h b/sound/soc/codecs/twl6040.h index 23aeed0..105a6fd 100644 --- a/sound/soc/codecs/twl6040.h +++ b/sound/soc/codecs/twl6040.h @@ -22,123 +22,7 @@ #ifndef __TWL6040_H__ #define __TWL6040_H__ -#define TWL6040_REG_ASICID 0x01 -#define TWL6040_REG_ASICREV 0x02 -#define TWL6040_REG_INTID 0x03 -#define TWL6040_REG_INTMR 0x04 -#define TWL6040_REG_NCPCTL 0x05 -#define TWL6040_REG_LDOCTL 0x06 -#define TWL6040_REG_HPPLLCTL 0x07 -#define TWL6040_REG_LPPLLCTL 0x08 -#define TWL6040_REG_LPPLLDIV 0x09 -#define TWL6040_REG_AMICBCTL 0x0A -#define TWL6040_REG_DMICBCTL 0x0B -#define TWL6040_REG_MICLCTL 0x0C -#define TWL6040_REG_MICRCTL 0x0D -#define TWL6040_REG_MICGAIN 0x0E -#define TWL6040_REG_LINEGAIN 0x0F -#define TWL6040_REG_HSLCTL 0x10 -#define TWL6040_REG_HSRCTL 0x11 -#define TWL6040_REG_HSGAIN 0x12 -#define TWL6040_REG_EARCTL 0x13 -#define TWL6040_REG_HFLCTL 0x14 -#define TWL6040_REG_HFLGAIN 0x15 -#define TWL6040_REG_HFRCTL 0x16 -#define TWL6040_REG_HFRGAIN 0x17 -#define TWL6040_REG_VIBCTLL 0x18 -#define TWL6040_REG_VIBDATL 0x19 -#define TWL6040_REG_VIBCTLR 0x1A -#define TWL6040_REG_VIBDATR 0x1B -#define TWL6040_REG_HKCTL1 0x1C -#define TWL6040_REG_HKCTL2 0x1D -#define TWL6040_REG_GPOCTL 0x1E -#define TWL6040_REG_ALB 0x1F -#define TWL6040_REG_DLB 0x20 -#define TWL6040_REG_TRIM1 0x28 -#define TWL6040_REG_TRIM2 0x29 -#define TWL6040_REG_TRIM3 0x2A -#define TWL6040_REG_HSOTRIM 0x2B -#define TWL6040_REG_HFOTRIM 0x2C -#define TWL6040_REG_ACCCTL 0x2D -#define TWL6040_REG_STATUS 0x2E - -#define TWL6040_CACHEREGNUM (TWL6040_REG_STATUS + 1) - -#define TWL6040_VIOREGNUM 18 -#define TWL6040_VDDREGNUM 21 - -/* INTID (0x03) fields */ - -#define TWL6040_THINT 0x01 -#define TWL6040_PLUGINT 0x02 -#define TWL6040_UNPLUGINT 0x04 -#define TWL6040_HOOKINT 0x08 -#define TWL6040_HFINT 0x10 -#define TWL6040_VIBINT 0x20 -#define TWL6040_READYINT 0x40 - -/* INTMR (0x04) fields */ - -#define TWL6040_PLUGMSK 0x02 -#define TWL6040_READYMSK 0x40 -#define TWL6040_ALLINT_MSK 0x7B - -/* NCPCTL (0x05) fields */ - -#define TWL6040_NCPENA 0x01 -#define TWL6040_NCPOPEN 0x40 - -/* LDOCTL (0x06) fields */ - -#define TWL6040_LSLDOENA 0x01 -#define TWL6040_HSLDOENA 0x04 -#define TWL6040_REFENA 0x40 -#define TWL6040_OSCENA 0x80 - -/* HPPLLCTL (0x07) fields */ - -#define TWL6040_HPLLENA 0x01 -#define TWL6040_HPLLRST 0x02 -#define TWL6040_HPLLBP 0x04 -#define TWL6040_HPLLSQRENA 0x08 -#define TWL6040_HPLLSQRBP 0x10 -#define TWL6040_MCLK_12000KHZ (0 << 5) -#define TWL6040_MCLK_19200KHZ (1 << 5) -#define TWL6040_MCLK_26000KHZ (2 << 5) -#define TWL6040_MCLK_38400KHZ (3 << 5) -#define TWL6040_MCLK_MSK 0x60 - -/* LPPLLCTL (0x08) fields */ - -#define TWL6040_LPLLENA 0x01 -#define TWL6040_LPLLRST 0x02 -#define TWL6040_LPLLSEL 0x04 -#define TWL6040_LPLLFIN 0x08 -#define TWL6040_HPLLSEL 0x10 - -/* HSLCTL (0x10) fields */ - -#define TWL6040_HSDACMODEL 0x02 -#define TWL6040_HSDRVMODEL 0x08 - -/* HSRCTL (0x11) fields */ - -#define TWL6040_HSDACMODER 0x02 -#define TWL6040_HSDRVMODER 0x08 - -/* ACCCTL (0x2D) fields */ - -#define TWL6040_RESETSPLIT 0x04 - -#define TWL6040_SYSCLK_SEL_LPPLL 1 -#define TWL6040_SYSCLK_SEL_HPPLL 2 - -#define TWL6040_HPPLL_ID 1 -#define TWL6040_LPPLL_ID 2 - -/* STATUS (0x2E) fields */ - -#define TWL6040_PLUGCOMP 0x02 +#include <linux/mfd/twl6040-codec.h> void twl6040_hs_jack_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, int report); diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c index 9d35b8c..29759e1 100644 --- a/sound/soc/davinci/davinci-pcm.c +++ b/sound/soc/davinci/davinci-pcm.c @@ -811,9 +811,11 @@ static void davinci_pcm_free(struct snd_pcm *pcm) static u64 davinci_pcm_dmamask = 0xffffffff; -static int davinci_pcm_new(struct snd_card *card, - struct snd_soc_dai *dai, struct snd_pcm *pcm) +static int davinci_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; if (!card->dev->dma_mask) diff --git a/sound/soc/ep93xx/ep93xx-pcm.c b/sound/soc/ep93xx/ep93xx-pcm.c index a456e49..e27c417 100644 --- a/sound/soc/ep93xx/ep93xx-pcm.c +++ b/sound/soc/ep93xx/ep93xx-pcm.c @@ -266,9 +266,11 @@ static void ep93xx_pcm_free_dma_buffers(struct snd_pcm *pcm) static u64 ep93xx_pcm_dmamask = 0xffffffff; -static int ep93xx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, - struct snd_pcm *pcm) +static int ep93xx_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; if (!card->dev->dma_mask) diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c index 6680c0b..5312d1b 100644 --- a/sound/soc/fsl/fsl_dma.c +++ b/sound/soc/fsl/fsl_dma.c @@ -294,9 +294,11 @@ static irqreturn_t fsl_dma_isr(int irq, void *dev_id) * Regardless of where the memory is actually allocated, since the device can * technically DMA to any 36-bit address, we do need to set the DMA mask to 36. */ -static int fsl_dma_new(struct snd_card *card, struct snd_soc_dai *dai, - struct snd_pcm *pcm) +static int fsl_dma_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; static u64 fsl_dma_dmamask = DMA_BIT_MASK(36); int ret; diff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c index cbaf8b7..61d2ecc 100644 --- a/sound/soc/fsl/mpc5200_dma.c +++ b/sound/soc/fsl/mpc5200_dma.c @@ -299,10 +299,11 @@ static struct snd_pcm_ops psc_dma_ops = { }; static u64 psc_dma_dmamask = 0xffffffff; -static int psc_dma_new(struct snd_card *card, struct snd_soc_dai *dai, - struct snd_pcm *pcm) +static int psc_dma_new(struct snd_soc_pcm_runtime *rtd) { - struct snd_soc_pcm_runtime *rtd = pcm->private_data; + struct snd_card *card = rtd->card->snd_card; + struct snd_soc_dai *dai = rtd->cpu_dai; + struct snd_pcm *pcm = rtd->pcm; struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai); size_t size = psc_dma_hardware.buffer_bytes_max; int rc = 0; diff --git a/sound/soc/imx/imx-pcm-fiq.c b/sound/soc/imx/imx-pcm-fiq.c index 413b78d..309c59e 100644 --- a/sound/soc/imx/imx-pcm-fiq.c +++ b/sound/soc/imx/imx-pcm-fiq.c @@ -238,12 +238,14 @@ static struct snd_pcm_ops imx_pcm_ops = { static int ssi_irq = 0; -static int imx_pcm_fiq_new(struct snd_card *card, struct snd_soc_dai *dai, - struct snd_pcm *pcm) +static int imx_pcm_fiq_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; - ret = imx_pcm_new(card, dai, pcm); + ret = imx_pcm_new(rtd); if (ret) return ret; diff --git a/sound/soc/imx/imx-ssi.c b/sound/soc/imx/imx-ssi.c index 3b56254..3a676cd 100644 --- a/sound/soc/imx/imx-ssi.c +++ b/sound/soc/imx/imx-ssi.c @@ -388,10 +388,11 @@ static int imx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) static u64 imx_pcm_dmamask = DMA_BIT_MASK(32); -int imx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, - struct snd_pcm *pcm) +int imx_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; if (!card->dev->dma_mask) diff --git a/sound/soc/imx/imx-ssi.h b/sound/soc/imx/imx-ssi.h index dc8a875..0a84cec 100644 --- a/sound/soc/imx/imx-ssi.h +++ b/sound/soc/imx/imx-ssi.h @@ -225,8 +225,7 @@ struct snd_soc_platform *imx_ssi_dma_mx2_init(struct platform_device *pdev, struct imx_ssi *ssi); int snd_imx_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma); -int imx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, - struct snd_pcm *pcm); +int imx_pcm_new(struct snd_soc_pcm_runtime *rtd); void imx_pcm_free(struct snd_pcm *pcm); /* diff --git a/sound/soc/jz4740/jz4740-pcm.c b/sound/soc/jz4740/jz4740-pcm.c index fb1483f..a7c9578 100644 --- a/sound/soc/jz4740/jz4740-pcm.c +++ b/sound/soc/jz4740/jz4740-pcm.c @@ -299,9 +299,11 @@ static void jz4740_pcm_free(struct snd_pcm *pcm) static u64 jz4740_pcm_dmamask = DMA_BIT_MASK(32); -int jz4740_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, - struct snd_pcm *pcm) +int jz4740_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; if (!card->dev->dma_mask) diff --git a/sound/soc/kirkwood/kirkwood-dma.c b/sound/soc/kirkwood/kirkwood-dma.c index e13c6ce..cd33de1 100644 --- a/sound/soc/kirkwood/kirkwood-dma.c +++ b/sound/soc/kirkwood/kirkwood-dma.c @@ -312,9 +312,11 @@ static int kirkwood_dma_preallocate_dma_buffer(struct snd_pcm *pcm, return 0; } -static int kirkwood_dma_new(struct snd_card *card, - struct snd_soc_dai *dai, struct snd_pcm *pcm) +static int kirkwood_dma_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; if (!card->dev->dma_mask) diff --git a/sound/soc/nuc900/nuc900-pcm.c b/sound/soc/nuc900/nuc900-pcm.c index 8263f56..d589ef1 100644 --- a/sound/soc/nuc900/nuc900-pcm.c +++ b/sound/soc/nuc900/nuc900-pcm.c @@ -315,9 +315,12 @@ static void nuc900_dma_free_dma_buffers(struct snd_pcm *pcm) } static u64 nuc900_pcm_dmamask = DMA_BIT_MASK(32); -static int nuc900_dma_new(struct snd_card *card, - struct snd_soc_dai *dai, struct snd_pcm *pcm) +static int nuc900_dma_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; + if (!card->dev->dma_mask) card->dev->dma_mask = &nuc900_pcm_dmamask; if (!card->dev->coherent_dma_mask) diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index 99054cf..ffcfeee 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig @@ -2,6 +2,14 @@ config SND_OMAP_SOC tristate "SoC Audio for the Texas Instruments OMAP chips" depends on ARCH_OMAP +config SND_OMAP_SOC_ABE_DSP + tristate + select SND_DYNAMIC_MINORS + +config SND_OMAP_SOC_MCASP + tristate + select SND_SOC_SPDIF + config SND_OMAP_SOC_MCBSP tristate select OMAP_MCBSP @@ -9,6 +17,12 @@ config SND_OMAP_SOC_MCBSP config SND_OMAP_SOC_MCPDM tristate +config SND_OMAP_SOC_ABE + tristate + +config SND_OMAP_SOC_HDMI + tristate + config SND_OMAP_SOC_N810 tristate "SoC Audio support for Nokia N810" depends on SND_OMAP_SOC && MACH_NOKIA_N810 && I2C @@ -92,13 +106,27 @@ config SND_OMAP_SOC_SDP3430 SDP3430. config SND_OMAP_SOC_SDP4430 - tristate "SoC Audio support for Texas Instruments SDP4430" - depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP_4430SDP + tristate "SoC Audio support for Texas Instruments SDP4430 or PandaBoard" + depends on TWL4030_CORE && (MACH_OMAP_4430SDP || MACH_OMAP4_PANDA) select SND_OMAP_SOC_MCPDM select SND_SOC_TWL6040 + select SND_OMAP_SOC_ABE + select SND_OMAP_SOC_MCBSP + select SND_SOC_DMIC + select SND_OMAP_SOC_DMIC + select SND_OMAP_SOC_ABE_DSP help Say Y if you want to add support for SoC audio on Texas Instruments - SDP4430. + SDP4430 or PandaBoard. + +config SND_OMAP_SOC_OMAP4_HDMI + tristate "SoC Audio support for Texas Instruments OMAP4 HDMI" + depends on SND_OMAP_SOC && OMAP4_DSS_HDMI && OMAP2_DSS && ARCH_OMAP4 + select SND_OMAP_SOC_HDMI + select SND_SOC_OMAP_HDMI_CODEC + help + Say Y if you want to add support for SoC HDMI audio on Texas Instruments + OMAP4 chips config SND_OMAP_SOC_OMAP3_PANDORA tristate "SoC Audio support for OMAP3 Pandora" diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile index 6c2c87e..f1deddc 100644 --- a/sound/soc/omap/Makefile +++ b/sound/soc/omap/Makefile @@ -1,11 +1,19 @@ # OMAP Platform Support snd-soc-omap-objs := omap-pcm.o +snd-soc-omap-mcasp-objs := omap-mcasp.o snd-soc-omap-mcbsp-objs := omap-mcbsp.o -snd-soc-omap-mcpdm-objs := omap-mcpdm.o mcpdm.o +snd-soc-omap-mcpdm-objs := omap-mcpdm.o +snd-soc-omap-abe-objs := omap-abe.o +snd-soc-omap-abe-dsp-objs := omap-abe-dsp.o +snd-soc-omap-hdmi-objs := omap-hdmi.o obj-$(CONFIG_SND_OMAP_SOC) += snd-soc-omap.o +obj-$(CONFIG_SND_OMAP_SOC_MCASP) += snd-soc-omap-mcasp.o obj-$(CONFIG_SND_OMAP_SOC_MCBSP) += snd-soc-omap-mcbsp.o obj-$(CONFIG_SND_OMAP_SOC_MCPDM) += snd-soc-omap-mcpdm.o +obj-$(CONFIG_SND_OMAP_SOC_ABE) += snd-soc-omap-abe.o +obj-$(CONFIG_SND_OMAP_SOC_ABE_DSP) += snd-soc-omap-abe-dsp.o abe/ +obj-$(CONFIG_SND_OMAP_SOC_HDMI) += snd-soc-omap-hdmi.o # OMAP Machine Support snd-soc-n810-objs := n810.o @@ -21,6 +29,7 @@ snd-soc-omap3pandora-objs := omap3pandora.o snd-soc-omap3beagle-objs := omap3beagle.o snd-soc-zoom2-objs := zoom2.o snd-soc-igep0020-objs := igep0020.o +snd-soc-omap4-hdmi-objs := omap4-hdmi-card.o obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o obj-$(CONFIG_SND_OMAP_SOC_RX51) += snd-soc-rx51.o @@ -36,3 +45,4 @@ obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o obj-$(CONFIG_SND_OMAP_SOC_OMAP3_BEAGLE) += snd-soc-omap3beagle.o obj-$(CONFIG_SND_OMAP_SOC_ZOOM2) += snd-soc-zoom2.o obj-$(CONFIG_SND_OMAP_SOC_IGEP0020) += snd-soc-igep0020.o +obj-$(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) += snd-soc-omap4-hdmi.o diff --git a/sound/soc/omap/abe/Makefile b/sound/soc/omap/abe/Makefile new file mode 100644 index 0000000..0d5649b --- /dev/null +++ b/sound/soc/omap/abe/Makefile @@ -0,0 +1,14 @@ +snd-soc-abe-hal-objs += abe_main.o \ + abe_core.o \ + abe_gain.o \ + abe_port.o \ + abe_aess.o \ + abe_dbg.o \ + abe_dat.o \ + abe_ini.o \ + abe_irq.o \ + abe_seq.o \ + abe_asrc.o \ + port_mgr.o \ + +obj-$(CONFIG_SND_OMAP_SOC_ABE_DSP) += snd-soc-abe-hal.o diff --git a/sound/soc/omap/abe/abe.h b/sound/soc/omap/abe/abe.h new file mode 100644 index 0000000..103a57c --- /dev/null +++ b/sound/soc/omap/abe/abe.h @@ -0,0 +1,141 @@ +/* + + This file is provided under a dual BSD/GPLv2 license. When using or + redistributing this file, you may do so under either license. + + GPL LICENSE SUMMARY + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License 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. + The full GNU General Public License is included in this distribution + in the file called LICENSE.GPL. + + BSD LICENSE + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name of Texas Instruments Incorporated nor the names of + its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef _ABE_H_ +#define _ABE_H_ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/err.h> +#include <linux/slab.h> +#include <linux/io.h> + +#include "abe_def.h" +#include "abe_define.h" +#include "abe_fw.h" +#include "abe_ext.h" +#include "abe_dbg.h" + +/* + * BASIC TYPES + */ +#define MAX_UINT8 ((((1L << 7) - 1) << 1) + 1) +#define MAX_UINT16 ((((1L << 15) - 1) << 1) + 1) +#define MAX_UINT32 ((((1L << 31) - 1) << 1) + 1) + +#define s8 char +#define u8 unsigned char +#define s16 short +#define u16 unsigned short +#define s32 int +#define u32 unsigned int + +struct omap_abe_equ { + /* type of filter */ + u32 equ_type; + /* filter length */ + u32 equ_length; + union { + /* parameters are the direct and recursive coefficients in */ + /* Q6.26 integer fixed-point format. */ + s32 type1[NBEQ1]; + struct { + /* center frequency of the band [Hz] */ + s32 freq[NBEQ2]; + /* gain of each band. [dB] */ + s32 gain[NBEQ2]; + /* Q factor of this band [dB] */ + s32 q[NBEQ2]; + } type2; + } coef; + s32 equ_param3; +}; + +extern struct omap_abe *abe; + +void omap_abe_dbg_log(struct omap_abe *abe, u32 x, u32 y, u32 z, u32 t); +void omap_abe_dbg_error(struct omap_abe *abe, int level, int error); +int omap_abe_set_opp_processing(struct omap_abe *abe, u32 opp); +int omap_abe_connect_debug_trace(struct omap_abe *abe, + struct omap_abe_dma *dma2); + +int omap_abe_use_compensated_gain(struct omap_abe *abe, int on_off); +int omap_abe_write_equalizer(struct omap_abe *abe, + u32 id, struct omap_abe_equ *param); + +int omap_abe_disable_gain(struct omap_abe *abe, u32 id, u32 p); +int omap_abe_enable_gain(struct omap_abe *abe, u32 id, u32 p); +int omap_abe_mute_gain(struct omap_abe *abe, u32 id, u32 p); +int omap_abe_unmute_gain(struct omap_abe *abe, u32 id, u32 p); + +int omap_abe_write_gain(struct omap_abe *abe, + u32 id, s32 f_g, u32 ramp, u32 p); +int omap_abe_write_mixer(struct omap_abe *abe, + u32 id, s32 f_g, u32 f_ramp, u32 p); +int omap_abe_read_gain(struct omap_abe *abe, + u32 id, u32 *f_g, u32 p); +int omap_abe_read_mixer(struct omap_abe *abe, + u32 id, u32 *f_g, u32 p); + +/* + * MACROS + */ +#define _log(x, y, z, t) { if (x & abe->dbg.mask) omap_abe_dbg_log(abe, x, y, z, t); } + +#endif/* _ABE_H_ */ diff --git a/sound/soc/omap/abe/abe_aess.c b/sound/soc/omap/abe/abe_aess.c new file mode 100644 index 0000000..eb35b58 --- /dev/null +++ b/sound/soc/omap/abe/abe_aess.c @@ -0,0 +1,191 @@ +/* + + This file is provided under a dual BSD/GPLv2 license. When using or + redistributing this file, you may do so under either license. + + GPL LICENSE SUMMARY + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License 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. + The full GNU General Public License is included in this distribution + in the file called LICENSE.GPL. + + BSD LICENSE + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name of Texas Instruments Incorporated nor the names of + its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/err.h> +#include <linux/slab.h> + +#include "abe_dbg.h" +#include "abe.h" +#include "abe_mem.h" +#include "abe_aess.h" + +/** + * omap_abe_hw_configuration + * + */ +void omap_abe_hw_configuration(struct omap_abe *abe) +{ + /* enables the DMAreq from AESS AESS_DMAENABLE_SET = 255 */ + omap_abe_reg_writel(abe, AESS_DMAENABLE_SET, DMA_ENABLE_ALL); + /* enables the MCU IRQ from AESS to Cortex A9 */ + omap_abe_reg_writel(abe, AESS_MCU_IRQENABLE_SET, INT_SET); +} + +/** + * omap_abe_clear_irq - clear ABE interrupt + * @abe: Pointer on abe handle + * + * This subroutine is call to clear MCU Irq + */ +int omap_abe_clear_irq(struct omap_abe *abe) +{ + omap_abe_reg_writel(abe, ABE_MCU_IRQSTATUS, INT_CLR); + return 0; +} +EXPORT_SYMBOL(omap_abe_clear_irq); + +/** + * abe_write_event_generator - Selects event generator source + * @abe: Pointer on abe handle + * @e: Event Generation Counter, McPDM, DMIC or default. + * + * Loads the AESS event generator hardware source. + * Loads the firmware parameters accordingly. + * Indicates to the FW which data stream is the most important to preserve + * in case all the streams are asynchronous. + * If the parameter is "default", then HAL decides which Event source + * is the best appropriate based on the opened ports. + * + * When neither the DMIC and the McPDM are activated, the AE will have + * its EVENT generator programmed with the EVENT_COUNTER. + * The event counter will be tuned in order to deliver a pulse frequency higher + * than 96 kHz. + * The DPLL output at 100% OPP is MCLK = (32768kHz x6000) = 196.608kHz + * The ratio is (MCLK/96000)+(1<<1) = 2050 + * (1<<1) in order to have the same speed at 50% and 100% OPP + * (only 15 MSB bits are used at OPP50%) + */ +int omap_abe_write_event_generator(struct omap_abe *abe, u32 e) +{ + u32 event, selection; + u32 counter = EVENT_GENERATOR_COUNTER_DEFAULT; + + _log(ABE_ID_WRITE_EVENT_GENERATOR, e, 0, 0); + + switch (e) { + case EVENT_TIMER: + selection = EVENT_SOURCE_COUNTER; + event = 0; + break; + case EVENT_44100: + selection = EVENT_SOURCE_COUNTER; + event = 0; + counter = EVENT_GENERATOR_COUNTER_44100; + break; + default: + omap_abe_dbg_error(abe, OMAP_ABE_ERR_API, ABE_BLOCK_COPY_ERR); + } + omap_abe_reg_writel(abe, EVENT_GENERATOR_COUNTER, counter); + omap_abe_reg_writel(abe, EVENT_SOURCE_SELECTION, selection); + omap_abe_reg_writel(abe, EVENT_GENERATOR_START, EVENT_GENERATOR_ON); + omap_abe_reg_writel(abe, AUDIO_ENGINE_SCHEDULER, event); + return 0; +} +EXPORT_SYMBOL(omap_abe_write_event_generator); + +/** + * omap_abe_start_event_generator - Starts event generator source + * @abe: Pointer on abe handle + * + * Start the event genrator of AESS. No more event will be send to AESS engine. + * Upper layer must wait 1/96kHz to be sure that engine reaches + * the IDLE instruction. + */ +int omap_abe_start_event_generator(struct omap_abe *abe) +{ + /* Start the event Generator */ + omap_abe_reg_writel(abe, EVENT_GENERATOR_START, 1); + return 0; +} +EXPORT_SYMBOL(omap_abe_start_event_generator); + +/** + * omap_abe_stop_event_generator - Stops event generator source + * @abe: Pointer on abe handle + * + * Stop the event genrator of AESS. No more event will be send to AESS engine. + * Upper layer must wait 1/96kHz to be sure that engine reaches + * the IDLE instruction. + */ +int omap_abe_stop_event_generator(struct omap_abe *abe) +{ + /* Stop the event Generator */ + omap_abe_reg_writel(abe, EVENT_GENERATOR_START, 0); + return 0; +} +EXPORT_SYMBOL(omap_abe_stop_event_generator); + +/** + * omap_abe_disable_irq - disable MCU/DSP ABE interrupt + * @abe: Pointer on abe handle + * + * This subroutine is disabling ABE MCU/DSP Irq + */ +int omap_abe_disable_irq(struct omap_abe *abe) +{ + /* disables the DMAreq from AESS AESS_DMAENABLE_CLR = 127 + * DMA_Req7 will still be enabled as it is used for ABE trace */ + omap_abe_reg_writel(abe, AESS_DMAENABLE_CLR, 0x7F); + /* disables the MCU IRQ from AESS to Cortex A9 */ + omap_abe_reg_writel(abe, AESS_MCU_IRQENABLE_CLR, 0x01); + return 0; +} +EXPORT_SYMBOL(omap_abe_disable_irq); diff --git a/sound/soc/omap/abe/abe_aess.h b/sound/soc/omap/abe/abe_aess.h new file mode 100644 index 0000000..70c54f8e --- /dev/null +++ b/sound/soc/omap/abe/abe_aess.h @@ -0,0 +1,113 @@ +/* + + This file is provided under a dual BSD/GPLv2 license. When using or + redistributing this file, you may do so under either license. + + GPL LICENSE SUMMARY + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License 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. + The full GNU General Public License is included in this distribution + in the file called LICENSE.GPL. + + BSD LICENSE + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name of Texas Instruments Incorporated nor the names of + its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef _ABE_AESS_H_ +#define _ABE_AESS_H_ + +#define AESS_REVISION 0x00 +#define AESS_MCU_IRQSTATUS 0x28 +#define AESS_MCU_IRQENABLE_SET 0x3C +#define AESS_MCU_IRQENABLE_CLR 0x40 +#define AESS_DMAENABLE_SET 0x60 +#define AESS_DMAENABLE_CLR 0x64 +#define EVENT_GENERATOR_COUNTER 0x68 +#define EVENT_GENERATOR_START 0x6C +#define EVENT_SOURCE_SELECTION 0x70 +#define AUDIO_ENGINE_SCHEDULER 0x74 + +/* + * AESS_MCU_IRQSTATUS bit field + */ +#define INT_CLEAR 0x01 + +/* + * AESS_MCU_IRQENABLE_SET bit field + */ +#define INT_SET 0x01 + +/* + * AESS_MCU_IRQENABLE_CLR bit field + */ +#define INT_CLR 0x01 + +/* + * AESS_DMAENABLE_SET bit fields + */ +#define DMA_ENABLE_ALL 0xFF + +/* + * AESS_DMAENABLE_CLR bit fields + */ +#define DMA_DISABLE_ALL 0xFF + +/* + * EVENT_GENERATOR_COUNTER COUNTER_VALUE bit field + */ +/* PLL output/desired sampling rate = (32768 * 6000)/96000 */ +#define EVENT_GENERATOR_COUNTER_DEFAULT (2048-1) +/* PLL output/desired sampling rate = (32768 * 6000)/88200 */ +#define EVENT_GENERATOR_COUNTER_44100 (2228-1) + + +int omap_abe_start_event_generator(struct omap_abe *abe); +int omap_abe_stop_event_generator(struct omap_abe *abe); +int omap_abe_write_event_generator(struct omap_abe *abe, u32 e); + +void omap_abe_hw_configuration(struct omap_abe *abe); + +#endif/* _ABE_AESS_H_ */ diff --git a/sound/soc/omap/abe/abe_api.h b/sound/soc/omap/abe/abe_api.h new file mode 100644 index 0000000..a24ec96 --- /dev/null +++ b/sound/soc/omap/abe/abe_api.h @@ -0,0 +1,511 @@ +/* + + This file is provided under a dual BSD/GPLv2 license. When using or + redistributing this file, you may do so under either license. + + GPL LICENSE SUMMARY + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License 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. + The full GNU General Public License is included in this distribution + in the file called LICENSE.GPL. + + BSD LICENSE + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name of Texas Instruments Incorporated nor the names of + its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef _ABE_API_H_ +#define _ABE_API_H_ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/err.h> +#include <linux/slab.h> + +#include "abe_dm_addr.h" +#include "abe_dbg.h" + +#define ABE_TASK_ID(ID) (OMAP_ABE_D_TASKSLIST_ADDR + sizeof(ABE_STask)*(ID)) + +#define TASK_ASRC_VX_DL_SLT 0 +#define TASK_ASRC_VX_DL_IDX 3 +#define TASK_VX_DL_SLT 1 +#define TASK_VX_DL_IDX 3 +#define TASK_DL2Mixer_SLT 1 +#define TASK_DL2Mixer_IDX 6 +#define TASK_DL1Mixer_SLT 2 +#define TASK_DL1Mixer_IDX 0 +#define TASK_VX_UL_SLT 12 +#define TASK_VX_UL_IDX 5 +#define TASK_BT_DL_48_8_SLT 14 +#define TASK_BT_DL_48_8_IDX 4 +#define TASK_ASRC_BT_UL_SLT 15 +#define TASK_ASRC_BT_UL_IDX 6 +#define TASK_ASRC_VX_UL_SLT 16 +#define TASK_ASRC_VX_UL_IDX 2 +#define TASK_BT_UL_8_48_SLT 17 +#define TASK_BT_UL_8_48_IDX 2 +#define TASK_IO_MM_DL_SLT 18 +#define TASK_IO_MM_DL_IDX 0 +#define TASK_ASRC_BT_DL_SLT 18 +#define TASK_ASRC_BT_DL_IDX 6 + +/** + * abe_reset_hal - reset the ABE/HAL + * @rdev: regulator source + * @constraints: constraints to apply + * + * Operations : reset the HAL by reloading the static variables and + * default AESS registers. + * Called after a PRCM cold-start reset of ABE + */ +abehal_status abe_reset_hal(void); +/** + * abe_load_fw_param - Load ABE Firmware memories + * @PMEM: Pointer of Program memory data + * @PMEM_SIZE: Size of PMEM data + * @CMEM: Pointer of Coeffients memory data + * @CMEM_SIZE: Size of CMEM data + * @SMEM: Pointer of Sample memory data + * @SMEM_SIZE: Size of SMEM data + * @DMEM: Pointer of Data memory data + * @DMEM_SIZE: Size of DMEM data + * + */ +abehal_status abe_load_fw_param(u32 *FW); +/** + * abe_irq_processing - Process ABE interrupt + * + * This subroutine is call upon reception of "MA_IRQ_99 ABE_MPU_IRQ" Audio + * back-end interrupt. This subroutine will check the ATC Hrdware, the + * IRQ_FIFO from the AE and act accordingly. Some IRQ source are originated + * for the delivery of "end of time sequenced tasks" notifications, some are + * originated from the Ping-Pong protocols, some are generated from + * the embedded debugger when the firmware stops on programmable break-points, + * etc ... + */ +abehal_status abe_irq_processing(void); +/** + * abe_irq_clear - clear ABE interrupt + * + * This subroutine is call to clear MCU Irq + */ +abehal_status abe_clear_irq(void); +/** + * abe_disable_irq - disable MCU/DSP ABE interrupt + * + * This subroutine is disabling ABE MCU/DSP Irq + */ +abehal_status abe_disable_irq(void); +/* + * abe_check_activity - check all ports are closed + */ +u32 abe_check_activity(void); +/** + * abe_wakeup - Wakeup ABE + * + * Wakeup ABE in case of retention + */ +abehal_status abe_wakeup(void); +/** + * abe_start_event_generator - Stops event generator source + * + * Start the event genrator of AESS. No more event will be send to AESS engine. + * Upper layer must wait 1/96kHz to be sure that engine reaches + * the IDLE instruction. + */ +abehal_status abe_start_event_generator(void); +/** + * abe_stop_event_generator - Stops event generator source + * + * Stop the event genrator of AESS. No more event will be send to AESS engine. + * Upper layer must wait 1/96kHz to be sure that engine reaches + * the IDLE instruction. + */ +abehal_status abe_stop_event_generator(void); + +/** + * abe_write_event_generator - Selects event generator source + * @e: Event Generation Counter, McPDM, DMIC or default. + * + * Loads the AESS event generator hardware source. + * Loads the firmware parameters accordingly. + * Indicates to the FW which data stream is the most important to preserve + * in case all the streams are asynchronous. + * If the parameter is "default", then HAL decides which Event source + * is the best appropriate based on the opened ports. + * + * When neither the DMIC and the McPDM are activated, the AE will have + * its EVENT generator programmed with the EVENT_COUNTER. + * The event counter will be tuned in order to deliver a pulse frequency higher + * than 96 kHz. + * The DPLL output at 100% OPP is MCLK = (32768kHz x6000) = 196.608kHz + * The ratio is (MCLK/96000)+(1<<1) = 2050 + * (1<<1) in order to have the same speed at 50% and 100% OPP + * (only 15 MSB bits are used at OPP50%) + */ +abehal_status abe_write_event_generator(u32 e); +/** + * abe_set_opp_processing - Set OPP mode for ABE Firmware + * @opp: OOPP mode + * + * New processing network and OPP: + * 0: Ultra Lowest power consumption audio player (no post-processing, no mixer) + * 1: OPP 25% (simple multimedia features, including low-power player) + * 2: OPP 50% (multimedia and voice calls) + * 3: OPP100% (EANC, multimedia complex use-cases) + * + * Rearranges the FW task network to the corresponding OPP list of features. + * The corresponding AE ports are supposed to be set/reset accordingly before + * this switch. + * + */ +abehal_status abe_set_opp_processing(u32 opp); +/** + * abe_set_ping_pong_buffer + * @port: ABE port ID + * @n_bytes: Size of Ping/Pong buffer + * + * Updates the next ping-pong buffer with "size" bytes copied from the + * host processor. This API notifies the FW that the data transfer is done. + */ +abehal_status abe_set_ping_pong_buffer(u32 port, u32 n_bytes); +/** + * abe_read_next_ping_pong_buffer + * @port: ABE portID + * @p: Next buffer address (pointer) + * @n: Next buffer size (pointer) + * + * Tell the next base address of the next ping_pong Buffer and its size + */ +abehal_status abe_read_next_ping_pong_buffer(u32 port, u32 *p, u32 *n); +/** + * abe_init_ping_pong_buffer + * @id: ABE port ID + * @size_bytes:size of the ping pong + * @n_buffers:number of buffers (2 = ping/pong) + * @p:returned address of the ping-pong list of base address (byte offset + from DMEM start) + * + * Computes the base address of the ping_pong buffers + */ +abehal_status abe_init_ping_pong_buffer(u32 id, u32 size_bytes, u32 n_buffers, + u32 *p); +/** + * abe_read_offset_from_ping_buffer + * @id: ABE port ID + * @n: returned address of the offset + * from the ping buffer start address (in samples) + * + * Computes the current firmware ping pong read pointer location, + * expressed in samples, as the offset from the start address of ping buffer. + */ +abehal_status abe_read_offset_from_ping_buffer(u32 id, u32 *n); +/** + * abe_plug_subroutine + * @id: returned sequence index after plugging a new subroutine + * @f: subroutine address to be inserted + * @n: number of parameters of this subroutine + * @params: pointer on parameters + * + * register a list of subroutines for call-back purpose + */ +abehal_status abe_plug_subroutine(u32 *id, abe_subroutine2 f, u32 n, + u32 *params); +/** + * abe_set_sequence_time_accuracy + * @fast: fast counter + * @slow: slow counter + * + */ +abehal_status abe_set_sequence_time_accuracy(u32 fast, u32 slow); +/** + * abe_reset_port + * @id: ABE port ID + * + * stop the port activity and reload default parameters on the associated + * processing features. + * Clears the internal AE buffers. + */ +abehal_status abe_reset_port(u32 id); +/** + * abe_read_remaining_data + * @id: ABE port_ID + * @n: size pointer to the remaining number of 32bits words + * + * computes the remaining amount of data in the buffer. + */ +abehal_status abe_read_remaining_data(u32 port, u32 *n); +/** + * abe_disable_data_transfer + * @id: ABE port id + * + * disables the ATC descriptor and stop IO/port activities + * disable the IO task (@f = 0) + * clear ATC DMEM buffer, ATC enabled + */ +abehal_status abe_disable_data_transfer(u32 id); +/** + * abe_enable_data_transfer + * @ip: ABE port id + * + * enables the ATC descriptor + * reset ATC pointers + * enable the IO task (@f <> 0) + */ +abehal_status abe_enable_data_transfer(u32 id); +/** + * abe_set_dmic_filter + * @d: DMIC decimation ratio : 16/25/32/40 + * + * Loads in CMEM a specific list of coefficients depending on the DMIC sampling + * frequency (2.4MHz or 3.84MHz). This table compensates the DMIC decimator + * roll-off at 20kHz. + * The default table is loaded with the DMIC 2.4MHz recommended configuration. + */ +abehal_status abe_set_dmic_filter(u32 d); +/** + * abe_connect_cbpr_dmareq_port + * @id: port name + * @f: desired data format + * @d: desired dma_request line (0..7) + * @a: returned pointer to the base address of the CBPr register and number of + * samples to exchange during a DMA_request. + * + * enables the data echange between a DMA and the ABE through the + * CBPr registers of AESS. + */ +abehal_status abe_connect_cbpr_dmareq_port(u32 id, abe_data_format_t *f, u32 d, + abe_dma_t *returned_dma_t); +/** + * abe_connect_irq_ping_pong_port + * @id: port name + * @f: desired data format + * @I: index of the call-back subroutine to call + * @s: half-buffer (ping) size + * @p: returned base address of the first (ping) buffer) + * + * enables the data echanges between a direct access to the DMEM + * memory of ABE using cache flush. On each IRQ activation a subroutine + * registered with "abe_plug_subroutine" will be called. This subroutine + * will generate an amount of samples, send them to DMEM memory and call + * "abe_set_ping_pong_buffer" to notify the new amount of samples in the + * pong buffer. + */ +abehal_status abe_connect_irq_ping_pong_port(u32 id, abe_data_format_t *f, + u32 subroutine_id, u32 size, + u32 *sink, u32 dsp_mcu_flag); +/** + * abe_connect_serial_port() + * @id: port name + * @f: data format + * @i: peripheral ID (McBSP #1, #2, #3) + * + * Operations : enables the data echanges between a McBSP and an ATC buffer in + * DMEM. This API is used connect 48kHz McBSP streams to MM_DL and 8/16kHz + * voice streams to VX_UL, VX_DL, BT_VX_UL, BT_VX_DL. It abstracts the + * abe_write_port API. + */ +abehal_status abe_connect_serial_port(u32 id, abe_data_format_t *f, + u32 mcbsp_id); +/** + * abe_read_port_address + * @dma: output pointer to the DMA iteration and data destination pointer + * + * This API returns the address of the DMA register used on this audio port. + * Depending on the protocol being used, adds the base address offset L3 + * (DMA) or MPU (ARM) + */ +abehal_status abe_read_port_address(u32 port, abe_dma_t *dma2); +/** + * abe_write_equalizer + * @id: name of the equalizer + * @param : equalizer coefficients + * + * Load the coefficients in CMEM. + */ +abehal_status abe_write_equalizer(u32 id, abe_equ_t *param); +/** + * abe_write_asrc + * @id: name of the port + * @param: drift value to compensate [ppm] + * + * Load the drift variables to the FW memory. This API can be called only + * when the corresponding port has been already opened and the ASRC has + * been correctly initialized with API abe_init_asrc_... If this API is + * used such that the drift has been changed from positive to negative drift + * or vice versa, there will be click in the output signal. Loading the drift + * value with zero disables the feature. + */ +abehal_status abe_write_asrc(u32 port, s32 dppm); +/** + * abe_write_aps + * @id: name of the aps filter + * @param: table of filter coefficients + * + * Load the filters and thresholds coefficients in FW memory. This AP + * can be called when the corresponding APS is not activated. After + * reloading the firmware the default coefficients corresponds to "no APS + * activated". + * Loading all the coefficients value with zero disables the feature. + */ +abehal_status abe_write_aps(u32 id, struct abe_aps_t *param); +/** + * abe_write_mixer + * @id: name of the mixer + * @param: list of input gains of the mixer + * @p: list of port corresponding to the above gains + * + * Load the gain coefficients in FW memory. This API can be called when + * the corresponding MIXER is not activated. After reloading the firmware + * the default coefficients corresponds to "all input and output mixer's gain + * in mute state". A mixer is disabled with a network reconfiguration + * corresponding to an OPP value. + */ +abehal_status abe_write_gain(u32 id, s32 f_g, u32 ramp, u32 p); +abehal_status abe_use_compensated_gain(u32 on_off); +abehal_status abe_enable_gain(u32 id, u32 p); +abehal_status abe_disable_gain(u32 id, u32 p); +abehal_status abe_mute_gain(u32 id, u32 p); +abehal_status abe_unmute_gain(u32 id, u32 p); +/** + * abe_write_mixer + * @id: name of the mixer + * @param: input gains and delay ramp of the mixer + * @p: port corresponding to the above gains + * + * Load the gain coefficients in FW memory. This API can be called when + * the corresponding MIXER is not activated. After reloading the firmware + * the default coefficients corresponds to "all input and output mixer's + * gain in mute state". A mixer is disabled with a network reconfiguration + * corresponding to an OPP value. + */ +abehal_status abe_write_mixer(u32 id, s32 f_g, u32 f_ramp, u32 p); +/** + * abe_read_gain + * @id: name of the mixer + * @param: list of input gains of the mixer + * @p: list of port corresponding to the above gains + * + */ +abehal_status abe_read_gain(u32 id, u32 *f_g, u32 p); +/** + * abe_read_mixer + * @id: name of the mixer + * @param: gains of the mixer + * @p: port corresponding to the above gains + * + * Load the gain coefficients in FW memory. This API can be called when + * the corresponding MIXER is not activated. After reloading the firmware + * the default coefficients corresponds to "all input and output mixer's + * gain in mute state". A mixer is disabled with a network reconfiguration + * corresponding to an OPP value. + */ +abehal_status abe_read_mixer(u32 id, u32 *f_g, u32 p); +/** + * abe_set_router_configuration + * @Id: name of the router + * @Conf: id of the configuration + * @param: list of output index of the route + * + * The uplink router takes its input from DMIC (6 samples), AMIC (2 samples) + * and PORT1/2 (2 stereo ports). Each sample will be individually stored in + * an intermediate table of 10 elements. The intermediate table is used to + * route the samples to three directions : REC1 mixer, 2 EANC DMIC source of + * filtering and MM recording audio path. + */ +abehal_status abe_set_router_configuration(u32 id, u32 k, u32 *param); +/** + * ABE_READ_DEBUG_TRACE + * + * Parameters : + * @data: data destination pointer + * @n : max number of read data + * + * Operations : + * Reads the AE circular data pointer that holds pairs of debug data + + * timestamps, and stores the pairs, via linear addressing, to the parameter + * pointer. + * Stops the copy when the max parameter is reached or when the FIFO is empty. + * + * Return value : + * None. + */ +abehal_status abe_read_debug_trace(u32 *data, u32 *n); +/** + * abe_connect_debug_trace + * @dma2:pointer to the DMEM trace buffer + * + * returns the address and size of the real-time debug trace buffer, + * the content of which will vary from one firmware release to an other + */ +abehal_status abe_connect_debug_trace(abe_dma_t *dma2); +/** + * abe_set_debug_trace + * @debug: debug ID from a list to be defined + * + * load a mask which filters the debug trace to dedicated types of data + */ +abehal_status abe_set_debug_trace(abe_dbg_t debug); +/** + * abe_init_mem - Allocate Kernel space memory map for ABE + * + * Memory map of ABE memory space for PMEM/DMEM/SMEM/DMEM + */ +void abe_init_mem(void __iomem **_io_base); + +/** + * abe_write_pdmdl_offset - write the desired offset on the DL1/DL2 paths + * + * Parameters: + * path: 1 for the DL1 ABE path, 2 for the DL2 ABE path + * offset_left: integer value that will be added on all PDM left samples + * offset_right: integer value that will be added on all PDM right samples + * + */ +void abe_write_pdmdl_offset(u32 path, u32 offset_left, u32 offset_right); + +#endif/* _ABE_API_H_ */ diff --git a/sound/soc/omap/abe/abe_asrc.c b/sound/soc/omap/abe/abe_asrc.c new file mode 100644 index 0000000..4a52235 --- /dev/null +++ b/sound/soc/omap/abe/abe_asrc.c @@ -0,0 +1,1231 @@ +/* + + This file is provided under a dual BSD/GPLv2 license. When using or + redistributing this file, you may do so under either license. + + GPL LICENSE SUMMARY + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License 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. + The full GNU General Public License is included in this distribution + in the file called LICENSE.GPL. + + BSD LICENSE + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name of Texas Instruments Incorporated nor the names of + its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/err.h> +#include <linux/slab.h> + +#include "abe_legacy.h" +#include "abe_dbg.h" + +#include "abe_typedef.h" +#include "abe_initxxx_labels.h" +#include "abe_dbg.h" +#include "abe_mem.h" +#include "abe_sm_addr.h" +#include "abe_cm_addr.h" + +/** + * abe_write_fifo + * @mem_bank: currently only ABE_DMEM supported + * @addr: FIFO descriptor address ( descriptor fields : READ ptr, WRITE ptr, + * FIFO START_ADDR, FIFO END_ADDR) + * @data: data to write to FIFO + * @number: number of 32-bit words to write to DMEM FIFO + * + * write DMEM FIFO and update FIFO descriptor, + * it is assumed that FIFO descriptor is located in DMEM + */ +void abe_write_fifo(u32 memory_bank, u32 descr_addr, u32 *data, u32 nb_data32) +{ + u32 fifo_addr[4]; + u32 i; + /* read FIFO descriptor from DMEM */ + omap_abe_mem_read(abe, OMAP_ABE_DMEM, descr_addr, + &fifo_addr[0], 4 * sizeof(u32)); + /* WRITE ptr < FIFO start address */ + if (fifo_addr[1] < fifo_addr[2]) + omap_abe_dbg_error(abe, OMAP_ABE_ERR_DBG, + ABE_FW_FIFO_WRITE_PTR_ERR); + /* WRITE ptr > FIFO end address */ + if (fifo_addr[1] > fifo_addr[3]) + omap_abe_dbg_error(abe, OMAP_ABE_ERR_DBG, + ABE_FW_FIFO_WRITE_PTR_ERR); + switch (memory_bank) { + case ABE_DMEM: + for (i = 0; i < nb_data32; i++) { + omap_abe_mem_write(abe, OMAP_ABE_DMEM, + (s32) fifo_addr[1], (u32 *) (data + i), + 4); + /* increment WRITE pointer */ + fifo_addr[1] = fifo_addr[1] + 4; + if (fifo_addr[1] > fifo_addr[3]) + fifo_addr[1] = fifo_addr[2]; + if (fifo_addr[1] == fifo_addr[0]) + omap_abe_dbg_error(abe, OMAP_ABE_ERR_DBG, + ABE_FW_FIFO_WRITE_PTR_ERR); + } + /* update WRITE pointer in DMEM */ + omap_abe_mem_write(abe, OMAP_ABE_DMEM, descr_addr + + sizeof(u32), &fifo_addr[1], 4); + break; + default: + break; + } +} + +/** + * abe_write_asrc + * @id: name of the port + * @param: drift value to compensate [ppm] + * + * Load the drift variables to the FW memory. This API can be called only + * when the corresponding port has been already opened and the ASRC has + * been correctly initialized with API abe_init_asrc_... If this API is + * used such that the drift has been changed from positive to negative drift + * or vice versa, there will be click in the output signal. Loading the drift + * value with zero disables the feature. + */ +abehal_status abe_write_asrc(u32 port, s32 dppm) +{ + s32 dtempvalue, adppm, drift_sign, drift_sign_addr, alpha_params_addr; + s32 alpha_params[3]; + _log(ABE_ID_WRITE_ASRC, port, dppm, dppm >> 8); + /* + * x = ppm + * + * - 1000000/x must be multiple of 16 + * - deltaalpha = round(2^20*x*16/1000000)=round(2^18/5^6*x) on 22 bits. + * then shifted by 2bits + * - minusdeltaalpha + * - oneminusepsilon = 1-deltaalpha/2. + * + * ppm = 250 + * - 1000000/250=4000 + * - deltaalpha = 4194.3 ~ 4195 => 0x00418c + */ + /* examples for -6250 ppm */ + /* atempvalue32[1] = -1; d_driftsign */ + /* atempvalue32[3] = 0x00066668; d_deltaalpha */ + /* atempvalue32[4] = 0xfff99998; d_minusdeltaalpha */ + /* atempvalue32[5] = 0x003ccccc; d_oneminusepsilon */ + /* example for 100 ppm */ + /* atempvalue32[1] = 1;* d_driftsign */ + /* atempvalue32[3] = 0x00001a38; d_deltaalpha */ + /* atempvalue32[4] = 0xffffe5c8; d_minusdeltaalpha */ + /* atempvalue32[5] = 0x003ccccc; d_oneminusepsilon */ + /* compute new value for the ppm */ + if (dppm >= 0) { + /* d_driftsign */ + drift_sign = 1; + adppm = dppm; + } else { + /* d_driftsign */ + drift_sign = -1; + adppm = (-1 * dppm); + } + if (dppm == 0) { + /* delta_alpha */ + alpha_params[0] = 0; + /* minusdelta_alpha */ + alpha_params[1] = 0; + /* one_minusepsilon */ + alpha_params[2] = 0x003ffff0; + } else { + dtempvalue = (adppm << 4) + adppm - ((adppm * 3481L) / 15625L); + /* delta_alpha */ + alpha_params[0] = dtempvalue << 2; + /* minusdelta_alpha */ + alpha_params[1] = (-dtempvalue) << 2; + /* one_minusepsilon */ + alpha_params[2] = (0x00100000 - (dtempvalue / 2)) << 2; + } + switch (port) { + /* asynchronous sample-rate-converter for the uplink voice path */ + case OMAP_ABE_VX_DL_PORT: + drift_sign_addr = OMAP_ABE_D_ASRCVARS_DL_VX_ADDR + (1 * sizeof(s32)); + alpha_params_addr = OMAP_ABE_D_ASRCVARS_DL_VX_ADDR + (3 * sizeof(s32)); + break; + /* asynchronous sample-rate-converter for the downlink voice path */ + case OMAP_ABE_VX_UL_PORT: + drift_sign_addr = OMAP_ABE_D_ASRCVARS_UL_VX_ADDR + (1 * sizeof(s32)); + alpha_params_addr = OMAP_ABE_D_ASRCVARS_UL_VX_ADDR + (3 * sizeof(s32)); + break; + /* asynchronous sample-rate-converter for the BT_UL path */ + case OMAP_ABE_BT_VX_UL_PORT: + drift_sign_addr = OMAP_ABE_D_ASRCVARS_BT_UL_ADDR + (1 * sizeof(s32)); + alpha_params_addr = OMAP_ABE_D_ASRCVARS_BT_UL_ADDR + (3 * sizeof(s32)); + break; + /* asynchronous sample-rate-converter for the BT_DL path */ + case OMAP_ABE_BT_VX_DL_PORT: + drift_sign_addr = OMAP_ABE_D_ASRCVARS_BT_DL_ADDR + (1 * sizeof(s32)); + alpha_params_addr = OMAP_ABE_D_ASRCVARS_BT_DL_ADDR + (3 * sizeof(s32)); + break; + default: + /* asynchronous sample-rate-converter for the MM_EXT_IN path */ + case OMAP_ABE_MM_EXT_IN_PORT: + drift_sign_addr = OMAP_ABE_D_ASRCVARS_MM_EXT_IN_ADDR + (1 * sizeof(s32)); + alpha_params_addr = + OMAP_ABE_D_ASRCVARS_MM_EXT_IN_ADDR + (3 * sizeof(s32)); + break; + } + omap_abe_mem_write(abe, OMAP_ABE_DMEM, drift_sign_addr, + (u32 *) &drift_sign, 4); + omap_abe_mem_write(abe, OMAP_ABE_DMEM, alpha_params_addr, + (u32 *) &alpha_params[0], 12); + return 0; +} +EXPORT_SYMBOL(abe_write_asrc); +/** + * abe_init_asrc_vx_dl + * + * Initialize the following ASRC VX_DL parameters : + * 1. DriftSign = D_AsrcVars[1] = 1 or -1 + * 2. Subblock = D_AsrcVars[2] = 0 + * 3. DeltaAlpha = D_AsrcVars[3] = + * (round(nb_phases * drift[ppm] * 10^-6 * 2^20)) << 2 + * 4. MinusDeltaAlpha = D_AsrcVars[4] = + * (-round(nb_phases * drift[ppm] * 10^-6 * 2^20)) << 2 + * 5. OneMinusEpsilon = D_AsrcVars[5] = 1 - DeltaAlpha/2 + * 6. AlphaCurrent = 0x000020 (CMEM), initial value of Alpha parameter + * 7. BetaCurrent = 0x3fffe0 (CMEM), initial value of Beta parameter + * AlphaCurrent + BetaCurrent = 1 (=0x400000 in CMEM = 2^20 << 2) + * 8. drift_ASRC = 0 & drift_io = 0 + * 9. SMEM for ASRC_DL_VX_Coefs pointer + * 10. CMEM for ASRC_DL_VX_Coefs pointer + * ASRC_DL_VX_Coefs = C_CoefASRC16_VX_ADDR/C_CoefASRC16_VX_sizeof/0/1/ + * C_CoefASRC15_VX_ADDR/C_CoefASRC15_VX_sizeof/0/1 + * 11. SMEM for XinASRC_DL_VX pointer + * 12. CMEM for XinASRC_DL_VX pointer + * XinASRC_DL_VX = S_XinASRC_DL_VX_ADDR/S_XinASRC_DL_VX_sizeof/0/1/0/0/0/0 + * 13. SMEM for IO_VX_DL_ASRC pointer + * 14. CMEM for IO_VX_DL_ASRC pointer + * IO_VX_DL_ASRC = + * S_XinASRC_DL_VX_ADDR/S_XinASRC_DL_VX_sizeof/ + * ASRC_DL_VX_FIR_L+ASRC_margin/1/0/0/0/0 + */ +void abe_init_asrc_vx_dl(s32 dppm) +{ + s32 el[45]; + s32 temp0, temp1, adppm, dtemp, mem_tag, mem_addr; + u32 i = 0; + u32 n_fifo_el = 42; + temp0 = 0; + temp1 = 1; + /* 1. DriftSign = D_AsrcVars[1] = 1 */ + mem_tag = ABE_DMEM; + mem_addr = OMAP_ABE_D_ASRCVARS_DL_VX_ADDR + (1 * sizeof(s32)); + el[i] = (mem_tag << 16) + mem_addr; + if (dppm >= 0) { + el[i + 1] = 1; + adppm = dppm; + } else { + el[i + 1] = -1; + adppm = (-1 * dppm); + } + /* dummy field */ + el[i + 2] = temp0; + i = i + 3; + dtemp = (adppm << 4) + adppm - ((adppm * 3481L) / 15625L); + /* 2. Subblock = D_AsrcVars[2] = 0 */ + mem_tag = ABE_DMEM; + mem_addr = OMAP_ABE_D_ASRCVARS_DL_VX_ADDR + (2 * sizeof(s32)); + el[i] = (mem_tag << 16) + mem_addr; + el[i + 1] = temp0; + /* dummy field */ + el[i + 2] = temp0; + i = i + 3; + /* 3. DeltaAlpha = D_AsrcVars[3] = 0 */ + mem_tag = ABE_DMEM; + mem_addr = OMAP_ABE_D_ASRCVARS_DL_VX_ADDR + (3 * sizeof(s32)); + el[i] = (mem_tag << 16) + mem_addr; + if (dppm == 0) + el[i + 1] = 0; + else + el[i + 1] = dtemp << 2; + /* dummy field */ + el[i + 2] = temp0; + i = i + 3; + /* 4. MinusDeltaAlpha = D_AsrcVars[4] = 0 */ + mem_tag = ABE_DMEM; + mem_addr = OMAP_ABE_D_ASRCVARS_DL_VX_ADDR + (4 * sizeof(s32)); + el[i] = (mem_tag << 16) + mem_addr; + if (dppm == 0) + el[i + 1] = 0; + else + el[i + 1] = (-dtemp) << 2; + /* dummy field */ + el[i + 2] = temp0; + i = i + 3; + /*5. OneMinusEpsilon = D_AsrcVars[5] = 0x00400000 */ + mem_tag = ABE_DMEM; + mem_addr = OMAP_ABE_D_ASRCVARS_DL_VX_ADDR + (5 * sizeof(s32)); + el[i] = (mem_tag << 16) + mem_addr; + if (dppm == 0) + el[i + 1] = 0x00400000; + else + el[i + 1] = (0x00100000 - (dtemp / 2)) << 2; + /* dummy field */ + el[i + 2] = temp0; + i = i + 3; + /* 6. AlphaCurrent = 0x000020 (CMEM) */ + mem_tag = ABE_CMEM; + mem_addr = OMAP_ABE_C_ALPHACURRENT_DL_VX_ADDR; + el[i] = (mem_tag << 16) + mem_addr; + el[i + 1] = 0x00000020; + /* dummy field */ + el[i + 2] = temp0; + i = i + 3; + /* 7. BetaCurrent = 0x3fffe0 (CMEM) */ + mem_tag = ABE_CMEM; + mem_addr = OMAP_ABE_C_BETACURRENT_DL_VX_ADDR; + el[i] = (mem_tag << 16) + mem_addr; + el[i + 1] = 0x003fffe0; + /* dummy field */ + el[i + 2] = temp0; + i = i + 3; + /* 8. drift_ASRC = 0 & drift_io = 0 */ + mem_tag = ABE_DMEM; + mem_addr = OMAP_ABE_D_IODESCR_ADDR + (OMAP_ABE_VX_DL_PORT * sizeof(struct ABE_SIODescriptor)) + + drift_asrc_; + el[i] = (mem_tag << 16) + mem_addr; + el[i + 1] = temp0; + /* dummy field */ + el[i + 2] = temp0; + i = i + 3; + /* 9. SMEM for ASRC_DL_VX_Coefs pointer */ + /* ASRC_DL_VX_Coefs = C_CoefASRC16_VX_ADDR/C_CoefASRC16_VX_sizeof/0/1/ + C_CoefASRC15_VX_ADDR/C_CoefASRC15_VX_sizeof/0/1 */ + mem_tag = ABE_SMEM; + mem_addr = ASRC_DL_VX_Coefs_labelID; + el[i] = (mem_tag << 16) + (mem_addr << 2); + if (dppm == 0) { + el[i + 1] = OMAP_ABE_C_COEFASRC16_VX_ADDR >> 2; + el[i + 1] = (el[i + 1] << 8) + (OMAP_ABE_C_COEFASRC16_VX_SIZE >> 2); + el[i + 2] = OMAP_ABE_C_COEFASRC15_VX_ADDR >> 2; + el[i + 2] = (el[i + 2] << 8) + (OMAP_ABE_C_COEFASRC15_VX_SIZE >> 2); + } else { + el[i + 1] = OMAP_ABE_C_COEFASRC1_VX_ADDR >> 2; + el[i + 1] = (el[i + 1] << 8) + (OMAP_ABE_C_COEFASRC1_VX_SIZE >> 2); + el[i + 2] = OMAP_ABE_C_COEFASRC2_VX_ADDR >> 2; + el[i + 2] = (el[i + 2] << 8) + (OMAP_ABE_C_COEFASRC2_VX_SIZE >> 2); + } + i = i + 3; + /* 10. CMEM for ASRC_DL_VX_Coefs pointer */ + /* ASRC_DL_VX_Coefs = C_CoefASRC16_VX_ADDR/C_CoefASRC16_VX_sizeof/0/1/ + C_CoefASRC15_VX_ADDR/C_CoefASRC15_VX_sizeof/0/1 */ + mem_tag = ABE_CMEM; + mem_addr = ASRC_DL_VX_Coefs_labelID; + el[i] = (mem_tag << 16) + (mem_addr << 2); + /* el[i+1] = iam1<<16 + inc1<<12 + iam2<<4 + inc2 */ + el[i + 1] = (temp0 << 16) + (temp1 << 12) + (temp0 << 4) + temp1; + /* dummy field */ + el[i + 2] = temp0; + i = i + 3; + /* 11. SMEM for XinASRC_DL_VX pointer */ + /* XinASRC_DL_VX = + S_XinASRC_DL_VX_ADDR/S_XinASRC_DL_VX_sizeof/0/1/0/0/0/0 */ + mem_tag = ABE_SMEM; + mem_addr = XinASRC_DL_VX_labelID; + el[i] = (mem_tag << 16) + (mem_addr << 2); + el[i + 1] = OMAP_ABE_S_XINASRC_DL_VX_ADDR >> 3; + el[i + 1] = (el[i + 1] << 8) + (OMAP_ABE_S_XINASRC_DL_VX_SIZE >> 3); + el[i + 2] = temp0; + i = i + 3; + /* 12. CMEM for XinASRC_DL_VX pointer */ + /* XinASRC_DL_VX = + S_XinASRC_DL_VX_ADDR/S_XinASRC_DL_VX_sizeof/0/1/0/0/0/0 */ + mem_tag = ABE_CMEM; + mem_addr = XinASRC_DL_VX_labelID; + el[i] = (mem_tag << 16) + (mem_addr << 2); + /* el[i+1] = iam1<<16 + inc1<<12 + iam2<<4 + inc2 */ + el[i + 1] = (temp0 << 16) + (temp1 << 12) + (temp0 << 4) + temp0; + /* dummy field */ + el[i + 2] = temp0; + i = i + 3; + /* 13. SMEM for IO_VX_DL_ASRC pointer */ + /* IO_VX_DL_ASRC = S_XinASRC_DL_VX_ADDR/S_XinASRC_DL_VX_sizeof/ + ASRC_DL_VX_FIR_L+ASRC_margin/1/0/0/0/0 */ + mem_tag = ABE_SMEM; + mem_addr = IO_VX_DL_ASRC_labelID; + el[i] = (mem_tag << 16) + (mem_addr << 2); + el[i + 1] = OMAP_ABE_S_XINASRC_DL_VX_ADDR >> 3; + el[i + 1] = (el[i + 1] << 8) + (OMAP_ABE_S_XINASRC_DL_VX_SIZE >> 3); + el[i + 2] = temp0; + i = i + 3; + /* 14. CMEM for IO_VX_DL_ASRC pointer */ + /* IO_VX_DL_ASRC = S_XinASRC_DL_VX_ADDR/S_XinASRC_DL_VX_sizeof/ + ASRC_DL_VX_FIR_L+ASRC_margin/1/0/0/0/0 */ + mem_tag = ABE_CMEM; + mem_addr = IO_VX_DL_ASRC_labelID; + el[i] = (mem_tag << 16) + (mem_addr << 2); + /* el[i+1] = iam1<<16 + inc1<<12 + iam2<<4 + inc2 */ + el[i + 1] = ((ASRC_DL_VX_FIR_L + ASRC_margin) << 16) + (temp1 << 12) + + (temp0 << 4) + temp0; + /* dummy field */ + el[i + 2] = temp0; + abe_write_fifo(ABE_DMEM, OMAP_ABE_D_FWMEMINITDESCR_ADDR, (u32 *) &el[0], + n_fifo_el); +} +/** + * abe_init_asrc_vx_ul + * + * Initialize the following ASRC VX_UL parameters : + * 1. DriftSign = D_AsrcVars[1] = 1 or -1 + * 2. Subblock = D_AsrcVars[2] = 0 + * 3. DeltaAlpha = D_AsrcVars[3] = + * (round(nb_phases * drift[ppm] * 10^-6 * 2^20)) << 2 + * 4. MinusDeltaAlpha = D_AsrcVars[4] = + * (-round(nb_phases * drift[ppm] * 10^-6 * 2^20)) << 2 + * 5. OneMinusEpsilon = D_AsrcVars[5] = 1 - DeltaAlpha/2 + * 6. AlphaCurrent = 0x000020 (CMEM), initial value of Alpha parameter + * 7. BetaCurrent = 0x3fffe0 (CMEM), initial value of Beta parameter + * AlphaCurrent + BetaCurrent = 1 (=0x400000 in CMEM = 2^20 << 2) + * 8. drift_ASRC = 0 & drift_io = 0 + * 9. SMEM for ASRC_UL_VX_Coefs pointer + * 10. CMEM for ASRC_UL_VX_Coefs pointer + * ASRC_UL_VX_Coefs = C_CoefASRC16_VX_ADDR/C_CoefASRC16_VX_sizeof/0/1/ + * C_CoefASRC15_VX_ADDR/C_CoefASRC15_VX_sizeof/0/1 + * 11. SMEM for XinASRC_UL_VX pointer + * 12. CMEM for XinASRC_UL_VX pointer + * XinASRC_UL_VX = S_XinASRC_UL_VX_ADDR/S_XinASRC_UL_VX_sizeof/0/1/0/0/0/0 + * 13. SMEM for UL_48_8_DEC pointer + * 14. CMEM for UL_48_8_DEC pointer + * UL_48_8_DEC = S_XinASRC_UL_VX_ADDR/S_XinASRC_UL_VX_sizeof/ + * ASRC_UL_VX_FIR_L+ASRC_margin/1/0/0/0/0 + * 15. SMEM for UL_48_16_DEC pointer + * 16. CMEM for UL_48_16_DEC pointer + * UL_48_16_DEC = S_XinASRC_UL_VX_ADDR/S_XinASRC_UL_VX_sizeof/ + * ASRC_UL_VX_FIR_L+ASRC_margin/1/0/0/0/0 + */ +void abe_init_asrc_vx_ul(s32 dppm) +{ + s32 el[51]; + s32 temp0, temp1, adppm, dtemp, mem_tag, mem_addr; + u32 i = 0; + u32 n_fifo_el = 48; + temp0 = 0; + temp1 = 1; + /* 1. DriftSign = D_AsrcVars[1] = 1 */ + mem_tag = ABE_DMEM; + mem_addr = OMAP_ABE_D_ASRCVARS_UL_VX_ADDR + (1 * sizeof(s32)); + el[i] = (mem_tag << 16) + mem_addr; + if (dppm >= 0) { + el[i + 1] = 1; + adppm = dppm; + } else { + el[i + 1] = -1; + adppm = (-1 * dppm); + } + /* dummy field */ + el[i + 2] = temp0; + i = i + 3; + dtemp = (adppm << 4) + adppm - ((adppm * 3481L) / 15625L); + /* 2. Subblock = D_AsrcVars[2] = 0 */ + mem_tag = ABE_DMEM; + mem_addr = OMAP_ABE_D_ASRCVARS_UL_VX_ADDR + (2 * sizeof(s32)); + el[i] = (mem_tag << 16) + mem_addr; + el[i + 1] = temp0; + /* dummy field */ + el[i + 2] = temp0; + i = i + 3; + /* 3. DeltaAlpha = D_AsrcVars[3] = 0 */ + mem_tag = ABE_DMEM; + mem_addr = OMAP_ABE_D_ASRCVARS_UL_VX_ADDR + (3 * sizeof(s32)); + el[i] = (mem_tag << 16) + mem_addr; + if (dppm == 0) + el[i + 1] = 0; + else + el[i + 1] = dtemp << 2; + /* dummy field */ + el[i + 2] = temp0; + i = i + 3; + /* 4. MinusDeltaAlpha = D_AsrcVars[4] = 0 */ + mem_tag = ABE_DMEM; + mem_addr = OMAP_ABE_D_ASRCVARS_UL_VX_ADDR + (4 * sizeof(s32)); + el[i] = (mem_tag << 16) + mem_addr; + if (dppm == 0) + el[i + 1] = 0; + else + el[i + 1] = (-dtemp) << 2; + /* dummy field */ + el[i + 2] = temp0; + i = i + 3; + /* 5. OneMinusEpsilon = D_AsrcVars[5] = 0x00400000 */ + mem_tag = ABE_DMEM; + mem_addr = OMAP_ABE_D_ASRCVARS_UL_VX_ADDR + (5 * sizeof(s32)); + el[i] = (mem_tag << 16) + mem_addr; + if (dppm == 0) + el[i + 1] = 0x00400000; + else + el[i + 1] = (0x00100000 - (dtemp / 2)) << 2; + /* dummy field */ + el[i + 2] = temp0; + i = i + 3; + /* 6. AlphaCurrent = 0x000020 (CMEM) */ + mem_tag = ABE_CMEM; + mem_addr = OMAP_ABE_C_ALPHACURRENT_UL_VX_ADDR; + el[i] = (mem_tag << 16) + mem_addr; + el[i + 1] = 0x00000020; + /* dummy field */ + el[i + 2] = temp0; + i = i + 3; + /* 7. BetaCurrent = 0x3fffe0 (CMEM) */ + mem_tag = ABE_CMEM; + mem_addr = OMAP_ABE_C_BETACURRENT_UL_VX_ADDR; + el[i] = (mem_tag << 16) + mem_addr; + el[i + 1] = 0x003fffe0; + /* dummy field */ + el[i + 2] = temp0; + i = i + 3; + /* 8. drift_ASRC = 0 & drift_io = 0 */ + mem_tag = ABE_DMEM; + mem_addr = OMAP_ABE_D_IODESCR_ADDR + (OMAP_ABE_VX_UL_PORT * sizeof(struct ABE_SIODescriptor)) + + drift_asrc_; + el[i] = (mem_tag << 16) + mem_addr; + el[i + 1] = temp0; + /* dummy field */ + el[i + 2] = temp0; + i = i + 3; + /* 9. SMEM for ASRC_UL_VX_Coefs pointer */ + /* ASRC_UL_VX_Coefs = C_CoefASRC16_VX_ADDR/C_CoefASRC16_VX_sizeof/0/1/ + C_CoefASRC15_VX_ADDR/C_CoefASRC15_VX_sizeof/0/1 */ + mem_tag = ABE_SMEM; + mem_addr = ASRC_UL_VX_Coefs_labelID; + el[i] = (mem_tag << 16) + (mem_addr << 2); + if (dppm == 0) { + el[i + 1] = OMAP_ABE_C_COEFASRC16_VX_ADDR >> 2; + el[i + 1] = (el[i + 1] << 8) + (OMAP_ABE_C_COEFASRC16_VX_SIZE >> 2); + el[i + 2] = OMAP_ABE_C_COEFASRC15_VX_ADDR >> 2; + el[i + 2] = (el[i + 2] << 8) + (OMAP_ABE_C_COEFASRC15_VX_SIZE >> 2); + } else { + el[i + 1] = OMAP_ABE_C_COEFASRC1_VX_ADDR >> 2; + el[i + 1] = (el[i + 1] << 8) + (OMAP_ABE_C_COEFASRC1_VX_SIZE >> 2); + el[i + 2] = OMAP_ABE_C_COEFASRC2_VX_ADDR >> 2; + el[i + 2] = (el[i + 2] << 8) + (OMAP_ABE_C_COEFASRC2_VX_SIZE >> 2); + } + i = i + 3; + /* 10. CMEM for ASRC_UL_VX_Coefs pointer */ + /* ASRC_UL_VX_Coefs = C_CoefASRC16_VX_ADDR/C_CoefASRC16_VX_sizeof/0/1/ + C_CoefASRC15_VX_ADDR/C_CoefASRC15_VX_sizeof/0/1 */ + mem_tag = ABE_CMEM; + mem_addr = ASRC_UL_VX_Coefs_labelID; + el[i] = (mem_tag << 16) + (mem_addr << 2); + /* el[i+1] = iam1<<16 + inc1<<12 + iam2<<4 + inc2 */ + el[i + 1] = (temp0 << 16) + (temp1 << 12) + (temp0 << 4) + temp1; + /* dummy field */ + el[i + 2] = temp0; + i = i + 3; + /* 11. SMEM for XinASRC_UL_VX pointer */ + /* XinASRC_UL_VX = S_XinASRC_UL_VX_ADDR/S_XinASRC_UL_VX_sizeof/0/1/ + 0/0/0/0 */ + mem_tag = ABE_SMEM; + mem_addr = XinASRC_UL_VX_labelID; + el[i] = (mem_tag << 16) + (mem_addr << 2); + el[i + 1] = OMAP_ABE_S_XINASRC_UL_VX_ADDR >> 3; + el[i + 1] = (el[i + 1] << 8) + (OMAP_ABE_S_XINASRC_UL_VX_SIZE >> 3); + el[i + 2] = temp0; + i = i + 3; + /* 12. CMEM for XinASRC_UL_VX pointer */ + /* XinASRC_UL_VX = S_XinASRC_UL_VX_ADDR/S_XinASRC_UL_VX_sizeof/0/1/ + 0/0/0/0 */ + mem_tag = ABE_CMEM; + mem_addr = XinASRC_UL_VX_labelID; + el[i] = (mem_tag << 16) + (mem_addr << 2); + /* el[i+1] = iam1<<16 + inc1<<12 + iam2<<4 + inc2 */ + el[i + 1] = (temp0 << 16) + (temp1 << 12) + (temp0 << 4) + temp0; + /* dummy field */ + el[i + 2] = temp0; + i = i + 3; + /* 13. SMEM for UL_48_8_DEC pointer */ + /* UL_48_8_DEC = S_XinASRC_UL_VX_ADDR/S_XinASRC_UL_VX_sizeof/ + ASRC_UL_VX_FIR_L+ASRC_margin/1/0/0/0/0 */ + mem_tag = ABE_SMEM; + mem_addr = UL_48_8_DEC_labelID; + el[i] = (mem_tag << 16) + (mem_addr << 2); + el[i + 1] = OMAP_ABE_S_XINASRC_UL_VX_ADDR >> 3; + el[i + 1] = (el[i + 1] << 8) + (OMAP_ABE_S_XINASRC_UL_VX_SIZE >> 3); + el[i + 2] = temp0; + i = i + 3; + /* 14. CMEM for UL_48_8_DEC pointer */ + /* UL_48_8_DEC = S_XinASRC_UL_VX_ADDR/S_XinASRC_UL_VX_sizeof/ + ASRC_UL_VX_FIR_L+ASRC_margin/1/0/0/0/0 */ + mem_tag = ABE_CMEM; + mem_addr = UL_48_8_DEC_labelID; + el[i] = (mem_tag << 16) + (mem_addr << 2); + /* el[i+1] = iam1<<16 + inc1<<12 + iam2<<4 + inc2 */ + el[i + 1] = ((ASRC_UL_VX_FIR_L + ASRC_margin) << 16) + (temp1 << 12) + + (temp0 << 4) + temp0; + /* dummy field */ + el[i + 2] = temp0; + i = i + 3; + /* 15. SMEM for UL_48_16_DEC pointer */ + /* UL_48_16_DEC = S_XinASRC_UL_VX_ADDR/S_XinASRC_UL_VX_sizeof/ + ASRC_UL_VX_FIR_L+ASRC_margin/1/0/0/0/0 */ + mem_tag = ABE_SMEM; + mem_addr = UL_48_16_DEC_labelID; + el[i] = (mem_tag << 16) + (mem_addr << 2); + el[i + 1] = OMAP_ABE_S_XINASRC_UL_VX_ADDR >> 3; + el[i + 1] = (el[i + 1] << 8) + (OMAP_ABE_S_XINASRC_UL_VX_SIZE >> 3); + el[i + 2] = temp0; + i = i + 3; + /* 16. CMEM for UL_48_16_DEC pointer */ + /* UL_48_16_DEC = S_XinASRC_UL_VX_ADDR/S_XinASRC_UL_VX_sizeof/ + ASRC_UL_VX_FIR_L+ASRC_margin/1/0/0/0/0 */ + mem_tag = ABE_CMEM; + mem_addr = UL_48_16_DEC_labelID; + el[i] = (mem_tag << 16) + (mem_addr << 2); + /* el[i+1] = iam1<<16 + inc1<<12 + iam2<<4 + inc2 */ + el[i + 1] = ((ASRC_UL_VX_FIR_L + ASRC_margin) << 16) + (temp1 << 12) + + (temp0 << 4) + temp0; + /* dummy field */ + el[i + 2] = temp0; + abe_write_fifo(ABE_DMEM, OMAP_ABE_D_FWMEMINITDESCR_ADDR, (u32 *) &el[0], + n_fifo_el); +} +/** + * abe_init_asrc_mm_ext_in + * + * Initialize the following ASRC MM_EXT_IN parameters : + * 1. DriftSign = D_AsrcVars[1] = 1 or -1 + * 2. Subblock = D_AsrcVars[2] = 0 + * 3. DeltaAlpha = D_AsrcVars[3] = + * (round(nb_phases * drift[ppm] * 10^-6 * 2^20)) << 2 + * 4. MinusDeltaAlpha = D_AsrcVars[4] = + * (-round(nb_phases * drift[ppm] * 10^-6 * 2^20)) << 2 + * 5. OneMinusEpsilon = D_AsrcVars[5] = 1 - DeltaAlpha/2 + * 6. AlphaCurrent = 0x000020 (CMEM), initial value of Alpha parameter + * 7. BetaCurrent = 0x3fffe0 (CMEM), initial value of Beta parameter + * AlphaCurrent + BetaCurrent = 1 (=0x400000 in CMEM = 2^20 << 2) + * 8. drift_ASRC = 0 & drift_io = 0 + * 9. SMEM for ASRC_MM_EXT_IN_Coefs pointer + * 10. CMEM for ASRC_MM_EXT_IN_Coefs pointer + * ASRC_MM_EXT_IN_Coefs = C_CoefASRC16_MM_ADDR/C_CoefASRC16_MM_sizeof/0/1/ + * C_CoefASRC15_MM_ADDR/C_CoefASRC15_MM_sizeof/0/1 + * 11. SMEM for XinASRC_MM_EXT_IN pointer + * 12. CMEM for XinASRC_MM_EXT_IN pointer + * XinASRC_MM_EXT_IN = S_XinASRC_MM_EXT_IN_ADDR/S_XinASRC_MM_EXT_IN_sizeof/0/1/ + * 0/0/0/0 + * 13. SMEM for IO_MM_EXT_IN_ASRC pointer + * 14. CMEM for IO_MM_EXT_IN_ASRC pointer + * IO_MM_EXT_IN_ASRC = S_XinASRC_MM_EXT_IN_ADDR/S_XinASRC_MM_EXT_IN_sizeof/ + * ASRC_MM_EXT_IN_FIR_L+ASRC_margin+ASRC_N_48k/1/0/0/0/0 + */ +void abe_init_asrc_mm_ext_in(s32 dppm) +{ + s32 el[45]; + s32 temp0, temp1, adppm, dtemp, mem_tag, mem_addr; + u32 i = 0; + u32 n_fifo_el = 42; + temp0 = 0; + temp1 = 1; + /* 1. DriftSign = D_AsrcVars[1] = 1 */ + mem_tag = ABE_DMEM; + mem_addr = OMAP_ABE_D_ASRCVARS_MM_EXT_IN_ADDR + (1 * sizeof(s32)); + el[i] = (mem_tag << 16) + mem_addr; + if (dppm >= 0) { + el[i + 1] = 1; + adppm = dppm; + } else { + el[i + 1] = -1; + adppm = (-1 * dppm); + } + /* dummy field */ + el[i + 2] = temp0; + i = i + 3; + dtemp = (adppm << 4) + adppm - ((adppm * 3481L) / 15625L); + /* 2. Subblock = D_AsrcVars[2] = 0 */ + mem_tag = ABE_DMEM; + mem_addr = OMAP_ABE_D_ASRCVARS_MM_EXT_IN_ADDR + (2 * sizeof(s32)); + el[i] = (mem_tag << 16) + mem_addr; + el[i + 1] = temp0; + /* dummy field */ + el[i + 2] = temp0; + i = i + 3; + /* 3. DeltaAlpha = D_AsrcVars[3] = 0 */ + mem_tag = ABE_DMEM; + mem_addr = OMAP_ABE_D_ASRCVARS_MM_EXT_IN_ADDR + (3 * sizeof(s32)); + el[i] = (mem_tag << 16) + mem_addr; + if (dppm == 0) + el[i + 1] = 0; + else + el[i + 1] = dtemp << 2; + /* dummy field */ + el[i + 2] = temp0; + i = i + 3; + /* 4. MinusDeltaAlpha = D_AsrcVars[4] = 0 */ + mem_tag = ABE_DMEM; + mem_addr = OMAP_ABE_D_ASRCVARS_MM_EXT_IN_ADDR + (4 * sizeof(s32)); + el[i] = (mem_tag << 16) + mem_addr; + if (dppm == 0) + el[i + 1] = 0; + else + el[i + 1] = (-dtemp) << 2; + /* dummy field */ + el[i + 2] = temp0; + i = i + 3; + /* 5. OneMinusEpsilon = D_AsrcVars[5] = 0x00400000 */ + mem_tag = ABE_DMEM; + mem_addr = OMAP_ABE_D_ASRCVARS_MM_EXT_IN_ADDR + (5 * sizeof(s32)); + el[i] = (mem_tag << 16) + mem_addr; + if (dppm == 0) + el[i + 1] = 0x00400000; + else + el[i + 1] = (0x00100000 - (dtemp / 2)) << 2; + /* dummy field */ + el[i + 2] = temp0; + i = i + 3; + /* 6. AlphaCurrent = 0x000020 (CMEM) */ + mem_tag = ABE_CMEM; + mem_addr = OMAP_ABE_C_ALPHACURRENT_MM_EXT_IN_ADDR; + el[i] = (mem_tag << 16) + mem_addr; + el[i + 1] = 0x00000020; + /* dummy field */ + el[i + 2] = temp0; + i = i + 3; + /* 7. BetaCurrent = 0x3fffe0 (CMEM) */ + mem_tag = ABE_CMEM; + mem_addr = OMAP_ABE_C_BETACURRENT_MM_EXT_IN_ADDR; + el[i] = (mem_tag << 16) + mem_addr; + el[i + 1] = 0x003fffe0; + /* dummy field */ + el[i + 2] = temp0; + i = i + 3; + /* 8. drift_ASRC = 0 & drift_io = 0 */ + mem_tag = ABE_DMEM; + mem_addr = OMAP_ABE_D_IODESCR_ADDR + (OMAP_ABE_MM_EXT_IN_PORT * sizeof(struct ABE_SIODescriptor)) + + drift_asrc_; + el[i] = (mem_tag << 16) + mem_addr; + el[i + 1] = temp0; + /* dummy field */ + el[i + 2] = temp0; + i = i + 3; + /* 9. SMEM for ASRC_MM_EXT_IN_Coefs pointer */ + /* ASRC_MM_EXT_IN_Coefs = C_CoefASRC16_MM_ADDR/C_CoefASRC16_MM_sizeof/ + 0/1/C_CoefASRC15_MM_ADDR/C_CoefASRC15_MM_sizeof/0/1 */ + mem_tag = ABE_SMEM; + mem_addr = ASRC_MM_EXT_IN_Coefs_labelID; + el[i] = (mem_tag << 16) + (mem_addr << 2); + if (dppm == 0) { + el[i + 1] = OMAP_ABE_C_COEFASRC16_MM_ADDR >> 2; + el[i + 1] = (el[i + 1] << 8) + (OMAP_ABE_C_COEFASRC16_MM_SIZE >> 2); + el[i + 2] = OMAP_ABE_C_COEFASRC15_MM_ADDR >> 2; + el[i + 2] = (el[i + 2] << 8) + (OMAP_ABE_C_COEFASRC15_MM_SIZE >> 2); + } else { + el[i + 1] = OMAP_ABE_C_COEFASRC1_MM_ADDR >> 2; + el[i + 1] = (el[i + 1] << 8) + (OMAP_ABE_C_COEFASRC1_MM_SIZE >> 2); + el[i + 2] = OMAP_ABE_C_COEFASRC2_MM_ADDR >> 2; + el[i + 2] = (el[i + 2] << 8) + (OMAP_ABE_C_COEFASRC2_MM_SIZE >> 2); + } + i = i + 3; + /*10. CMEM for ASRC_MM_EXT_IN_Coefs pointer */ + /* ASRC_MM_EXT_IN_Coefs = C_CoefASRC16_MM_ADDR/C_CoefASRC16_MM_sizeof/ + 0/1/C_CoefASRC15_MM_ADDR/C_CoefASRC15_MM_sizeof/0/1 */ + mem_tag = ABE_CMEM; + mem_addr = ASRC_MM_EXT_IN_Coefs_labelID; + el[i] = (mem_tag << 16) + (mem_addr << 2); + /* el[i+1] = iam1<<16 + inc1<<12 + iam2<<4 + inc2 */ + el[i + 1] = (temp0 << 16) + (temp1 << 12) + (temp0 << 4) + temp1; + /* dummy field */ + el[i + 2] = temp0; + i = i + 3; + /* 11. SMEM for XinASRC_MM_EXT_IN pointer */ + /* XinASRC_MM_EXT_IN = S_XinASRC_MM_EXT_IN_ADDR/ + S_XinASRC_MM_EXT_IN_sizeof/0/1/0/0/0/0 */ + mem_tag = ABE_SMEM; + mem_addr = XinASRC_MM_EXT_IN_labelID; + el[i] = (mem_tag << 16) + (mem_addr << 2); + el[i + 1] = OMAP_ABE_S_XINASRC_MM_EXT_IN_ADDR >> 3; + el[i + 1] = (el[i + 1] << 8) + (OMAP_ABE_S_XINASRC_MM_EXT_IN_SIZE >> 3); + el[i + 2] = temp0; + i = i + 3; + /* 12. CMEM for XinASRC_MM_EXT_IN pointer */ + /* XinASRC_MM_EXT_IN = S_XinASRC_MM_EXT_IN_ADDR/ + S_XinASRC_MM_EXT_IN_sizeof/0/1/0/0/0/0 */ + mem_tag = ABE_CMEM; + mem_addr = XinASRC_MM_EXT_IN_labelID; + el[i] = (mem_tag << 16) + (mem_addr << 2); + /* el[i+1] = iam1<<16 + inc1<<12 + iam2<<4 + inc2 */ + el[i + 1] = (temp0 << 16) + (temp1 << 12) + (temp0 << 4) + temp0; + /* dummy field */ + el[i + 2] = temp0; + i = i + 3; + /* 13. SMEM for IO_MM_EXT_IN_ASRC pointer */ + /* IO_MM_EXT_IN_ASRC = + S_XinASRC_MM_EXT_IN_ADDR/S_XinASRC_MM_EXT_IN_sizeof/ + ASRC_MM_EXT_IN_FIR_L+ASRC_margin+ASRC_N_48k/1/0/0/0/0 */ + mem_tag = ABE_SMEM; + mem_addr = IO_MM_EXT_IN_ASRC_labelID; + el[i] = (mem_tag << 16) + (mem_addr << 2); + el[i + 1] = OMAP_ABE_S_XINASRC_MM_EXT_IN_ADDR >> 3; + el[i + 1] = (el[i + 1] << 8) + (OMAP_ABE_S_XINASRC_MM_EXT_IN_SIZE >> 3); + el[i + 2] = temp0; + i = i + 3; + /* 14. CMEM for IO_MM_EXT_IN_ASRC pointer */ + /* IO_MM_EXT_IN_ASRC = + S_XinASRC_MM_EXT_IN_ADDR/S_XinASRC_MM_EXT_IN_sizeof/ + ASRC_MM_EXT_IN_FIR_L+ASRC_margin+ASRC_N_48k/1/0/0/0/0 */ + mem_tag = ABE_CMEM; + mem_addr = IO_MM_EXT_IN_ASRC_labelID; + el[i] = (mem_tag << 16) + (mem_addr << 2); + /* el[i+1] = iam1<<16 + inc1<<12 + iam2<<4 + inc2 */ + el[i + 1] = ((ASRC_MM_EXT_IN_FIR_L + ASRC_margin + ASRC_N_48k) << 16) + + (temp1 << 12) + (temp0 << 4) + temp0; + /* dummy field */ + el[i + 2] = temp0; + abe_write_fifo(ABE_DMEM, OMAP_ABE_D_FWMEMINITDESCR_ADDR, (u32 *) &el[0], + n_fifo_el); +} +/** + * abe_init_asrc_bt_ul + * + * Initialize the following ASRC BT_UL parameters : + * 1. DriftSign = D_AsrcVars[1] = 1 or -1 + * 2. Subblock = D_AsrcVars[2] = 0 + * 3. DeltaAlpha = D_AsrcVars[3] = + * (round(nb_phases * drift[ppm] * 10^-6 * 2^20)) << 2 + * 4. MinusDeltaAlpha = D_AsrcVars[4] = + * (-round(nb_phases * drift[ppm] * 10^-6 * 2^20)) << 2 + * 5. OneMinusEpsilon = D_AsrcVars[5] = 1 - DeltaAlpha/2 + * 6. AlphaCurrent = 0x000020 (CMEM), initial value of Alpha parameter + * 7. BetaCurrent = 0x3fffe0 (CMEM), initial value of Beta parameter + * AlphaCurrent + BetaCurrent = 1 (=0x400000 in CMEM = 2^20 << 2) + * 8. drift_ASRC = 0 & drift_io = 0 + * 9. SMEM for ASRC_BT_UL_Coefs pointer + * 10. CMEM for ASRC_BT_UL_Coefs pointer + * ASRC_BT_UL_Coefs = C_CoefASRC16_VX_ADDR/C_CoefASRC16_VX_sizeof/0/1/ + * C_CoefASRC15_VX_ADDR/C_CoefASRC15_VX_sizeof/0/1 + * 11. SMEM for XinASRC_BT_UL pointer + * 12. CMEM for XinASRC_BT_UL pointer + * XinASRC_BT_UL = S_XinASRC_BT_UL_ADDR/S_XinASRC_BT_UL_sizeof/0/1/0/0/0/0 + * 13. SMEM for IO_BT_UL_ASRC pointer + * 14. CMEM for IO_BT_UL_ASRC pointer + * IO_BT_UL_ASRC = S_XinASRC_BT_UL_ADDR/S_XinASRC_BT_UL_sizeof/ + * ASRC_BT_UL_FIR_L+ASRC_margin/1/0/0/0/0 + */ +void abe_init_asrc_bt_ul(s32 dppm) +{ + s32 el[45]; + s32 temp0, temp1, adppm, dtemp, mem_tag, mem_addr; + u32 i = 0; + u32 n_fifo_el = 42; + temp0 = 0; + temp1 = 1; + /* 1. DriftSign = D_AsrcVars[1] = 1 */ + mem_tag = ABE_DMEM; + mem_addr = OMAP_ABE_D_ASRCVARS_BT_UL_ADDR + (1 * sizeof(s32)); + el[i] = (mem_tag << 16) + mem_addr; + if (dppm >= 0) { + el[i + 1] = 1; + adppm = dppm; + } else { + el[i + 1] = -1; + adppm = (-1 * dppm); + } + /* dummy field */ + el[i + 2] = temp0; + i = i + 3; + dtemp = (adppm << 4) + adppm - ((adppm * 3481L) / 15625L); + /* 2. Subblock = D_AsrcVars[2] = 0 */ + mem_tag = ABE_DMEM; + mem_addr = OMAP_ABE_D_ASRCVARS_BT_UL_ADDR + (2 * sizeof(s32)); + el[i] = (mem_tag << 16) + mem_addr; + el[i + 1] = temp0; + /* dummy field */ + el[i + 2] = temp0; + i = i + 3; + /* 3. DeltaAlpha = D_AsrcVars[3] = 0 */ + mem_tag = ABE_DMEM; + mem_addr = OMAP_ABE_D_ASRCVARS_BT_UL_ADDR + (3 * sizeof(s32)); + el[i] = (mem_tag << 16) + mem_addr; + if (dppm == 0) + el[i + 1] = 0; + else + el[i + 1] = dtemp << 2; + /* dummy field */ + el[i + 2] = temp0; + i = i + 3; + /* 4. MinusDeltaAlpha = D_AsrcVars[4] = 0 */ + mem_tag = ABE_DMEM; + mem_addr = OMAP_ABE_D_ASRCVARS_BT_UL_ADDR + (4 * sizeof(s32)); + el[i] = (mem_tag << 16) + mem_addr; + if (dppm == 0) + el[i + 1] = 0; + else + el[i + 1] = (-dtemp) << 2; + /* dummy field */ + el[i + 2] = temp0; + i = i + 3; + /*5. OneMinusEpsilon = D_AsrcVars[5] = 0x00400000 */ + mem_tag = ABE_DMEM; + mem_addr = OMAP_ABE_D_ASRCVARS_BT_UL_ADDR + (5 * sizeof(s32)); + el[i] = (mem_tag << 16) + mem_addr; + if (dppm == 0) + el[i + 1] = 0x00400000; + else + el[i + 1] = (0x00100000 - (dtemp / 2)) << 2; + /* dummy field */ + el[i + 2] = temp0; + i = i + 3; + /* 6. AlphaCurrent = 0x000020 (CMEM) */ + mem_tag = ABE_CMEM; + mem_addr = OMAP_ABE_C_ALPHACURRENT_BT_UL_ADDR; + el[i] = (mem_tag << 16) + mem_addr; + el[i + 1] = 0x00000020; + /* dummy field */ + el[i + 2] = temp0; + i = i + 3; + /* 7. BetaCurrent = 0x3fffe0 (CMEM) */ + mem_tag = ABE_CMEM; + mem_addr = OMAP_ABE_C_BETACURRENT_BT_UL_ADDR; + el[i] = (mem_tag << 16) + mem_addr; + el[i + 1] = 0x003fffe0; + /* dummy field */ + el[i + 2] = temp0; + i = i + 3; + /* 8. drift_ASRC = 0 & drift_io = 0 */ + mem_tag = ABE_DMEM; + mem_addr = OMAP_ABE_D_IODESCR_ADDR + (OMAP_ABE_BT_VX_UL_PORT * sizeof(struct ABE_SIODescriptor)) + + drift_asrc_; + el[i] = (mem_tag << 16) + mem_addr; + el[i + 1] = temp0; + /* dummy field */ + el[i + 2] = temp0; + i = i + 3; + /* 9. SMEM for ASRC_BT_UL_Coefs pointer */ + /* ASRC_BT_UL_Coefs = C_CoefASRC16_VX_ADDR/C_CoefASRC16_VX_sizeof/0/1/ + C_CoefASRC15_VX_ADDR/C_CoefASRC15_VX_sizeof/0/1 */ + mem_tag = ABE_SMEM; + mem_addr = ASRC_BT_UL_Coefs_labelID; + el[i] = (mem_tag << 16) + (mem_addr << 2); + if (dppm == 0) { + el[i + 1] = OMAP_ABE_C_COEFASRC16_VX_ADDR >> 2; + el[i + 1] = (el[i + 1] << 8) + (OMAP_ABE_C_COEFASRC16_VX_SIZE >> 2); + el[i + 2] = OMAP_ABE_C_COEFASRC15_VX_ADDR >> 2; + el[i + 2] = (el[i + 2] << 8) + (OMAP_ABE_C_COEFASRC15_VX_SIZE >> 2); + } else { + el[i + 1] = OMAP_ABE_C_COEFASRC1_VX_ADDR >> 2; + el[i + 1] = (el[i + 1] << 8) + (OMAP_ABE_C_COEFASRC1_VX_SIZE >> 2); + el[i + 2] = OMAP_ABE_C_COEFASRC2_VX_ADDR >> 2; + el[i + 2] = (el[i + 2] << 8) + (OMAP_ABE_C_COEFASRC2_VX_SIZE >> 2); + } + i = i + 3; + /* 10. CMEM for ASRC_BT_UL_Coefs pointer */ + /* ASRC_BT_UL_Coefs = C_CoefASRC16_VX_ADDR/C_CoefASRC16_VX_sizeof/0/1/ + C_CoefASRC15_VX_ADDR/C_CoefASRC15_VX_sizeof/0/1 */ + mem_tag = ABE_CMEM; + mem_addr = ASRC_BT_UL_Coefs_labelID; + el[i] = (mem_tag << 16) + (mem_addr << 2); + /* el[i+1] = iam1<<16 + inc1<<12 + iam2<<4 + inc2 */ + el[i + 1] = (temp0 << 16) + (temp1 << 12) + (temp0 << 4) + temp1; + /* dummy field */ + el[i + 2] = temp0; + i = i + 3; + /* 11. SMEM for XinASRC_BT_UL pointer */ + /* XinASRC_BT_UL = S_XinASRC_BT_UL_ADDR/S_XinASRC_BT_UL_sizeof/0/1/ + 0/0/0/0 */ + mem_tag = ABE_SMEM; + mem_addr = XinASRC_BT_UL_labelID; + el[i] = (mem_tag << 16) + (mem_addr << 2); + el[i + 1] = OMAP_ABE_S_XINASRC_BT_UL_ADDR >> 3; + el[i + 1] = (el[i + 1] << 8) + (OMAP_ABE_S_XINASRC_BT_UL_SIZE >> 3); + el[i + 2] = temp0; + i = i + 3; + /* 12. CMEM for XinASRC_BT_UL pointer */ + /* XinASRC_BT_UL = S_XinASRC_BT_UL_ADDR/S_XinASRC_BT_UL_sizeof/0/1/ + 0/0/0/0 */ + mem_tag = ABE_CMEM; + mem_addr = XinASRC_BT_UL_labelID; + el[i] = (mem_tag << 16) + (mem_addr << 2); + /* el[i+1] = iam1<<16 + inc1<<12 + iam2<<4 + inc2 */ + el[i + 1] = (temp0 << 16) + (temp1 << 12) + (temp0 << 4) + temp0; + /* dummy field */ + el[i + 2] = temp0; + i = i + 3; + /* 13. SMEM for IO_BT_UL_ASRC pointer */ + /* IO_BT_UL_ASRC = S_XinASRC_BT_UL_ADDR/S_XinASRC_BT_UL_sizeof/ + ASRC_BT_UL_FIR_L+ASRC_margin/1/0/0/0/0 */ + mem_tag = ABE_SMEM; + mem_addr = IO_BT_UL_ASRC_labelID; + el[i] = (mem_tag << 16) + (mem_addr << 2); + el[i + 1] = OMAP_ABE_S_XINASRC_BT_UL_ADDR >> 3; + el[i + 1] = (el[i + 1] << 8) + (OMAP_ABE_S_XINASRC_BT_UL_SIZE >> 3); + el[i + 2] = temp0; + i = i + 3; + /* 14. CMEM for IO_BT_UL_ASRC pointer */ + /* IO_BT_UL_ASRC = S_XinASRC_BT_UL_ADDR/S_XinASRC_BT_UL_sizeof/ + ASRC_BT_UL_FIR_L+ASRC_margin/1/0/0/0/0 */ + mem_tag = ABE_CMEM; + mem_addr = IO_BT_UL_ASRC_labelID; + el[i] = (mem_tag << 16) + (mem_addr << 2); + /* el[i+1] = iam1<<16 + inc1<<12 + iam2<<4 + inc2 */ + el[i + 1] = ((ASRC_BT_UL_FIR_L + ASRC_margin) << 16) + (temp1 << 12) + + (temp0 << 4) + temp0; + /* dummy field */ + el[i + 2] = temp0; + abe_write_fifo(ABE_DMEM, OMAP_ABE_D_FWMEMINITDESCR_ADDR, (u32 *) &el[0], + n_fifo_el); +} +/** + * abe_init_asrc_bt_dl + * + * Initialize the following ASRC BT_DL parameters : + * 1. DriftSign = D_AsrcVars[1] = 1 or -1 + * 2. Subblock = D_AsrcVars[2] = 0 + * 3. DeltaAlpha = D_AsrcVars[3] = + * (round(nb_phases * drift[ppm] * 10^-6 * 2^20)) << 2 + * 4. MinusDeltaAlpha = D_AsrcVars[4] = + * (-round(nb_phases * drift[ppm] * 10^-6 * 2^20)) << 2 + * 5. OneMinusEpsilon = D_AsrcVars[5] = 1 - DeltaAlpha/2 + * 6. AlphaCurrent = 0x000020 (CMEM), initial value of Alpha parameter + * 7. BetaCurrent = 0x3fffe0 (CMEM), initial value of Beta parameter + * AlphaCurrent + BetaCurrent = 1 (=0x400000 in CMEM = 2^20 << 2) + * 8. drift_ASRC = 0 & drift_io = 0 + * 9. SMEM for ASRC_BT_DL_Coefs pointer + * 10. CMEM for ASRC_BT_DL_Coefs pointer + * ASRC_BT_DL_Coefs = C_CoefASRC16_VX_ADDR/C_CoefASRC16_VX_sizeof/0/1/ + * C_CoefASRC15_VX_ADDR/C_CoefASRC15_VX_sizeof/0/1 + * 11. SMEM for XinASRC_BT_DL pointer + * 12. CMEM for XinASRC_BT_DL pointer + * XinASRC_BT_DL = S_XinASRC_BT_DL_ADDR/S_XinASRC_BT_DL_sizeof/0/1/0/0/0/0 + * 13. SMEM for DL_48_8_DEC pointer + * 14. CMEM for DL_48_8_DEC pointer + * DL_48_8_DEC = S_XinASRC_BT_DL_ADDR/S_XinASRC_BT_DL_sizeof/ + * ASRC_BT_DL_FIR_L+ASRC_margin/1/0/0/0/0 + * 15. SMEM for DL_48_16_DEC pointer + * 16. CMEM for DL_48_16_DEC pointer + * DL_48_16_DEC = S_XinASRC_BT_DL_ADDR/S_XinASRC_BT_DL_sizeof/ + * ASRC_BT_DL_FIR_L+ASRC_margin/1/0/0/0/0 + */ +void abe_init_asrc_bt_dl(s32 dppm) +{ + s32 el[51]; + s32 temp0, temp1, adppm, dtemp, mem_tag, mem_addr; + u32 i = 0; + u32 n_fifo_el = 48; + temp0 = 0; + temp1 = 1; + /* 1. DriftSign = D_AsrcVars[1] = 1 */ + mem_tag = ABE_DMEM; + mem_addr = OMAP_ABE_D_ASRCVARS_BT_DL_ADDR + (1 * sizeof(s32)); + el[i] = (mem_tag << 16) + mem_addr; + if (dppm >= 0) { + el[i + 1] = 1; + adppm = dppm; + } else { + el[i + 1] = -1; + adppm = (-1 * dppm); + } + /* dummy field */ + el[i + 2] = temp0; + i = i + 3; + dtemp = (adppm << 4) + adppm - ((adppm * 3481L) / 15625L); + /* 2. Subblock = D_AsrcVars[2] = 0 */ + mem_tag = ABE_DMEM; + mem_addr = OMAP_ABE_D_ASRCVARS_BT_DL_ADDR + (2 * sizeof(s32)); + el[i] = (mem_tag << 16) + mem_addr; + el[i + 1] = temp0; + /* dummy field */ + el[i + 2] = temp0; + i = i + 3; + /* 3. DeltaAlpha = D_AsrcVars[3] = 0 */ + mem_tag = ABE_DMEM; + mem_addr = OMAP_ABE_D_ASRCVARS_BT_DL_ADDR + (3 * sizeof(s32)); + el[i] = (mem_tag << 16) + mem_addr; + if (dppm == 0) + el[i + 1] = 0; + else + el[i + 1] = dtemp << 2; + /* dummy field */ + el[i + 2] = temp0; + i = i + 3; + /* 4. MinusDeltaAlpha = D_AsrcVars[4] = 0 */ + mem_tag = ABE_DMEM; + mem_addr = OMAP_ABE_D_ASRCVARS_BT_DL_ADDR + (4 * sizeof(s32)); + el[i] = (mem_tag << 16) + mem_addr; + if (dppm == 0) + el[i + 1] = 0; + else + el[i + 1] = (-dtemp) << 2; + /* dummy field */ + el[i + 2] = temp0; + i = i + 3; + /* 5. OneMinusEpsilon = D_AsrcVars[5] = 0x00400000 */ + mem_tag = ABE_DMEM; + mem_addr = OMAP_ABE_D_ASRCVARS_BT_DL_ADDR + (5 * sizeof(s32)); + el[i] = (mem_tag << 16) + mem_addr; + if (dppm == 0) + el[i + 1] = 0x00400000; + else + el[i + 1] = (0x00100000 - (dtemp / 2)) << 2; + /* dummy field */ + el[i + 2] = temp0; + i = i + 3; + /* 6. AlphaCurrent = 0x000020 (CMEM) */ + mem_tag = ABE_CMEM; + mem_addr = OMAP_ABE_C_ALPHACURRENT_BT_DL_ADDR; + el[i] = (mem_tag << 16) + mem_addr; + el[i + 1] = 0x00000020; + /* dummy field */ + el[i + 2] = temp0; + i = i + 3; + /* 7. BetaCurrent = 0x3fffe0 (CMEM) */ + mem_tag = ABE_CMEM; + mem_addr = OMAP_ABE_C_BETACURRENT_BT_DL_ADDR; + el[i] = (mem_tag << 16) + mem_addr; + el[i + 1] = 0x003fffe0; + /* dummy field */ + el[i + 2] = temp0; + i = i + 3; + /* 8. drift_ASRC = 0 & drift_io = 0 */ + mem_tag = ABE_DMEM; + mem_addr = OMAP_ABE_D_IODESCR_ADDR + (OMAP_ABE_BT_VX_DL_PORT * sizeof(struct ABE_SIODescriptor)) + + drift_asrc_; + el[i] = (mem_tag << 16) + mem_addr; + el[i + 1] = temp0; + /* dummy field */ + el[i + 2] = temp0; + i = i + 3; + /* 9. SMEM for ASRC_BT_DL_Coefs pointer */ + /* ASRC_BT_DL_Coefs = C_CoefASRC16_VX_ADDR/C_CoefASRC16_VX_sizeof/0/1/ + C_CoefASRC15_VX_ADDR/C_CoefASRC15_VX_sizeof/0/1 */ + mem_tag = ABE_SMEM; + mem_addr = ASRC_BT_DL_Coefs_labelID; + el[i] = (mem_tag << 16) + (mem_addr << 2); + if (dppm == 0) { + el[i + 1] = OMAP_ABE_C_COEFASRC16_VX_ADDR >> 2; + el[i + 1] = (el[i + 1] << 8) + (OMAP_ABE_C_COEFASRC16_VX_SIZE >> 2); + el[i + 2] = OMAP_ABE_C_COEFASRC15_VX_ADDR >> 2; + el[i + 2] = (el[i + 2] << 8) + (OMAP_ABE_C_COEFASRC15_VX_SIZE >> 2); + } else { + el[i + 1] = OMAP_ABE_C_COEFASRC1_VX_ADDR >> 2; + el[i + 1] = (el[i + 1] << 8) + (OMAP_ABE_C_COEFASRC1_VX_SIZE >> 2); + el[i + 2] = OMAP_ABE_C_COEFASRC2_VX_ADDR >> 2; + el[i + 2] = (el[i + 2] << 8) + (OMAP_ABE_C_COEFASRC2_VX_SIZE >> 2); + } + i = i + 3; + /* 10. CMEM for ASRC_BT_DL_Coefs pointer */ + /* ASRC_BT_DL_Coefs = C_CoefASRC16_VX_ADDR/C_CoefASRC16_VX_sizeof/0/1/ + C_CoefASRC15_VX_ADDR/C_CoefASRC15_VX_sizeof/0/1 */ + mem_tag = ABE_CMEM; + mem_addr = ASRC_BT_DL_Coefs_labelID; + el[i] = (mem_tag << 16) + (mem_addr << 2); + /* el[i+1] = iam1<<16 + inc1<<12 + iam2<<4 + inc2 */ + el[i + 1] = (temp0 << 16) + (temp1 << 12) + (temp0 << 4) + temp1; + /* dummy field */ + el[i + 2] = temp0; + i = i + 3; + /* 11. SMEM for XinASRC_BT_DL pointer */ + /* XinASRC_BT_DL = + S_XinASRC_BT_DL_ADDR/S_XinASRC_BT_DL_sizeof/0/1/0/0/0/0 */ + mem_tag = ABE_SMEM; + mem_addr = XinASRC_BT_DL_labelID; + el[i] = (mem_tag << 16) + (mem_addr << 2); + el[i + 1] = OMAP_ABE_S_XINASRC_BT_DL_ADDR >> 3; + el[i + 1] = (el[i + 1] << 8) + (OMAP_ABE_S_XINASRC_BT_DL_SIZE >> 3); + el[i + 2] = temp0; + i = i + 3; + /* 12. CMEM for XinASRC_BT_DL pointer */ + /* XinASRC_BT_DL = + S_XinASRC_BT_DL_ADDR/S_XinASRC_BT_DL_sizeof/0/1/0/0/0/0 */ + mem_tag = ABE_CMEM; + mem_addr = XinASRC_BT_DL_labelID; + el[i] = (mem_tag << 16) + (mem_addr << 2); + /* el[i+1] = iam1<<16 + inc1<<12 + iam2<<4 + inc2 */ + el[i + 1] = (temp0 << 16) + (temp1 << 12) + (temp0 << 4) + temp0; + /* dummy field */ + el[i + 2] = temp0; + i = i + 3; + /* 13. SMEM for DL_48_8_DEC pointer */ + /* DL_48_8_DEC = S_XinASRC_BT_DL_ADDR/S_XinASRC_BT_DL_sizeof/ + ASRC_BT_DL_FIR_L+ASRC_margin/1/0/0/0/0 */ + mem_tag = ABE_SMEM; + mem_addr = DL_48_8_DEC_labelID; + el[i] = (mem_tag << 16) + (mem_addr << 2); + el[i + 1] = OMAP_ABE_S_XINASRC_BT_DL_ADDR >> 3; + el[i + 1] = (el[i + 1] << 8) + (OMAP_ABE_S_XINASRC_BT_DL_SIZE >> 3); + el[i + 2] = temp0; + i = i + 3; + /* 14. CMEM for DL_48_8_DEC pointer */ + /* DL_48_8_DEC = S_XinASRC_BT_DL_ADDR/S_XinASRC_BT_DL_sizeof/ + ASRC_BT_DL_FIR_L+ASRC_margin/1/0/0/0/0 */ + mem_tag = ABE_CMEM; + mem_addr = DL_48_8_DEC_labelID; + el[i] = (mem_tag << 16) + (mem_addr << 2); + /* el[i+1] = iam1<<16 + inc1<<12 + iam2<<4 + inc2 */ + el[i + 1] = ((ASRC_BT_DL_FIR_L + ASRC_margin) << 16) + (temp1 << 12) + + (temp0 << 4) + temp0; + /* dummy field */ + el[i + 2] = temp0; + i = i + 3; + /* 15. SMEM for DL_48_16_DEC pointer */ + /* DL_48_16_DEC = S_XinASRC_BT_DL_ADDR/S_XinASRC_BT_DL_sizeof/ + ASRC_BT_DL_FIR_L+ASRC_margin/1/0/0/0/0 */ + mem_tag = ABE_SMEM; + mem_addr = DL_48_16_DEC_labelID; + el[i] = (mem_tag << 16) + (mem_addr << 2); + el[i + 1] = OMAP_ABE_S_XINASRC_BT_DL_ADDR >> 3; + el[i + 1] = (el[i + 1] << 8) + (OMAP_ABE_S_XINASRC_BT_DL_SIZE >> 3); + el[i + 2] = temp0; + i = i + 3; + /* 16. CMEM for DL_48_16_DEC pointer */ + /* DL_48_16_DEC = S_XinASRC_BT_DL_ADDR/S_XinASRC_BT_DL_sizeof/ + ASRC_BT_DL_FIR_L+ASRC_margin/1/0/0/0/0 */ + mem_tag = ABE_CMEM; + mem_addr = DL_48_16_DEC_labelID; + el[i] = (mem_tag << 16) + (mem_addr << 2); + /* el[i+1] = iam1<<16 + inc1<<12 + iam2<<4 + inc2 */ + el[i + 1] = ((ASRC_BT_DL_FIR_L + ASRC_margin) << 16) + (temp1 << 12) + + (temp0 << 4) + temp0; + /* dummy field */ + el[i + 2] = temp0; + abe_write_fifo(ABE_DMEM, OMAP_ABE_D_FWMEMINITDESCR_ADDR, (u32 *) &el[0], + n_fifo_el); +} diff --git a/sound/soc/omap/abe/abe_cm_addr.h b/sound/soc/omap/abe/abe_cm_addr.h new file mode 100644 index 0000000..2715002 --- /dev/null +++ b/sound/soc/omap/abe/abe_cm_addr.h @@ -0,0 +1,221 @@ +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2010-2011 Texas Instruments Incorporated, + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License 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. + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * BSD LICENSE + * + * Copyright(c) 2010-2011 Texas Instruments Incorporated, + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#define OMAP_ABE_INIT_CM_ADDR 0x0 +#define OMAP_ABE_INIT_CM_SIZE 0x640 +#define OMAP_ABE_C_DATA_LSB_2_ADDR 0x640 +#define OMAP_ABE_C_DATA_LSB_2_SIZE 0x4 +#define OMAP_ABE_C_1_ALPHA_ADDR 0x644 +#define OMAP_ABE_C_1_ALPHA_SIZE 0x48 +#define OMAP_ABE_C_ALPHA_ADDR 0x68C +#define OMAP_ABE_C_ALPHA_SIZE 0x48 +#define OMAP_ABE_C_GAINSWRAMP_ADDR 0x6D4 +#define OMAP_ABE_C_GAINSWRAMP_SIZE 0x38 +#define OMAP_ABE_C_GAINS_DL1M_ADDR 0x70C +#define OMAP_ABE_C_GAINS_DL1M_SIZE 0x10 +#define OMAP_ABE_C_GAINS_DL2M_ADDR 0x71C +#define OMAP_ABE_C_GAINS_DL2M_SIZE 0x10 +#define OMAP_ABE_C_GAINS_ECHOM_ADDR 0x72C +#define OMAP_ABE_C_GAINS_ECHOM_SIZE 0x8 +#define OMAP_ABE_C_GAINS_SDTM_ADDR 0x734 +#define OMAP_ABE_C_GAINS_SDTM_SIZE 0x8 +#define OMAP_ABE_C_GAINS_VXRECM_ADDR 0x73C +#define OMAP_ABE_C_GAINS_VXRECM_SIZE 0x10 +#define OMAP_ABE_C_GAINS_ULM_ADDR 0x74C +#define OMAP_ABE_C_GAINS_ULM_SIZE 0x10 +#define OMAP_ABE_C_GAINS_BTUL_ADDR 0x75C +#define OMAP_ABE_C_GAINS_BTUL_SIZE 0x8 +#define OMAP_ABE_C_SDT_COEFS_ADDR 0x764 +#define OMAP_ABE_C_SDT_COEFS_SIZE 0x24 +#define OMAP_ABE_C_COEFASRC1_VX_ADDR 0x788 +#define OMAP_ABE_C_COEFASRC1_VX_SIZE 0x4C +#define OMAP_ABE_C_COEFASRC2_VX_ADDR 0x7D4 +#define OMAP_ABE_C_COEFASRC2_VX_SIZE 0x4C +#define OMAP_ABE_C_COEFASRC3_VX_ADDR 0x820 +#define OMAP_ABE_C_COEFASRC3_VX_SIZE 0x4C +#define OMAP_ABE_C_COEFASRC4_VX_ADDR 0x86C +#define OMAP_ABE_C_COEFASRC4_VX_SIZE 0x4C +#define OMAP_ABE_C_COEFASRC5_VX_ADDR 0x8B8 +#define OMAP_ABE_C_COEFASRC5_VX_SIZE 0x4C +#define OMAP_ABE_C_COEFASRC6_VX_ADDR 0x904 +#define OMAP_ABE_C_COEFASRC6_VX_SIZE 0x4C +#define OMAP_ABE_C_COEFASRC7_VX_ADDR 0x950 +#define OMAP_ABE_C_COEFASRC7_VX_SIZE 0x4C +#define OMAP_ABE_C_COEFASRC8_VX_ADDR 0x99C +#define OMAP_ABE_C_COEFASRC8_VX_SIZE 0x4C +#define OMAP_ABE_C_COEFASRC9_VX_ADDR 0x9E8 +#define OMAP_ABE_C_COEFASRC9_VX_SIZE 0x4C +#define OMAP_ABE_C_COEFASRC10_VX_ADDR 0xA34 +#define OMAP_ABE_C_COEFASRC10_VX_SIZE 0x4C +#define OMAP_ABE_C_COEFASRC11_VX_ADDR 0xA80 +#define OMAP_ABE_C_COEFASRC11_VX_SIZE 0x4C +#define OMAP_ABE_C_COEFASRC12_VX_ADDR 0xACC +#define OMAP_ABE_C_COEFASRC12_VX_SIZE 0x4C +#define OMAP_ABE_C_COEFASRC13_VX_ADDR 0xB18 +#define OMAP_ABE_C_COEFASRC13_VX_SIZE 0x4C +#define OMAP_ABE_C_COEFASRC14_VX_ADDR 0xB64 +#define OMAP_ABE_C_COEFASRC14_VX_SIZE 0x4C +#define OMAP_ABE_C_COEFASRC15_VX_ADDR 0xBB0 +#define OMAP_ABE_C_COEFASRC15_VX_SIZE 0x4C +#define OMAP_ABE_C_COEFASRC16_VX_ADDR 0xBFC +#define OMAP_ABE_C_COEFASRC16_VX_SIZE 0x4C +#define OMAP_ABE_C_ALPHACURRENT_UL_VX_ADDR 0xC48 +#define OMAP_ABE_C_ALPHACURRENT_UL_VX_SIZE 0x4 +#define OMAP_ABE_C_BETACURRENT_UL_VX_ADDR 0xC4C +#define OMAP_ABE_C_BETACURRENT_UL_VX_SIZE 0x4 +#define OMAP_ABE_C_ALPHACURRENT_DL_VX_ADDR 0xC50 +#define OMAP_ABE_C_ALPHACURRENT_DL_VX_SIZE 0x4 +#define OMAP_ABE_C_BETACURRENT_DL_VX_ADDR 0xC54 +#define OMAP_ABE_C_BETACURRENT_DL_VX_SIZE 0x4 +#define OMAP_ABE_C_COEFASRC1_MM_ADDR 0xC58 +#define OMAP_ABE_C_COEFASRC1_MM_SIZE 0x48 +#define OMAP_ABE_C_COEFASRC2_MM_ADDR 0xCA0 +#define OMAP_ABE_C_COEFASRC2_MM_SIZE 0x48 +#define OMAP_ABE_C_COEFASRC3_MM_ADDR 0xCE8 +#define OMAP_ABE_C_COEFASRC3_MM_SIZE 0x48 +#define OMAP_ABE_C_COEFASRC4_MM_ADDR 0xD30 +#define OMAP_ABE_C_COEFASRC4_MM_SIZE 0x48 +#define OMAP_ABE_C_COEFASRC5_MM_ADDR 0xD78 +#define OMAP_ABE_C_COEFASRC5_MM_SIZE 0x48 +#define OMAP_ABE_C_COEFASRC6_MM_ADDR 0xDC0 +#define OMAP_ABE_C_COEFASRC6_MM_SIZE 0x48 +#define OMAP_ABE_C_COEFASRC7_MM_ADDR 0xE08 +#define OMAP_ABE_C_COEFASRC7_MM_SIZE 0x48 +#define OMAP_ABE_C_COEFASRC8_MM_ADDR 0xE50 +#define OMAP_ABE_C_COEFASRC8_MM_SIZE 0x48 +#define OMAP_ABE_C_COEFASRC9_MM_ADDR 0xE98 +#define OMAP_ABE_C_COEFASRC9_MM_SIZE 0x48 +#define OMAP_ABE_C_COEFASRC10_MM_ADDR 0xEE0 +#define OMAP_ABE_C_COEFASRC10_MM_SIZE 0x48 +#define OMAP_ABE_C_COEFASRC11_MM_ADDR 0xF28 +#define OMAP_ABE_C_COEFASRC11_MM_SIZE 0x48 +#define OMAP_ABE_C_COEFASRC12_MM_ADDR 0xF70 +#define OMAP_ABE_C_COEFASRC12_MM_SIZE 0x48 +#define OMAP_ABE_C_COEFASRC13_MM_ADDR 0xFB8 +#define OMAP_ABE_C_COEFASRC13_MM_SIZE 0x48 +#define OMAP_ABE_C_COEFASRC14_MM_ADDR 0x1000 +#define OMAP_ABE_C_COEFASRC14_MM_SIZE 0x48 +#define OMAP_ABE_C_COEFASRC15_MM_ADDR 0x1048 +#define OMAP_ABE_C_COEFASRC15_MM_SIZE 0x48 +#define OMAP_ABE_C_COEFASRC16_MM_ADDR 0x1090 +#define OMAP_ABE_C_COEFASRC16_MM_SIZE 0x48 +#define OMAP_ABE_C_ALPHACURRENT_MM_EXT_IN_ADDR 0x10D8 +#define OMAP_ABE_C_ALPHACURRENT_MM_EXT_IN_SIZE 0x4 +#define OMAP_ABE_C_BETACURRENT_MM_EXT_IN_ADDR 0x10DC +#define OMAP_ABE_C_BETACURRENT_MM_EXT_IN_SIZE 0x4 +#define OMAP_ABE_C_DL2_L_COEFS_ADDR 0x10E0 +#define OMAP_ABE_C_DL2_L_COEFS_SIZE 0x64 +#define OMAP_ABE_C_DL2_R_COEFS_ADDR 0x1144 +#define OMAP_ABE_C_DL2_R_COEFS_SIZE 0x64 +#define OMAP_ABE_C_DL1_COEFS_ADDR 0x11A8 +#define OMAP_ABE_C_DL1_COEFS_SIZE 0x64 +#define OMAP_ABE_C_SRC_3_LP_COEFS_ADDR 0x120C +#define OMAP_ABE_C_SRC_3_LP_COEFS_SIZE 0x34 +#define OMAP_ABE_C_SRC_3_LP_GAIN_COEFS_ADDR 0x1240 +#define OMAP_ABE_C_SRC_3_LP_GAIN_COEFS_SIZE 0x34 +#define OMAP_ABE_C_SRC_3_HP_COEFS_ADDR 0x1274 +#define OMAP_ABE_C_SRC_3_HP_COEFS_SIZE 0x14 +#define OMAP_ABE_C_SRC_6_LP_COEFS_ADDR 0x1288 +#define OMAP_ABE_C_SRC_6_LP_COEFS_SIZE 0x34 +#define OMAP_ABE_C_SRC_6_LP_GAIN_COEFS_ADDR 0x12BC +#define OMAP_ABE_C_SRC_6_LP_GAIN_COEFS_SIZE 0x34 +#define OMAP_ABE_C_SRC_6_HP_COEFS_ADDR 0x12F0 +#define OMAP_ABE_C_SRC_6_HP_COEFS_SIZE 0x1C +#define OMAP_ABE_C_ALPHACURRENT_ECHO_REF_ADDR 0x130C +#define OMAP_ABE_C_ALPHACURRENT_ECHO_REF_SIZE 0x4 +#define OMAP_ABE_C_BETACURRENT_ECHO_REF_ADDR 0x1310 +#define OMAP_ABE_C_BETACURRENT_ECHO_REF_SIZE 0x4 +#define OMAP_ABE_C_VIBRA2_CONSTS_ADDR 0x1314 +#define OMAP_ABE_C_VIBRA2_CONSTS_SIZE 0x10 +#define OMAP_ABE_C_VIBRA1_COEFFS_ADDR 0x1324 +#define OMAP_ABE_C_VIBRA1_COEFFS_SIZE 0x2C +#define OMAP_ABE_C_48_96_LP_COEFS_ADDR 0x1350 +#define OMAP_ABE_C_48_96_LP_COEFS_SIZE 0x3C +#define OMAP_ABE_C_96_48_AMIC_COEFS_ADDR 0x138C +#define OMAP_ABE_C_96_48_AMIC_COEFS_SIZE 0x4C +#define OMAP_ABE_C_96_48_DMIC_COEFS_ADDR 0x13D8 +#define OMAP_ABE_C_96_48_DMIC_COEFS_SIZE 0x4C +#define OMAP_ABE_C_INPUT_SCALE_ADDR 0x1424 +#define OMAP_ABE_C_INPUT_SCALE_SIZE 0x4 +#define OMAP_ABE_C_OUTPUT_SCALE_ADDR 0x1428 +#define OMAP_ABE_C_OUTPUT_SCALE_SIZE 0x4 +#define OMAP_ABE_C_MUTE_SCALING_ADDR 0x142C +#define OMAP_ABE_C_MUTE_SCALING_SIZE 0x4 +#define OMAP_ABE_C_GAINS_0DB_ADDR 0x1430 +#define OMAP_ABE_C_GAINS_0DB_SIZE 0x8 +#define OMAP_ABE_C_ALPHACURRENT_BT_DL_ADDR 0x1438 +#define OMAP_ABE_C_ALPHACURRENT_BT_DL_SIZE 0x4 +#define OMAP_ABE_C_BETACURRENT_BT_DL_ADDR 0x143C +#define OMAP_ABE_C_BETACURRENT_BT_DL_SIZE 0x4 +#define OMAP_ABE_C_ALPHACURRENT_BT_UL_ADDR 0x1440 +#define OMAP_ABE_C_ALPHACURRENT_BT_UL_SIZE 0x4 +#define OMAP_ABE_C_BETACURRENT_BT_UL_ADDR 0x1444 +#define OMAP_ABE_C_BETACURRENT_BT_UL_SIZE 0x4 +#define OMAP_ABE_C_SRC_FIR6_LP_GAIN_COEFS_ADDR 0x1448 +#define OMAP_ABE_C_SRC_FIR6_LP_GAIN_COEFS_SIZE 0x2A0 +#define OMAP_ABE_C_SRC_44P1_COEFS_ADDR 0x16E8 +#define OMAP_ABE_C_SRC_44P1_COEFS_SIZE 0x480 +#define OMAP_ABE_C_SRC_MM_DL_44P1_STEP_ADDR 0x1B68 +#define OMAP_ABE_C_SRC_MM_DL_44P1_STEP_SIZE 0x8 +#define OMAP_ABE_C_SRC_TONES_44P1_STEP_ADDR 0x1B70 +#define OMAP_ABE_C_SRC_TONES_44P1_STEP_SIZE 0x8 +#define OMAP_ABE_C_SRC_44P1_MULFAC2_ADDR 0x1B78 +#define OMAP_ABE_C_SRC_44P1_MULFAC2_SIZE 0x8 +#define OMAP_ABE_C_SRC_FIR12_LP_GAIN_COEFS_ADDR 0x1B80 +#define OMAP_ABE_C_SRC_FIR12_LP_GAIN_COEFS_SIZE 0x1E4 +#define OMAP_ABE_C_SRC_6_HP_NEW_COEFS_ADDR 0x1D64 +#define OMAP_ABE_C_SRC_6_HP_NEW_COEFS_SIZE 0x1C diff --git a/sound/soc/omap/abe/abe_core.c b/sound/soc/omap/abe/abe_core.c new file mode 100644 index 0000000..7a9ae11 --- /dev/null +++ b/sound/soc/omap/abe/abe_core.c @@ -0,0 +1,929 @@ +/* + + This file is provided under a dual BSD/GPLv2 license. When using or + redistributing this file, you may do so under either license. + + GPL LICENSE SUMMARY + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License 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. + The full GNU General Public License is included in this distribution + in the file called LICENSE.GPL. + + BSD LICENSE + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name of Texas Instruments Incorporated nor the names of + its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/err.h> +#include <linux/slab.h> + +#include "abe_dbg.h" +#include "abe.h" +#include "abe_gain.h" +#include "abe_aess.h" +#include "abe_port.h" +#include "abe_mem.h" +#include "abe_taskid.h" + +#define OMAP_ABE_IRQ_FIFO_MASK ((OMAP_ABE_D_MCUIRQFIFO_SIZE >> 2) - 1) + +void abe_init_asrc_vx_dl(s32 dppm); +void abe_init_asrc_vx_ul(s32 dppm); +void abe_init_asrc_mm_ext_in(s32 dppm); +void abe_init_asrc_bt_ul(s32 dppm); +void abe_init_asrc_bt_dl(s32 dppm); + +void abe_src_filters_saturation_monitoring(void); +void abe_irq_aps(u32 aps_info); +void abe_irq_ping_pong(void); +void abe_irq_check_for_sequences(u32 seq_info); +extern u32 abe_size_pingpong; +extern u32 abe_base_address_pingpong[]; + +void abe_add_subroutine(u32 *id, abe_subroutine2 f, u32 nparam, u32 *params); + + +/** + * abe_omap_abe_reset_hal - reset the ABE/HAL + * @abe: Pointer on abe handle + * + * Operations : reset the ABE by reloading the static variables and + * default AESS registers. + * Called after a PRCM cold-start reset of ABE + */ +int omap_abe_reset_hal(struct omap_abe *abe) +{ + u32 i; + + omap_abe_dbg_reset(&abe->dbg); + + _log(ABE_ID_RESET_HAL, 0, 0, 0); + + /* IRQ & DBG circular read pointer in DMEM */ + abe->irq_dbg_read_ptr = 0; + + /* default = disable the mixer's adaptive gain control */ + omap_abe_use_compensated_gain(abe, 0); + + /* reset the default gain values */ + for (i = 0; i < MAX_NBGAIN_CMEM; i++) { + abe->muted_gains_indicator[i] = 0; + abe->desired_gains_decibel[i] = (u32) GAIN_MUTE; + abe->desired_gains_linear[i] = 0; + abe->desired_ramp_delay_ms[i] = 0; + abe->muted_gains_decibel[i] = (u32) GAIN_TOOLOW; + } + omap_abe_hw_configuration(abe); + return 0; +} +EXPORT_SYMBOL(omap_abe_reset_hal); + +/** + * omap_abe_wakeup - Wakeup ABE + * @abe: Pointer on abe handle + * + * Wakeup ABE in case of retention + */ +int omap_abe_wakeup(struct omap_abe *abe) +{ + /* Restart event generator */ + omap_abe_write_event_generator(abe, EVENT_TIMER); + + /* reconfigure DMA Req and MCU Irq visibility */ + omap_abe_hw_configuration(abe); + return 0; +} +EXPORT_SYMBOL(omap_abe_wakeup); + +/** + * abe_monitoring + * + * checks the internal status of ABE and HAL + */ +void abe_monitoring(void) +{ + +} + +/** + * omap_abe_irq_processing - Process ABE interrupt + * @abe: Pointer on abe handle + * + * This subroutine is call upon reception of "MA_IRQ_99 ABE_MPU_IRQ" Audio + * back-end interrupt. This subroutine will check the ATC Hrdware, the + * IRQ_FIFO from the AE and act accordingly. Some IRQ source are originated + * for the delivery of "end of time sequenced tasks" notifications, some are + * originated from the Ping-Pong protocols, some are generated from + * the embedded debugger when the firmware stops on programmable break-points, + * etc ... + */ +int omap_abe_irq_processing(struct omap_abe *abe) +{ + u32 abe_irq_dbg_write_ptr, i, cmem_src, sm_cm; + abe_irq_data_t IRQ_data; + + _log(ABE_ID_IRQ_PROCESSING, 0, 0, 0); + + /* extract the write pointer index from CMEM memory (INITPTR format) */ + /* CMEM address of the write pointer in bytes */ + cmem_src = MCU_IRQ_FIFO_ptr_labelID << 2; + omap_abe_mem_read(abe, OMAP_ABE_CMEM, cmem_src, + &sm_cm, sizeof(abe_irq_dbg_write_ptr)); + /* AESS left-pointer index located on MSBs */ + abe_irq_dbg_write_ptr = sm_cm >> 16; + abe_irq_dbg_write_ptr &= 0xFF; + /* loop on the IRQ FIFO content */ + for (i = 0; i < OMAP_ABE_D_MCUIRQFIFO_SIZE; i++) { + /* stop when the FIFO is empty */ + if (abe_irq_dbg_write_ptr == abe->irq_dbg_read_ptr) + break; + /* read the IRQ/DBG FIFO */ + omap_abe_mem_read(abe, OMAP_ABE_DMEM, + (OMAP_ABE_D_MCUIRQFIFO_ADDR + + (abe->irq_dbg_read_ptr << 2)), + (u32 *) &IRQ_data, sizeof(IRQ_data)); + abe->irq_dbg_read_ptr = (abe->irq_dbg_read_ptr + 1) & OMAP_ABE_IRQ_FIFO_MASK; + /* select the source of the interrupt */ + switch (IRQ_data.tag) { + case IRQtag_APS: + _log(ABE_ID_IRQ_PROCESSING, IRQ_data.data, 0, 1); + abe_irq_aps(IRQ_data.data); + break; + case IRQtag_PP: + _log(ABE_ID_IRQ_PROCESSING, 0, 0, 2); + abe_irq_ping_pong(); + break; + case IRQtag_COUNT: + _log(ABE_ID_IRQ_PROCESSING, IRQ_data.data, 0, 3); + abe_irq_check_for_sequences(IRQ_data.data); + abe_monitoring(); + break; + default: + break; + } + } + return 0; +} +EXPORT_SYMBOL(omap_abe_irq_processing); + +/** + * oamp_abe_set_ping_pong_buffer + * @abe: Pointer on abe handle + * @port: ABE port ID + * @n_bytes: Size of Ping/Pong buffer + * + * Updates the next ping-pong buffer with "size" bytes copied from the + * host processor. This API notifies the FW that the data transfer is done. + */ +int omap_abe_set_ping_pong_buffer(struct omap_abe *abe, u32 port, u32 n_bytes) +{ + u32 sio_pp_desc_address, struct_offset, n_samples, datasize, + base_and_size, *src; + struct ABE_SPingPongDescriptor desc_pp; + + _log(ABE_ID_SET_PING_PONG_BUFFER, port, n_bytes, n_bytes >> 8); + + /* ping_pong is only supported on MM_DL */ + if (port != OMAP_ABE_MM_DL_PORT) { + omap_abe_dbg_error(abe, OMAP_ABE_ERR_API, + ABE_PARAMETER_ERROR); + } + /* translates the number of bytes in samples */ + /* data size in DMEM words */ + datasize = omap_abe_dma_port_iter_factor((struct omap_abe_data_format *)&((abe_port[port]).format)); + /* data size in bytes */ + datasize = datasize << 2; + n_samples = n_bytes / datasize; + omap_abe_mem_read(abe, OMAP_ABE_DMEM, OMAP_ABE_D_PINGPONGDESC_ADDR, + (u32 *) &desc_pp, sizeof(desc_pp)); + /* + * read the port SIO descriptor and extract the current pointer + * address after reading the counter + */ + if ((desc_pp.counter & 0x1) == 0) { + struct_offset = (u32) &(desc_pp.nextbuff0_BaseAddr) - + (u32) &(desc_pp); + base_and_size = desc_pp.nextbuff0_BaseAddr; + } else { + struct_offset = (u32) &(desc_pp.nextbuff1_BaseAddr) - + (u32) &(desc_pp); + base_and_size = desc_pp.nextbuff1_BaseAddr; + } + + base_and_size = abe->pp_buf_addr[abe->pp_buf_id_next]; + abe->pp_buf_id_next = (abe->pp_buf_id_next + 1) & 0x03; + + base_and_size = (base_and_size & 0xFFFFL) + (n_samples << 16); + sio_pp_desc_address = OMAP_ABE_D_PINGPONGDESC_ADDR + struct_offset; + src = &base_and_size; + omap_abe_mem_write(abe, OMAP_ABE_DMEM, sio_pp_desc_address, + (u32 *) &base_and_size, sizeof(u32)); + + return 0; +} +EXPORT_SYMBOL(omap_abe_set_ping_pong_buffer); + +/** + * omap_abe_read_next_ping_pong_buffer + * @abe: Pointer on abe handle + * @port: ABE portID + * @p: Next buffer address (pointer) + * @n: Next buffer size (pointer) + * + * Tell the next base address of the next ping_pong Buffer and its size + */ +int omap_abe_read_next_ping_pong_buffer(struct omap_abe *abe, u32 port, u32 *p, u32 *n) +{ + u32 sio_pp_desc_address; + struct ABE_SPingPongDescriptor desc_pp; + + _log(ABE_ID_READ_NEXT_PING_PONG_BUFFER, port, 0, 0); + + /* ping_pong is only supported on MM_DL */ + if (port != OMAP_ABE_MM_DL_PORT) { + omap_abe_dbg_error(abe, OMAP_ABE_ERR_API, + ABE_PARAMETER_ERROR); + } + /* read the port SIO descriptor and extract the current pointer + address after reading the counter */ + sio_pp_desc_address = OMAP_ABE_D_PINGPONGDESC_ADDR; + omap_abe_mem_read(abe, OMAP_ABE_DMEM, sio_pp_desc_address, + (u32 *) &desc_pp, sizeof(struct ABE_SPingPongDescriptor)); + if ((desc_pp.counter & 0x1) == 0) { + _log(ABE_ID_READ_NEXT_PING_PONG_BUFFER, port, 0, 0); + *p = desc_pp.nextbuff0_BaseAddr; + } else { + _log(ABE_ID_READ_NEXT_PING_PONG_BUFFER, port, 1, 0); + *p = desc_pp.nextbuff1_BaseAddr; + } + /* translates the number of samples in bytes */ + *n = abe_size_pingpong; + + return 0; +} +EXPORT_SYMBOL(omap_abe_read_next_ping_pong_buffer); + +/** + * omap_abe_init_ping_pong_buffer + * @abe: Pointer on abe handle + * @id: ABE port ID + * @size_bytes:size of the ping pong + * @n_buffers:number of buffers (2 = ping/pong) + * @p:returned address of the ping-pong list of base addresses + * (byte offset from DMEM start) + * + * Computes the base address of the ping_pong buffers + */ +int omap_abe_init_ping_pong_buffer(struct omap_abe *abe, + u32 id, u32 size_bytes, u32 n_buffers, + u32 *p) +{ + u32 i, dmem_addr; + + _log(ABE_ID_INIT_PING_PONG_BUFFER, id, size_bytes, n_buffers); + + /* ping_pong is supported in 2 buffers configuration right now but FW + is ready for ping/pong/pung/pang... */ + if (id != OMAP_ABE_MM_DL_PORT || n_buffers > MAX_PINGPONG_BUFFERS) { + omap_abe_dbg_error(abe, OMAP_ABE_ERR_API, + ABE_PARAMETER_ERROR); + } + for (i = 0; i < n_buffers; i++) { + dmem_addr = OMAP_ABE_D_PING_ADDR + (i * size_bytes); + /* base addresses of the ping pong buffers in U8 unit */ + abe_base_address_pingpong[i] = dmem_addr; + } + + for (i = 0; i < 4; i++) + abe->pp_buf_addr[i] = OMAP_ABE_D_PING_ADDR + (i * size_bytes); + abe->pp_buf_id = 0; + abe->pp_buf_id_next = 0; + abe->pp_first_irq = 1; + + /* global data */ + abe_size_pingpong = size_bytes; + *p = (u32) OMAP_ABE_D_PING_ADDR; + return 0; +} +EXPORT_SYMBOL(omap_abe_init_ping_pong_buffer); + +/** + * omap_abe_read_offset_from_ping_buffer + * @abe: Pointer on abe handle + * @id: ABE port ID + * @n: returned address of the offset + * from the ping buffer start address (in samples) + * + * Computes the current firmware ping pong read pointer location, + * expressed in samples, as the offset from the start address of ping buffer. + */ +int omap_abe_read_offset_from_ping_buffer(struct omap_abe *abe, + u32 id, u32 *n) +{ + u32 sio_pp_desc_address; + struct ABE_SPingPongDescriptor desc_pp; + + /* ping_pong is only supported on MM_DL */ + if (OMAP_ABE_MM_DL_PORT != id) { + omap_abe_dbg_error(abe, OMAP_ABE_ERR_API, + ABE_PARAMETER_ERROR); + } else { + /* read the port SIO ping pong descriptor */ + sio_pp_desc_address = OMAP_ABE_D_PINGPONGDESC_ADDR; + omap_abe_mem_read(abe, OMAP_ABE_DMEM, + sio_pp_desc_address, (u32 *) &desc_pp, + sizeof(struct ABE_SPingPongDescriptor)); + /* extract the current ping pong buffer read pointer based on + the value of the counter */ + if ((desc_pp.counter & 0x1) == 0) { + /* the next is buffer0, hence the current is buffer1 */ + *n = desc_pp.nextbuff1_Samples - + desc_pp.workbuff_Samples; + } else { + /* the next is buffer1, hence the current is buffer0 */ + *n = desc_pp.nextbuff0_Samples - + desc_pp.workbuff_Samples; + } + switch (abe_port[OMAP_ABE_MM_DL_PORT].format.samp_format) { + case MONO_MSB: + case MONO_RSHIFTED_16: + case STEREO_16_16: + *n += abe->pp_buf_id * abe_size_pingpong / 4; + break; + case STEREO_MSB: + case STEREO_RSHIFTED_16: + *n += abe->pp_buf_id * abe_size_pingpong / 8; + break; + default: + omap_abe_dbg_error(abe, OMAP_ABE_ERR_API, + ABE_PARAMETER_ERROR); + return -EINVAL; + } + } + + return 0; +} +EXPORT_SYMBOL(omap_abe_read_offset_from_ping_buffer); + +/** + * abe_set_router_configuration + * @Id: name of the router + * @Conf: id of the configuration + * @param: list of output index of the route + * + * The uplink router takes its input from DMIC (6 samples), AMIC (2 samples) + * and PORT1/2 (2 stereo ports). Each sample will be individually stored in + * an intermediate table of 10 elements. + * + * Example of router table parameter for voice uplink with phoenix microphones + * + * indexes 0 .. 9 = MM_UL description (digital MICs and MMEXTIN) + * DMIC1_L_labelID, DMIC1_R_labelID, DMIC2_L_labelID, DMIC2_R_labelID, + * MM_EXT_IN_L_labelID, MM_EXT_IN_R_labelID, ZERO_labelID, ZERO_labelID, + * ZERO_labelID, ZERO_labelID, + * indexes 10 .. 11 = MM_UL2 description (recording on DMIC3) + * DMIC3_L_labelID, DMIC3_R_labelID, + * indexes 12 .. 13 = VX_UL description (VXUL based on PDMUL data) + * AMIC_L_labelID, AMIC_R_labelID, + * indexes 14 .. 15 = RESERVED (NULL) + * ZERO_labelID, ZERO_labelID, + */ +int omap_abe_set_router_configuration(struct omap_abe *abe, + u32 id, u32 k, u32 *param) +{ + _log(ABE_ID_SET_ROUTER_CONFIGURATION, id, (u32) param, (u32) param >> 8); + + omap_abe_mem_write(abe, OMAP_ABE_DMEM, + OMAP_ABE_D_AUPLINKROUTING_ADDR, + param, OMAP_ABE_D_AUPLINKROUTING_SIZE); + return 0; +} +EXPORT_SYMBOL(omap_abe_set_router_configuration); + +/** + * abe_set_opp_processing - Set OPP mode for ABE Firmware + * @opp: OOPP mode + * + * New processing network and OPP: + * 0: Ultra Lowest power consumption audio player (no post-processing, no mixer) + * 1: OPP 25% (simple multimedia features, including low-power player) + * 2: OPP 50% (multimedia and voice calls) + * 3: OPP100% ( multimedia complex use-cases) + * + * Rearranges the FW task network to the corresponding OPP list of features. + * The corresponding AE ports are supposed to be set/reset accordingly before + * this switch. + * + */ +int omap_abe_set_opp_processing(struct omap_abe *abe, u32 opp) +{ + u32 dOppMode32, sio_desc_address; + struct ABE_SIODescriptor sio_desc; + + _log(ABE_ID_SET_OPP_PROCESSING, opp, 0, 0); + + switch (opp) { + case ABE_OPP25: + /* OPP25% */ + dOppMode32 = DOPPMODE32_OPP25; + break; + case ABE_OPP50: + /* OPP50% */ + dOppMode32 = DOPPMODE32_OPP50; + break; + default: + omap_abe_dbg_error(abe, OMAP_ABE_ERR_API, + ABE_BLOCK_COPY_ERR); + case ABE_OPP100: + /* OPP100% */ + dOppMode32 = DOPPMODE32_OPP100; + break; + } + /* Write Multiframe inside DMEM */ + omap_abe_mem_write(abe, OMAP_ABE_DMEM, + OMAP_ABE_D_MAXTASKBYTESINSLOT_ADDR, &dOppMode32, sizeof(u32)); + +#if 0 + /* Disable BT / MM Ext ASRC dynamic switch */ + + sio_desc_address = OMAP_ABE_D_IODESCR_ADDR + (OMAP_ABE_MM_EXT_IN_PORT * + sizeof(struct ABE_SIODescriptor)); + omap_abe_mem_read(abe, OMAP_ABE_DMEM, sio_desc_address, + (u32 *) &sio_desc, sizeof(sio_desc)); + if (dOppMode32 == DOPPMODE32_OPP100) { + /* ASRC input buffer, size 40 */ + sio_desc.smem_addr1 = smem_mm_ext_in_opp100; + /* Init MM_EXT_IN ASRC and enable its adaptation */ + abe_init_asrc_mm_ext_in(250); + } else + /* at OPP 50 or without ASRC */ + sio_desc.smem_addr1 = smem_mm_ext_in_opp50; + + omap_abe_mem_write(abe, OMAP_ABE_DMEM, sio_desc_address, + (u32 *) &sio_desc, sizeof(sio_desc)); + + sio_desc_address = OMAP_ABE_D_IODESCR_ADDR + (OMAP_ABE_BT_VX_UL_PORT * + sizeof(struct ABE_SIODescriptor)); + omap_abe_mem_read(abe, OMAP_ABE_DMEM, sio_desc_address, + (u32 *) &sio_desc, sizeof(sio_desc)); + + if (abe_port[OMAP_ABE_BT_VX_UL_PORT].format.f == 8000) { + if (dOppMode32 == DOPPMODE32_OPP100) + /* ASRC input buffer, size 40 */ + sio_desc.smem_addr1 = smem_bt_vx_ul_opp100; + else + /* at OPP 50 without ASRC */ + sio_desc.smem_addr1 = BT_UL_8k_labelID; + } else { + if (dOppMode32 == DOPPMODE32_OPP100) + /* ASRC input buffer, size 40 */ + sio_desc.smem_addr1 = smem_bt_vx_ul_opp100; + else + /* at OPP 50 without ASRC */ + sio_desc.smem_addr1 = BT_UL_16k_labelID; + } + + omap_abe_mem_write(abe, OMAP_ABE_DMEM, sio_desc_address, + (u32 *) &sio_desc, sizeof(sio_desc)); + + sio_desc_address = OMAP_ABE_D_IODESCR_ADDR + (OMAP_ABE_BT_VX_DL_PORT * + sizeof(struct ABE_SIODescriptor)); + omap_abe_mem_read(abe, OMAP_ABE_DMEM, sio_desc_address, + (u32 *) &sio_desc, sizeof(sio_desc)); + +#define ABE_TASK_ID(ID) (OMAP_ABE_D_TASKSLIST_ADDR + sizeof(ABE_STask)*(ID)) +#define TASK_BT_DL_48_8_SLT 14 +#define TASK_BT_DL_48_8_IDX 4 + if (abe_port[OMAP_ABE_BT_VX_DL_PORT].format.f == 8000) { + if (dOppMode32 == DOPPMODE32_OPP100) { + abe->MultiFrame[TASK_BT_DL_48_8_SLT][TASK_BT_DL_48_8_IDX] = + ABE_TASK_ID(C_ABE_FW_TASK_BT_DL_48_8_FIR_OPP100); + sio_desc.smem_addr1 = BT_DL_8k_opp100_labelID; + } else { + abe->MultiFrame[TASK_BT_DL_48_8_SLT][TASK_BT_DL_48_8_IDX] = + ABE_TASK_ID(C_ABE_FW_TASK_BT_DL_48_8_FIR); + sio_desc.smem_addr1 = BT_DL_8k_labelID; + } + } else { + if (dOppMode32 == DOPPMODE32_OPP100) { + abe->MultiFrame[TASK_BT_DL_48_8_SLT][TASK_BT_DL_48_8_IDX] = + ABE_TASK_ID(C_ABE_FW_TASK_BT_DL_48_16_OPP100); + sio_desc.smem_addr1 = BT_DL_16k_opp100_labelID; + } else { + abe->MultiFrame[TASK_BT_DL_48_8_SLT][TASK_BT_DL_48_8_IDX] = + ABE_TASK_ID(C_ABE_FW_TASK_BT_DL_48_16); + sio_desc.smem_addr1 = BT_DL_16k_labelID; + } + } + + omap_abe_mem_write(abe, OMAP_ABE_DMEM, OMAP_ABE_D_MULTIFRAME_ADDR, + (u32 *) abe->MultiFrame, sizeof(abe->MultiFrame)); + + omap_abe_mem_write(abe, OMAP_ABE_DMEM, sio_desc_address, + (u32 *) &sio_desc, sizeof(sio_desc)); + + if (dOppMode32 == DOPPMODE32_OPP100) { + /* Init BT_VX_UL ASRC and enable its adaptation */ + abe_init_asrc_bt_ul(250); + /* Init BT_VX_DL ASRC and enable its adaptation */ + abe_init_asrc_bt_dl(-250); + } +#endif + return 0; + +} +EXPORT_SYMBOL(omap_abe_set_opp_processing); + +/** + * omap_abe_reset_vx_ul_src_filters - reset VX-UL port SRC filters + * + * it is assumed that filters are located in SMEM + */ +int omap_abe_reset_vx_ul_src_filters(struct omap_abe *abe) +{ + if (abe_port[OMAP_ABE_VX_UL_PORT].format.f == 8000) { + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_VX_UL_48_8_LP_DATA_ADDR, + OMAP_ABE_S_VX_UL_48_8_LP_DATA_SIZE); + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_VX_UL_48_8_HP_DATA_ADDR, + OMAP_ABE_S_VX_UL_48_8_HP_DATA_SIZE); + } else if (abe_port[OMAP_ABE_VX_UL_PORT].format.f == 16000) { + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_VX_UL_48_16_LP_DATA_ADDR, + OMAP_ABE_S_VX_UL_48_16_LP_DATA_SIZE); + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_VX_UL_48_16_HP_DATA_ADDR, + OMAP_ABE_S_VX_UL_48_16_HP_DATA_SIZE); + } + return 0; +} +EXPORT_SYMBOL(omap_abe_reset_vx_ul_src_filters); + +/** + * omap_abe_reset_mic_ul_src_filters - reset AMIC or DMICs or BT UL SRC filters + * + * it is assumed that filters are located in SMEM + */ +int omap_abe_reset_mic_ul_src_filters(struct omap_abe *abe) +{ + u16 vx[NBROUTE_UL]; + + omap_abe_mem_read(abe, OMAP_ABE_DMEM, + OMAP_ABE_D_AUPLINKROUTING_ADDR, + (u32 *)vx, OMAP_ABE_D_AUPLINKROUTING_SIZE); + + switch (vx[12]) { + case ZERO_labelID: + /* no MIC used */ + return 0; + case DMIC1_L_labelID: + case DMIC1_R_labelID: + /* DMIC0 used */ + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_DMIC0_96_48_DATA_ADDR, + OMAP_ABE_S_DMIC0_96_48_DATA_SIZE); + break; + case DMIC2_L_labelID: + case DMIC2_R_labelID: + /* DMIC1 used */ + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_DMIC1_96_48_DATA_ADDR, + OMAP_ABE_S_DMIC1_96_48_DATA_SIZE); + break; + case DMIC3_L_labelID: + case DMIC3_R_labelID: + /* DMIC2 used */ + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_DMIC2_96_48_DATA_ADDR, + OMAP_ABE_S_DMIC2_96_48_DATA_SIZE); + break; + case BT_UL_L_labelID: + case BT_UL_R_labelID: + /* BT MIC used */ + if (abe_port[OMAP_ABE_BT_VX_UL_PORT].format.f == 8000) { + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_BT_UL_8_48_HP_DATA_ADDR, + OMAP_ABE_S_BT_UL_8_48_HP_DATA_SIZE); + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_BT_UL_8_48_LP_DATA_ADDR, + OMAP_ABE_S_BT_UL_8_48_LP_DATA_SIZE); + } else if (abe_port[OMAP_ABE_BT_VX_UL_PORT].format.f == 16000) { + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_BT_UL_16_48_HP_DATA_ADDR, + OMAP_ABE_S_BT_UL_16_48_HP_DATA_SIZE); + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_BT_UL_16_48_LP_DATA_ADDR, + OMAP_ABE_S_BT_UL_16_48_LP_DATA_SIZE); + } + break; + case AMIC_L_labelID: + case AMIC_R_labelID: + /* AMIC used */ + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_AMIC_96_48_DATA_ADDR, + OMAP_ABE_S_AMIC_96_48_DATA_SIZE); + break; + default: + break; + } + return 0; +} +EXPORT_SYMBOL(omap_abe_reset_mic_ul_src_filters); + +/** + * omap_abe_reset_vx_dl_src_filters - reset VX-DL port SRC filters + * + * it is assumed that filters are located in SMEM + */ +int omap_abe_reset_vx_dl_src_filters(struct omap_abe *abe) +{ + if (abe_port[OMAP_ABE_VX_DL_PORT].format.f == 8000) { + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_VX_DL_8_48_HP_DATA_ADDR, + OMAP_ABE_S_VX_DL_8_48_HP_DATA_SIZE); + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_VX_DL_8_48_LP_DATA_ADDR, + OMAP_ABE_S_VX_DL_8_48_LP_DATA_SIZE); + } else if (abe_port[OMAP_ABE_VX_DL_PORT].format.f == 16000) { + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_VX_DL_16_48_HP_DATA_ADDR, + OMAP_ABE_S_VX_DL_16_48_HP_DATA_SIZE); + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_VX_DL_16_48_LP_DATA_ADDR, + OMAP_ABE_S_VX_DL_16_48_LP_DATA_SIZE); + } + return 0; +} +EXPORT_SYMBOL(omap_abe_reset_vx_dl_src_filters); + +/** + * omap_abe_reset_dl1_src_filters - reset DL1 path filters + * + * it is assumed that filters are located in SMEM + */ +int omap_abe_reset_dl1_src_filters(struct omap_abe *abe) +{ + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_DL1_M_EQ_DATA_ADDR, + OMAP_ABE_S_DL1_M_EQ_DATA_SIZE); + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_EARP_48_96_LP_DATA_ADDR, + OMAP_ABE_S_EARP_48_96_LP_DATA_SIZE); + return 0; +} +EXPORT_SYMBOL(omap_abe_reset_dl1_src_filters); + +/** + * omap_abe_reset_dl2_src_filters - reset DL2 path filters + * + * it is assumed that filters are located in SMEM + */ +int omap_abe_reset_dl2_src_filters(struct omap_abe *abe) +{ + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_DL2_M_LR_EQ_DATA_ADDR, + OMAP_ABE_S_DL2_M_LR_EQ_DATA_SIZE); + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_IHF_48_96_LP_DATA_ADDR, + OMAP_ABE_S_IHF_48_96_LP_DATA_SIZE); + return 0; +} +EXPORT_SYMBOL(omap_abe_reset_dl2_src_filters); + +/** + * omap_abe_reset_bt_dl_src_filters - reset bluetooth DL SRC path filters + * + * it is assumed that filters are located in SMEM + */ +int omap_abe_reset_bt_dl_src_filters(struct omap_abe *abe) +{ + if (abe_port[OMAP_ABE_BT_VX_DL_PORT].format.f == 8000) { + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_BT_DL_48_8_LP_DATA_ADDR, + OMAP_ABE_S_BT_DL_48_8_LP_DATA_SIZE); + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_BT_DL_48_8_HP_DATA_ADDR, + OMAP_ABE_S_BT_DL_48_8_HP_DATA_SIZE); + } else if (abe_port[OMAP_ABE_BT_VX_DL_PORT].format.f == 16000) { + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_BT_DL_48_16_LP_DATA_ADDR, + OMAP_ABE_S_BT_DL_48_16_LP_DATA_SIZE); + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_BT_DL_48_16_HP_DATA_ADDR, + OMAP_ABE_S_BT_DL_48_16_HP_DATA_SIZE); + } + return 0; +} +EXPORT_SYMBOL(omap_abe_reset_bt_dl_src_filters); + +/** + * abe_check_filter_is_saturating + * @abe: pointer to omap_abe struct + * @address: filter address + * @size: filter size in byte + * + * Check if filter is saturating + * it is assumed that filter is located in SMEM + * if saturated return 1 otherwise 0. + */ +int abe_check_filter_is_saturating(struct omap_abe *abe, u32 address, u32 size) +{ + /* largest buffer size among all filter buffers in SMEM */ + u32 filter[OMAP_ABE_S_XINASRC_UL_VX_SIZE >> 2]; + int found = 0, i = 0; + + omap_abe_mem_read(abe, ABE_SMEM, address, filter, size); + + size >>= 2; + while ((i < size) && (filter[i] < 0x700000 || filter[i] > 0x900000)) + i++; + + if (i < size) + found = 1; + + return found; +} + +/** + * abe_ul_src_filters_saturation_monitoring - monitor ABE UL SRC filters and + * check if some are saturating, if it's the case then reset these filters. + * + * it is assumed that filter is located in SMEM + */ +void abe_ul_src_filters_saturation_monitoring(struct omap_abe *abe) +{ + int saturating = 0; + u16 vx[NBROUTE_UL]; + + omap_abe_mem_read(abe, ABE_DMEM, + OMAP_ABE_D_AUPLINKROUTING_ADDR, + (u32 *)vx, OMAP_ABE_D_AUPLINKROUTING_SIZE); + + switch (vx[12]) { + case ZERO_labelID: + /* no MIC used */ + return; + case DMIC1_L_labelID: + case DMIC1_R_labelID: + /* DMIC0 used */ + saturating = abe_check_filter_is_saturating(abe, + OMAP_ABE_S_DMIC1_ADDR, + OMAP_ABE_S_DMIC1_SIZE); + break; + case DMIC2_L_labelID: + case DMIC2_R_labelID: + /* DMIC1 used */ + saturating = abe_check_filter_is_saturating(abe, + OMAP_ABE_S_DMIC2_ADDR, + OMAP_ABE_S_DMIC2_SIZE); + break; + case DMIC3_L_labelID: + case DMIC3_R_labelID: + /* DMIC2 used */ + saturating = abe_check_filter_is_saturating(abe, + OMAP_ABE_S_DMIC3_ADDR, + OMAP_ABE_S_DMIC3_SIZE); + break; + case BT_UL_L_labelID: + case BT_UL_R_labelID: + /* BT MIC used */ + saturating = abe_check_filter_is_saturating(abe, + OMAP_ABE_S_BT_UL_ADDR, + OMAP_ABE_S_BT_UL_SIZE); + break; + case AMIC_L_labelID: + case AMIC_R_labelID: + /* AMIC used */ + saturating = abe_check_filter_is_saturating(abe, + OMAP_ABE_S_AMIC_ADDR, + OMAP_ABE_S_AMIC_SIZE); + break; + default: + return; + } + + if (saturating) { + omap_abe_reset_mic_ul_src_filters(abe); + omap_abe_reset_vx_ul_src_filters(abe); + } +} + +/** + * abe_vx_dl_src_filters_saturation_monitoring - monitor ABE VX-DL SRC filters and + * check if some are saturating, if it's the case then reset these filters. + * + * it is assumed that filter is located in SMEM + */ +void abe_vx_dl_src_filters_saturation_monitoring(struct omap_abe *abe) +{ + if (abe_check_filter_is_saturating(abe, OMAP_ABE_S_VX_DL_ADDR, + OMAP_ABE_S_VX_DL_SIZE)) { + omap_abe_reset_vx_dl_src_filters(abe); + omap_abe_reset_dl1_src_filters(abe); + omap_abe_reset_dl2_src_filters(abe); + } + + if (abe_check_filter_is_saturating(abe, OMAP_ABE_S_BT_DL_ADDR, + OMAP_ABE_S_BT_DL_SIZE)) + omap_abe_reset_bt_dl_src_filters(abe); +} + +/** + * abe_src_filters_saturation_monitoring - monitor ABE SRC filters and + * check if some are saturating, if it's the case then reset these filters. + * + * it is assumed that filter is located in SMEM + */ +void omap_abe_src_filters_saturation_monitoring(struct omap_abe *abe) +{ + abe_ul_src_filters_saturation_monitoring(abe); + abe_vx_dl_src_filters_saturation_monitoring(abe); +} + +/** + * omap_abe_check_activity - Check if some ABE activity. + * + * Check if any ABE ports are running. + * return 1: still activity on ABE + * return 0: no more activity on ABE. Event generator can be stopped + * + */ +int omap_abe_check_activity(struct omap_abe *abe) +{ + int i, ret = 0; + + for (i = 0; i < (LAST_PORT_ID - 1); i++) { + if (abe_port[abe_port_priority[i]].status == + OMAP_ABE_PORT_ACTIVITY_RUNNING) + break; + } + if (i < (LAST_PORT_ID - 1)) + ret = 1; + return ret; +} +EXPORT_SYMBOL(omap_abe_check_activity); + +/** + * abe_plug_subroutine + * @id: returned sequence index after plugging a new subroutine + * @f: subroutine address to be inserted + * @n: number of parameters of this subroutine + * @params: pointer on parameters + * + * register a list of subroutines for call-back purpose + */ +abehal_status abe_plug_subroutine(u32 *id, abe_subroutine2 f, u32 n, + u32 *params) +{ + _log(ABE_ID_PLUG_SUBROUTINE, (u32) (*id), (u32) f, n); + + abe_add_subroutine(id, (abe_subroutine2) f, n, (u32 *) params); + return 0; +} +EXPORT_SYMBOL(abe_plug_subroutine); diff --git a/sound/soc/omap/abe/abe_dat.c b/sound/soc/omap/abe/abe_dat.c new file mode 100644 index 0000000..0111bae --- /dev/null +++ b/sound/soc/omap/abe/abe_dat.c @@ -0,0 +1,458 @@ +/* + + This file is provided under a dual BSD/GPLv2 license. When using or + redistributing this file, you may do so under either license. + + GPL LICENSE SUMMARY + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License 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. + The full GNU General Public License is included in this distribution + in the file called LICENSE.GPL. + + BSD LICENSE + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name of Texas Instruments Incorporated nor the names of + its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include "abe_legacy.h" + +struct omap_abe *abe; + +/* + * HAL/FW ports status / format / sampling / protocol(call_back) / features + * / gain / name + */ +abe_port_t abe_port[LAST_PORT_ID]; /* list of ABE ports */ +const abe_port_t abe_port_init[LAST_PORT_ID] = { + /* Status Data Format Drift Call-Back Protocol+selector desc_addr; + buf_addr; buf_size; iter; irq_addr irq_data DMA_T $Features + reseted at start Port Name for the debug trace */ + /* DMIC */ { + OMAP_ABE_PORT_ACTIVITY_IDLE, {96000, SIX_MSB}, + NODRIFT, NOCALLBACK, 1, (DMIC_ITER/6), + { + SNK_P, DMIC_PORT_PROT, + {{dmem_dmic, dmem_dmic_size, DMIC_ITER} } + }, + {0, 0}, + {EQDMIC, 0}, "DMIC"}, + /* PDM_UL */ { + OMAP_ABE_PORT_ACTIVITY_IDLE, {96000, STEREO_MSB}, + NODRIFT, NOCALLBACK, smem_amic, (MCPDM_UL_ITER/2), + { + SNK_P, MCPDMUL_PORT_PROT, + {{dmem_amic, dmem_amic_size, MCPDM_UL_ITER} } + }, + {0, 0}, + {EQAMIC, 0}, "PDM_UL"}, + /* BT_VX_UL */ { + OMAP_ABE_PORT_ACTIVITY_IDLE, {8000, STEREO_MSB}, + NODRIFT, NOCALLBACK, smem_bt_vx_ul_opp50, 1, + { + SNK_P, SERIAL_PORT_PROT, {{ + (MCBSP1_DMA_TX*ATC_SIZE), + dmem_bt_vx_ul, + dmem_bt_vx_ul_size, + (1*SCHED_LOOP_8kHz) + } } + }, + {0, 0}, {0}, "BT_VX_UL"}, + /* MM_UL */ { + OMAP_ABE_PORT_ACTIVITY_IDLE, {48000, STEREO_MSB}, + NODRIFT, NOCALLBACK, smem_mm_ul, 1, + { + SRC_P, DMAREQ_PORT_PROT, {{ + (CBPr_DMA_RTX3*ATC_SIZE), + dmem_mm_ul, dmem_mm_ul_size, + (10*SCHED_LOOP_48kHz), + ABE_DMASTATUS_RAW, (1 << 3) + } } + }, + {CIRCULAR_BUFFER_PERIPHERAL_R__3, 120}, + {UPROUTE, 0}, "MM_UL"}, + /* MM_UL2 */ { + OMAP_ABE_PORT_ACTIVITY_IDLE, {48000, STEREO_MSB}, + NODRIFT, NOCALLBACK, smem_mm_ul2, 1, + { + SRC_P, DMAREQ_PORT_PROT, {{ + (CBPr_DMA_RTX4*ATC_SIZE), + dmem_mm_ul2, dmem_mm_ul2_size, + (2*SCHED_LOOP_48kHz), + ABE_DMASTATUS_RAW, (1 << 4) + } } + }, + {CIRCULAR_BUFFER_PERIPHERAL_R__4, 24}, + {UPROUTE, 0}, "MM_UL2"}, + /* VX_UL */ { + OMAP_ABE_PORT_ACTIVITY_IDLE, {8000, MONO_MSB}, + NODRIFT, NOCALLBACK, smem_vx_ul, 1, + { + SRC_P, DMAREQ_PORT_PROT, {{ + (CBPr_DMA_RTX2*ATC_SIZE), + dmem_vx_ul, dmem_vx_ul_size, + (1*SCHED_LOOP_8kHz), + ABE_DMASTATUS_RAW, (1 << 2) + } } + }, { + CIRCULAR_BUFFER_PERIPHERAL_R__2, 2}, + {ASRC2, 0}, "VX_UL"}, + /* MM_DL */ { + OMAP_ABE_PORT_ACTIVITY_IDLE, {48000, STEREO_MSB}, + NODRIFT, NOCALLBACK, smem_mm_dl, 1, + { + SNK_P, PINGPONG_PORT_PROT, {{ + (CBPr_DMA_RTX0*ATC_SIZE), + dmem_mm_dl, dmem_mm_dl_size, + (2*SCHED_LOOP_48kHz), + ABE_DMASTATUS_RAW, (1 << 0) + } } + }, + {CIRCULAR_BUFFER_PERIPHERAL_R__0, 24}, + {ASRC3, 0}, "MM_DL"}, + /* VX_DL */ { + OMAP_ABE_PORT_ACTIVITY_IDLE, {8000, MONO_MSB}, + NODRIFT, NOCALLBACK, smem_vx_dl, 1, + { + SNK_P, DMAREQ_PORT_PROT, {{ + (CBPr_DMA_RTX1*ATC_SIZE), + dmem_vx_dl, dmem_vx_dl_size, + (1*SCHED_LOOP_8kHz), + ABE_DMASTATUS_RAW, (1 << 1) + } } + }, + {CIRCULAR_BUFFER_PERIPHERAL_R__1, 2}, + {ASRC1, 0}, "VX_DL"}, + /* TONES_DL */ { + OMAP_ABE_PORT_ACTIVITY_IDLE, {48000, STEREO_MSB}, + NODRIFT, NOCALLBACK, smem_tones_dl, 1, + { + SNK_P, DMAREQ_PORT_PROT, {{ + (CBPr_DMA_RTX5*ATC_SIZE), + dmem_tones_dl, + dmem_tones_dl_size, + (2*SCHED_LOOP_48kHz), + ABE_DMASTATUS_RAW, (1 << 5) + } } + }, + {CIRCULAR_BUFFER_PERIPHERAL_R__5, 24}, + {0}, "TONES_DL"}, + /* VIB_DL */ { + OMAP_ABE_PORT_ACTIVITY_IDLE, {24000, STEREO_MSB}, + NODRIFT, NOCALLBACK, smem_vib, 1, + { + SNK_P, DMAREQ_PORT_PROT, {{ + (CBPr_DMA_RTX6*ATC_SIZE), + dmem_vib_dl, dmem_vib_dl_size, + (2*SCHED_LOOP_24kHz), + ABE_DMASTATUS_RAW, (1 << 6) + } } + }, + {CIRCULAR_BUFFER_PERIPHERAL_R__6, 12}, + {0}, "VIB_DL"}, + /* BT_VX_DL */ { + OMAP_ABE_PORT_ACTIVITY_IDLE, {8000, MONO_MSB}, + NODRIFT, NOCALLBACK, smem_bt_vx_dl_opp50, 1, + { + SRC_P, SERIAL_PORT_PROT, {{ + (MCBSP1_DMA_RX*ATC_SIZE), + dmem_bt_vx_dl, + dmem_bt_vx_dl_size, + (1*SCHED_LOOP_8kHz), + } } + }, + {0, 0}, {0}, "BT_VX_DL"}, + /* PDM_DL */ { + OMAP_ABE_PORT_ACTIVITY_IDLE, {96000, SIX_MSB}, + NODRIFT, NOCALLBACK, 1, (MCPDM_DL_ITER/6), + {SRC_P, MCPDMDL_PORT_PROT, {{dmem_mcpdm, + dmem_mcpdm_size} } }, + {0, 0}, + {MIXDL1, EQ1, APS1, MIXDL2, EQ2L, EQ2R, APS2L, APS2R, 0}, + "PDM_DL"}, + /* MM_EXT_OUT */ + { + OMAP_ABE_PORT_ACTIVITY_IDLE, {48000, STEREO_MSB}, + NODRIFT, NOCALLBACK, smem_mm_ext_out, 1, + { + SRC_P, SERIAL_PORT_PROT, {{ + (MCBSP1_DMA_TX*ATC_SIZE), + dmem_mm_ext_out, dmem_mm_ext_out_size, + (2*SCHED_LOOP_48kHz) + } } + }, {0, 0}, {0}, "MM_EXT_OUT"}, + /* MM_EXT_IN */ + { + OMAP_ABE_PORT_ACTIVITY_IDLE, {48000, STEREO_MSB}, + NODRIFT, NOCALLBACK, smem_mm_ext_in_opp100, 1, + { + SNK_P, SERIAL_PORT_PROT, {{ + (MCBSP1_DMA_RX*ATC_SIZE), + dmem_mm_ext_in, dmem_mm_ext_in_size, + (2*SCHED_LOOP_48kHz) + } } + }, + {0, 0}, {0}, "MM_EXT_IN"}, + /* PCM3_TX */ { + OMAP_ABE_PORT_ACTIVITY_IDLE, {48000, STEREO_MSB}, + NODRIFT, NOCALLBACK, 1, 1, + { + SRC_P, TDM_SERIAL_PORT_PROT, {{ + (MCBSP3_DMA_TX * + ATC_SIZE), + dmem_mm_ext_out, + dmem_mm_ext_out_size, + (2*SCHED_LOOP_48kHz) + } } + }, + {0, 0}, {0}, "TDM_OUT"}, + /* PCM3_RX */ { + OMAP_ABE_PORT_ACTIVITY_IDLE, {48000, STEREO_MSB}, + NODRIFT, NOCALLBACK, 1, 1, + { + SRC_P, TDM_SERIAL_PORT_PROT, {{ + (MCBSP3_DMA_RX * + ATC_SIZE), + dmem_mm_ext_in, + dmem_mm_ext_in_size, + (2*SCHED_LOOP_48kHz) + } } + }, + {0, 0}, {0}, "TDM_IN"}, + /* SCHD_DBG_PORT */ { + OMAP_ABE_PORT_ACTIVITY_IDLE, {48000, MONO_MSB}, + NODRIFT, NOCALLBACK, 1, 1, + { + SRC_P, DMAREQ_PORT_PROT, {{ + (CBPr_DMA_RTX7 * + ATC_SIZE), + dmem_mm_trace, + dmem_mm_trace_size, + (2*SCHED_LOOP_48kHz), + ABE_DMASTATUS_RAW, + (1 << 4) + } } + }, {CIRCULAR_BUFFER_PERIPHERAL_R__7, 24}, + {FEAT_SEQ, FEAT_CTL, FEAT_GAINS, 0}, "SCHD_DBG"}, +}; +/* + * AESS/ATC destination and source address translation (except McASPs) + * from the original 64bits words address + */ +const u32 abe_atc_dstid[ABE_ATC_DESC_SIZE >> 3] = { + /* DMA_0 DMIC PDM_DL PDM_UL McB1TX McB1RX McB2TX McB2RX 0 .. 7 */ + 0, 0, 12, 0, 1, 0, 2, 0, + /* McB3TX McB3RX SLIMT0 SLIMT1 SLIMT2 SLIMT3 SLIMT4 SLIMT5 8 .. 15 */ + 3, 0, 4, 5, 6, 7, 8, 9, + /* SLIMT6 SLIMT7 SLIMR0 SLIMR1 SLIMR2 SLIMR3 SLIMR4 SLIMR5 16 .. 23 */ + 10, 11, 0, 0, 0, 0, 0, 0, + /* SLIMR6 SLIMR7 McASP1X ----- ----- McASP1R ----- ----- 24 .. 31 */ + 0, 0, 14, 0, 0, 0, 0, 0, + /* CBPrT0 CBPrT1 CBPrT2 CBPrT3 CBPrT4 CBPrT5 CBPrT6 CBPrT7 32 .. 39 */ + 63, 63, 63, 63, 63, 63, 63, 63, + /* CBP_T0 CBP_T1 CBP_T2 CBP_T3 CBP_T4 CBP_T5 CBP_T6 CBP_T7 40 .. 47 */ + 0, 0, 0, 0, 0, 0, 0, 0, + /* CBP_T8 CBP_T9 CBP_T10 CBP_T11 CBP_T12 CBP_T13 CBP_T14 + CBP_T15 48 .. 63 */ + 0, 0, 0, 0, 0, 0, 0, 0, +}; +const u32 abe_atc_srcid[ABE_ATC_DESC_SIZE >> 3] = { + /* DMA_0 DMIC PDM_DL PDM_UL McB1TX McB1RX McB2TX McB2RX 0 .. 7 */ + 0, 12, 0, 13, 0, 1, 0, 2, + /* McB3TX McB3RX SLIMT0 SLIMT1 SLIMT2 SLIMT3 SLIMT4 SLIMT5 8 .. 15 */ + 0, 3, 0, 0, 0, 0, 0, 0, + /* SLIMT6 SLIMT7 SLIMR0 SLIMR1 SLIMR2 SLIMR3 SLIMR4 SLIMR5 16 .. 23 */ + 0, 0, 4, 5, 6, 7, 8, 9, + /* SLIMR6 SLIMR7 McASP1X ----- ----- McASP1R ----- ----- 24 .. 31 */ + 10, 11, 0, 0, 0, 14, 0, 0, + /* CBPrT0 CBPrT1 CBPrT2 CBPrT3 CBPrT4 CBPrT5 CBPrT6 CBPrT7 32 .. 39 */ + 63, 63, 63, 63, 63, 63, 63, 63, + /* CBP_T0 CBP_T1 CBP_T2 CBP_T3 CBP_T4 CBP_T5 CBP_T6 CBP_T7 40 .. 47 */ + 0, 0, 0, 0, 0, 0, 0, 0, + /* CBP_T8 CBP_T9 CBP_T10 CBP_T11 CBP_T12 CBP_T13 CBP_T14 + CBP_T15 48 .. 63 */ + 0, 0, 0, 0, 0, 0, 0, 0, +}; +/* + * preset default routing configurations + * This is given as implementation EXAMPLES + * the programmer uses "abe_set_router_configuration" with its own tables + */ +const abe_router_t abe_router_ul_table_preset[NBROUTE_CONFIG][NBROUTE_UL] = { + /* VOICE UPLINK WITH PHOENIX MICROPHONES - UPROUTE_CONFIG_AMIC */ + { + /* 0 .. 9 = MM_UL */ + DMIC1_L_labelID, DMIC1_R_labelID, DMIC2_L_labelID, DMIC2_R_labelID, + MM_EXT_IN_L_labelID, MM_EXT_IN_R_labelID, AMIC_L_labelID, + AMIC_L_labelID, + ZERO_labelID, ZERO_labelID, + /* 10 .. 11 = MM_UL2 */ + AMIC_L_labelID, AMIC_L_labelID, + /* 12 .. 13 = VX_UL */ + AMIC_L_labelID, AMIC_R_labelID, + /* 14 .. 15 = RESERVED */ + ZERO_labelID, ZERO_labelID, + }, + /* VOICE UPLINK WITH THE FIRST DMIC PAIR - UPROUTE_CONFIG_DMIC1 */ + { + /* 0 .. 9 = MM_UL */ + DMIC2_L_labelID, DMIC2_R_labelID, DMIC3_L_labelID, DMIC3_R_labelID, + DMIC1_L_labelID, DMIC1_R_labelID, ZERO_labelID, ZERO_labelID, + ZERO_labelID, ZERO_labelID, + /* 10 .. 11 = MM_UL2 */ + DMIC1_L_labelID, DMIC1_R_labelID, + /* 12 .. 13 = VX_UL */ + DMIC1_L_labelID, DMIC1_R_labelID, + /* 14 .. 15 = RESERVED */ + ZERO_labelID, ZERO_labelID, + }, + /* VOICE UPLINK WITH THE SECOND DMIC PAIR - UPROUTE_CONFIG_DMIC2 */ + { + /* 0 .. 9 = MM_UL */ + DMIC3_L_labelID, DMIC3_R_labelID, DMIC1_L_labelID, DMIC1_R_labelID, + DMIC2_L_labelID, DMIC2_R_labelID, ZERO_labelID, ZERO_labelID, + ZERO_labelID, ZERO_labelID, + /* 10 .. 11 = MM_UL2 */ + DMIC2_L_labelID, DMIC2_R_labelID, + /* 12 .. 13 = VX_UL */ + DMIC2_L_labelID, DMIC2_R_labelID, + /* 14 .. 15 = RESERVED */ + ZERO_labelID, ZERO_labelID, + }, + /* VOICE UPLINK WITH THE LAST DMIC PAIR - UPROUTE_CONFIG_DMIC3 */ + { + /* 0 .. 9 = MM_UL */ + AMIC_L_labelID, AMIC_R_labelID, DMIC2_L_labelID, DMIC2_R_labelID, + DMIC3_L_labelID, DMIC3_R_labelID, ZERO_labelID, ZERO_labelID, + ZERO_labelID, ZERO_labelID, + /* 10 .. 11 = MM_UL2 */ + DMIC3_L_labelID, DMIC3_R_labelID, + /* 12 .. 13 = VX_UL */ + DMIC3_L_labelID, DMIC3_R_labelID, + /* 14 .. 15 = RESERVED */ + ZERO_labelID, ZERO_labelID, + }, + /* VOICE UPLINK WITH THE BT - UPROUTE_CONFIG_BT */ + { + /* 0 .. 9 = MM_UL */ + BT_UL_L_labelID, BT_UL_R_labelID, DMIC2_L_labelID, DMIC2_R_labelID, + DMIC3_L_labelID, DMIC3_R_labelID, DMIC1_L_labelID, DMIC1_R_labelID, + ZERO_labelID, ZERO_labelID, + /* 10 .. 11 = MM_UL2 */ + AMIC_L_labelID, AMIC_R_labelID, + /* 12 .. 13 = VX_UL */ + BT_UL_L_labelID, BT_UL_R_labelID, + /* 14 .. 15 = RESERVED */ + ZERO_labelID, ZERO_labelID, + }, + /* VOICE UPLINK WITH THE BT - UPROUTE_ECHO_MMUL2 */ + { + /* 0 .. 9 = MM_UL */ + MM_EXT_IN_L_labelID, MM_EXT_IN_R_labelID, BT_UL_L_labelID, + BT_UL_R_labelID, AMIC_L_labelID, AMIC_R_labelID, + ZERO_labelID, ZERO_labelID, ZERO_labelID, ZERO_labelID, + /* 10 .. 11 = MM_UL2 */ + EchoRef_L_labelID, EchoRef_R_labelID, + /* 12 .. 13 = VX_UL */ + AMIC_L_labelID, AMIC_L_labelID, + /* 14 .. 15 = RESERVED */ + ZERO_labelID, ZERO_labelID, + }, +}; +/* all default routing configurations */ +abe_router_t abe_router_ul_table[NBROUTE_CONFIG_MAX][NBROUTE_UL]; + +const abe_sequence_t seq_null = { + NOMASK, {CL_M1, 0, {0, 0, 0, 0}, 0}, {CL_M1, 0, {0, 0, 0, 0}, 0} +}; +/* table of new subroutines called in the sequence */ +abe_subroutine2 abe_all_subsubroutine[MAXNBSUBROUTINE]; +/* number of parameters per calls */ +u32 abe_all_subsubroutine_nparam[MAXNBSUBROUTINE]; +/* index of the subroutine */ +u32 abe_subroutine_id[MAXNBSUBROUTINE]; +/* paramters of the subroutine (if any) */ +u32 *abe_all_subroutine_params[MAXNBSUBROUTINE]; +u32 abe_subroutine_write_pointer; +/* table of all sequences */ +abe_sequence_t abe_all_sequence[MAXNBSEQUENCE]; +u32 abe_sequence_write_pointer; +/* current number of pending sequences (avoids to look in the table) */ +u32 abe_nb_pending_sequences; +/* pending sequences due to ressource collision */ +u32 abe_pending_sequences[MAXNBSEQUENCE]; +/* mask of unsharable ressources among other sequences */ +u32 abe_global_sequence_mask; +/* table of active sequences */ +abe_seq_t abe_active_sequence[MAXACTIVESEQUENCE][MAXSEQUENCESTEPS]; +/* index of the plugged subroutine doing ping-pong cache-flush DMEM accesses */ +u32 abe_irq_pingpong_player_id; +EXPORT_SYMBOL(abe_irq_pingpong_player_id); +/* index of the plugged subroutine doing acoustics protection adaptation */ +u32 abe_irq_aps_adaptation_id; +/* base addresses of the ping pong buffers in bytes addresses */ +u32 abe_base_address_pingpong[MAX_PINGPONG_BUFFERS]; +/* size of each ping/pong buffers */ +u32 abe_size_pingpong; +/* number of ping/pong buffer being used */ +u32 abe_nb_pingpong; +/* + * MAIN PORT SELECTION + */ +const u32 abe_port_priority[LAST_PORT_ID - 1] = { + OMAP_ABE_PDM_DL_PORT, + OMAP_ABE_PDM_UL_PORT, + OMAP_ABE_MM_EXT_OUT_PORT, + OMAP_ABE_MM_EXT_IN_PORT, + OMAP_ABE_DMIC_PORT, + OMAP_ABE_MM_UL_PORT, + OMAP_ABE_MM_UL2_PORT, + OMAP_ABE_MM_DL_PORT, + OMAP_ABE_TONES_DL_PORT, + OMAP_ABE_VX_UL_PORT, + OMAP_ABE_VX_DL_PORT, + OMAP_ABE_BT_VX_DL_PORT, + OMAP_ABE_BT_VX_UL_PORT, + OMAP_ABE_VIB_DL_PORT, +}; diff --git a/sound/soc/omap/abe/abe_dbg.c b/sound/soc/omap/abe/abe_dbg.c new file mode 100644 index 0000000..d1b160f --- /dev/null +++ b/sound/soc/omap/abe/abe_dbg.c @@ -0,0 +1,201 @@ +/* + + This file is provided under a dual BSD/GPLv2 license. When using or + redistributing this file, you may do so under either license. + + GPL LICENSE SUMMARY + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License 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. + The full GNU General Public License is included in this distribution + in the file called LICENSE.GPL. + + BSD LICENSE + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name of Texas Instruments Incorporated nor the names of + its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/err.h> +#include <linux/slab.h> + +#include "abe_dbg.h" +#include "abe.h" +#include "abe_mem.h" + +/** + * omap_abe_dbg_reset + * @dbg: Pointer on abe debug handle + * + * Called in order to reset Audio Back End debug global data. + * This ensures that ABE debug trace pointer is reset correctly. + */ +int omap_abe_dbg_reset(struct omap_abe_dbg *dbg) +{ + dbg->activity_log_write_pointer = 0; + dbg->mask = 0; + + return 0; +} + +/** + * omap_abe_connect_debug_trace + * @abe: Pointer on abe handle + * @dma2:pointer to the DMEM trace buffer + * + * returns the address and size of the real-time debug trace buffer, + * the content of which will vary from one firmware release to another + */ +int omap_abe_connect_debug_trace(struct omap_abe *abe, + struct omap_abe_dma *dma2) +{ + _log(ABE_ID_CONNECT_DEBUG_TRACE, 0, 0, 0); + + /* return tohe base address of the ping buffer in L3 and L4 spaces */ + (*dma2).data = (void *)(OMAP_ABE_D_DEBUG_FIFO_ADDR + + ABE_DEFAULT_BASE_ADDRESS_L3 + ABE_DMEM_BASE_OFFSET_MPU); + (*dma2).l3_dmem = (void *)(OMAP_ABE_D_DEBUG_FIFO_ADDR + + ABE_DEFAULT_BASE_ADDRESS_L3 + ABE_DMEM_BASE_OFFSET_MPU); + (*dma2).l4_dmem = (void *)(OMAP_ABE_D_DEBUG_FIFO_ADDR + + ABE_DEFAULT_BASE_ADDRESS_L4 + ABE_DMEM_BASE_OFFSET_MPU); + (*dma2).iter = (OMAP_ABE_D_DEBUG_FIFO_SIZE + OMAP_ABE_D_DEBUG_FIFO_HAL_SIZE)>>2; + + return 0; +} +EXPORT_SYMBOL(omap_abe_connect_debug_trace); + +/** + * omap_abe_set_debug_trace + * @dbg: Pointer on abe debug handle + * @debug: debug log level + * + * Set the debug level for ABE trace. This level allows to manage the number + * of information put inside the ABE trace buffer. This buffer can contains + * both AESS firmware and MPU traces. + */ +int omap_abe_set_debug_trace(struct omap_abe_dbg *dbg, int debug) +{ + _log(ABE_ID_SET_DEBUG_TRACE, 0, 0, 0); + + dbg->mask = debug; + + return 0; +} +EXPORT_SYMBOL(omap_abe_set_debug_trace); + +/** + * omap_abe_dbg_log - Log ABE trace inside circular buffer + * @x: data to be logged + * @y: data to be logged + * @z: data to be logged + * @t: data to be logged + * Parameter : + * + * abe_dbg_activity_log : global circular buffer holding the data + * abe_dbg_activity_log_write_pointer : circular write pointer + * + * saves data in the log file + */ +void omap_abe_dbg_log(struct omap_abe *abe, u32 x, u32 y, u32 z, u32 t) +{ + u32 time_stamp, data; + struct omap_abe_dbg *dbg = &abe->dbg; + + if (dbg->activity_log_write_pointer >= + (OMAP_ABE_D_DEBUG_HAL_TASK_SIZE - 2)) + dbg->activity_log_write_pointer = 0; + + /* copy in DMEM trace buffer and CortexA9 local buffer and a small 7 + words circular buffer of the DMA trace ending with 0x55555555 + (tag for last word) */ + omap_abe_mem_read(abe, OMAP_ABE_DMEM, OMAP_ABE_D_LOOPCOUNTER_ADDR, + (u32 *) &time_stamp, sizeof(time_stamp)); + dbg->activity_log[dbg->activity_log_write_pointer] = time_stamp; + omap_abe_mem_write(abe, OMAP_ABE_DMEM, + OMAP_ABE_D_DEBUG_HAL_TASK_ADDR + + (dbg->activity_log_write_pointer << 2), + (u32 *) &time_stamp, sizeof(time_stamp)); + dbg->activity_log_write_pointer++; + + data = ((x & MAX_UINT8) << 24) | ((y & MAX_UINT8) << 16) | + ((z & MAX_UINT8) << 8) + | (t & MAX_UINT8); + dbg->activity_log[dbg->activity_log_write_pointer] = data; + omap_abe_mem_write(abe, OMAP_ABE_DMEM, + OMAP_ABE_D_DEBUG_HAL_TASK_ADDR + + (dbg->activity_log_write_pointer << 2), + (u32 *) &data, sizeof(data)); + + omap_abe_mem_write(abe, OMAP_ABE_DMEM, + OMAP_ABE_D_DEBUG_FIFO_HAL_ADDR + + ((dbg->activity_log_write_pointer << 2) & + (OMAP_ABE_D_DEBUG_FIFO_HAL_SIZE - 1)), (u32 *) &data, + sizeof(data)); + + data = ABE_DBG_MAGIC_NUMBER; + omap_abe_mem_write(abe, OMAP_ABE_DMEM, + OMAP_ABE_D_DEBUG_FIFO_HAL_ADDR + + (((dbg->activity_log_write_pointer + 1) << 2) & + (OMAP_ABE_D_DEBUG_FIFO_HAL_SIZE - 1)), + (u32 *) &data, sizeof(data)); + dbg->activity_log_write_pointer++; + + if (dbg->activity_log_write_pointer >= OMAP_ABE_D_DEBUG_HAL_TASK_SIZE) + dbg->activity_log_write_pointer = 0; +} + +/** + * omap_abe_dbg_error_log - Log ABE error + * @abe: Pointer on abe handle + * @level: level of error + * @error: error ID to log + * + * Log the ABE errors. + */ +void omap_abe_dbg_error(struct omap_abe *abe, int level, int error) +{ + omap_abe_dbg_log(abe, error, MAX_UINT8, MAX_UINT8, MAX_UINT8); +} diff --git a/sound/soc/omap/abe/abe_dbg.h b/sound/soc/omap/abe/abe_dbg.h new file mode 100644 index 0000000..8639806 --- /dev/null +++ b/sound/soc/omap/abe/abe_dbg.h @@ -0,0 +1,231 @@ +/* + + This file is provided under a dual BSD/GPLv2 license. When using or + redistributing this file, you may do so under either license. + + GPL LICENSE SUMMARY + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License 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. + The full GNU General Public License is included in this distribution + in the file called LICENSE.GPL. + + BSD LICENSE + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name of Texas Instruments Incorporated nor the names of + its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef _ABE_DBG_H_ +#define _ABE_DBG_H_ + +#include <linux/mutex.h> + +#include "abe_typ.h" +#include "abe_dm_addr.h" + +/* + * Debug trace format + * TIME 2 bytes from ABE : 4kHz period of the FW scheduler + * SUBID 1 byte : HAL API index + * From 0 to 16 bytes : parameters of the subroutine + * on every 32 dumps a tag is pushed on the debug trace : 0x55555555 + */ +#define dbg_bitfield_offset 8 +#define dbg_api_calls 0 +#define dbg_mapi (1L << (dbg_api_calls + dbg_bitfield_offset)) +#define dbg_external_data_access 1 +#define dbg_mdata (1L << (dbg_external_data_access + dbg_bitfield_offset)) +#define dbg_err_codes 2 +#define dbg_merr (1L << (dbg_api_calls + dbg_bitfield_offset)) +#define ABE_DBG_MAGIC_NUMBER 0x55555555 +/* + * IDs used for traces + */ +#define ABE_ID_RESET_HAL (1 + dbg_mapi) +#define ABE_ID_LOAD_FW (2 + dbg_mapi) +#define ABE_ID_DEFAULT_CONFIGURATION (3 + dbg_mapi) +#define ABE_ID_IRQ_PROCESSING (4 + dbg_mapi) +#define ABE_ID_EVENT_GENERATOR_SWITCH (5 + dbg_mapi) +#define ABE_ID_READ_HARDWARE_CONFIGURATION (6 + dbg_mapi) +#define ABE_ID_READ_LOWEST_OPP (7 + dbg_mapi) +#define ABE_ID_WRITE_GAIN (8 + dbg_mapi) +#define ABE_ID_SET_ASRC_DRIFT_CONTROL (9 + dbg_mapi) +#define ABE_ID_PLUG_SUBROUTINE (10 + dbg_mapi) +#define ABE_ID_UNPLUG_SUBROUTINE (11 + dbg_mapi) +#define ABE_ID_PLUG_SEQUENCE (12 + dbg_mapi) +#define ABE_ID_LAUNCH_SEQUENCE (13 + dbg_mapi) +#define ABE_ID_LAUNCH_SEQUENCE_param (14 + dbg_mapi) +#define ABE_ID_CONNECT_IRQ_PING_PONG_PORT (15 + dbg_mapi) +#define ABE_ID_READ_ANALOG_GAIN_DL (16 + dbg_mapi) +#define ABE_ID_READ_ANALOG_GAIN_UL (17 + dbg_mapi) +#define ABE_ID_ENABLE_DYN_UL_GAIN (18 + dbg_mapi) +#define ABE_ID_DISABLE_DYN_UL_GAIN (19 + dbg_mapi) +#define ABE_ID_ENABLE_DYN_EXTENSION (20 + dbg_mapi) +#define ABE_ID_DISABLE_DYN_EXTENSION (21 + dbg_mapi) +#define ABE_ID_NOTIFY_ANALOG_GAIN_CHANGED (22 + dbg_mapi) +#define ABE_ID_RESET_PORT (23 + dbg_mapi) +#define ABE_ID_READ_REMAINING_DATA (24 + dbg_mapi) +#define ABE_ID_DISABLE_DATA_TRANSFER (25 + dbg_mapi) +#define ABE_ID_ENABLE_DATA_TRANSFER (26 + dbg_mapi) +#define ABE_ID_READ_GLOBAL_COUNTER (27 + dbg_mapi) +#define ABE_ID_SET_DMIC_FILTER (28 + dbg_mapi) +#define ABE_ID_SET_OPP_PROCESSING (29 + dbg_mapi) +#define ABE_ID_SET_PING_PONG_BUFFER (30 + dbg_mapi) +#define ABE_ID_READ_PORT_ADDRESS (31 + dbg_mapi) +#define ABE_ID_LOAD_FW_param (32 + dbg_mapi) +#define ABE_ID_WRITE_HEADSET_OFFSET (33 + dbg_mapi) +#define ABE_ID_READ_GAIN_RANGES (34 + dbg_mapi) +#define ABE_ID_WRITE_EQUALIZER (35 + dbg_mapi) +#define ABE_ID_WRITE_ASRC (36 + dbg_mapi) +#define ABE_ID_WRITE_APS (37 + dbg_mapi) +#define ABE_ID_WRITE_MIXER (38 + dbg_mapi) +#define ABE_ID_WRITE_EANC (39 + dbg_mapi) +#define ABE_ID_WRITE_ROUTER (40 + dbg_mapi) +#define ABE_ID_READ_PORT_GAIN (41 + dbg_mapi) +#define ABE_ID_ASRC (42 + dbg_mapi) +#define ABE_ID_READ_APS (43 + dbg_mapi) +#define ABE_ID_READ_APS_energy (44 + dbg_mapi) +#define ABE_ID_READ_MIXER (45 + dbg_mapi) +#define ABE_READ_EANC (46 + dbg_mapi) +#define ABE_ID_READ_ROUTER (47 + dbg_mapi) +#define ABE_ID_READ_DEBUG_TRACE (48 + dbg_mapi) +#define ABE_ID_SET_SEQUENCE_TIME_ACCURACY (49 + dbg_mapi) +#define ABE_ID_SET_DEBUG_PINS (50 + dbg_mapi) +#define ABE_ID_SELECT_MAIN_PORT (51 + dbg_mapi) +#define ABE_ID_WRITE_EVENT_GENERATOR (52 + dbg_mapi) +#define ABE_ID_READ_USE_CASE_OPP (53 + dbg_mapi) +#define ABE_ID_SELECT_DATA_SOURCE (54 + dbg_mapi) +#define ABE_ID_READ_NEXT_PING_PONG_BUFFER (55 + dbg_mapi) +#define ABE_ID_INIT_PING_PONG_BUFFER (56 + dbg_mapi) +#define ABE_ID_CONNECT_CBPR_DMAREQ_PORT (57 + dbg_mapi) +#define ABE_ID_CONNECT_DMAREQ_PORT (58 + dbg_mapi) +#define ABE_ID_CONNECT_DMAREQ_PING_PONG_PORT (59 + dbg_mapi) +#define ABE_ID_CONNECT_SERIAL_PORT (60 + dbg_mapi) +#define ABE_ID_CONNECT_SLIMBUS_PORT (61 + dbg_mapi) +#define ABE_ID_READ_GAIN (62 + dbg_mapi) +#define ABE_ID_SET_ROUTER_CONFIGURATION (63 + dbg_mapi) +#define ABE_ID_CONNECT_DEBUG_TRACE (64 + dbg_mapi) +#define ABE_ID_SET_DEBUG_TRACE (65 + dbg_mapi) +#define ABE_ID_REMOTE_DEBUGGER_INTERFACE (66 + dbg_mapi) +#define ABE_ID_ENABLE_TEST_PATTERN (67 + dbg_mapi) +#define ABE_ID_CONNECT_TDM_PORT (68 + dbg_mapi) +/* + * IDs used for error codes + */ +#define NOERR 0 +#define ABE_SET_MEMORY_CONFIG_ERR (1 + dbg_merr) +#define ABE_BLOCK_COPY_ERR (2 + dbg_merr) +#define ABE_SEQTOOLONG (3 + dbg_merr) +#define ABE_BADSAMPFORMAT (4 + dbg_merr) +#define ABE_SET_ATC_ABE_BLOCK_COPY_ERR MEMORY_CONFIG_ERR (5 + dbg_merr) +#define ABE_PROTOCOL_ERROR (6 + dbg_merr) +#define ABE_PARAMETER_ERROR (7 + dbg_merr) +/* port programmed while still running */ +#define ABE_PORT_REPROGRAMMING (8 + dbg_merr) +#define ABE_READ_USE_CASE_OPP_ERR (9 + dbg_merr) +#define ABE_PARAMETER_OVERFLOW (10 + dbg_merr) +#define ABE_FW_FIFO_WRITE_PTR_ERR (11 + dbg_merr) + +/* + * IDs used for error codes + */ +#define OMAP_ABE_ERR_LIB (1 << 1) +#define OMAP_ABE_ERR_API (1 << 2) +#define OMAP_ABE_ERR_INI (1 << 3) +#define OMAP_ABE_ERR_SEQ (1 << 4) +#define OMAP_ABE_ERR_DBG (1 << 5) +#define OMAP_ABE_ERR_EXT (1 << 6) + +struct omap_abe_dbg { + /* Debug Data */ + u32 activity_log[OMAP_ABE_D_DEBUG_HAL_TASK_SIZE]; + u32 activity_log_write_pointer; + u32 mask; +}; + +struct omap_abe_dma { + /* OCP L3 pointer to the first address of the */ + void *data; + /* destination buffer (either DMA or Ping-Pong read/write pointers). */ + /* address L3 when addressing the DMEM buffer instead of CBPr */ + void *l3_dmem; + /* address L3 translated to L4 the ARM memory space */ + void *l4_dmem; + /* number of iterations for the DMA data moves. */ + u32 iter; +}; + +struct omap_abe { + void __iomem *io_base[5]; + u32 firmware_version_number; + u16 MultiFrame[25][8]; + u32 compensated_mixer_gain; + u8 muted_gains_indicator[MAX_NBGAIN_CMEM]; + u32 desired_gains_decibel[MAX_NBGAIN_CMEM]; + u32 muted_gains_decibel[MAX_NBGAIN_CMEM]; + u32 desired_gains_linear[MAX_NBGAIN_CMEM]; + u32 desired_ramp_delay_ms[MAX_NBGAIN_CMEM]; + int pp_buf_id; + int pp_buf_id_next; + int pp_buf_addr[4]; + int pp_first_irq; + struct mutex mutex; + u32 warm_boot; + + u32 irq_dbg_read_ptr; + u32 dbg_param; + + struct omap_abe_dbg dbg; +}; + +/** + * omap_abe_dbg_reset + * @dbg: Pointer on abe debug handle + * + * Called in order to reset Audio Back End debug global data. + * This ensures that ABE debug trace pointer is reset correctly. + */ +int omap_abe_dbg_reset(struct omap_abe_dbg *dbg); + +#endif /* _ABE_DBG_H_ */ diff --git a/sound/soc/omap/abe/abe_def.h b/sound/soc/omap/abe/abe_def.h new file mode 100644 index 0000000..0051bab --- /dev/null +++ b/sound/soc/omap/abe/abe_def.h @@ -0,0 +1,308 @@ +/* + + This file is provided under a dual BSD/GPLv2 license. When using or + redistributing this file, you may do so under either license. + + GPL LICENSE SUMMARY + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License 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. + The full GNU General Public License is included in this distribution + in the file called LICENSE.GPL. + + BSD LICENSE + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name of Texas Instruments Incorporated nor the names of + its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef _ABE_DEF_H_ +#define _ABE_DEF_H_ +/* + * HARDWARE AND PERIPHERAL DEFINITIONS + */ +/* MM_DL */ +#define ABE_CBPR0_IDX 0 +/* VX_DL */ +#define ABE_CBPR1_IDX 1 +/* VX_UL */ +#define ABE_CBPR2_IDX 2 +/* MM_UL */ +#define ABE_CBPR3_IDX 3 +/* MM_UL2 */ +#define ABE_CBPR4_IDX 4 +/* TONES */ +#define ABE_CBPR5_IDX 5 +/* VIB */ +#define ABE_CBPR6_IDX 6 +/* DEBUG/CTL */ +#define ABE_CBPR7_IDX 7 +#define CIRCULAR_BUFFER_PERIPHERAL_R__0 (0x100 + ABE_CBPR0_IDX*4) +#define CIRCULAR_BUFFER_PERIPHERAL_R__1 (0x100 + ABE_CBPR1_IDX*4) +#define CIRCULAR_BUFFER_PERIPHERAL_R__2 (0x100 + ABE_CBPR2_IDX*4) +#define CIRCULAR_BUFFER_PERIPHERAL_R__3 (0x100 + ABE_CBPR3_IDX*4) +#define CIRCULAR_BUFFER_PERIPHERAL_R__4 (0x100 + ABE_CBPR4_IDX*4) +#define CIRCULAR_BUFFER_PERIPHERAL_R__5 (0x100 + ABE_CBPR5_IDX*4) +#define CIRCULAR_BUFFER_PERIPHERAL_R__6 (0x100 + ABE_CBPR6_IDX*4) +#define CIRCULAR_BUFFER_PERIPHERAL_R__7 (0x100 + ABE_CBPR7_IDX*4) +#define PING_PONG_WITH_MCU_IRQ 1 +#define PING_PONG_WITH_DSP_IRQ 2 +/* ID used for LIB memory copy subroutines */ +#define COPY_FROM_ABE_TO_HOST 1 +#define COPY_FROM_HOST_TO_ABE 2 +/* + * INTERNAL DEFINITIONS + */ +#define ABE_FIRMWARE_MAX_SIZE 26629 +/* 24 Q6.26 coefficients */ +#define NBEQ1 25 +/* 2x12 Q6.26 coefficients */ +#define NBEQ2 13 +/* TBD APS first set of parameters */ +#define NBAPS1 10 +/* TBD APS second set of parameters */ +#define NBAPS2 10 +/* Mixer used for sending tones to the uplink voice path */ +#define NBMIX_AUDIO_UL 2 +/* Main downlink mixer */ +#define NBMIX_DL1 4 +/* Handsfree downlink mixer */ +#define NBMIX_DL2 4 +/* Side-tone mixer */ +#define NBMIX_SDT 2 +/* Echo reference mixer */ +#define NBMIX_ECHO 2 +/* Voice record mixer */ +#define NBMIX_VXREC 4 +/* unsigned version of (-1) */ +#define CC_M1 0xFF +#define CS_M1 0xFFFF +#define CL_M1 0xFFFFFFFFL +/* + Mixer ID Input port ID Comments + DL1_MIXER 0 MMDL path + 1 MMUL2 path + 2 VXDL path + 3 TONES path + SDT_MIXER 0 Uplink path + 1 Downlink path + ECHO_MIXER 0 DL1_MIXER path + 1 DL2_MIXER path + AUDUL_MIXER 0 TONES_DL path + 1 Uplink path + 2 MM_DL path + VXREC_MIXER 0 TONES_DL path + 1 VX_DL path + 2 MM_DL path + 3 VX_UL path +*/ +#define MIX_VXUL_INPUT_MM_DL 0 +#define MIX_VXUL_INPUT_TONES 1 +#define MIX_VXUL_INPUT_VX_UL 2 +#define MIX_VXUL_INPUT_VX_DL 3 +#define MIX_DL1_INPUT_MM_DL 0 +#define MIX_DL1_INPUT_MM_UL2 1 +#define MIX_DL1_INPUT_VX_DL 2 +#define MIX_DL1_INPUT_TONES 3 +#define MIX_DL2_INPUT_MM_DL 0 +#define MIX_DL2_INPUT_MM_UL2 1 +#define MIX_DL2_INPUT_VX_DL 2 +#define MIX_DL2_INPUT_TONES 3 +#define MIX_SDT_INPUT_UP_MIXER 0 +#define MIX_SDT_INPUT_DL1_MIXER 1 +#define MIX_AUDUL_INPUT_MM_DL 0 +#define MIX_AUDUL_INPUT_TONES 1 +#define MIX_AUDUL_INPUT_UPLINK 2 +#define MIX_AUDUL_INPUT_VX_DL 3 +#define MIX_VXREC_INPUT_MM_DL 0 +#define MIX_VXREC_INPUT_TONES 1 +#define MIX_VXREC_INPUT_VX_UL 2 +#define MIX_VXREC_INPUT_VX_DL 3 +#define MIX_ECHO_DL1 0 +#define MIX_ECHO_DL2 1 +/* nb of samples to route */ +#define NBROUTE_UL 16 +/* 10 routing tables max */ +#define NBROUTE_CONFIG_MAX 10 +/* 5 pre-computed routing tables */ +#define NBROUTE_CONFIG 6 +/* AMIC on VX_UL */ +#define UPROUTE_CONFIG_AMIC 0 +/* DMIC first pair on VX_UL */ +#define UPROUTE_CONFIG_DMIC1 1 +/* DMIC second pair on VX_UL */ +#define UPROUTE_CONFIG_DMIC2 2 +/* DMIC last pair on VX_UL */ +#define UPROUTE_CONFIG_DMIC3 3 +/* BT_UL on VX_UL */ +#define UPROUTE_CONFIG_BT 4 +/* ECHO_REF on MM_UL2 */ +#define UPROUTE_ECHO_MMUL2 5 +/* call-back indexes */ +#define MAXCALLBACK 100 +/* subroutines */ +#define MAXNBSUBROUTINE 100 +/* time controlled sequenced */ +#define MAXNBSEQUENCE 20 +/* maximum simultaneous active sequences */ +#define MAXACTIVESEQUENCE 20 +/* max number of steps in the sequences */ +#define MAXSEQUENCESTEPS 2 +/* max number of feature associated to a port */ +#define MAXFEATUREPORT 12 +#define SUB_0_PARAM 0 +/* number of parameters per sequence calls */ +#define SUB_1_PARAM 1 +#define SUB_2_PARAM 2 +#define SUB_3_PARAM 3 +#define SUB_4_PARAM 4 +/* active sequence mask = 0 means the line is free */ +#define FREE_LINE 0 +/* no ask for collision protection */ +#define NOMASK (1 << 0) +/* do not allow a PDM OFF during the execution of this sequence */ +#define MASK_PDM_OFF (1 << 1) +/* do not allow a PDM ON during the execution of this sequence */ +#define MASK_PDM_ON (1 << 2) +/* explicit name of the feature */ +#define NBCHARFEATURENAME 16 +/* explicit name of the port */ +#define NBCHARPORTNAME 16 +/* sink / input port from Host point of view (or AESS for DMIC/McPDM/.. */ +#define SNK_P ABE_ATC_DIRECTION_IN +/* source / ouptut port */ +#define SRC_P ABE_ATC_DIRECTION_OUT +/* no ASRC applied */ +#define NODRIFT 0 +/* for abe_set_asrc_drift_control */ +#define FORCED_DRIFT_CONTROL 1 +/* for abe_set_asrc_drift_control */ +#define ADPATIVE_DRIFT_CONTROL 2 +/* number of task/slot depending on the OPP value */ +#define DOPPMODE32_OPP100 (0x00000010) +#define DOPPMODE32_OPP50 (0x0000000C) +#define DOPPMODE32_OPP25 (0x0000004) +/* + * ABE CONST AREA FOR PARAMETERS TRANSLATION + */ +#define GAIN_MAXIMUM 3000L +#define GAIN_24dB 2400L +#define GAIN_18dB 1800L +#define GAIN_12dB 1200L +#define GAIN_6dB 600L +/* default gain = 1 */ +#define GAIN_0dB 0L +#define GAIN_M6dB -600L +#define GAIN_M7dB -700L +#define GAIN_M12dB -1200L +#define GAIN_M18dB -1800L +#define GAIN_M24dB -2400L +#define GAIN_M30dB -3000L +#define GAIN_M40dB -4000L +#define GAIN_M50dB -5000L +/* muted gain = -120 decibels */ +#define MUTE_GAIN -12000L +#define GAIN_TOOLOW -13000L +#define GAIN_MUTE MUTE_GAIN +#define RAMP_MINLENGTH 0L +/* ramp_t is in milli- seconds */ +#define RAMP_0MS 0L +#define RAMP_1MS 1L +#define RAMP_2MS 2L +#define RAMP_5MS 5L +#define RAMP_10MS 10L +#define RAMP_20MS 20L +#define RAMP_50MS 50L +#define RAMP_100MS 100L +#define RAMP_200MS 200L +#define RAMP_500MS 500L +#define RAMP_1000MS 1000L +#define RAMP_MAXLENGTH 10000L +/* for abe_translate_gain_format */ +#define LINABE_TO_DECIBELS 1 +#define DECIBELS_TO_LINABE 2 +/* for abe_translate_ramp_format */ +#define IIRABE_TO_MICROS 1 +#define MICROS_TO_IIABE 2 +/* + * ABE CONST AREA FOR PERIPHERAL TUNING + */ +/* port idled IDLE_P */ +#define OMAP_ABE_PORT_ACTIVITY_IDLE 1 +/* port initialized, ready to be activated */ +#define OMAP_ABE_PORT_INITIALIZED 3 +/* port activated RUN_P */ +#define OMAP_ABE_PORT_ACTIVITY_RUNNING 2 +#define NOCALLBACK 0 +#define NOPARAMETER 0 +/* number of ATC access upon AMIC DMArequests, all the FIFOs are enabled */ +#define MCPDM_UL_ITER 4 +/* All the McPDM FIFOs are enabled simultaneously */ +#define MCPDM_DL_ITER 24 +/* All the DMIC FIFOs are enabled simultaneously */ +#define DMIC_ITER 12 +/* TBD later if needed */ +#define MAX_PINGPONG_BUFFERS 2 +/* + * Indexes to the subroutines + */ +#define SUB_WRITE_MIXER 1 +#define SUB_WRITE_PORT_GAIN 2 +/* OLD WAY */ +#define c_feat_init_eq 1 +#define c_feat_read_eq1 2 +#define c_write_eq1 3 +#define c_feat_read_eq2 4 +#define c_write_eq2 5 +#define c_feat_read_eq3 6 +#define c_write_eq3 7 +/* max number of gain to be controlled by HAL */ +#define MAX_NBGAIN_CMEM 36 +/* + * MACROS + */ +#define maximum(a, b) (((a) < (b)) ? (b) : (a)) +#define minimum(a, b) (((a) > (b)) ? (b) : (a)) +#define absolute(a) (((a) > 0) ? (a) : ((-1)*(a))) +#define HAL_VERSIONS 9 +#endif/* _ABE_DEF_H_ */ diff --git a/sound/soc/omap/abe/abe_define.h b/sound/soc/omap/abe/abe_define.h new file mode 100644 index 0000000..412fea8 --- /dev/null +++ b/sound/soc/omap/abe/abe_define.h @@ -0,0 +1,120 @@ +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2010-2011 Texas Instruments Incorporated, + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License 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. + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * BSD LICENSE + * + * Copyright(c) 2010-2011 Texas Instruments Incorporated, + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef _ABE_DEFINE_H_ +#define _ABE_DEFINE_H_ +#define ATC_DESCRIPTOR_NUMBER 64 +#define PROCESSING_SLOTS 25 +#define TASK_POOL_LENGTH 136 +#define MCU_IRQ 0x24 +#define MCU_IRQ_SHIFT2 0x90 +#define DMA_REQ_SHIFT2 0x210 +#define DSP_IRQ 0x4c +#define IRQtag_APS 0x000a +#define IRQtag_COUNT 0x000c +#define IRQtag_PP 0x000d +#define DMAreq_7 0x0080 +#define IRQ_FIFO_LENGTH 16 +#define SDT_EQ_ORDER 4 +#define DL_EQ_ORDER 12 +#define MIC_FILTER_ORDER 4 +#define GAINS_WITH_RAMP1 14 +#define GAINS_WITH_RAMP2 22 +#define GAINS_WITH_RAMP_TOTAL 36 +#define ASRC_MEMLENGTH 40 +#define ASRC_UL_VX_FIR_L 19 +#define ASRC_DL_VX_FIR_L 19 +#define ASRC_MM_EXT_IN_FIR_L 18 +#define ASRC_margin 2 +#define ASRC_N_8k 2 +#define ASRC_N_16k 4 +#define ASRC_N_48k 12 +#define VIBRA_N 5 +#define VIBRA1_IIR_MEMSIZE 11 +#define SAMP_LOOP_96K 24 +#define SAMP_LOOP_48K 12 +#define SAMP_LOOP_48KM1 11 +#define SAMP_LOOP_48KM2 10 +#define SAMP_LOOP_16K 4 +#define SAMP_LOOP_8K 2 +#define INPUT_SCALE_SHIFTM2 5156 +#define SATURATION 8420 +#define SATURATION_7FFF 8416 +#define OUTPUT_SCALE_SHIFTM2 5160 +#define NTAPS_SRC_44P1 24 +#define NTAPS_SRC_44P1_M4 96 +#define NTAPS_SRC_44P1_THR 60 +#define NTAPS_SRC_44P1_THRM4 240 +#define DRIFT_COUNTER_44P1M1 443 +#define NB_OF_PHASES_SRC44P1 12 +#define NB_OF_PHASES_SRC44P1M1 11 +#define SRC44P1_BUFFER_SIZE 96 +#define SRC44P1_BUFFER_SIZE_M4 384 +#define SRC44P1_INIT_RPTR 60 +#define MUTE_SCALING 5164 +#define ABE_PMEM 1 +#define ABE_CMEM 2 +#define ABE_SMEM 3 +#define ABE_DMEM 4 +#define ABE_ATC 5 +#define ASRC_BT_UL_FIR_L 19 +#define ASRC_BT_DL_FIR_L 19 +#define SRC44P1_COEF_ADDR 1466 +#define NTAPS_P_SRC_44P1_M4 192 +#define MAX_SMEM_CHECK 32 +#define SATURATION_EQ 9780 +#endif /* _ABE_DEFINE_H_ */ diff --git a/sound/soc/omap/abe/abe_dm_addr.h b/sound/soc/omap/abe/abe_dm_addr.h new file mode 100644 index 0000000..3abf5a5 --- /dev/null +++ b/sound/soc/omap/abe/abe_dm_addr.h @@ -0,0 +1,243 @@ +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2010-2011 Texas Instruments Incorporated, + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License 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. + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * BSD LICENSE + * + * Copyright(c) 2010-2011 Texas Instruments Incorporated, + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#define OMAP_ABE_D_ATCDESCRIPTORS_ADDR 0x0 +#define OMAP_ABE_D_ATCDESCRIPTORS_SIZE 0x200 +#define OMAP_ABE_STACK_ADDR 0x200 +#define OMAP_ABE_STACK_SIZE 0x70 +#define OMAP_ABE_D_VERSION_ADDR 0x270 +#define OMAP_ABE_D_VERSION_SIZE 0x4 +#define OMAP_ABE_D_IODESCR_ADDR 0x274 +#define OMAP_ABE_D_IODESCR_SIZE 0x280 +#define OMAP_ABE_D_ZERO_ADDR 0x4F4 +#define OMAP_ABE_D_ZERO_SIZE 0x4 +#define OMAP_ABE_DBG_TRACE1_ADDR 0x4F8 +#define OMAP_ABE_DBG_TRACE1_SIZE 0x1 +#define OMAP_ABE_DBG_TRACE2_ADDR 0x4F9 +#define OMAP_ABE_DBG_TRACE2_SIZE 0x1 +#define OMAP_ABE_DBG_TRACE3_ADDR 0x4FA +#define OMAP_ABE_DBG_TRACE3_SIZE 0x1 +#define OMAP_ABE_D_MULTIFRAME_ADDR 0x4FC +#define OMAP_ABE_D_MULTIFRAME_SIZE 0x190 +#define OMAP_ABE_D_IDLETASK_ADDR 0x68C +#define OMAP_ABE_D_IDLETASK_SIZE 0x2 +#define OMAP_ABE_D_TYPELENGTHCHECK_ADDR 0x68E +#define OMAP_ABE_D_TYPELENGTHCHECK_SIZE 0x2 +#define OMAP_ABE_D_MAXTASKBYTESINSLOT_ADDR 0x690 +#define OMAP_ABE_D_MAXTASKBYTESINSLOT_SIZE 0x2 +#define OMAP_ABE_D_REWINDTASKBYTES_ADDR 0x692 +#define OMAP_ABE_D_REWINDTASKBYTES_SIZE 0x2 +#define OMAP_ABE_D_PCURRENTTASK_ADDR 0x694 +#define OMAP_ABE_D_PCURRENTTASK_SIZE 0x2 +#define OMAP_ABE_D_PFASTLOOPBACK_ADDR 0x696 +#define OMAP_ABE_D_PFASTLOOPBACK_SIZE 0x2 +#define OMAP_ABE_D_PNEXTFASTLOOPBACK_ADDR 0x698 +#define OMAP_ABE_D_PNEXTFASTLOOPBACK_SIZE 0x4 +#define OMAP_ABE_D_PPCURRENTTASK_ADDR 0x69C +#define OMAP_ABE_D_PPCURRENTTASK_SIZE 0x2 +#define OMAP_ABE_D_SLOTCOUNTER_ADDR 0x6A0 +#define OMAP_ABE_D_SLOTCOUNTER_SIZE 0x2 +#define OMAP_ABE_D_LOOPCOUNTER_ADDR 0x6A4 +#define OMAP_ABE_D_LOOPCOUNTER_SIZE 0x4 +#define OMAP_ABE_D_REWINDFLAG_ADDR 0x6A8 +#define OMAP_ABE_D_REWINDFLAG_SIZE 0x2 +#define OMAP_ABE_D_SLOT23_CTRL_ADDR 0x6AC +#define OMAP_ABE_D_SLOT23_CTRL_SIZE 0x4 +#define OMAP_ABE_D_MCUIRQFIFO_ADDR 0x6B0 +#define OMAP_ABE_D_MCUIRQFIFO_SIZE 0x40 +#define OMAP_ABE_D_PINGPONGDESC_ADDR 0x6F0 +#define OMAP_ABE_D_PINGPONGDESC_SIZE 0x20 +#define OMAP_ABE_D_PP_MCU_IRQ_ADDR 0x710 +#define OMAP_ABE_D_PP_MCU_IRQ_SIZE 0x2 +#define OMAP_ABE_D_SRC44P1_MMDL_STRUCT_ADDR 0x714 +#define OMAP_ABE_D_SRC44P1_MMDL_STRUCT_SIZE 0x12 +#define OMAP_ABE_D_SRC44P1_TONES_STRUCT_ADDR 0x728 +#define OMAP_ABE_D_SRC44P1_TONES_STRUCT_SIZE 0x12 +#define OMAP_ABE_D_CTRLPORTFIFO_ADDR 0x740 +#define OMAP_ABE_D_CTRLPORTFIFO_SIZE 0x10 +#define OMAP_ABE_D_IDLE_STATE_ADDR 0x750 +#define OMAP_ABE_D_IDLE_STATE_SIZE 0x4 +#define OMAP_ABE_D_STOP_REQUEST_ADDR 0x754 +#define OMAP_ABE_D_STOP_REQUEST_SIZE 0x4 +#define OMAP_ABE_D_REF0_ADDR 0x758 +#define OMAP_ABE_D_REF0_SIZE 0x2 +#define OMAP_ABE_D_DEBUGREGISTER_ADDR 0x75C +#define OMAP_ABE_D_DEBUGREGISTER_SIZE 0x8C +#define OMAP_ABE_D_GCOUNT_ADDR 0x7E8 +#define OMAP_ABE_D_GCOUNT_SIZE 0x2 +#define OMAP_ABE_D_FASTCOUNTER_ADDR 0x7EC +#define OMAP_ABE_D_FASTCOUNTER_SIZE 0x4 +#define OMAP_ABE_D_SLOWCOUNTER_ADDR 0x7F0 +#define OMAP_ABE_D_SLOWCOUNTER_SIZE 0x4 +#define OMAP_ABE_D_AUPLINKROUTING_ADDR 0x7F4 +#define OMAP_ABE_D_AUPLINKROUTING_SIZE 0x20 +#define OMAP_ABE_D_VIRTAUDIOLOOP_ADDR 0x814 +#define OMAP_ABE_D_VIRTAUDIOLOOP_SIZE 0x4 +#define OMAP_ABE_D_ASRCVARS_DL_VX_ADDR 0x818 +#define OMAP_ABE_D_ASRCVARS_DL_VX_SIZE 0x20 +#define OMAP_ABE_D_ASRCVARS_UL_VX_ADDR 0x838 +#define OMAP_ABE_D_ASRCVARS_UL_VX_SIZE 0x20 +#define OMAP_ABE_D_COEFADDRESSES_VX_ADDR 0x858 +#define OMAP_ABE_D_COEFADDRESSES_VX_SIZE 0x20 +#define OMAP_ABE_D_ASRCVARS_MM_EXT_IN_ADDR 0x878 +#define OMAP_ABE_D_ASRCVARS_MM_EXT_IN_SIZE 0x20 +#define OMAP_ABE_D_COEFADDRESSES_MM_ADDR 0x898 +#define OMAP_ABE_D_COEFADDRESSES_MM_SIZE 0x20 +#define OMAP_ABE_D_TRACEBUFADR_ADDR 0x8B8 +#define OMAP_ABE_D_TRACEBUFADR_SIZE 0x2 +#define OMAP_ABE_D_TRACEBUFOFFSET_ADDR 0x8BA +#define OMAP_ABE_D_TRACEBUFOFFSET_SIZE 0x2 +#define OMAP_ABE_D_TRACEBUFLENGTH_ADDR 0x8BC +#define OMAP_ABE_D_TRACEBUFLENGTH_SIZE 0x2 +#define OMAP_ABE_D_MAXTASKBYTESINSLOT_SAVED_ADDR 0x8C0 +#define OMAP_ABE_D_MAXTASKBYTESINSLOT_SAVED_SIZE 0x4 +#define OMAP_ABE_D_PEMPTY_ADDR 0x8C4 +#define OMAP_ABE_D_PEMPTY_SIZE 0x50 +#define OMAP_ABE_D_ECHO_REF_48_16_WRAP_ADDR 0x914 +#define OMAP_ABE_D_ECHO_REF_48_16_WRAP_SIZE 0x8 +#define OMAP_ABE_D_ECHO_REF_48_8_WRAP_ADDR 0x91C +#define OMAP_ABE_D_ECHO_REF_48_8_WRAP_SIZE 0x8 +#define OMAP_ABE_D_BT_UL_16_48_WRAP_ADDR 0x924 +#define OMAP_ABE_D_BT_UL_16_48_WRAP_SIZE 0x8 +#define OMAP_ABE_D_BT_UL_8_48_WRAP_ADDR 0x92C +#define OMAP_ABE_D_BT_UL_8_48_WRAP_SIZE 0x8 +#define OMAP_ABE_D_BT_DL_48_16_WRAP_ADDR 0x934 +#define OMAP_ABE_D_BT_DL_48_16_WRAP_SIZE 0x8 +#define OMAP_ABE_D_BT_DL_48_8_WRAP_ADDR 0x93C +#define OMAP_ABE_D_BT_DL_48_8_WRAP_SIZE 0x8 +#define OMAP_ABE_D_VX_DL_16_48_WRAP_ADDR 0x944 +#define OMAP_ABE_D_VX_DL_16_48_WRAP_SIZE 0x8 +#define OMAP_ABE_D_VX_DL_8_48_WRAP_ADDR 0x94C +#define OMAP_ABE_D_VX_DL_8_48_WRAP_SIZE 0x8 +#define OMAP_ABE_D_VX_UL_48_16_WRAP_ADDR 0x954 +#define OMAP_ABE_D_VX_UL_48_16_WRAP_SIZE 0x8 +#define OMAP_ABE_D_VX_UL_48_8_WRAP_ADDR 0x95C +#define OMAP_ABE_D_VX_UL_48_8_WRAP_SIZE 0x8 +#define OMAP_ABE_D_ASRCVARS_BT_UL_ADDR 0x964 +#define OMAP_ABE_D_ASRCVARS_BT_UL_SIZE 0x20 +#define OMAP_ABE_D_ASRCVARS_BT_DL_ADDR 0x984 +#define OMAP_ABE_D_ASRCVARS_BT_DL_SIZE 0x20 +#define OMAP_ABE_D_BT_DL_48_8_OPP100_WRAP_ADDR 0x9A4 +#define OMAP_ABE_D_BT_DL_48_8_OPP100_WRAP_SIZE 0x8 +#define OMAP_ABE_D_BT_DL_48_16_OPP100_WRAP_ADDR 0x9AC +#define OMAP_ABE_D_BT_DL_48_16_OPP100_WRAP_SIZE 0x8 +#define OMAP_ABE_D_VX_DL_8_48_FIR_WRAP_ADDR 0x9B4 +#define OMAP_ABE_D_VX_DL_8_48_FIR_WRAP_SIZE 0x8 +#define OMAP_ABE_D_BT_UL_8_48_FIR_WRAP_ADDR 0x9BC +#define OMAP_ABE_D_BT_UL_8_48_FIR_WRAP_SIZE 0x8 +#define OMAP_ABE_D_TASKSLIST_ADDR 0x9C4 +#define OMAP_ABE_D_TASKSLIST_SIZE 0x880 +#define OMAP_ABE_D_HW_TEST_ADDR 0x1244 +#define OMAP_ABE_D_HW_TEST_SIZE 0x28 +#define OMAP_ABE_D_TRACEBUFADR_HAL_ADDR 0x126C +#define OMAP_ABE_D_TRACEBUFADR_HAL_SIZE 0x4 +#define OMAP_ABE_D_CHECK_LIST_SMEM_ADDR 0x1270 +#define OMAP_ABE_D_CHECK_LIST_SMEM_SIZE 0x80 +#define OMAP_ABE_D_CHECK_LIST_LEFT_IDX_ADDR 0x12F0 +#define OMAP_ABE_D_CHECK_LIST_LEFT_IDX_SIZE 0x2 +#define OMAP_ABE_D_CHECK_LIST_RIGHT_IDX_ADDR 0x12F2 +#define OMAP_ABE_D_CHECK_LIST_RIGHT_IDX_SIZE 0x2 +#define OMAP_ABE_D_BT_DL_48_8_FIR_WRAP_ADDR 0x12F4 +#define OMAP_ABE_D_BT_DL_48_8_FIR_WRAP_SIZE 0x8 +#define OMAP_ABE_D_BT_DL_48_8_FIR_OPP100_WRAP_ADDR 0x12FC +#define OMAP_ABE_D_BT_DL_48_8_FIR_OPP100_WRAP_SIZE 0x8 +#define OMAP_ABE_D_VX_UL_48_8_FIR_WRAP_ADDR 0x1304 +#define OMAP_ABE_D_VX_UL_48_8_FIR_WRAP_SIZE 0x8 +#define OMAP_ABE_D_DEBUG_FW_TASK_ADDR 0x1400 +#define OMAP_ABE_D_DEBUG_FW_TASK_SIZE 0x100 +#define OMAP_ABE_D_DEBUG_FIFO_ADDR 0x1500 +#define OMAP_ABE_D_DEBUG_FIFO_SIZE 0x60 +#define OMAP_ABE_D_DEBUG_FIFO_HAL_ADDR 0x1560 +#define OMAP_ABE_D_DEBUG_FIFO_HAL_SIZE 0x20 +#define OMAP_ABE_D_FWMEMINIT_ADDR 0x1580 +#define OMAP_ABE_D_FWMEMINIT_SIZE 0x3C0 +#define OMAP_ABE_D_FWMEMINITDESCR_ADDR 0x1940 +#define OMAP_ABE_D_FWMEMINITDESCR_SIZE 0x10 +#define OMAP_ABE_D_BT_DL_FIFO_ADDR 0x1C00 +#define OMAP_ABE_D_BT_DL_FIFO_SIZE 0x1E0 +#define OMAP_ABE_D_BT_UL_FIFO_ADDR 0x1E00 +#define OMAP_ABE_D_BT_UL_FIFO_SIZE 0x1E0 +#define OMAP_ABE_D_MM_EXT_OUT_FIFO_ADDR 0x2000 +#define OMAP_ABE_D_MM_EXT_OUT_FIFO_SIZE 0x1E0 +#define OMAP_ABE_D_MM_EXT_IN_FIFO_ADDR 0x2200 +#define OMAP_ABE_D_MM_EXT_IN_FIFO_SIZE 0x1E0 +#define OMAP_ABE_D_MM_UL2_FIFO_ADDR 0x2400 +#define OMAP_ABE_D_MM_UL2_FIFO_SIZE 0x1E0 +#define OMAP_ABE_D_DMIC_UL_FIFO_ADDR 0x2600 +#define OMAP_ABE_D_DMIC_UL_FIFO_SIZE 0x1E0 +#define OMAP_ABE_D_MM_UL_FIFO_ADDR 0x2800 +#define OMAP_ABE_D_MM_UL_FIFO_SIZE 0x1E0 +#define OMAP_ABE_D_MM_DL_FIFO_ADDR 0x2A00 +#define OMAP_ABE_D_MM_DL_FIFO_SIZE 0x1E0 +#define OMAP_ABE_D_TONES_DL_FIFO_ADDR 0x2C00 +#define OMAP_ABE_D_TONES_DL_FIFO_SIZE 0x1E0 +#define OMAP_ABE_D_VIB_DL_FIFO_ADDR 0x2E00 +#define OMAP_ABE_D_VIB_DL_FIFO_SIZE 0x1E0 +#define OMAP_ABE_D_DEBUG_HAL_TASK_ADDR 0x3000 +#define OMAP_ABE_D_DEBUG_HAL_TASK_SIZE 0x800 +#define OMAP_ABE_D_MCPDM_DL_FIFO_ADDR 0x3800 +#define OMAP_ABE_D_MCPDM_DL_FIFO_SIZE 0x1E0 +#define OMAP_ABE_D_MCPDM_UL_FIFO_ADDR 0x3A00 +#define OMAP_ABE_D_MCPDM_UL_FIFO_SIZE 0x1E0 +#define OMAP_ABE_D_VX_UL_FIFO_ADDR 0x3C00 +#define OMAP_ABE_D_VX_UL_FIFO_SIZE 0x1E0 +#define OMAP_ABE_D_VX_DL_FIFO_ADDR 0x3E00 +#define OMAP_ABE_D_VX_DL_FIFO_SIZE 0x1E0 +#define OMAP_ABE_D_PING_ADDR 0x4000 +#define OMAP_ABE_D_PING_SIZE 0x6000 +#define OMAP_ABE_D_PONG_ADDR 0xA000 +#define OMAP_ABE_D_PONG_SIZE 0x6000 diff --git a/sound/soc/omap/abe/abe_ext.h b/sound/soc/omap/abe/abe_ext.h new file mode 100644 index 0000000..8fb1aac --- /dev/null +++ b/sound/soc/omap/abe/abe_ext.h @@ -0,0 +1,242 @@ +/* + + This file is provided under a dual BSD/GPLv2 license. When using or + redistributing this file, you may do so under either license. + + GPL LICENSE SUMMARY + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License 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. + The full GNU General Public License is included in this distribution + in the file called LICENSE.GPL. + + BSD LICENSE + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name of Texas Instruments Incorporated nor the names of + its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef _ABE_EXT_H_ +#define _ABE_EXT_H_ + +/* + * OS DEPENDENT MMU CONFIGURATION + */ +#define ABE_PMEM_BASE_OFFSET_MPU 0xe0000 +#define ABE_CMEM_BASE_OFFSET_MPU 0xa0000 +#define ABE_SMEM_BASE_OFFSET_MPU 0xc0000 +#define ABE_DMEM_BASE_OFFSET_MPU 0x80000 +#define ABE_ATC_BASE_OFFSET_MPU 0xf1000 +/* default base address for io_base */ +#define ABE_DEFAULT_BASE_ADDRESS_L3 0x49000000L +#define ABE_DEFAULT_BASE_ADDRESS_L4 0x40100000L +#define ABE_DEFAULT_BASE_ADDRESS_DEFAULT ABE_DEFAULT_BASE_ADDRESS_L3 +/* + * HARDWARE AND PERIPHERAL DEFINITIONS + */ +/* PMEM SIZE in bytes (1024 words of 64 bits: : #32bits words x 4)*/ +#define ABE_PMEM_SIZE 8192 +/* CMEM SIZE in bytes (2048 coeff : #32bits words x 4)*/ +#define ABE_CMEM_SIZE 8192 +/* SMEM SIZE in bytes (3072 stereo samples : #32bits words x 4)*/ +#define ABE_SMEM_SIZE 24576 +/* DMEM SIZE in bytes */ +#define ABE_DMEM_SIZE 65536L +/* ATC REGISTERS SIZE in bytes */ +#define ABE_ATC_DESC_SIZE 512 +/* holds the MCU Irq signal */ +#define ABE_MCU_IRQSTATUS_RAW 0x24 +/* status : clear the IRQ */ +#define ABE_MCU_IRQSTATUS 0x28 +/* holds the DSP Irq signal */ +#define ABE_DSP_IRQSTATUS_RAW 0x4C +/* holds the DMA req lines to the sDMA */ +#define ABE_DMASTATUS_RAW 0x84 +#define EVENT_GENERATOR_COUNTER 0x68 +/* PLL output/desired sampling rate = (32768 * 6000)/96000 */ +#define EVENT_GENERATOR_COUNTER_DEFAULT (2048-1) +/* PLL output/desired sampling rate = (32768 * 6000)/88200 */ +#define EVENT_GENERATOR_COUNTER_44100 (2228-1) +/* start / stop the EVENT generator */ +#define EVENT_GENERATOR_START 0x6C +#define EVENT_GENERATOR_ON 1 +#define EVENT_GENERATOR_OFF 0 +/* selection of the EVENT generator source */ +#define EVENT_SOURCE_SELECTION 0x70 +#define EVENT_SOURCE_DMA 0 +#define EVENT_SOURCE_COUNTER 1 +/* selection of the ABE DMA req line from ATC */ +#define AUDIO_ENGINE_SCHEDULER 0x74 +#define ABE_ATC_DMIC_DMA_REQ 1 +#define ABE_ATC_MCPDMDL_DMA_REQ 2 +#define ABE_ATC_MCPDMUL_DMA_REQ 3 +/* Direction=0 means input from ABE point of view */ +#define ABE_ATC_DIRECTION_IN 0 +/* Direction=1 means output from ABE point of view */ +#define ABE_ATC_DIRECTION_OUT 1 +/* + * DMA requests + */ +/*Internal connection doesn't connect at ABE boundary */ +#define External_DMA_0 0 +/*Transmit request digital microphone */ +#define DMIC_DMA_REQ 1 +/*Multichannel PDM downlink */ +#define McPDM_DMA_DL 2 +/*Multichannel PDM uplink */ +#define McPDM_DMA_UP 3 +/*MCBSP module 1 - transmit request */ +#define MCBSP1_DMA_TX 4 +/*MCBSP module 1 - receive request */ +#define MCBSP1_DMA_RX 5 +/*MCBSP module 2 - transmit request */ +#define MCBSP2_DMA_TX 6 +/*MCBSP module 2 - receive request */ +#define MCBSP2_DMA_RX 7 +/*MCBSP module 3 - transmit request */ +#define MCBSP3_DMA_TX 8 +/*MCBSP module 3 - receive request */ +#define MCBSP3_DMA_RX 9 +/*SLIMBUS module 1 - transmit request channel 0 */ +#define SLIMBUS1_DMA_TX0 10 +/*SLIMBUS module 1 - transmit request channel 1 */ +#define SLIMBUS1_DMA_TX1 11 +/*SLIMBUS module 1 - transmit request channel 2 */ +#define SLIMBUS1_DMA_TX2 12 +/*SLIMBUS module 1 - transmit request channel 3 */ +#define SLIMBUS1_DMA_TX3 13 +/*SLIMBUS module 1 - transmit request channel 4 */ +#define SLIMBUS1_DMA_TX4 14 +/*SLIMBUS module 1 - transmit request channel 5 */ +#define SLIMBUS1_DMA_TX5 15 +/*SLIMBUS module 1 - transmit request channel 6 */ +#define SLIMBUS1_DMA_TX6 16 +/*SLIMBUS module 1 - transmit request channel 7 */ +#define SLIMBUS1_DMA_TX7 17 +/*SLIMBUS module 1 - receive request channel 0 */ +#define SLIMBUS1_DMA_RX0 18 +/*SLIMBUS module 1 - receive request channel 1 */ +#define SLIMBUS1_DMA_RX1 19 +/*SLIMBUS module 1 - receive request channel 2 */ +#define SLIMBUS1_DMA_RX2 20 +/*SLIMBUS module 1 - receive request channel 3 */ +#define SLIMBUS1_DMA_RX3 21 +/*SLIMBUS module 1 - receive request channel 4 */ +#define SLIMBUS1_DMA_RX4 22 +/*SLIMBUS module 1 - receive request channel 5 */ +#define SLIMBUS1_DMA_RX5 23 +/*SLIMBUS module 1 - receive request channel 6 */ +#define SLIMBUS1_DMA_RX6 24 +/*SLIMBUS module 1 - receive request channel 7 */ +#define SLIMBUS1_DMA_RX7 25 +/*McASP - Data transmit DMA request line */ +#define McASP1_AXEVT 26 +/*McASP - Data receive DMA request line */ +#define McASP1_AREVT 29 +/*DUMMY FIFO @@@ */ +#define _DUMMY_FIFO_ 30 +/*DMA of the Circular buffer peripheral 0 */ +#define CBPr_DMA_RTX0 32 +/*DMA of the Circular buffer peripheral 1 */ +#define CBPr_DMA_RTX1 33 +/*DMA of the Circular buffer peripheral 2 */ +#define CBPr_DMA_RTX2 34 +/*DMA of the Circular buffer peripheral 3 */ +#define CBPr_DMA_RTX3 35 +/*DMA of the Circular buffer peripheral 4 */ +#define CBPr_DMA_RTX4 36 +/*DMA of the Circular buffer peripheral 5 */ +#define CBPr_DMA_RTX5 37 +/*DMA of the Circular buffer peripheral 6 */ +#define CBPr_DMA_RTX6 38 +/*DMA of the Circular buffer peripheral 7 */ +#define CBPr_DMA_RTX7 39 +/* + * ATC DESCRIPTORS - DESTINATIONS + */ +#define DEST_DMEM_access 0x00 +#define DEST_MCBSP1_ TX 0x01 +#define DEST_MCBSP2_ TX 0x02 +#define DEST_MCBSP3_TX 0x03 +#define DEST_SLIMBUS1_TX0 0x04 +#define DEST_SLIMBUS1_TX1 0x05 +#define DEST_SLIMBUS1_TX2 0x06 +#define DEST_SLIMBUS1_TX3 0x07 +#define DEST_SLIMBUS1_TX4 0x08 +#define DEST_SLIMBUS1_TX5 0x09 +#define DEST_SLIMBUS1_TX6 0x0A +#define DEST_SLIMBUS1_TX7 0x0B +#define DEST_MCPDM_DL 0x0C +#define DEST_MCASP_TX0 0x0D +#define DEST_MCASP_TX1 0x0E +#define DEST_MCASP_TX2 0x0F +#define DEST_MCASP_TX3 0x10 +#define DEST_EXTPORT0 0x11 +#define DEST_EXTPORT1 0x12 +#define DEST_EXTPORT2 0x13 +#define DEST_EXTPORT3 0x14 +#define DEST_MCPDM_ON 0x15 +#define DEST_CBP_CBPr 0x3F +/* + * ATC DESCRIPTORS - SOURCES + */ +#define SRC_DMEM_access 0x0 +#define SRC_MCBSP1_ RX 0x01 +#define SRC_MCBSP2_RX 0x02 +#define SRC_MCBSP3_RX 0x03 +#define SRC_SLIMBUS1_RX0 0x04 +#define SRC_SLIMBUS1_RX1 0x05 +#define SRC_SLIMBUS1_RX2 0x06 +#define SRC_SLIMBUS1_RX3 0x07 +#define SRC_SLIMBUS1_RX4 0x08 +#define SRC_SLIMBUS1_RX5 0x09 +#define SRC_SLIMBUS1_RX6 0x0A +#define SRC_SLIMBUS1_RX7 0x0B +#define SRC_DMIC_UP 0x0C +#define SRC_MCPDM_UP 0x0D +#define SRC_MCASP_RX0 0x0E +#define SRC_MCASP_RX1 0x0F +#define SRC_MCASP_RX2 0x10 +#define SRC_MCASP_RX3 0x11 +#define SRC_CBP_CBPr 0x3F +#endif/* _ABE_EXT_H_ */ diff --git a/sound/soc/omap/abe/abe_firmware.c b/sound/soc/omap/abe/abe_firmware.c new file mode 100644 index 0000000..1676f3c --- /dev/null +++ b/sound/soc/omap/abe/abe_firmware.c @@ -0,0 +1,14355 @@ +0xabeabe00, +0x00000000, +0x0000d2a4, +0x00000d8c, +0x00000001, +0x00009495, +0x00000006, +0x20314c44, +0x61757145, +0x657a696c, +0x00000072, +0x00000000, +0x00000005, +0x00000019, +0x74616c46, +0x73657220, +0x736e6f70, +0x00000065, +0x00000000, +0x68676948, +0x7361702d, +0x64302073, +0x00000042, +0x00000000, +0x68676948, +0x7361702d, +0x312d2073, +0x00426432, +0x00000000, +0x68676948, +0x7361702d, +0x322d2073, +0x00426430, +0x00000000, +0x7a684b34, +0x46504c20, +0x30202020, +0x00004264, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x20324c44, +0x7466654c, +0x75714520, +0x7a696c61, +0x00007265, +0x00000005, +0x00000019, +0x74616c46, +0x73657220, +0x736e6f70, +0x00000065, +0x00000000, +0x68676948, +0x7361702d, +0x64302073, +0x00000042, +0x00000000, +0x68676948, +0x7361702d, +0x312d2073, +0x00426432, +0x00000000, +0x68676948, +0x7361702d, +0x322d2073, +0x00426430, +0x00000000, +0x48303534, +0x6948207a, +0x702d6867, +0x00737361, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x20324c44, +0x68676952, +0x71452074, +0x696c6175, +0x0072657a, +0x00000005, +0x00000019, +0x74616c46, +0x73657220, +0x736e6f70, +0x00000065, +0x00000000, +0x68676948, +0x7361702d, +0x64302073, +0x00000042, +0x00000000, +0x68676948, +0x7361702d, +0x312d2073, +0x00426432, +0x00000000, +0x68676948, +0x7361702d, +0x322d2073, +0x00426430, +0x00000000, +0x48303534, +0x6948207a, +0x702d6867, +0x00737361, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x65646953, +0x656e6f74, +0x75714520, +0x7a696c61, +0x00007265, +0x00000004, +0x00000009, +0x74616c46, +0x73657220, +0x736e6f70, +0x00000065, +0x00000000, +0x68676948, +0x7361702d, +0x64302073, +0x00000042, +0x00000000, +0x68676948, +0x7361702d, +0x312d2073, +0x00426432, +0x00000000, +0x68676948, +0x7361702d, +0x312d2073, +0x00426438, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x43494d41, +0x75714520, +0x7a696c61, +0x00007265, +0x00000000, +0x00000003, +0x00000013, +0x68676948, +0x7361702d, +0x64302073, +0x00000042, +0x00000000, +0x68676948, +0x7361702d, +0x312d2073, +0x00426432, +0x00000000, +0x68676948, +0x7361702d, +0x312d2073, +0x00426438, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x43494d44, +0x75714520, +0x7a696c61, +0x00007265, +0x00000000, +0x00000003, +0x00000013, +0x68676948, +0x7361702d, +0x64302073, +0x00000042, +0x00000000, +0x68676948, +0x7361702d, +0x312d2073, +0x00426432, +0x00000000, +0x68676948, +0x7361702d, +0x312d2073, +0x00426438, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00040002, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0xff8cbb51, +0x000ace72, +0xfff53192, +0x007344b1, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x0067cd91, +0xfff596e6, +0x000b29a2, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0xffc65da8, +0x00567385, +0xffa98c7d, +0x0039a258, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x0067cd91, +0xfff596e6, +0x000b29a2, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0xffe8f244, +0x00452938, +0xffbad6c8, +0x00170dbc, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x0067cd91, +0xfff596e6, +0x000b29a2, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x0002e630, +0x0008b290, +0x0008b290, +0x0002e630, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x0058ae58, +0xfffa666a, +0x0007da1e, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00040002, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0xff8cbb51, +0x000ace72, +0xfff53192, +0x007344b1, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x0067cd91, +0xfff596e6, +0x000b29a2, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0xffc65da8, +0x00567385, +0xffa98c7d, +0x0039a258, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x0067cd91, +0xfff596e6, +0x000b29a2, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0xffe8f244, +0x00452938, +0xffbad6c8, +0x00170dbc, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x0067cd91, +0xfff596e6, +0x000b29a2, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x007ac72d, +0xfff8538e, +0x007ac72d, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0xff8a3b19, +0x0007aac2, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00040002, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0xff8cbb51, +0x000ace72, +0xfff53192, +0x007344b1, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x0067cd91, +0xfff596e6, +0x000b29a2, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0xffc65da8, +0x00567385, +0xffa98c7d, +0x0039a258, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x0067cd91, +0xfff596e6, +0x000b29a2, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0xffe8f244, +0x00452938, +0xffbad6c8, +0x00170dbc, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x0067cd91, +0xfff596e6, +0x000b29a2, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x007ac72d, +0xfff8538e, +0x007ac72d, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0xff8a3b19, +0x0007aac2, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00040002, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0xff8cbb51, +0x000ace72, +0xfff53192, +0x007344b1, +0x00000000, +0x0067cd91, +0xfff596e6, +0x000b29a2, +0x00000000, +0xffc65da8, +0x00567385, +0xffa98c7d, +0x0039a258, +0x00000000, +0x0067cd91, +0xfff596e6, +0x000b29a2, +0x00000000, +0xffe8f244, +0x00452938, +0xffbad6c8, +0x00170dbc, +0x00000000, +0x0067cd91, +0xfff596e6, +0x000b29a2, +0xffc1248b, +0xfffd1080, +0xfffaca4c, +0xfffab048, +0xfffdb0ac, +0x00024f54, +0x00054fb8, +0x000535b4, +0x0002ef80, +0x003edb7b, +0x001d92ec, +0xff962b59, +0x000bd422, +0xffe48132, +0x002dbdc2, +0xffc7a94a, +0x0033fbe6, +0xffdd3502, +0x000fea26, +0xfff0490f, +0xffd10817, +0xffaca4df, +0xffab0493, +0xffdb0acb, +0x0024f537, +0x0054fb6f, +0x00535b23, +0x002ef7eb, +0x000fb6f3, +0x001d930c, +0xff962afd, +0x000bd42a, +0xffe48122, +0x002dbdda, +0xffc7a932, +0x0033fbf6, +0xffdd34fa, +0x000fea26, +0xfff82487, +0xffe8840b, +0xffd6526f, +0xffd5824b, +0xffed8567, +0x00127a9b, +0x002a7db7, +0x0029ad93, +0x00177bf7, +0x0007db7b, +0x001d930c, +0xff962afd, +0x000bd42a, +0xffe48122, +0x002dbdda, +0xffc7a932, +0x0033fbf6, +0xffdd34fa, +0x000fea26, +0xffc1248b, +0xfffd1080, +0xfffaca4c, +0xfffab048, +0xfffdb0ac, +0x00024f54, +0x00054fb8, +0x000535b4, +0x0002ef80, +0x003edb7b, +0x001d92ec, +0xff962b59, +0x000bd422, +0xffe48132, +0x002dbdc2, +0xffc7a94a, +0x0033fbe6, +0xffdd3502, +0x000fea26, +0xfff0490f, +0xffd10817, +0xffaca4df, +0xffab0493, +0xffdb0acb, +0x0024f537, +0x0054fb6f, +0x00535b23, +0x002ef7eb, +0x000fb6f3, +0x001d930c, +0xff962afd, +0x000bd42a, +0xffe48122, +0x002dbdda, +0xffc7a932, +0x0033fbf6, +0xffdd34fa, +0x000fea26, +0xfff82487, +0xffe8840b, +0xffd6526f, +0xffd5824b, +0xffed8567, +0x00127a9b, +0x002a7db7, +0x0029ad93, +0x00177bf7, +0x0007db7b, +0x001d930c, +0xff962afd, +0x000bd42a, +0xffe48122, +0x002dbdda, +0xffc7a932, +0x0033fbf6, +0xffdd34fa, +0x000fea26, +0x00009495, +0x00002000, +0x00001d80, +0x00004000, +0x00005510, +0x1600200f, +0x0a000960, +0x08200000, +0x08200000, +0x07800000, +0x160075ce, +0x014000e0, +0x014000e1, +0x014000e2, +0x014000e3, +0x014000e4, +0x014000e5, +0x014000e6, +0x014000e7, +0x014000e8, +0x014000e9, +0x014000ea, +0x014000eb, +0x014000ec, +0x014000ed, +0x014000ef, +0x014000ef, +0x144000e4, +0x9e000000, +0x0a200e30, +0x9e000040, +0x0a200e30, +0x9e000080, +0x0a200e30, +0x9e0000c0, +0x0a200e30, +0x9e080000, +0x0a200e30, +0x9e080100, +0x0a200e30, +0x9e080200, +0x0a200e30, +0x9e080300, +0x0a200e30, +0x9e080400, +0x0a200e30, +0x9e080500, +0x0a200e30, +0x9e080600, +0x0a200e30, +0x9e080700, +0x0a200e30, +0x9c050800, +0x0a200e30, +0x16000010, +0x16000001, +0x17000102, +0x01400042, +0x17800103, +0x01400043, +0x98020000, +0x160003c6, +0x07800000, +0x07800000, +0x9c03b660, +0x0a0003f0, +0x9d0c8118, +0x07800000, +0x9c0c07b0, +0x9f16001a, +0x9f12021a, +0x9f12031a, +0x9f12051a, +0x9f092020, +0x9f082030, +0x9c0c07b0, +0x9f092060, +0x9f082070, +0x988003d0, +0x07800000, +0x9d0c8118, +0x08200000, +0x160003c6, +0x07800000, +0x07800000, +0x9c03b660, +0x0a000540, +0x9d0c8158, +0x07800000, +0x9c0c07b0, +0x9f16001a, +0x9f12021a, +0x9f12031a, +0x9f12051a, +0x9f040040, +0x9c0c07b0, +0x9f03fc10, +0x07800000, +0x9f092060, +0x9f082070, +0x07800000, +0x98800520, +0x07800000, +0x9d0c8158, +0x08200000, +0x160003c6, +0x07800000, +0x07800000, +0x9c03b660, +0x0a0006b0, +0x9d0c8118, +0x07800000, +0x9c0c07b0, +0x9f15001a, +0x9f11041a, +0x9f092020, +0x9f082030, +0x9c0c07b0, +0x9f092060, +0x9f082070, +0x98800690, +0x07800000, +0x9d0c8118, +0x08200000, +0x400002c0, +0x048002ff, +0x000000c5, +0x000004c6, +0x9c028000, +0x400006c7, +0x12000155, +0x013ffefe, +0xc00008c4, +0x1e080000, +0x020005de, +0x00000ac3, +0xdc02b160, +0x04c3ff2d, +0xdc01ba70, +0x128002dd, +0xdc02a440, +0x048fffdd, +0x9c061830, +0x0b200000, +0x003ffefe, +0x000002c4, +0x400004c5, +0x048ffeff, +0x000006c6, +0x000008c7, +0x9d02a040, +0x9d02a950, +0x9d01b260, +0x9d02bc70, +0x08200000, +0x16006906, +0x00000068, +0x16008c05, +0x01000058, +0x160069ca, +0x000000a9, +0x16008c06, +0x00000068, +0x0400089b, +0x4000009c, +0x1600694e, +0x410000ec, +0x0600000c, +0x160130cd, +0x0a800a60, +0x0a200770, +0x04800299, +0x410000a9, +0x05c00b90, +0x4ac009f0, +0x04a01085, +0x16006a04, +0x40000047, +0x16006a8e, +0x04200599, +0x400000e1, +0x04800177, +0x010000a9, +0x41000047, +0x04a00111, +0x410000e1, +0x06000001, +0x4aa00c40, +0x16006a4d, +0x400000d6, +0x16004fc9, +0x400002d7, +0x04800166, +0x410000a9, +0x04900077, +0x010000d6, +0x010002d7, +0x16006906, +0x00000068, +0x16008c05, +0x01000058, +0x1600c005, +0x16007541, +0x16000002, +0x40000011, +0x16007500, +0x9e0e0550, +0xdd140530, +0x160ffff4, +0x41000002, +0x06000001, +0x08400000, +0x01000004, +0x9d140550, +0x0a8009a0, +0x0a000c40, +0x048006ff, +0x013ffafb, +0x013ffcfc, +0x413ffefe, +0x04a0020b, +0x004002bc, +0x0600000c, +0x160130cd, +0x0a800de0, +0x0a200770, +0x0a000d80, +0x003ffefe, +0x003ffcfc, +0x003ffafb, +0x048ffaff, +0x08200000, +0x07800000, +0x01400040, +0x01400041, +0x01400042, +0x01400043, +0x08200000, +0x160004a4, +0x160004b5, +0x160004c6, +0x16000007, +0x9c032040, +0x9c032950, +0x9c033260, +0x9e0f0070, +0x9e0f0170, +0x9e0f0270, +0x9d032040, +0x9d032950, +0x9d033260, +0x08200000, +0x9f158048, +0x9c0c07b0, +0x9f092020, +0x9f082030, +0x9c0c07b0, +0x9f092060, +0x9f082070, +0x07800000, +0x07800000, +0x9d088118, +0x98800f70, +0x08200000, +0x9f158048, +0x9f040040, +0x9c0c07b0, +0x9f03fc10, +0x07800000, +0x9f092020, +0x9f082030, +0x9c0c07b0, +0x9f092060, +0x9f082070, +0x07800000, +0x07800000, +0x9d188148, +0x98801030, +0x08200000, +0x9f158048, +0x9c0c07b0, +0x9f092060, +0x9f082070, +0x9c0c07b0, +0x9f092020, +0x9f082030, +0x07800000, +0x9d188148, +0x9d188108, +0x98801120, +0x08200000, +0x9f158048, +0x9c0c07b0, +0x9f092060, +0x9f082070, +0x9c0c07b0, +0x9f092020, +0x9f082030, +0x07800000, +0x9d1e8148, +0x9d1e8108, +0x988011e0, +0x08200000, +0x9f158018, +0x9f040010, +0x9c0c07b0, +0x9f03fc10, +0x9f092020, +0x9f082030, +0x9c0c07b0, +0x9f092060, +0x9f082070, +0x9d1e8108, +0x988012a0, +0x08200000, +0x9c080048, +0x9f1d0010, +0x07800000, +0x07800000, +0x9d0c8118, +0x98801360, +0x08200000, +0x9c180028, +0x9f1d0010, +0x07800000, +0x07800000, +0x9d0c8108, +0x988013d0, +0x08200000, +0x9c180068, +0x9c180028, +0x9f1d0010, +0x07800000, +0x07800000, +0x9d0c8148, +0x98801440, +0x08200000, +0x9c1e0048, +0x9c1e0008, +0x9f1d0010, +0x07800000, +0x07800000, +0x9d0c8148, +0x988014c0, +0x08200000, +0x9c1e0008, +0x9f1d0010, +0x07800000, +0x07800000, +0x9d0c8108, +0x98801540, +0x08200000, +0x160004a4, +0x160004b5, +0x160004c6, +0x160000bd, +0x9c032340, +0x9c032c50, +0x9c033560, +0x9c180028, +0x9c180068, +0x9f1d0010, +0x9c1800a8, +0x9c1800e8, +0x9f1d00b0, +0x07800000, +0x9d0c8318, +0x9d0c84b8, +0x9c180028, +0x9c180068, +0x9f1d0010, +0x07800000, +0x07800000, +0x9d0c8518, +0x98801620, +0x9d032340, +0x9d032c50, +0x9d033560, +0x08200000, +0x160003c2, +0x16000504, +0x16000515, +0x16000526, +0x9c011720, +0x9c03a440, +0x9c03ad50, +0x9c03b660, +0x160000bd, +0x9f158418, +0x9c0c02b0, +0x9f091020, +0x9f081030, +0x9c0c02b0, +0x9f091060, +0x9f081070, +0x07800000, +0x9d180108, +0x9d180148, +0x9f158518, +0x9c0c02b0, +0x9f091020, +0x9f081030, +0x9c0c02b0, +0x9f091060, +0x9f081070, +0x07800000, +0x9d180108, +0x9d180148, +0x9c0c0618, +0x07800000, +0x07800000, +0x9d180108, +0x9d180148, +0x988017f0, +0x9d032440, +0x9d032d50, +0x9d033660, +0x08200000, +0x1600000d, +0x9e0f00d0, +0x00800e0d, +0x9f158038, +0x07800000, +0x04a002dd, +0x9d188108, +0x9f158038, +0x07800000, +0x98801a30, +0x9d188108, +0x08200000, +0x9e088100, +0x07800000, +0x07800000, +0x12800277, +0x04c0ff77, +0x04a00174, +0x12800266, +0x04c0ff66, +0x04000645, +0x060ffff4, +0x17000454, +0x12000244, +0x9e0f0140, +0x07800000, +0x07800000, +0x9c0c0118, +0x07800000, +0x07800000, +0x9d0c8118, +0x98801bb0, +0x08200000, +0x08200000, +0x08200000, +0x08200000, +0x9c038600, +0x07800000, +0x07800000, +0x9c180770, +0xdc100348, +0x160fff05, +0x9f000810, +0x9f118412, +0x9f001010, +0x9f002810, +0x9c0c00b8, +0x160ffd80, +0x9d0c8410, +0x9f1d8012, +0x9f001810, +0x9f0400d0, +0x9c0c0210, +0x16000204, +0xdd0e00b0, +0x16000005, +0x9f1d80b2, +0x9f0000b0, +0x9f0020b0, +0x9f0400d0, +0x05800560, +0x0a801dd0, +0x9c0c0510, +0x0a001de0, +0x9c0c0618, +0x16000014, +0x9d0c81e8, +0x9d0c8148, +0x0a801e50, +0x9c0c05b0, +0x9c0c0510, +0x0a001e70, +0x9c0c06b8, +0x9c0c0618, +0x07800000, +0x9d0c81e8, +0x9d0c8148, +0x98801c50, +0x9d180750, +0x08200000, +0x9d019220, +0x048002ff, +0x14400004, +0x413ffefe, +0x16000040, +0x9c010910, +0x0a203df0, +0x14400040, +0x9c030810, +0x16000171, +0x9c009f30, +0x9c019220, +0x0a2038f0, +0x003ffefe, +0x9c009830, +0x048ffeff, +0x08200000, +0x08200000, +0x08200000, +0x08200000, +0x08200000, +0x40000024, +0x048002ff, +0x41000224, +0x16000005, +0x413ffefe, +0x04000400, +0x9e0f0150, +0x01000025, +0x0a202390, +0x403ffefe, +0x16000007, +0x9e0f0170, +0x048ffeff, +0x08200000, +0x40000024, +0x048002ff, +0x41000224, +0x16000005, +0x413ffefe, +0x16000016, +0x41800dc6, +0x04000400, +0x9e0f0150, +0x01000025, +0x0a202cd0, +0x403ffefe, +0x16000007, +0x9e0f0170, +0x048ffeff, +0x08200000, +0x048002ff, +0x413ffefe, +0x16000005, +0x01000025, +0x0a202390, +0x40000024, +0x16000005, +0x403ffefe, +0x04200454, +0x41000224, +0x048ffeff, +0x08200000, +0x048002ff, +0x413ffefe, +0x16000005, +0x01000025, +0x01800dc5, +0x0a202cd0, +0x40000024, +0x16000005, +0x403ffefe, +0x04200454, +0x41000224, +0x048ffeff, +0x08200000, +0x048008ff, +0x413ff8f8, +0x1440000d, +0x9c038e10, +0x413ffaf9, +0x04a001dd, +0x413ffcfa, +0x16000001, +0x413ffefb, +0x160000f0, +0x9c100400, +0x9c100480, +0x9c1d06c4, +0x9f085030, +0x9c180674, +0x9c180650, +0x058001a0, +0x0aa02890, +0x04800144, +0x04400044, +0x05800040, +0x0aa025d0, +0x05800160, +0x0ac02570, +0x9e090000, +0x07800000, +0x07800000, +0x9e0d0500, +0x9d040508, +0x0a002760, +0x9d040008, +0x9e090000, +0x07800000, +0x9d040008, +0x9e0d0500, +0x0a002760, +0x9d040008, +0x9e090000, +0x07800000, +0x07800000, +0x9e0d0500, +0x1280010a, +0x048001a9, +0x05800940, +0x0aa02760, +0x05800160, +0x40000628, +0x160ffff9, +0x0ac026f0, +0x05800180, +0x0ae02760, +0x160ffff6, +0x160ffff7, +0x0a002730, +0x05800810, +0x0ae02760, +0x16000016, +0x16000007, +0x9d044690, +0x04a00144, +0x9d180674, +0x05800160, +0x9d180654, +0x0ac027d0, +0x0420040a, +0x04a001ab, +0x4a002800, +0x044000bb, +0x0480014b, +0x044000bb, +0x1440004a, +0x120001aa, +0x42000a38, +0x120001bb, +0x42000b39, +0x12000288, +0x12000299, +0x9e0e8280, +0xca0029a0, +0x1e0e8390, +0xdd040604, +0x05800160, +0x0ac02940, +0x9d040008, +0x9e090000, +0x07800000, +0x05800040, +0x9e0d0500, +0x0aa029a0, +0x9d040508, +0x0a0029a0, +0x9e090000, +0x05800040, +0x9d040008, +0x9e0d0500, +0x0a8029a0, +0x9d040508, +0x9c1d06c4, +0xdc1d0644, +0x1f0400b0, +0x9c100700, +0xdc1d06c4, +0x1f040010, +0x9d108480, +0x9f0940b0, +0x9d108700, +0x00000cc9, +0x06000008, +0x0aa02ba0, +0xdc1d0684, +0x14400005, +0xdc1d0604, +0x160fff8a, +0x04a00255, +0xdd108480, +0x16000017, +0xdd108700, +0x160ffff8, +0x05800540, +0x0aa02b60, +0x05800160, +0x0ac02b50, +0x01000027, +0x0a002b60, +0x01000028, +0x9e088000, +0xa0054dba, +0xa005c81a, +0x0a002c30, +0x9e088000, +0xa0054dba, +0xa005c81a, +0x160fffaa, +0x9f1f80b0, +0x9f1e0010, +0x9f040020, +0x9f040070, +0x9f020810, +0x9d0446a0, +0x9e0f0070, +0x9d0c8118, +0x98802430, +0x003ffefb, +0x003ffcfa, +0x003ffaf9, +0x003ff8f8, +0x048ff8ff, +0x08200000, +0x048008ff, +0x413ff8f8, +0x1440000d, +0x9c038e10, +0x413ffaf9, +0x04a001dd, +0x413ffcfa, +0x16000001, +0x413ffefb, +0x04a00100, +0x9c100400, +0x9c100480, +0x9c1d06c4, +0x9f085030, +0x9c180674, +0x9c180650, +0x058001a0, +0x4aa03200, +0x160000f7, +0x04800144, +0x04400744, +0x05800740, +0x0aa02f20, +0x05800160, +0x0ac02ec0, +0x9e090000, +0x07800000, +0x07800000, +0x9e0d0500, +0x9d040508, +0x0a0030c0, +0x9d040008, +0x9e090000, +0x07800000, +0x9d040008, +0x9e0d0500, +0x0a0030c0, +0x9d040008, +0x9e090000, +0x160000f7, +0x07800000, +0x9e0d0500, +0x1280017a, +0x048001a9, +0x05800940, +0x0aa030c0, +0x05800160, +0x00000ec8, +0x40000688, +0x160ffff9, +0x0ac03050, +0x05800810, +0x0ae030c0, +0x160ffff6, +0x160ffff7, +0x0a003090, +0x05800180, +0x0ae030c0, +0x16000016, +0x16000007, +0x9d044690, +0x04a00144, +0x9d180674, +0x05800160, +0x9d180654, +0x4ac03140, +0x160000f7, +0x0420047a, +0x04a001ab, +0x4a003170, +0x044007bb, +0x0480014b, +0x044007bb, +0x1440004a, +0x120001aa, +0x42000a38, +0x120001bb, +0x42000b39, +0x12000288, +0x12000299, +0x9e0e8280, +0xca003310, +0x1e0e8390, +0xdd040604, +0x05800160, +0x0ac032b0, +0x9d040008, +0x9e090000, +0x07800000, +0x060000f4, +0x9e0d0500, +0x0aa03310, +0x9d040508, +0x0a003310, +0x9e090000, +0x060000f4, +0x9d040008, +0x9e0d0500, +0x0a803310, +0x9d040508, +0x060000f4, +0x0aa03590, +0x9c1d0600, +0x9f065060, +0x9f020830, +0x9f095010, +0xdc1d0600, +0x160fffe9, +0x9f065060, +0x9f020c30, +0x0600000a, +0x0a803590, +0x9f095010, +0x00800dcb, +0x16000028, +0x0600000a, +0x0aa03590, +0x0600000b, +0x0a803500, +0x0600000d, +0x0aa03590, +0x9d044480, +0x9d044780, +0x9c100480, +0x9c100700, +0x9d044490, +0x9d044790, +0x9d044680, +0x9d108480, +0x9d108700, +0x0a003610, +0x058000d0, +0x0aa03590, +0x9d044490, +0x9c100700, +0x9d044790, +0x9d108480, +0x9d108700, +0x9d044480, +0x9d044780, +0x9c1d06c4, +0xdc1d0644, +0x1f0400b0, +0x9c100700, +0x9f040010, +0x9d108480, +0x07800000, +0x9d108700, +0x9c1d06c4, +0x07800000, +0x9f0940b0, +0x07800000, +0x00800cc9, +0x06000008, +0x0aa037c0, +0xdc1d0684, +0x160000f5, +0xdc1d0604, +0x160fff8a, +0x04a00255, +0xdd108480, +0x16000017, +0xdd108700, +0x160ffff8, +0x05800540, +0x0aa03780, +0x05800160, +0x0ac03770, +0x01000027, +0x0a003780, +0x01000028, +0x9e088000, +0xa0054dba, +0xa005c81a, +0x0a003850, +0x9e088000, +0xa0054dba, +0xa005c81a, +0x160fffaa, +0x9f1f80b0, +0x9f1e0010, +0x9f040020, +0x9f040070, +0x9f020810, +0x9d0446a0, +0x9e0f0070, +0x9d0c8118, +0x98802d70, +0x003ffefb, +0x003ffcfa, +0x003ffaf9, +0x003ff8f8, +0x048ff8ff, +0x08200000, +0x9c0c0018, +0x1440001d, +0x04a001dd, +0x9d0c8318, +0x07800000, +0x9c0c0018, +0xa00602ba, +0x07800000, +0x9d0c8318, +0x9d0c81b8, +0x9d0c02b8, +0x98803940, +0x07800000, +0xa00602ba, +0x07800000, +0x07800000, +0x9d0c81b8, +0x9d0c82b8, +0x08200000, +0x9c0c0018, +0x160000ad, +0x07800000, +0x9d0c8318, +0x07800000, +0x9c0c0018, +0xa00602ba, +0x07800000, +0x9d0c8318, +0x9d0c81b8, +0x9d0c02b8, +0x07800000, +0x9c0c0018, +0xa00602ba, +0x07800000, +0x9d0c8318, +0x9d0c02b8, +0x98803a70, +0x9c0c0018, +0xa00602ba, +0x07800000, +0x9d0c8318, +0x9d0c81b8, +0x9d0c02b8, +0x07800000, +0xa00602ba, +0x07800000, +0x07800000, +0x9d0c02b8, +0x08200000, +0x9c0c0038, +0x1440001d, +0x04a001dd, +0x9d0c8338, +0x07800000, +0xa00602ba, +0xa006821a, +0x9c0c0038, +0x07800000, +0x9d0c8298, +0x9d0c8338, +0x9d0c8198, +0x98803c50, +0x07800000, +0xa00602ba, +0xa006821a, +0x07800000, +0x07800000, +0x9d0c8298, +0x9d0c8198, +0x08200000, +0xdc0c0018, +0x04a00201, +0x04a001dd, +0xdd040008, +0x06000001, +0x04a00111, +0x0aa03d70, +0x9d0c8118, +0x98803d50, +0x08200000, +0x9c0c02b0, +0x9c0c0018, +0x04a00205, +0x07800000, +0x9d0c8118, +0xdd0c81b8, +0x06000005, +0x04a00155, +0x0aa03e40, +0x98803e00, +0x08200000, +0x9c039e30, +0x07800000, +0x9c0c0018, +0x9f138510, +0x1600004d, +0x07800000, +0x9d0c8318, +0x07800000, +0x9c0c0510, +0xa00602ba, +0x07800000, +0x9d0c8318, +0x9d0c81b8, +0x9d0c02b8, +0x07800000, +0x9c0c0018, +0x9f138510, +0xa00602ba, +0x07800000, +0x9d0c8318, +0x9d0c81b8, +0x9d0c02b8, +0x98803f20, +0x9c0c0510, +0xa00602ba, +0x07800000, +0x9d0c8318, +0x9d0c81b8, +0x9d0c02b8, +0x07800000, +0xa00602ba, +0x07800000, +0x07800000, +0x9d0c81b8, +0x9d0c82b8, +0x08200000, +0x9c0c0018, +0x1440001d, +0x04a001dd, +0x9d0c8218, +0x07800000, +0x9c0c0018, +0xa00582ba, +0x07800000, +0x07800000, +0x9d0c81b8, +0x98804140, +0x1440001d, +0x9d0c8218, +0x04a001dd, +0xa00582ba, +0x07800000, +0x07800000, +0x9d0c81b8, +0x988041c0, +0x08200000, +0x9c0c0018, +0x1440001d, +0x04a002dd, +0xa00582ba, +0x07800000, +0x07800000, +0x9d0c81b8, +0x9d0c8218, +0x07800000, +0x07800000, +0x9c0c0018, +0x07800000, +0x07800000, +0x9d0c8218, +0x9d0c81b8, +0x988042c0, +0x9c0c0018, +0x1440001d, +0x04a002dd, +0xa00582ba, +0x07800000, +0x07800000, +0x9d0c81b8, +0x9d0c8218, +0x07800000, +0x07800000, +0x9c0c0018, +0x07800000, +0x07800000, +0x9d0c8218, +0x9d0c81b8, +0x988043c0, +0x08200000, +0x9f160028, +0x9f168298, +0x04a001dd, +0x07800000, +0x9d0c8128, +0x07800000, +0x9f160028, +0x9f168298, +0x98804470, +0x9d0c8128, +0x08200000, +0x9f160020, +0x9f168098, +0x9c0c03b0, +0x9f092020, +0x9f082030, +0x9c0c03b0, +0x9f092060, +0x9f082070, +0x07800000, +0x07800000, +0x9d0c8108, +0x9d0c8258, +0x988044e0, +0x08200000, +0x9f160020, +0x9f168098, +0x9c0c02b0, +0x9f092020, +0x9f082030, +0x9c0c02b0, +0x9f092060, +0x9f082070, +0x07800000, +0x07800000, +0x9d0c8118, +0x988045c0, +0x08200000, +0x9d008810, +0x1280020d, +0x07800000, +0x9c038810, +0x9e0e0620, +0x04a001dd, +0x9f16801a, +0x9f12011a, +0x9f039810, +0x9f026810, +0x9f118610, +0x9f1680ba, +0x9f1201ba, +0x9f0398b0, +0x9f0268b0, +0x9f1186b0, +0x9d0c8718, +0x9d108248, +0x9d108208, +0x9d0c87b8, +0x9d1082c8, +0x9d108288, +0x988046f0, +0x08200000, +0x00000003, +0x00000205, +0x1440001d, +0x9c039830, +0x9c03aa50, +0x07800000, +0x9c0c0018, +0x9c0c02b8, +0x07800000, +0x07800000, +0x9d0c8128, +0x98804870, +0x08200000, +0x00001007, +0x048002ff, +0x013ffefe, +0x06000007, +0x00801605, +0x16013523, +0x0a804a30, +0x12000155, +0x0200035e, +0x0b200000, +0x00800405, +0x16013523, +0x12000155, +0x0200035e, +0x0b200000, +0x00801705, +0x16013523, +0x12000155, +0x0200035e, +0x0b200000, +0x003ffefe, +0x048ffeff, +0x07800000, +0x08200000, +0x00800b03, +0x16000181, +0x048004ff, +0x40800a0d, +0x04000101, +0x00000212, +0x00000017, +0x9e0e0420, +0x00000416, +0xdc180404, +0x06000003, +0x9c180480, +0x0aa04ee0, +0x9c052b20, +0x9c042820, +0x9c023970, +0x40800e04, +0x16000005, +0x40800503, +0x0600000d, +0x9d01b060, +0x4a804c40, +0x0400033d, +0x04200427, +0x04200d77, +0x05800750, +0x0ae04c40, +0x16000006, +0x16000145, +0x0a004ec0, +0x160fffd6, +0x05800420, +0x0ae04dc0, +0x160fffe6, +0x04000344, +0x05800420, +0x0ae04eb0, +0x160ffff6, +0x04000344, +0x05800420, +0x0ae04eb0, +0x16000006, +0x04000344, +0x05800420, +0x0ae04eb0, +0x16000016, +0x04000344, +0x05800420, +0x0ae04eb0, +0x16000026, +0x04000344, +0x05800420, +0x0ae04eb0, +0x16000036, +0x013ffcf6, +0x12000132, +0x04000233, +0x9e088300, +0x40800e02, +0x16000005, +0x04000233, +0x12000233, +0x04200377, +0x05800570, +0x16001e02, +0x17800523, +0x04000377, +0x9e0f0070, +0x003ffcf6, +0x00800715, +0x01000606, +0x0a0052f0, +0x9c042b20, +0x9c052920, +0x9c023870, +0x07800000, +0x07800000, +0x9d00b360, +0x16000004, +0x16000005, +0x160fffb6, +0x00800503, +0x05800420, +0x0ae051f0, +0x160fffc6, +0x04000344, +0x05800420, +0x0ae052d0, +0x160fffd6, +0x04000344, +0x05800420, +0x0ae052d0, +0x160fffe6, +0x04000344, +0x05800420, +0x0ae052d0, +0x160ffff6, +0x04000344, +0x05800420, +0x0ae052d0, +0x16000006, +0x04000344, +0x05800420, +0x0ae052d0, +0x16000016, +0x04000344, +0x05800420, +0x0ae052d0, +0x16000026, +0x04000344, +0x05800420, +0x0ae052d0, +0x16000036, +0x04000344, +0x05800420, +0x0ae052d0, +0x16000046, +0x04000344, +0x05800420, +0x0ae052d0, +0x16000056, +0x013ffcf6, +0x12000232, +0x04000233, +0x9e088300, +0x16000005, +0x12000233, +0x04000377, +0x04a1e077, +0x05800570, +0x16001e02, +0x17800523, +0x04000377, +0x9e0f0170, +0x003ffcf6, +0x01000606, +0x00800715, +0x16013526, +0x413ffefe, +0x12000155, +0x00000202, +0x00800d04, +0x0200056e, +0x16020e05, +0x16014246, +0x16014287, +0x0400042d, +0x04a001dd, +0x9e0e0750, +0x9e0e0260, +0x9e0e0370, +0x0b200000, +0x00000806, +0x003ffefe, +0x0000021d, +0x9e0e0560, +0x40800b05, +0x048ffcff, +0x408007d7, +0x06000005, +0x40800f02, +0x04c07f77, +0x4a805540, +0x04500273, +0x00800a02, +0x9e088100, +0x00000011, +0x418007d3, +0x16000003, +0x12800277, +0x018003d7, +0x9d140530, +0x9d038810, +0x08200000, +0x00800a02, +0x9e088000, +0x00000011, +0x418007d3, +0x16000003, +0x12800277, +0x018000d7, +0x9d140530, +0x9d038910, +0x08200000, +0x00001807, +0x00801e02, +0x16000003, +0x9c01b970, +0x06000082, +0x17000233, +0x9e088100, +0x07800000, +0x12000c33, +0x04c3ff66, +0x04500366, +0x07800000, +0x16000003, +0x9e0c8100, +0x16007f46, +0x00000064, +0x1600003d, +0x04a00122, +0x9c03a040, +0x04800266, +0x9e0f0130, +0x04800433, +0x06000002, +0x9c0c0038, +0x9c0c0078, +0x9c0c00b8, +0x9d0c810c, +0x9d0c815c, +0x9d0c81ac, +0x98805750, +0x0aa056d0, +0x9e0f0120, +0x08200000, +0x00001004, +0x0080070d, +0x06000004, +0x00800203, +0x0b800000, +0x40800905, +0x048002ff, +0x40001604, +0x040003dd, +0x413ffefe, +0x06000004, +0x9c03a950, +0x4aa05920, +0x144000d2, +0x0a205be0, +0x40001604, +0x1440002d, +0x06000004, +0x0a805a60, +0x05800d40, +0x0ae05960, +0x0a205a90, +0x0a005a10, +0x042004d2, +0x1440004d, +0x0a205a90, +0x0a205be0, +0x06000002, +0x0a805a10, +0x1440002d, +0x00001604, +0x05800d40, +0x0ac05a60, +0x0a205a90, +0x003ffefe, +0x40800905, +0x048ffeff, +0x9d03a950, +0x08200000, +0x04a0012d, +0x0a201a90, +0x0a005a10, +0x16014246, +0x40800605, +0x048002ff, +0x413ffefe, +0x144000d3, +0x1601352e, +0x9e0e0260, +0x12000155, +0x420005ee, +0x04a001dd, +0x0b200000, +0x9e088000, +0x403ffefe, +0x16000006, +0x40001605, +0x048ffeff, +0x9e0e8040, +0x9e0f0060, +0x04200355, +0x01001605, +0x08200000, +0x40800b0d, +0x16000246, +0x40000403, +0x04c001d7, +0x06000007, +0x4a805cd0, +0x16000017, +0x00001e04, +0x06000004, +0x0a805df0, +0x40001c05, +0x048001dd, +0x01001604, +0x01001405, +0x0a005d40, +0x00001a04, +0x06000004, +0x0a805df0, +0x40001805, +0x048001dd, +0x01001604, +0x01001405, +0x9e0e8050, +0x41800b0d, +0x16000005, +0x40800a04, +0x05c00630, +0x0a805de0, +0x12000233, +0x9e0e0530, +0x9d140550, +0x0a005df0, +0x01800017, +0x08200000, +0x048008ff, +0x413ff8f8, +0x1440001d, +0x013ffaf9, +0x413ffcfa, +0x16006a49, +0x413ffefb, +0x16015002, +0x00000095, +0x00000296, +0x9c018201, +0x01000025, +0x41400226, +0x16002743, +0x04800122, +0x9e088200, +0x9e090300, +0x07800000, +0x12800277, +0x128002bb, +0x01c00127, +0x01c0012b, +0x9c018201, +0x98805ef0, +0x04800633, +0x1440001d, +0x00000034, +0x04802833, +0x01c00124, +0x98805fa0, +0x16002102, +0x9e0e0220, +0x16000806, +0x16007eca, +0x16007f0b, +0x9d140270, +0x000000a8, +0x000000b9, +0x04a00188, +0x04a00199, +0x16000005, +0x16000006, +0x06000008, +0x0aa060e0, +0x16000015, +0x000002a8, +0x06000009, +0x0aa06120, +0x16000016, +0x000002b9, +0x16007102, +0x410000a8, +0x12000166, +0x410000b9, +0x04500655, +0x40800021, +0x16006a4d, +0x41800027, +0x06000004, +0x0aa06210, +0x06000005, +0x0aa06290, +0x06000001, +0x0aa06320, +0x0a006410, +0x160000a8, +0x400000d6, +0x12000c88, +0x04500487, +0x07800000, +0x06000005, +0x9d180078, +0x0a806300, +0x160000c8, +0x400000d6, +0x12000c88, +0x04500587, +0x07800000, +0x07800000, +0x9d180078, +0x06000001, +0x0a806390, +0x160000d8, +0x400000d6, +0x12000c88, +0x04500187, +0x07800000, +0x07800000, +0x9d180078, +0x16000903, +0x16000fb9, +0x16000016, +0x9e0e0530, +0x16000007, +0x9d03c890, +0x07800000, +0x9d140570, +0x16006ac8, +0x40000280, +0x16000013, +0x00000084, +0x06000000, +0x40000049, +0x16006a82, +0x4a8064b0, +0x16000005, +0x04200959, +0x05800590, +0x41000045, +0x160ffff6, +0x17000353, +0x17800363, +0x04800233, +0x01000023, +0x16015002, +0x01004a23, +0x403ffefb, +0x16002202, +0x9e0e0220, +0x403ffcfa, +0x16000806, +0x003ffaf9, +0x003ff8f8, +0x9d140270, +0x048ff8ff, +0x08200000, +0x048008ff, +0x413ff8f8, +0x16015002, +0x013ffaf9, +0x013ffcfa, +0x413ffefb, +0x04803322, +0x16008385, +0x16000e0d, +0x00000454, +0x00000856, +0x9c0768d0, +0x01c00124, +0x01c00126, +0x40000087, +0x16003129, +0x0000028d, +0x40000c54, +0x12000299, +0x00000e56, +0x01c00127, +0x0180012d, +0x9e0e0490, +0x41400224, +0x16003138, +0x41400226, +0x12000288, +0x9c100480, +0x9f03e0b0, +0x9e0e0580, +0x9e010080, +0xdc1005c0, +0x1600060d, +0x9f03e0b0, +0x01400229, +0x9e0080c0, +0x0140022a, +0x9c01ead0, +0x01400225, +0x41400226, +0x16000633, +0x9e090200, +0x04800122, +0x9c029c30, +0x128002bb, +0x01c0012b, +0x160005bd, +0x9e088400, +0x07800000, +0x9c01ead0, +0x12800277, +0x01c00127, +0x9e090200, +0x16000023, +0x1600005d, +0x128002bb, +0x9c029c30, +0x01c0012b, +0x04800122, +0x9e088400, +0x9c01ead0, +0x07800000, +0x12800277, +0x9e090200, +0x07800000, +0x01c00127, +0x128002bb, +0x01c0012b, +0x04800222, +0x16008185, +0x16000e2d, +0x00000454, +0x00000856, +0x9c0768d0, +0x01c00124, +0x01c00126, +0x40000087, +0x16003149, +0x0000028d, +0x40000c54, +0x12000299, +0x00000e56, +0x01c00127, +0x0180012d, +0x9e0e0490, +0x41400224, +0x16003158, +0x41400226, +0x12000288, +0x9c100480, +0x9f03e0b0, +0x9e0e0580, +0x9e010080, +0xdc1005c0, +0x1600009d, +0x9f03e0b0, +0x01400229, +0x9e0080c0, +0x0140022a, +0x9c01ead0, +0x01400225, +0x16000563, +0x01400226, +0x9e090200, +0x9c029c30, +0x07800000, +0x128002bb, +0x9e088400, +0x01c0022b, +0x07800000, +0x12800277, +0x01c00227, +0x003ffefb, +0x003ffcfa, +0x003ffaf9, +0x003ff8f8, +0x048ff8ff, +0x08200000, +0x16000023, +0x16012f01, +0x16000bf5, +0x00000010, +0x04800200, +0x9c01aa50, +0x04c07f00, +0x16012704, +0x01000010, +0x04000400, +0x00000005, +0x07800000, +0x07800000, +0x9c00a850, +0x07800000, +0x07800000, +0x9e088000, +0x9f038490, +0x07800000, +0x12800266, +0x04c0ff6d, +0x9c0c0018, +0x9f0b0010, +0x9f092080, +0x98806e90, +0x9c0c0330, +0x07800000, +0x07800000, +0x9f0920e0, +0x07800000, +0x07800000, +0x06000004, +0x0a8070e0, +0x00000010, +0x04800200, +0x9c01aa50, +0x04c07f00, +0x16012704, +0x04000400, +0x00000005, +0x07800000, +0x07800000, +0x9c00a850, +0x07800000, +0x07800000, +0x9e088000, +0x9f038490, +0x07800000, +0x12800266, +0x04c0ff6d, +0x9f038410, +0x07800000, +0x07800000, +0x9c0c00b0, +0x07800000, +0x07800000, +0x9d0c8038, +0x98807090, +0x00000010, +0x04800200, +0x04c07f00, +0x07800000, +0x01000010, +0x04a00133, +0x06000003, +0x0aa06d50, +0x08200000, +0x16000023, +0x16012f21, +0x16000bf5, +0x00000010, +0x04800200, +0x9c01aa50, +0x04c07f00, +0x16012704, +0x01000010, +0x04000400, +0x00000005, +0x07800000, +0x07800000, +0x9c00a850, +0x07800000, +0x07800000, +0x9e088000, +0x9f038490, +0x07800000, +0x12800266, +0x04c0ff6d, +0x9c0c0018, +0x9f0b0010, +0x9f092090, +0x988072c0, +0x9c0c0330, +0x07800000, +0x07800000, +0x9f0920e0, +0x07800000, +0x07800000, +0x06000004, +0x0a807510, +0x00000010, +0x04800200, +0x9c01aa50, +0x04c07f00, +0x16012704, +0x04000400, +0x00000005, +0x07800000, +0x07800000, +0x9c00a850, +0x07800000, +0x07800000, +0x9e088000, +0x9f038490, +0x07800000, +0x12800266, +0x04c0ff6d, +0x9f038410, +0x07800000, +0x07800000, +0x9c0c00b0, +0x07800000, +0x07800000, +0x9d0c8098, +0x988074c0, +0x00000010, +0x04800200, +0x04c07f00, +0x07800000, +0x01000010, +0x04a00133, +0x06000003, +0x0aa07180, +0x08200000, +0x00000004, +0x00000405, +0x00000806, +0x00000c07, +0x05c00540, +0x0b800000, +0x9e0e8040, +0x9c180034, +0x07800000, +0x07800000, +0x06000033, +0x9e0e8220, +0x0aa076c0, +0x9c1d0004, +0x9c1d0044, +0x07800000, +0x9d0c0210, +0x0a007770, +0x06000023, +0x0aa07720, +0x9c1d0004, +0x9d040004, +0x9d100200, +0x0a007770, +0x06000043, +0x0aa07770, +0x9c180024, +0x9d040004, +0x9d180200, +0x04800c44, +0x05c00740, +0x17800644, +0x01000004, +0x0a0075e0, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x07800000, +0x07800000, +0x07800000, +0x08400000, +0x0a000000, +0x00000000, +0x00000000, +0x00001000, +0x00001000, +0x00001000, +0x00001000, +0x00001000, +0x00001000, +0x00001000, +0x00151000, +0x00201000, +0x00001000, +0x00001000, +0x00001000, +0x00001000, +0x00001000, +0x00001001, +0x00000000, +0x00001011, +0x00001011, +0x00021031, +0x00041051, +0x00061071, +0x00081091, +0x000a10b1, +0x000c10d1, +0x00001001, +0x00001001, +0x00001000, +0x00001000, +0x00001001, +0x00001001, +0x00001011, +0x00001000, +0x00001000, +0x00001000, +0x00001000, +0x00001000, +0x00001001, +0x00001000, +0x00001000, +0x00001000, +0x00001000, +0x00001041, +0x00001000, +0x00000000, +0x00001000, +0x00001000, +0x00001000, +0x00001000, +0x00001000, +0x00001000, +0x00001001, +0x00001001, +0x00001000, +0x00001000, +0x00001001, +0x00001000, +0x00001001, +0x00001001, +0x00001001, +0x00000000, +0x00000000, +0x00001001, +0x00001001, +0x00001000, +0x00001001, +0x00001001, +0x00001001, +0x00001001, +0x00001001, +0x00001001, +0x00001000, +0x00001000, +0x00001000, +0x00001000, +0x00001000, +0x00001000, +0x00000000, +0x00000000, +0x00001000, +0x00001000, +0x00001000, +0x00000000, +0x00000000, +0x00000000, +0x00001000, +0x00001001, +0x00000001, +0x00001000, +0x00000858, +0x00001000, +0x00001001, +0x00000001, +0x00001000, +0x00000858, +0x00151000, +0x00000858, +0x00000858, +0x00151000, +0x00001000, +0x00001001, +0x00000001, +0x00001000, +0x00000898, +0x00001000, +0x00001001, +0x00001000, +0x00001000, +0x00001001, +0x00001001, +0x000010c1, +0x00001000, +0x000010c1, +0x00001001, +0x00001000, +0x00001000, +0x00001000, +0x00001000, +0x00001000, +0x00001000, +0x00001061, +0x00001031, +0x00001061, +0x00001021, +0x00001061, +0x00001031, +0x00001061, +0x00001021, +0x00001061, +0x00001031, +0x00001061, +0x00001021, +0x00001061, +0x00001031, +0x00001061, +0x00001021, +0x00001061, +0x00001021, +0x00001061, +0x00001031, +0x00151000, +0x00001000, +0x00001000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00001071, +0x000000aa, +0x00001071, +0x00000000, +0x00000000, +0x00000000, +0x00001000, +0x00001000, +0x0000004d, +0x000000a8, +0x00001000, +0x00001000, +0x00001000, +0x00001000, +0x00000000, +0x00000000, +0x00001000, +0x003c1000, +0x00001000, +0x003c1000, +0x00001001, +0x00001000, +0x0000004d, +0x00001000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00001001, +0x00001001, +0x00001000, +0x00001051, +0x00001000, +0x00001001, +0x00001051, +0x00001001, +0x000000c6, +0x00001000, +0x00001001, +0x00001001, +0x00001001, +0x00001001, +0x00001001, +0x0000fff9, +0x00001000, +0x00001000, +0x00000000, +0x00001001, +0x00001091, +0x00001000, +0x00001000, +0x00000000, +0x00000000, +0x00001091, +0x00001091, +0x00001091, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00001000, +0x00000000, +0x00000000, +0x00000000, +0x00001000, +0x00001000, +0x00001000, +0x00001000, +0x00001000, +0x00001000, +0x00001000, +0x00001000, +0x00001000, +0x00001000, +0x00001000, +0x00001000, +0x00001000, +0x00001000, +0x00001000, +0x00001001, +0x00001001, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00001000, +0x00001001, +0x00000000, +0x00011001, +0x00001000, +0x00151000, +0x00001001, +0x00000001, +0x00001000, +0x00000858, +0x00000858, +0x00001000, +0x00151000, +0x00151000, +0x00001000, +0x00001000, +0x00001000, +0x00001000, +0x00001001, +0x00000001, +0x00001000, +0x00000858, +0x00000858, +0x00000000, +0x00000000, +0x00001001, +0x00000000, +0x00000000, +0x00001000, +0x00000000, +0x00000000, +0x00001001, +0x00000000, +0x00001001, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00001001, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000008, +0x00700001, +0x00700001, +0x00700001, +0x00700001, +0x00700001, +0x00700001, +0x00700001, +0x00700001, +0x00700001, +0x00700001, +0x00700001, +0x00700001, +0x00700001, +0x00700001, +0x00700001, +0x00700001, +0x00700001, +0x00700001, +0x00100001, +0x00100001, +0x00100001, +0x00100001, +0x00100001, +0x00100001, +0x00100001, +0x00100001, +0x00100001, +0x00100001, +0x00100001, +0x00100001, +0x00100001, +0x00100001, +0x00100001, +0x00100001, +0x00100001, +0x00100001, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00040002, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00fc4793, +0x000a8b43, +0x00e7110b, +0x003411d3, +0x009d1cfb, +0x0002b6a8, +0x00fb8ca8, +0x0006dac8, +0x00f610e8, +0x000d8628, +0x00eed498, +0x0013f0e8, +0x00eb9d08, +0x000f02e8, +0x00056260, +0x00bf42f0, +0x006a9a5d, +0x005ed280, +0x00023c94, +0x00fb2e83, +0x000c8ac3, +0x00e408e3, +0x0037ceab, +0x0099fe5b, +0x0002b430, +0x00fbb618, +0x000661c0, +0x00f71850, +0x000b9710, +0x00f220d0, +0x000eb9d8, +0x00f37700, +0x0003c304, +0x00142c90, +0x00b09170, +0x0066c791, +0x006d23e0, +0x000208b8, +0x00fa9443, +0x000d8413, +0x00e2e293, +0x00386703, +0x009badeb, +0x000296d8, +0x00fc0144, +0x0005c418, +0x00f83d98, +0x0009a2c0, +0x00f53c30, +0x000a1678, +0x00fa10a0, +0x00fadbf0, +0x001ef5c0, +0x00a7ab80, +0x0061b101, +0x00782010, +0x000464a8, +0x00fa1fab, +0x000e2353, +0x00e28193, +0x003770b3, +0x00a04a0b, +0x000264f0, +0x00fc6e8c, +0x0004f108, +0x00f9b218, +0x00073f50, +0x00f8ea80, +0x0004be58, +0x005c1863, +0x00f141c8, +0x002a0528, +0x009fa4a8, +0x005b6439, +0x0042ccf5, +0x0005d8f0, +0x00f9f08b, +0x000e2e23, +0x00e33ce3, +0x00348833, +0x00a80de3, +0x00022008, +0x00fcf654, +0x0003fc0c, +0x00fb4d68, +0x0004b6b0, +0x00fcaf74, +0x00dcf75b, +0x000875d0, +0x00e88c00, +0x00334af8, +0x009a9170, +0x0053f3c9, +0x00498425, +0x0007d850, +0x00fa0193, +0x000db28b, +0x00e4f083, +0x0030005b, +0x00b24bfb, +0x007356ab, +0x00fd8f38, +0x0002f50c, +0x00fcf624, +0x00022f7c, +0x0014e623, +0x00fa8240, +0x000ec210, +0x00e12888, +0x003a6068, +0x00989408, +0x004b98d9, +0x004fdc61, +0x000aadb0, +0x00fa47fb, +0x000cc843, +0x00e76cb3, +0x002a3303, +0x00be6543, +0x005c437b, +0x008ca913, +0x007977d3, +0x00a7922b, +0x00ef1dc3, +0x0003bf5c, +0x00f604a8, +0x00143b08, +0x00db27e8, +0x003f50c0, +0x009968b8, +0x00427b21, +0x0055cb8d, +0x000e5198, +0x00faba2b, +0x000b83a3, +0x00ea894b, +0x00236a23, +0x00cbda13, +0x004398b3, +0x00b6e5bb, +0x003575db, +0x000eee5b, +0x00fd6ac0, +0x0006e2f8, +0x00f20c30, +0x0018d298, +0x00d68e40, +0x00423000, +0x009cd148, +0x00716ee8, +0x005b537d, +0x0012b270, +0x00fb4feb, +0x0009f65b, +0x00ee2313, +0x001be763, +0x00da372b, +0x002a1533, +0x00e15813, +0x00f2fbd3, +0x007127a3, +0x00fb4778, +0x0009ae08, +0x00eeab88, +0x001c7728, +0x00d365f8, +0x004306e0, +0x00a2a0d0, +0x005cd070, +0x00606a75, +0x0017d078, +0x00fc00bb, +0x0008330b, +0x00f2141b, +0x0013f29b, +0x00e8fcc3, +0x00108f73, +0x000aabc3, +0x00b409ab, +0x00032d94, +0x00f961f0, +0x000c0d48, +0x00ebf900, +0x001f1310, +0x00d1bd70, +0x0041db98, +0x00aaa7f0, +0x004768e0, +0x0064f695, +0x001db640, +0x00fcc40b, +0x00064cab, +0x00f635fb, +0x000bd423, +0x00f7ab83, +0x00f7da9b, +0x00319613, +0x00fdea24, +0x00046be0, +0x00f7c838, +0x000def88, +0x00ea0778, +0x002095b8, +0x00d19bf0, +0x003ebd10, +0x00b4aec0, +0x00318e40, +0x0068d739, +0x002477b8, +0x00fd9103, +0x000456bb, +0x00fa6163, +0x0003d51b, +0x0005c47b, +0x00e0c55b, +0x0054da23, +0x00fd2110, +0x000575e0, +0x00f68680, +0x000f46d0, +0x00e8e4e8, +0x0020f5c0, +0x00d2fe70, +0x0039c7a8, +0x00c06ee8, +0x001ba3e0, +0x006be82d, +0x002c29d8, +0x00fe5ef3, +0x000264b3, +0x00fe6f83, +0x00fc3c73, +0x0012cf0b, +0x00cc0f3b, +0x00735b43, +0x00fc7b10, +0x00064398, +0x00f5a608, +0x001009d8, +0x00e89830, +0x002033b8, +0x00d5d488, +0x003327e0, +0x00cd9208, +0x000617a0, +0x006e0619, +0x0034dcb8, +0x00ff2633, +0x0000878b, +0x00023efb, +0x00f54613, +0x001e683b, +0x00ba501b, +0x00023104, +0x00fbfc98, +0x0006cfe8, +0x00f52c00, +0x001034f8, +0x00e92088, +0x001e5960, +0x00da0390, +0x002b1358, +0x00dbbf58, +0x00f14c40, +0x006f129d, +0x003ea030, +0x00ffdfeb, +0x00feceb3, +0x0005b193, +0x00ef271b, +0x00283a63, +0x00ac06cb, +0x00027b84, +0x00fba8d8, +0x00071778, +0x00f51a98, +0x000fc900, +0x00ea7720, +0x001b7880, +0x00df6710, +0x0021ca50, +0x00ea95d0, +0x00dda780, +0x006ef2a5, +0x00497dd8, +0x00000003, +0x00fd4a6b, +0x0008a803, +0x00ea151b, +0x002ff333, +0x00a1a463, +0x0002aad0, +0x00fb81d8, +0x00071978, +0x00f56fc8, +0x000ecde0, +0x00ec89f0, +0x0017b2e0, +0x00e5c408, +0x0017aaa0, +0x00f99118, +0x00cbaf78, +0x006d93e5, +0x005561e0, +0x00000020, +0x003fffe0, +0x00000020, +0x003fffe0, +0x00069cf3, +0x00eda3d3, +0x00284343, +0x00b2821b, +0x000228bc, +0x00fc4508, +0x0006a660, +0x00f19bc0, +0x007f26c5, +0x00107398, +0x00f8cbc0, +0x0003fef8, +0x00fdafb8, +0x00539323, +0x00d40cc3, +0x0014740b, +0x00f855f3, +0x0001b16b, +0x000c0373, +0x00ddec9b, +0x004b880b, +0x00fdb6d0, +0x00041728, +0x00f8ede8, +0x000c8b38, +0x00e57730, +0x007ca649, +0x0022b568, +0x00f146b8, +0x00081d20, +0x00fb4da0, +0x0002a8ac, +0x00a5ff43, +0x002a4a93, +0x00efdbfb, +0x0003c6eb, +0x00101e33, +0x00d13c0b, +0x0068d11b, +0x00fcce9c, +0x0005bc08, +0x00f61488, +0x001185c8, +0x00dbb070, +0x00788dfd, +0x00367598, +0x00e9b5b8, +0x000c31f8, +0x00f8f1a0, +0x00040178, +0x00fdde98, +0x0040ab93, +0x00e6e21b, +0x0006309b, +0x0012ea3b, +0x00c7c91b, +0x007f746f, +0x00fc1754, +0x00070c10, +0x00f3cc50, +0x00157878, +0x00d45408, +0x0072f70d, +0x004b56d0, +0x00e26390, +0x001012a8, +0x00f6b500, +0x00054a20, +0x00fd2bf0, +0x0056a233, +0x00ddc993, +0x0008d62b, +0x00147503, +0x00c1a1c3, +0x00023c70, +0x00fb9490, +0x0007fff0, +0x00f221f8, +0x00185148, +0x00cf5d50, +0x006c0395, +0x0060f058, +0x00db9f08, +0x00139340, +0x00f4b188, +0x00067398, +0x00fc8844, +0x006b2573, +0x00d501e3, +0x000b96fb, +0x0014d9d3, +0x00beae3b, +0x00025f04, +0x00fb4790, +0x00089470, +0x00f11b68, +0x001a0988, +0x00ccb738, +0x0063ddc5, +0x0076d0d4, +0x00d5b880, +0x001688a8, +0x00f30060, +0x00076f18, +0x00fbfbf8, +0x007d228f, +0x00cd04b3, +0x000e4b13, +0x00143ecb, +0x00beb5b3, +0x000266a0, +0x00fb2f48, +0x0008ca48, +0x00f0b7e8, +0x001aa578, +0x00cc3da8, +0x005ab67d, +0x004640a1, +0x00d0ff50, +0x0018ca30, +0x00f1b920, +0x00082ea8, +0x00fb8f00, +0x00022e24, +0x00c650c3, +0x0010c49b, +0x0012d1ab, +0x00c1642b, +0x0002555c, +0x00fb48b0, +0x0008a5d0, +0x00f0f0a0, +0x001a3350, +0x00cdbf38, +0x0050c415, +0x0050c415, +0x00cdbf38, +0x001a3350, +0x00f0f0a0, +0x0008a5d0, +0x00fb48b0, +0x0002555c, +0x00c1642b, +0x0012d1ab, +0x0010c49b, +0x00c650c3, +0x00022e24, +0x00fb8f00, +0x00082ea8, +0x00f1b920, +0x0018ca30, +0x00d0ff50, +0x004640a1, +0x005ab67d, +0x00cc3da8, +0x001aa578, +0x00f0b7e8, +0x0008ca48, +0x00fb2f48, +0x000266a0, +0x00beb5b3, +0x00143ecb, +0x000e4b13, +0x00cd04b3, +0x007d228f, +0x00fbfbf8, +0x00076f18, +0x00f30060, +0x001688a8, +0x00d5b880, +0x0076d0d4, +0x0063ddc5, +0x00ccb738, +0x001a0988, +0x00f11b68, +0x00089470, +0x00fb4790, +0x00025f04, +0x00beae3b, +0x0014d9d3, +0x000b96fb, +0x00d501e3, +0x006b2573, +0x00fc8844, +0x00067398, +0x00f4b188, +0x00139340, +0x00db9f08, +0x0060f058, +0x006c0395, +0x00cf5d50, +0x00185148, +0x00f221f8, +0x0007fff0, +0x00fb9490, +0x00023c70, +0x00c1a1c3, +0x00147503, +0x0008d62b, +0x00ddc993, +0x0056a233, +0x00fd2bf0, +0x00054a20, +0x00f6b500, +0x001012a8, +0x00e26390, +0x004b56d0, +0x0072f70d, +0x00d45408, +0x00157878, +0x00f3cc50, +0x00070c10, +0x00fc1754, +0x007f746f, +0x00c7c91b, +0x0012ea3b, +0x0006309b, +0x00e6e21b, +0x0040ab93, +0x00fdde98, +0x00040178, +0x00f8f1a0, +0x000c31f8, +0x00e9b5b8, +0x00367598, +0x00788dfd, +0x00dbb070, +0x001185c8, +0x00f61488, +0x0005bc08, +0x00fcce9c, +0x0068d11b, +0x00d13c0b, +0x00101e33, +0x0003c6eb, +0x00efdbfb, +0x002a4a93, +0x00a5ff43, +0x0002a8ac, +0x00fb4da0, +0x00081d20, +0x00f146b8, +0x0022b568, +0x007ca649, +0x00e57730, +0x000c8b38, +0x00f8ede8, +0x00041728, +0x00fdb6d0, +0x004b880b, +0x00ddec9b, +0x000c0373, +0x0001b16b, +0x00f855f3, +0x0014740b, +0x00d40cc3, +0x00539323, +0x00fdafb8, +0x0003fef8, +0x00f8cbc0, +0x00107398, +0x007f26c5, +0x00f19bc0, +0x0006a660, +0x00fc4508, +0x000228bc, +0x00b2821b, +0x00284343, +0x00eda3d3, +0x00069cf3, +0x00000003, +0x00000003, +0x00000003, +0x00000003, +0x00000003, +0x00000003, +0x00000003, +0x00000003, +0x00000003, +0x00040002, +0x00000003, +0x00000003, +0x00000003, +0x00000003, +0x00000003, +0x00000003, +0x00000003, +0x00000003, +0x00000020, +0x003fffe0, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00040002, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00040002, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00040002, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x004b54e7, +0x002866b7, +0x0002526c, +0x005d3e43, +0x0002526c, +0x002866b7, +0x004b54e7, +0x0090828c, +0x00097262, +0x00e8875a, +0x0021f9ea, +0x00e1aff2, +0x000feece, +0x000387fc, +0x0079341b, +0x0006f740, +0x00045eec, +0x0006f740, +0x0079341b, +0x000387fc, +0x0090828c, +0x00097262, +0x00e8875a, +0x0021f9ea, +0x00e1aff2, +0x000feece, +0x007de295, +0x00f821da, +0x007de295, +0x008431e5, +0x0007dde2, +0x0012f747, +0x00c81d03, +0x005f165b, +0x0094600b, +0x005f165b, +0x00c81d03, +0x0012f747, +0x00aa0ab1, +0x001057be, +0x00d5b832, +0x003b8bf6, +0x00cfd2ca, +0x00154066, +0x0071cb9f, +0x00fac2b8, +0x0008ea18, +0x00f5e900, +0x0008ea18, +0x00fac2b8, +0x0071cb9f, +0x00aa0ab1, +0x001057be, +0x00d5b832, +0x003b8bf6, +0x00cfd2ca, +0x00154066, +0x008e3ba9, +0x000aaa6a, +0x00f5559a, +0x0071c459, +0x00651dd9, +0x00f5c6b6, +0x000b0ede, +0x00000020, +0x003fffe0, +0x00269ec3, +0x000d0ff4, +0x00051eba, +0x00640001, +0x0002f290, +0x00fdd340, +0x0002a810, +0x0002a810, +0x00fdd340, +0x0002f290, +0x0045a895, +0x00f4a186, +0x0018a312, +0x00e445b2, +0x0010419e, +0x000b68e0, +0x0021f7f0, +0x0044471c, +0x005c5e48, +0x005c5e48, +0x0044471c, +0x0021f7f0, +0x000b68e0, +0x0020ff38, +0x00b24b3d, +0x00062d86, +0x00f4f6ea, +0x000d3f5a, +0x00f2ea1a, +0x00075f92, +0x00c1248b, +0x00fd1080, +0x00faca4c, +0x00fab048, +0x00fdb0ac, +0x00024f54, +0x00054fb8, +0x000535b4, +0x0002ef80, +0x003edb7b, +0x001d92ec, +0x00962b59, +0x000bd422, +0x00e48132, +0x002dbdc2, +0x00c7a94a, +0x0033fbe6, +0x00dd3502, +0x000fea26, +0x00c1248b, +0x00fd1080, +0x00faca4c, +0x00fab048, +0x00fdb0ac, +0x00024f54, +0x00054fb8, +0x000535b4, +0x0002ef80, +0x003edb7b, +0x001d92ec, +0x00962b59, +0x000bd422, +0x00e48132, +0x002dbdc2, +0x00c7a94a, +0x0033fbe6, +0x00dd3502, +0x000fea26, +0x00400000, +0x00100002, +0x007f0001, +0x00040002, +0x00040002, +0x00000020, +0x003fffe0, +0x00000020, +0x003fffe0, +0x0000e95b, +0x00045e13, +0x00e38bd3, +0x0049a0eb, +0x0086a523, +0x00021a60, +0x00b3b22b, +0x00c008cb, +0x0003ee58, +0x00f98190, +0x0007bebc, +0x00f927cc, +0x000369f8, +0x000210a0, +0x00f7d700, +0x000cf630, +0x00f0b350, +0x000f00d8, +0x00f45884, +0x0004930c, +0x000cca50, +0x00d5b1a0, +0x0036ee50, +0x00c50200, +0x00c1a4a3, +0x005fc0f5, +0x004f99c8, +0x00026924, +0x00ff83fb, +0x0008de8b, +0x00de91f3, +0x0044c043, +0x00a56883, +0x0040eb8b, +0x001e74a3, +0x00fd21b0, +0x000554e4, +0x00f94c68, +0x000647f4, +0x00fc5390, +0x00c48fa3, +0x00067e44, +0x00f4b078, +0x000daa00, +0x00f31630, +0x00095c18, +0x00fd153c, +0x00f92d4c, +0x00187260, +0x00d118b0, +0x002e0ce0, +0x00dfc588, +0x00d88710, +0x005ade01, +0x0069ab18, +0x000581a8, +0x00ff0f2b, +0x000a2003, +0x00e0f9b3, +0x00341ca3, +0x00d0769b, +0x00f72c73, +0x0079f1eb, +0x00fbed28, +0x0005aab8, +0x00fa5660, +0x0003b918, +0x00028fb3, +0x00fb129c, +0x00098f30, +0x00f3bff8, +0x000bc1d8, +0x00f7e048, +0x000228e8, +0x0005dda0, +0x00f00dc0, +0x001eb940, +0x00d459f0, +0x001db068, +0x00fcb1e0, +0x00bb70e0, +0x00500125, +0x00423c25, +0x000cb760, +0x00ff3a63, +0x0008dcf3, +0x00e89f33, +0x001cf00b, +0x00fdff03, +0x00b7a13b, +0x0002d9ac, +0x00fb9038, +0x0004ee8c, +0x00fc6088, +0x0025bba3, +0x000396e8, +0x00f82434, +0x000abf70, +0x00f51e3c, +0x0007b174, +0x0083c45b, +0x00fadcd0, +0x000d0158, +0x00eaba28, +0x001ef828, +0x00de61d8, +0x00091358, +0x00172bd8, +0x00aaa5f8, +0x007f9968, +0x004ead35, +0x0016d358, +0x00ff9df3, +0x00063423, +0x00f2bc93, +0x0004db3b, +0x002510d3, +0x008d0163, +0x00032dec, +0x00fc0c14, +0x00035394, +0x00bfd6bb, +0x00fd7bc4, +0x000653e0, +0x00f6c644, +0x0009e92c, +0x00f874d4, +0x00025014, +0x000466f8, +0x00f4e050, +0x00113910, +0x00e9e9d8, +0x0019a460, +0x00ed06b8, +0x00f3f088, +0x002b3ea8, +0x00a75d50, +0x00573b88, +0x0058acdd, +0x00253e48, +0x00ffe99b, +0x00034623, +0x00fca67b, +0x00f0ade3, +0x003f433b, +0x00fdf30c, +0x0002e438, +0x00fd3880, +0x004d26e3, +0x006be023, +0x00fafa08, +0x0007c8c0, +0x00f72900, +0x000747f8, +0x00fd12b4, +0x00fcac44, +0x0009b130, +0x00f14b30, +0x0011de10, +0x00ed7168, +0x00102888, +0x00fd78fc, +0x00e1dd38, +0x003632e8, +0x00b0f308, +0x002ad4a0, +0x005ec5d9, +0x00385800, +0x00fed5c7, +0x0001d26f, +0x00fa588b, +0x000daca7, +0x00e3d6d3, +0x00339bc7, +0x00a97e63, +0x00021db8, +0x00fcd778, +0x00049f28, +0x00f8fde8, +0x000d23e8, +0x007d7e59, +0x00f89bb0, +0x000259b4, +0x00d1846b, +0x0003ff83, +0x000bf0f7, +0x00f0e3cf, +0x000ca4f7, +0x00f77a0b, +0x0004c883, +0x00fdcf83, +0x0000c0c7, +0x00ff662f, +0x0002ff27, +0x00f6afb3, +0x0016defb, +0x00cfc55f, +0x005b288f, +0x00fd84f0, +0x000411f4, +0x00f99078, +0x000a2044, +0x00ef1978, +0x0024d648, +0x007aa5a5, +0x00e7c3e8, +0x000aa4ec, +0x00fa6a80, +0x000304e0, +0x009a1a6f, +0x0032b7db, +0x00e8d6d7, +0x000963f3, +0x00fcc6cf, +0x0000dc7b, +0x00ffda2f, +0x00ff1ed3, +0x0004309f, +0x00f31b9b, +0x001faed3, +0x00bcc34f, +0x00020190, +0x00fc755c, +0x0005e8c8, +0x00f675cc, +0x000f6978, +0x00e54b98, +0x003efe58, +0x007512ad, +0x00daf028, +0x001174bc, +0x00f652f4, +0x000589a8, +0x00fce2b4, +0x006b13b7, +0x00ca4a77, +0x00188ddf, +0x00f61837, +0x000357df, +0x00ff2823, +0x00fed6b7, +0x00054b13, +0x00efed7f, +0x0027599b, +0x00ac68e3, +0x00028110, +0x00fb8cf0, +0x00077d74, +0x00f3c420, +0x00141628, +0x00dc4340, +0x005ac084, +0x006d00dd, +0x00d23fd0, +0x00167f08, +0x00f33398, +0x00077ccc, +0x00fbb300, +0x00025c40, +0x00b2862b, +0x0024406f, +0x00f10627, +0x00052b3f, +0x00feadf3, +0x00fe9647, +0x00062edf, +0x00ed7c03, +0x002d1867, +0x00a04bef, +0x0002df40, +0x00fae088, +0x0008acc0, +0x00f1b5e8, +0x0017c370, +0x00d4b638, +0x0077237c, +0x0062c57d, +0x00cd9f14, +0x00199c28, +0x00f12c50, +0x0008c91c, +0x00fae638, +0x0002d380, +0x00a270f7, +0x002c1793, +0x00edb29f, +0x00065057, +0x00fe69af, +0x00fe678b, +0x0006badb, +0x00ec1c5f, +0x00302fa7, +0x0099df87, +0x00031180, +0x00fa8294, +0x000957b0, +0x00f07efc, +0x001a1714, +0x00cf5714, +0x00498dbd, +0x0056cb65, +0x00cccae8, +0x001ac64c, +0x00f04854, +0x0009661c, +0x00fa8180, +0x00030f60, +0x009a52c3, +0x00300017, +0x00ec1ad7, +0x0006cf1f, +0x00fe552f, +0x00fe552f, +0x0006cf1f, +0x00ec1ad7, +0x00300017, +0x009a52c3, +0x00030f60, +0x00fa8180, +0x0009661c, +0x00f04854, +0x001ac64c, +0x00cccae8, +0x0056cb65, +0x00498dbd, +0x00cf5714, +0x001a1714, +0x00f07efc, +0x000957b0, +0x00fa8294, +0x00031180, +0x0099df87, +0x00302fa7, +0x00ec1c5f, +0x0006badb, +0x00fe678b, +0x00fe69af, +0x00065057, +0x00edb29f, +0x002c1793, +0x00a270f7, +0x0002d380, +0x00fae638, +0x0008c91c, +0x00f12c50, +0x00199c28, +0x00cd9f14, +0x0062c57d, +0x0077237c, +0x00d4b638, +0x0017c370, +0x00f1b5e8, +0x0008acc0, +0x00fae088, +0x0002df40, +0x00a04bef, +0x002d1867, +0x00ed7c03, +0x00062edf, +0x00fe9647, +0x00feadf3, +0x00052b3f, +0x00f10627, +0x0024406f, +0x00b2862b, +0x00025c40, +0x00fbb300, +0x00077ccc, +0x00f33398, +0x00167f08, +0x00d23fd0, +0x006d00dd, +0x005ac084, +0x00dc4340, +0x00141628, +0x00f3c420, +0x00077d74, +0x00fb8cf0, +0x00028110, +0x00ac68e3, +0x0027599b, +0x00efed7f, +0x00054b13, +0x00fed6b7, +0x00ff2823, +0x000357df, +0x00f61837, +0x00188ddf, +0x00ca4a77, +0x006b13b7, +0x00fce2b4, +0x000589a8, +0x00f652f4, +0x001174bc, +0x00daf028, +0x007512ad, +0x003efe58, +0x00e54b98, +0x000f6978, +0x00f675cc, +0x0005e8c8, +0x00fc755c, +0x00020190, +0x00bcc34f, +0x001faed3, +0x00f31b9b, +0x0004309f, +0x00ff1ed3, +0x00ffda2f, +0x0000dc7b, +0x00fcc6cf, +0x000963f3, +0x00e8d6d7, +0x0032b7db, +0x009a1a6f, +0x000304e0, +0x00fa6a80, +0x000aa4ec, +0x00e7c3e8, +0x007aa5a5, +0x0024d648, +0x00ef1978, +0x000a2044, +0x00f99078, +0x000411f4, +0x00fd84f0, +0x005b288f, +0x00cfc55f, +0x0016defb, +0x00f6afb3, +0x0002ff27, +0x00ff662f, +0x0000c0c7, +0x00fdcf83, +0x0004c883, +0x00f77a0b, +0x000ca4f7, +0x00f0e3cf, +0x000bf0f7, +0x0003ff83, +0x00d1846b, +0x000259b4, +0x00f89bb0, +0x007d7e59, +0x000d23e8, +0x00f8fde8, +0x00049f28, +0x00fcd778, +0x00021db8, +0x00a97e63, +0x00339bc7, +0x00e3d6d3, +0x000daca7, +0x00fa588b, +0x0001d26f, +0x00fed5c7, +0x00000000, +0x00040002, +0x00000000, +0x00040002, +0x00020002, +0x00f80002, +0x001a88b7, +0x003bed83, +0x00789f93, +0x000353c8, +0x000558c0, +0x0007faa0, +0x000b314c, +0x000edf48, +0x0012cfec, +0x0016b8f4, +0x001a3f88, +0x001d00ec, +0x001e9df0, +0x001ec7e4, +0x001d4d44, +0x001a2424, +0x00157070, +0x000f8484, +0x0008db70, +0x00020cec, +0x00fbbc5c, +0x00f684d0, +0x00f2e4e0, +0x00f12d44, +0x00f174d8, +0x00f3945c, +0x00f72ab0, +0x00fba984, +0x001a22e3, +0x0004bcfc, +0x0008115c, +0x0009fa78, +0x000a45e0, +0x0008fffc, +0x00067070, +0x00030d88, +0x00da2f23, +0x00fc1730, +0x00f99a54, +0x00f84c00, +0x00f851a8, +0x00f9982c, +0x00fbd928, +0x00aa16cf, +0x0061c6c3, +0x0003fa04, +0x00059d78, +0x0006357c, +0x0005b618, +0x0004437c, +0x000229bc, +0x00f3803f, +0x00fd9c14, +0x00fbf354, +0x00fb16bc, +0x00fb2258, +0x00fc0838, +0x00fd94b0, +0x00de4c6f, +0x0056ddab, +0x0002e608, +0x0003d744, +0x00040c18, +0x000384e8, +0x000263b0, +0x00391a1f, +0x00d43a5f, +0x00fdf2ec, +0x00fd06bc, +0x00fcb100, +0x00fcf934, +0x00fdc9dc, +0x00bd738f, +0x00106c83, +0x005be09f, +0x00024a04, +0x0002ae04, +0x00028fd4, +0x007f0d8f, +0x004529ff, +0x00020d4b, +0x00c2867f, +0x00920a0f, +0x00fde2b0, +0x00fde758, +0x0093e747, +0x00c0cb77, +0x00f754ab, +0x002d163f, +0x00585e1f, +0x0071ef8b, +0x00763257, +0x0065a79f, +0x00449a33, +0x001a255f, +0x00eec953, +0x00cad5f7, +0x00b4f72f, +0x00b1226f, +0x00c00eeb, +0x00df46af, +0x0009c1f7, +0x0038e64f, +0x0065b5ef, +0x000227dc, +0x00028480, +0x0002a3a4, +0x000285b0, +0x00023398, +0x006f1f67, +0x004caed7, +0x002a2af7, +0x000b7d53, +0x00f3677b, +0x00e349ef, +0x00db2ccf, +0x00d9fec3, +0x00ddf61b, +0x00e4fe17, +0x00ed1b4f, +0x00f068f7, +0x0084edbd, +0x007b1245, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00762489, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00009494, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000010, +0x00000000, +0x00000000, +0x000004fc, +0x00000000, +0x00000000, +0x00000018, +0x000004f4, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00a0000c, +0x003c00a1, +0x00000000, +0x00000000, +0x000005ba, +0x00a2000c, +0x003c00a3, +0x00000000, +0x00000000, +0x000005ba, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x0000000a, +0x7fff7fff, +0x7fff7fff, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000004, +0x00000001, +0x00000000, +0x00000000, +0x00000000, +0x003ffff0, +0x00000000, +0x00400000, +0x00000004, +0x00000001, +0x00000000, +0x00000000, +0x00000000, +0x003ffff0, +0x00000000, +0x00400000, +0x01f501e2, +0x021b0208, +0x0241022e, +0x02670254, +0x028d027a, +0x02b302a0, +0x02d902c6, +0x02ff02ec, +0x00000004, +0x00000001, +0x00000000, +0x00000000, +0x00000000, +0x003ffff0, +0x00000000, +0x00400000, +0x03280316, +0x034c033a, +0x0370035e, +0x03940382, +0x03b803a6, +0x03dc03ca, +0x040003ee, +0x04240412, +0x00001400, +0x000000ff, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x0aa40c24, +0x00000c34, +0x0a940c04, +0x00000c14, +0x0e640bb4, +0x00000ba4, +0x0e540b94, +0x00000b84, +0x0a840be4, +0x00000bf4, +0x0a740bc4, +0x00000bd4, +0x0e440b34, +0x00000b24, +0x0e340b14, +0x00000b04, +0x0a640b64, +0x00000b74, +0x0a540b44, +0x00000b54, +0x00000004, +0x00000001, +0x00000000, +0x00000000, +0x00000000, +0x003ffff0, +0x00000000, +0x00400000, +0x00000004, +0x00000001, +0x00000000, +0x00000000, +0x00000000, +0x003ffff0, +0x00000000, +0x00400000, +0x0a740bc4, +0x000010f4, +0x0a840be4, +0x00001104, +0x11340b14, +0x00000000, +0x11540b94, +0x00000000, +0x00560014, +0x00570003, +0x005a0058, +0x00000013, +0x00560014, +0x00570006, +0x00610058, +0x00000013, +0x00560019, +0x00570003, +0x005a0058, +0x033c0013, +0x00560019, +0x00570006, +0x00610058, +0x033c0013, +0x00640014, +0x0065010d, +0x00680066, +0x00000012, +0x005b0015, +0x005c0002, +0x005f005d, +0x00000013, +0x005b0015, +0x005c0005, +0x0062005d, +0x00000013, +0x005b001a, +0x005c0002, +0x005f005d, +0x038c0013, +0x005b001a, +0x005c0005, +0x0062005d, +0x038c0013, +0x01050003, +0x0001008e, +0x00900001, +0x00000000, +0x01060003, +0x0001008f, +0x00910001, +0x00000000, +0x01070003, +0x00010129, +0x00900001, +0x00000000, +0x01070003, +0x0001012a, +0x00910001, +0x00000000, +0x00ab0003, +0x0001008e, +0x00900001, +0x00000000, +0x00ab0003, +0x0001008f, +0x00910001, +0x00000000, +0x0032000b, +0x00710030, +0x004e0072, +0x00000000, +0x00010013, +0x00010001, +0x01100001, +0x00000000, +0x00010013, +0x00010001, +0x01110001, +0x00000000, +0x000d000a, +0x000f000e, +0x00110010, +0x00000000, +0x00280000, +0x002b002a, +0x002d002c, +0x00000000, +0x00240000, +0x00790024, +0x00920074, +0x00000000, +0x00030000, +0x007a0003, +0x009300ad, +0x00000000, +0x00240000, +0x007b0024, +0x00940077, +0x00000000, +0x00060000, +0x007c0006, +0x00950078, +0x00000000, +0x00290000, +0x007d0105, +0x00920073, +0x00000000, +0x008e0000, +0x007e0060, +0x00930075, +0x00000000, +0x00290000, +0x007f0106, +0x00940076, +0x00000000, +0x008f0000, +0x00800063, +0x00950078, +0x00000000, +0x01080000, +0x00810108, +0x00920074, +0x00000000, +0x010b0000, +0x0082010b, +0x00930075, +0x00000000, +0x01080000, +0x00830108, +0x00940077, +0x00000000, +0x010c0000, +0x0084010c, +0x00950078, +0x00000000, +0x00310000, +0x00850107, +0x00920073, +0x00000000, +0x01290000, +0x00860109, +0x00930075, +0x00000000, +0x00310000, +0x00870107, +0x00940076, +0x00000000, +0x012a0000, +0x0088010a, +0x00950078, +0x00000000, +0x00270000, +0x008b00ab, +0x00920073, +0x00000000, +0x008e0000, +0x008c008d, +0x00930075, +0x00000000, +0x00270000, +0x008900ab, +0x00940076, +0x00000000, +0x008f0000, +0x008a008d, +0x00950078, +0x00000000, +0x00310000, +0x006f002f, +0x004e0070, +0x00000000, +0x00300018, +0x00980051, +0x009700d0, +0x00000000, +0x002f0018, +0x00960050, +0x009700d2, +0x00000000, +0x002e0008, +0x003c0031, +0x00000017, +0x00000000, +0x00220008, +0x003c0032, +0x00000018, +0x00000000, +0x0137000c, +0x00010001, +0x01380001, +0x00000000, +0x0001000d, +0x00010001, +0x00db0001, +0x00000000, +0x0001000d, +0x00010001, +0x00dc0001, +0x00000000, +0x0001000d, +0x00010001, +0x00dd0001, +0x00000000, +0x0001000d, +0x00010001, +0x00de0001, +0x00000000, +0x0001000d, +0x00010001, +0x00df0001, +0x00000000, +0x0001000d, +0x00010001, +0x00e00001, +0x00000000, +0x0001000d, +0x00010001, +0x00e10001, +0x00000000, +0x0001000d, +0x00010001, +0x00e20001, +0x00000000, +0x0001000d, +0x00010001, +0x00e30001, +0x00000000, +0x0001000d, +0x00010001, +0x00e40001, +0x00000000, +0x0001000d, +0x00010001, +0x00e50001, +0x00000000, +0x0001000d, +0x00010001, +0x00e60001, +0x00000000, +0x0001000d, +0x00010001, +0x00e70001, +0x00000000, +0x0001000d, +0x00010001, +0x00e80001, +0x00000000, +0x00fb000e, +0x00010001, +0x00fc0001, +0x00000000, +0x002f0005, +0x001c0027, +0x00000030, +0x00000000, +0x002a0005, +0x001d002e, +0x00000021, +0x00000000, +0x00080006, +0x00260021, +0x0000001a, +0x00000000, +0x00080006, +0x00260022, +0x0000001b, +0x00000000, +0x00080007, +0x00260021, +0x0000001a, +0x00000000, +0x00080007, +0x00260022, +0x0000001b, +0x00000000, +0x00080006, +0x006a0069, +0x0000001e, +0x00000000, +0x00080006, +0x006a0029, +0x0000001f, +0x00000000, +0x00080007, +0x006a0029, +0x0000001f, +0x00000000, +0x00c10001, +0x00ca0052, +0x0000011e, +0x00000000, +0x00030004, +0x000c0024, +0x00900001, +0x00000000, +0x00060004, +0x000c0024, +0x00910001, +0x00000000, +0x010b0004, +0x000c0108, +0x00900001, +0x00000000, +0x010c0004, +0x000c0108, +0x00910001, +0x00000000, +0x00300004, +0x00fe0051, +0x00fd0001, +0x00000000, +0x002f0004, +0x00fe0050, +0x00fd0001, +0x00000000, +0x00410002, +0x00430042, +0x00000016, +0x00000000, +0x00330002, +0x00350034, +0x00000013, +0x00000000, +0x00360002, +0x00380037, +0x00000014, +0x00000000, +0x00390002, +0x003b003a, +0x00000015, +0x00000000, +0x00690002, +0x006c006b, +0x00000019, +0x00000000, +0x01080002, +0x0040003f, +0x00000020, +0x00000000, +0x00080002, +0x00470046, +0x00000019, +0x00000000, +0x00cf0002, +0x00c900c0, +0x00000019, +0x00000000, +0x010d0002, +0x010f010e, +0x00000019, +0x00000000, +0x00270002, +0x00450044, +0x00000019, +0x00000000, +0x00010002, +0x00010001, +0x00000019, +0x00000000, +0x00010009, +0x00010028, +0x00530001, +0x00000000, +0x00010009, +0x00010023, +0x00540001, +0x00000000, +0x00c00011, +0x00c200c1, +0x00c700c3, +0x00000000, +0x00c80010, +0x00cb00ca, +0x00ce00cc, +0x00000000, +0x00010013, +0x00010001, +0x01120001, +0x00000000, +0x00010013, +0x00010001, +0x01130001, +0x00000000, +0x00010013, +0x00010001, +0x01140001, +0x00000000, +0x00010013, +0x00010001, +0x01150001, +0x00000000, +0x00010013, +0x00010001, +0x01160001, +0x00000000, +0x00010013, +0x00010001, +0x01170001, +0x00000000, +0x00010013, +0x00010001, +0x01180001, +0x00000000, +0x00010013, +0x00010001, +0x01190001, +0x00000000, +0x0001000f, +0x00010001, +0x00010001, +0x00000000, +0x00490012, +0x00d30041, +0x00d600d4, +0x00000000, +0x004a0012, +0x00d80033, +0x00d700d5, +0x00000000, +0x004b0012, +0x00d90036, +0x00d700d5, +0x00000000, +0x004c0012, +0x00da0039, +0x00d700d5, +0x00000000, +0x011b0016, +0x011c0001, +0x011d0001, +0x00000000, +0x00010017, +0x00010001, +0x00000001, +0x00000000, +0x011f0014, +0x0121010b, +0x01240122, +0x00000013, +0x011f0014, +0x0121010c, +0x01250122, +0x00000013, +0x011f0019, +0x0121010b, +0x01240122, +0x04040013, +0x011f0019, +0x0121010c, +0x01250122, +0x04040013, +0x01260015, +0x012d012b, +0x0130012e, +0x00000013, +0x01260015, +0x012d012c, +0x0131012e, +0x00000013, +0x0126001a, +0x012d012b, +0x0130012e, +0x02c40013, +0x0126001a, +0x012d012c, +0x0131012e, +0x02c40013, +0x01290000, +0x00860127, +0x00930075, +0x00000000, +0x012a0000, +0x00880128, +0x00950078, +0x00000000, +0x00010013, +0x00010001, +0x01320001, +0x00000000, +0x00010013, +0x00010001, +0x01330001, +0x00000000, +0x0003001b, +0x01340024, +0x01350001, +0x00000000, +0x00010013, +0x00010001, +0x01360001, +0x00000000, +0x010b001b, +0x013a0108, +0x01350001, +0x00000000, +0x00010013, +0x00010001, +0x01390001, +0x00000000, +0x00a7001c, +0x004d0008, +0x009e009c, +0x00000000, +0x00a9001c, +0x00a80025, +0x009f009d, +0x00000000, +0x00a7001d, +0x004d0008, +0x009e009c, +0x00000000, +0x00a9001d, +0x00a80025, +0x009f009d, +0x00000000, +0x00a7001e, +0x004d0008, +0x00ac009c, +0x00000000, +0x00a7001f, +0x004d0008, +0x00ac009c, +0x00000000, +0x00010020, +0x00010001, +0x00000001, +0x00000000, +0x00010021, +0x00010001, +0x00000001, +0x00000000, +0x00310022, +0x013c0107, +0x013d0001, +0x00000000, +0x00010013, +0x00010001, +0x013e0001, +0x00000000, +0x00010013, +0x00010001, +0x013f0001, +0x00000000, +0x00010013, +0x00010001, +0x01400001, +0x00000000, +0x00290022, +0x01410105, +0x013d0001, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00003000, +0x0041008a, +0x003300d3, +0x003600d8, +0x003900d9, +0x010500da, +0x0105007d, +0x0060007e, +0x0060007e, +0x010b007d, +0x010b0082, +0x01080081, +0x01080082, +0x00030081, +0x00030134, +0x00030079, +0x0024007a, +0x00240134, +0x00240079, +0x0107007a, +0x0107013c, +0x01090086, +0x0109013c, +0x002a0086, +0x002f002b, +0x0050006f, +0x00300096, +0x00510071, +0x00ab0098, +0x00ab008b, +0x008d008c, +0x008d008b, +0x008d008c, +0x00000000, +0x0a7411f4, +0x00000bd4, +0x0a7411f4, +0x000010f4, +0x0a541234, +0x00000b54, +0x0443038f, +0x03d5044e, +0x006403df, +0x004d0038, +0x0481045c, +0x03c00469, +0x048e057f, +0x00e905e0, +0x01ed01c1, +0x00d303a2, +0x02020220, +0x065e075a, +0x022c03ea, +0x040e0210, +0x01ff0200, +0x01fe0201, +0x071706d4, +0x00020422, +0x010300f7, +0x011e0112, +0x0136012a, +0x0154013d, +0x0144014c, +0x0176015b, +0x0003019d, +0x01bf01be, +0x055e01c0, +0x01a904a6, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00001580, +0x00001580, +0x00001580, +0x0000193f, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00046f03, +0x00000000, +0x00047202, +0x00000000, +0x0006ba03, +0x00000000, +0x0004bc05, +0x00000000, +0x0004c104, +0x00000000, +0x0006b505, +0x00000000, +0x0001dc0c, +0x00000000, +0x0004c528, +0x00000000, +0x00051528, +0x00000000, +0x0006ef06, +0x00000000, +0x00028318, +0x00000000, +0x00019312, +0x00000000, +0x0001a512, +0x00019000, +0x0001b524, +0x00019112, +0x0001a312, +0x00120024, +0x0006dc00, +0x0001b50e, +0x0001b50e, +0x0001b50e, +0x0001b50e, +0x0001b50e, +0x0001b50e, +0x0001b50e, +0x0001b50e, +0x0001b50e, +0x0001b50e, +0x0001b50e, +0x0001b50e, +0x0001b50e, +0x0001b50e, +0x0001b50e, +0x0001b50e, +0x0001b80c, +0x0001c304, +0x0001b80c, +0x0001c704, +0x00000000, +0x0001cb02, +0x00000000, +0x0001cd02, +0x0001c40c, +0x0001cf04, +0x0001c40c, +0x0001d304, +0x0001d702, +0x0001d702, +0x00000000, +0x0001e80c, +0x00000000, +0x0001f40c, +0x00000000, +0x0001d00c, +0x00000000, +0x0001c40c, +0x00000000, +0x0001b80c, +0x0001c40c, +0x0001d00c, +0x00000000, +0x0002000c, +0x00000000, +0x0002180c, +0x00000000, +0x0002240c, +0x00000000, +0x0002560c, +0x00026209, +0x00026209, +0x00000000, +0x0001d909, +0x000b0009, +0x00000000, +0x00000000, +0x00020c0c, +0x00000000, +0x0006bd0c, +0x00000000, +0x0006c90c, +0x00000000, +0x0006d50c, +0x00000000, +0x0006e10c, +0x00000000, +0x00029b0c, +0x00028318, +0x0002cb0c, +0x00083900, +0x0002d70c, +0x00000000, +0x0002a70c, +0x00028300, +0x0002e30c, +0x00083900, +0x0002ef0c, +0x00000000, +0x0002b30c, +0x00028318, +0x0002fb0c, +0x00083900, +0x0003070c, +0x00083801, +0x00083901, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00028318, +0x0003130c, +0x00083900, +0x00031f0c, +0x00000000, +0x0002bf0c, +0x00028318, +0x00032b0c, +0x00083900, +0x0003370c, +0x00028318, +0x0003430c, +0x00083900, +0x00034f0c, +0x00028318, +0x00035b0c, +0x00083900, +0x0003670c, +0x00000000, +0x00037378, +0x00000000, +0x0003eb18, +0x00000000, +0x00040318, +0x00000000, +0x00041b18, +0x00000000, +0x00043318, +0x00000000, +0x0008c860, +0x000b0019, +0x00000000, +0x000b0009, +0x00000000, +0x00000000, +0x00047418, +0x00000000, +0x00048c18, +0x00000000, +0x0004a418, +0x000b080c, +0x00000000, +0x000b0808, +0x00000000, +0x000b07f4, +0x00000000, +0x00000000, +0x0004c528, +0x0002ec13, +0x0002ff13, +0x0004c528, +0x00031400, +0x00031500, +0x00020600, +0x00590002, +0x00038c00, +0x00000000, +0x0004ed28, +0x0002ec13, +0x0002ff13, +0x0004ed28, +0x00031200, +0x00031300, +0x00020e00, +0x005e0002, +0x00033c00, +0x00000000, +0x0004ed28, +0x00590004, +0x00038c00, +0x005e0004, +0x00033c00, +0x00000000, +0x0004ed28, +0x00000000, +0x00051528, +0x00041212, +0x00042412, +0x00051528, +0x00043600, +0x00043700, +0x00021e00, +0x0067000c, +0x00047c00, +0x00000000, +0x00053d0c, +0x0002180c, +0x0001b80c, +0x00000000, +0x0005490c, +0x00083900, +0x0005550c, +0x00028318, +0x0005610c, +0x00083900, +0x00056d0c, +0x00059219, +0x00059219, +0x00000000, +0x00046a19, +0x00057919, +0x00057919, +0x00045119, +0x00043819, +0x00000000, +0x0004a20d, +0x00000000, +0x0004af0d, +0x00000000, +0x0004bc07, +0x00000000, +0x0004830d, +0x00000000, +0x0004900d, +0x00000000, +0x00049d05, +0x0005cf0d, +0x0005cf0d, +0x0005dc07, +0x0005dc07, +0x0005e30d, +0x0005e30d, +0x0005f005, +0x0005f005, +0x0005f50d, +0x0005f50d, +0x00060207, +0x00060207, +0x0006090d, +0x0006090d, +0x00061605, +0x00061605, +0x00061b0d, +0x00061b0d, +0x00062807, +0x00062807, +0x00062f0d, +0x00062f0d, +0x00063c05, +0x00063c05, +0x0006410d, +0x0006410d, +0x00064e07, +0x00064e07, +0x0006550d, +0x0006550d, +0x00066205, +0x00066205, +0x00067b0d, +0x00067b0d, +0x00068805, +0x00068805, +0x0006670d, +0x0006670d, +0x00067407, +0x00067407, +0x00000000, +0x00068d28, +0x00000000, +0x0005c902, +0x00000000, +0x0005cb04, +0x00000006, +0x00000000, +0x00000003, +0x00000000, +0x000b000d, +0x00000000, +0x00010007, +0x00000000, +0x000b000d, +0x00000000, +0x00030005, +0x00000000, +0x0005ab0f, +0x0005ab0f, +0x0000000f, +0x00000000, +0x0005ba0f, +0x0005ba0f, +0x00030007, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x0005ba01, +0x00000000, +0x0005ba01, +0x00140364, +0x00000007, +0x002803b4, +0x00000007, +0x00000000, +0x0006da02, +0x00000000, +0x00098802, +0x00000000, +0x0006dc02, +0x00000000, +0x00098a02, +0x0006de02, +0x00098c01, +0x00000000, +0x00000000, +0x00000000, +0x0008c860, +0x00000000, +0x0008c860, +0x00000000, +0x00092860, +0x00000000, +0x00092860, +0x00050c01, +0x00083918, +0x00000000, +0x0004630c, +0x001406f0, +0x00000007, +0x00000000, +0x00075907, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00098d01, +0x00098d01, +0x00000000, +0x00072706, +0x00028300, +0x00074518, +0x00075d0b, +0x00075d0b, +0x00000000, +0x0004c90b, +0x00019000, +0x00072d18, +0x00075d0b, +0x00075d0b, +0x00074518, +0x00072706, +0x00c4000b, +0x0000c500, +0x00000000, +0x0006f506, +0x00083900, +0x0006f506, +0x00028318, +0x0006fc18, +0x0004c504, +0x0006fb00, +0x00019000, +0x00071400, +0x00023100, +0x00071512, +0x00ea00cd, +0x000026ff, +0x00000000, +0x0006ef06, +0x0006ee00, +0x0004d40f, +0x00000000, +0x00000000, +0x0006ed00, +0x0004d40f, +0x00078013, +0x00078013, +0x00000000, +0x0004e313, +0x00000000, +0x0004f613, +0x00170013, +0x00000000, +0x00170013, +0x00000000, +0x00079313, +0x00079313, +0x0007a613, +0x0007a613, +0x0007b913, +0x0007b913, +0x00000274, +0x00000000, +0x0000029c, +0x00000000, +0x000002c4, +0x00000000, +0x000002ec, +0x00000000, +0x00000314, +0x00000000, +0x0000033c, +0x00000000, +0x00000364, +0x00000000, +0x0000038c, +0x00000000, +0x000003b4, +0x00000000, +0x000003dc, +0x00000000, +0x00000404, +0x00000000, +0x0000042c, +0x00000000, +0x00000454, +0x00000000, +0x0000047c, +0x00000000, +0x000004a4, +0x00000000, +0x000004cc, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x0001ac10, +0x000f00eb, +0x00000000, +0x00000002, +0x00000000, +0x00000000, +0x00019000, +0x00000000, +0x00019a0c, +0x00000000, +0x0007cc02, +0x00000000, +0x0007ce04, +0x00000000, +0x0007d206, +0x00000000, +0x0007d80c, +0x00000000, +0x0007e418, +0x00000000, +0x00044b0c, +0x00000000, +0x0004570c, +0x00000000, +0x0002300c, +0x00000000, +0x00023c0c, +0x00000000, +0x00024802, +0x00000000, +0x00024b04, +0x00000000, +0x00025002, +0x00000000, +0x00025204, +0x00000000, +0x0007fc0c, +0x00028318, +0x0008080c, +0x00083900, +0x0008140c, +0x00000914, +0x00000000, +0x0000091c, +0x00000000, +0x00000924, +0x00000000, +0x0000092c, +0x00000000, +0x00000934, +0x00000000, +0x0000093c, +0x00000000, +0x00000944, +0x00000000, +0x0000094c, +0x00000000, +0x00000954, +0x00000000, +0x0000095c, +0x00000000, +0x00000000, +0x00013d00, +0x00000000, +0x00056000, +0x00013d00, +0x00019000, +0x00001940, +0x00000000, +0x00050c00, +0x00050c01, +0x00000000, +0x00083a28, +0x00000000, +0x00083a28, +0x0002ec13, +0x0002ff13, +0x00083a28, +0x00051000, +0x00051100, +0x00025900, +0x00230002, +0x0002c401, +0x00230004, +0x0002c401, +0x00000000, +0x00086228, +0x00000000, +0x00086228, +0x00000000, +0x00086228, +0x00000000, +0x00088a02, +0x00000000, +0x00088c04, +0x00000000, +0x00024803, +0x00000000, +0x00024b05, +0x0002ec13, +0x0002ff13, +0x00086228, +0x00050e00, +0x00050f00, +0x00026100, +0x002f0002, +0x00040401, +0x002f0004, +0x00040401, +0x000009a4, +0x00000000, +0x000009ac, +0x00000000, +0x000512a8, +0x0008901c, +0x0006001c, +0x00000000, +0x000009b4, +0x00000000, +0x00000000, +0x00100020, +0x001006f0, +0x00000007, +0x000009bc, +0x00000000, +0x000512a8, +0x0008ac1c, +0x000b0011, +0x00000000, +0x0006e079, +0x00099f79, +0x00060079, +0x00000000, +0x000012f4, +0x00000000, +0x000012fc, +0x00000000, +0x00001304, +0x00000000, +0x0006e079, +0x000a2979, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000001, +0x00000010, +0x00000001, +0x00000010, +0x00000001, +0x00000010, +0x00000001, +0x00000010, +0x00000001, +0x00000010, +0x00000001, +0x00000010, +0x00000001, +0x00000010, +0x00000001, +0x00000010, +0x00000001, +0x00000010, +0x00000001, +0x00000010, +0x00000001, +0x00000010, +0x00000001, +0x00000010, +0x00000001, +0x00000010, +0x00000001, +0x00000010, +0x00000001, +0x00000010, +0x00000001, +0x00000010, +0x00000001, +0x00000010, +0x00000000, +0x00000000, +0x00400000, +0x00400000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000001, +0x00000001, +0x00000001, +0x00000001, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x0000001b, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000003, +0x00000000, +0x00000003, +0x00000000, +0x00000003, +0x00000000, +0x00000006, +0x00000000, +0x00000006, +0x00000000, +0x00000006, +0x00000000, +0x00000009, +0x00000000, +0x00000009, +0x00000000, +0x00000009, +0x00000000, +0x00000005, +0x00000000, +0x00000005, +0x00000000, +0x00000005, +0x00000000, +0x00000007, +0x00000000, +0x00000007, +0x00000000, +0x00000007, +0x00000000, +0x00000008, +0x00000000, +0x00000008, +0x00000000, +0x00000008, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00e66666, +0x00199999, +0x00199999, +0x00199999, +0x00000000, +0x00000000, +0x00e66666, +0x00e66666, +0x00ffffff, +0x00ffffff, +0x00199999, +0x00199999, +0x00f33333, +0x000ccccc, +0x00f33333, +0x00f33333, +0x00199999, +0x00e66666, +0x00f33333, +0x00f33333, +0x00f33333, +0x000ccccc, +0x00199999, +0x00199999, +0x000ccccc, +0x00162b95, +0x00f33333, +0x000ccccc, +0x00e66666, +0x00000000, +0x00f33333, +0x00f33333, +0x000ccccc, +0x00e9d46a, +0x00199999, +0x00e66666, +0x000ccccc, +0x00e9d46a, +0x00f33333, +0x00f33333, +0x00e66666, +0x00ffffff, +0x00f33333, +0x000ccccc, +0x000ccccc, +0x00162b95, +0x00199999, +0x00199999, +0x00162b95, +0x0018ba4a, +0x000ccccc, +0x00162b95, +0x00000000, +0x00121a18, +0x00f33333, +0x000ccccc, +0x00e9d46a, +0x0006a032, +0x00e66666, +0x00000000, +0x00e9d46a, +0x00f95fcd, +0x00f33333, +0x00f33333, +0x00ffffff, +0x00ede5e7, +0x000ccccc, +0x00e9d46a, +0x00162b95, +0x00e745b5, +0x00199999, +0x00e66666, +0x00162b95, +0x00e745b5, +0x000ccccc, +0x00e9d46a, +0x00000000, +0x00ede5e7, +0x00f33333, +0x00f33333, +0x00e9d46a, +0x00f95fcf, +0x00e66666, +0x00ffffff, +0x00e9d46a, +0x0006a032, +0x00f33333, +0x000ccccc, +0x00ffffff, +0x00121a18, +0x000ccccc, +0x00162b95, +0x00162b95, +0x0018ba4a, +0x00199999, +0x00199999, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x007fffff, +0x00800000, +0x001fffff, +0x00e00000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x000049cc, +0x000049cc, +0x004fffff, +0x00b00000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, +0x00000000, diff --git a/sound/soc/omap/abe/abe_functionsid.h b/sound/soc/omap/abe/abe_functionsid.h new file mode 100644 index 0000000..1c02770 --- /dev/null +++ b/sound/soc/omap/abe/abe_functionsid.h @@ -0,0 +1,122 @@ +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2010-2011 Texas Instruments Incorporated, + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License 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. + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * BSD LICENSE + * + * Copyright(c) 2010-2011 Texas Instruments Incorporated, + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef _ABE_FUNCTIONSID_H_ +#define _ABE_FUNCTIONSID_H_ +/* + * TASK function ID definitions + */ +#define C_ABE_FW_FUNCTION_IIR 0 +#define C_ABE_FW_FUNCTION_monoToStereoPack 1 +#define C_ABE_FW_FUNCTION_stereoToMonoSplit 2 +#define C_ABE_FW_FUNCTION_decimator 3 +#define C_ABE_FW_FUNCTION_OS0Fill 4 +#define C_ABE_FW_FUNCTION_mixer2 5 +#define C_ABE_FW_FUNCTION_mixer4 6 +#define C_ABE_FW_FUNCTION_mixer4_dual_mono 7 +#define C_ABE_FW_FUNCTION_inplaceGain 8 +#define C_ABE_FW_FUNCTION_StreamRouting 9 +#define C_ABE_FW_FUNCTION_gainConverge 10 +#define C_ABE_FW_FUNCTION_dualIir 11 +#define C_ABE_FW_FUNCTION_IO_DL_pp 12 +#define C_ABE_FW_FUNCTION_IO_generic 13 +#define C_ABE_FW_FUNCTION_irq_fifo_debug 14 +#define C_ABE_FW_FUNCTION_synchronize_pointers 15 +#define C_ABE_FW_FUNCTION_VIBRA2 16 +#define C_ABE_FW_FUNCTION_VIBRA1 17 +#define C_ABE_FW_FUNCTION_IIR_SRC_MIC 18 +#define C_ABE_FW_FUNCTION_wrappers 19 +#define C_ABE_FW_FUNCTION_ASRC_DL_wrapper 20 +#define C_ABE_FW_FUNCTION_ASRC_UL_wrapper 21 +#define C_ABE_FW_FUNCTION_mem_init 22 +#define C_ABE_FW_FUNCTION_debug_vx_asrc 23 +#define C_ABE_FW_FUNCTION_IIR_SRC2 24 +#define C_ABE_FW_FUNCTION_ASRC_DL_wrapper_sibling 25 +#define C_ABE_FW_FUNCTION_ASRC_UL_wrapper_sibling 26 +#define C_ABE_FW_FUNCTION_FIR6 27 +#define C_ABE_FW_FUNCTION_SRC44P1 28 +#define C_ABE_FW_FUNCTION_SRC44P1_1211 29 +#define C_ABE_FW_FUNCTION_SRC44P1_PP 30 +#define C_ABE_FW_FUNCTION_SRC44P1_1211_PP 31 +#define C_ABE_FW_FUNCTION_CHECK_IIR_LEFT 32 +#define C_ABE_FW_FUNCTION_CHECK_IIR_RIGHT 33 +#define C_ABE_FW_FUNCTION_FIR12_2 34 +/* + * COPY function ID definitions + */ +#define NULL_COPY_CFPID 0 +#define S2D_STEREO_16_16_CFPID 1 +#define S2D_MONO_MSB_CFPID 2 +#define S2D_STEREO_MSB_CFPID 3 +#define S2D_STEREO_RSHIFTED_16_CFPID 4 +#define S2D_MONO_RSHIFTED_16_CFPID 5 +#define D2S_STEREO_16_16_CFPID 6 +#define D2S_MONO_MSB_CFPID 7 +#define D2S_MONO_RSHIFTED_16_CFPID 8 +#define D2S_STEREO_RSHIFTED_16_CFPID 9 +#define D2S_STEREO_MSB_CFPID 10 +#define COPY_DMIC_CFPID 11 +#define COPY_MCPDM_DL_CFPID 12 +#define COPY_MM_UL_CFPID 13 +#define SPLIT_SMEM_CFPID 14 +#define MERGE_SMEM_CFPID 15 +#define SPLIT_TDM_CFPID 16 +#define MERGE_TDM_CFPID 17 +#define ROUTE_MM_UL_CFPID 18 +#define IO_IP_CFPID 19 +#define COPY_UNDERFLOW_CFPID 20 +#endif /* _ABE_FUNCTIONSID_H_ */ diff --git a/sound/soc/omap/abe/abe_fw.h b/sound/soc/omap/abe/abe_fw.h new file mode 100644 index 0000000..a29dbb3 --- /dev/null +++ b/sound/soc/omap/abe/abe_fw.h @@ -0,0 +1,214 @@ +/* + + This file is provided under a dual BSD/GPLv2 license. When using or + redistributing this file, you may do so under either license. + + GPL LICENSE SUMMARY + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License 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. + The full GNU General Public License is included in this distribution + in the file called LICENSE.GPL. + + BSD LICENSE + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name of Texas Instruments Incorporated nor the names of + its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef _ABE_FW_H_ +#define _ABE_FW_H_ + +#include "abe_cm_addr.h" +#include "abe_sm_addr.h" +#include "abe_dm_addr.h" +#include "abe_typedef.h" +/* + * GLOBAL DEFINITION + */ +/* one scheduler loop = 4kHz = 12 samples at 48kHz */ +#define FW_SCHED_LOOP_FREQ 4000 +/* one scheduler loop = 4kHz = 12 samples at 48kHz */ +#define FW_SCHED_LOOP_FREQ_DIV1000 (FW_SCHED_LOOP_FREQ/1000) +#define EVENT_FREQUENCY 96000 +#define SLOTS_IN_SCHED_LOOP (96000/FW_SCHED_LOOP_FREQ) +#define SCHED_LOOP_8kHz (8000/FW_SCHED_LOOP_FREQ) +#define SCHED_LOOP_16kHz (16000/FW_SCHED_LOOP_FREQ) +#define SCHED_LOOP_24kHz (24000/FW_SCHED_LOOP_FREQ) +#define SCHED_LOOP_48kHz (48000/FW_SCHED_LOOP_FREQ) +#define TASKS_IN_SLOT 8 +/* + * DMEM AREA - SCHEDULER + */ +#define dmem_mm_trace OMAP_ABE_D_DEBUG_FIFO_ADDR +#define dmem_mm_trace_size ((OMAP_ABE_D_DEBUG_FIFO_SIZE)/4) +#define ATC_SIZE 8 /* 8 bytes per descriptors */ +struct omap_abe_atc_desc { + unsigned rdpt:7; /* first 32bits word of the descriptor */ + unsigned reserved0:1; + unsigned cbsize:7; + unsigned irqdest:1; + unsigned cberr:1; + unsigned reserved1:5; + unsigned cbdir:1; + unsigned nw:1; + unsigned wrpt:7; + unsigned reserved2:1; + unsigned badd:12; /* second 32bits word of the descriptor */ + unsigned iter:7; /* iteration field overlaps 16-bit boundary */ + unsigned srcid:6; + unsigned destid:6; + unsigned desen:1; +}; +/* + * Infinite counter incremented on each sheduler periods (~250 us) + * uint16 dmem_debug_time_stamp + */ +#define dmem_debug_time_stamp OMAP_ABE_D_LOOPCOUNTER_ADDR +/* + * ATC BUFFERS + IO TASKS SMEM buffers + */ +#define dmem_dmic OMAP_ABE_D_DMIC_UL_FIFO_ADDR +#define dmem_dmic_size (OMAP_ABE_D_DMIC_UL_FIFO_SIZE/4) +#define dmem_amic OMAP_ABE_D_MCPDM_UL_FIFO_ADDR +#define dmem_amic_size (OMAP_ABE_D_MCPDM_UL_FIFO_SIZE/4) +#define smem_amic AMIC_96_labelID +#define dmem_mcpdm OMAP_ABE_D_MCPDM_DL_FIFO_ADDR +#define dmem_mcpdm_size (OMAP_ABE_D_MCPDM_DL_FIFO_SIZE/4) +#define dmem_mm_ul OMAP_ABE_D_MM_UL_FIFO_ADDR +#define dmem_mm_ul_size (OMAP_ABE_D_MM_UL_FIFO_SIZE/4) +/* managed directly by the router */ +#define smem_mm_ul MM_UL_labelID +#define dmem_mm_ul2 OMAP_ABE_D_MM_UL2_FIFO_ADDR +#define dmem_mm_ul2_size (OMAP_ABE_D_MM_UL2_FIFO_SIZE/4) +/* managed directly by the router */ +#define smem_mm_ul2 MM_UL2_labelID +#define dmem_mm_dl OMAP_ABE_D_MM_DL_FIFO_ADDR +#define dmem_mm_dl_size (OMAP_ABE_D_MM_DL_FIFO_SIZE/4) +#define smem_mm_dl MM_DL_labelID +#define dmem_vx_dl OMAP_ABE_D_VX_DL_FIFO_ADDR +#define dmem_vx_dl_size (OMAP_ABE_D_VX_DL_FIFO_SIZE/4) +#define smem_vx_dl IO_VX_DL_ASRC_labelID /* Voice_16k_DL_labelID */ +#define dmem_vx_ul OMAP_ABE_D_VX_UL_FIFO_ADDR +#define dmem_vx_ul_size (OMAP_ABE_D_VX_UL_FIFO_SIZE/4) +#define smem_vx_ul Voice_8k_UL_labelID +#define dmem_tones_dl OMAP_ABE_D_TONES_DL_FIFO_ADDR +#define dmem_tones_dl_size (OMAP_ABE_D_TONES_DL_FIFO_SIZE/4) +#define smem_tones_dl Tones_labelID +#define dmem_vib_dl OMAP_ABE_D_VIB_DL_FIFO_ADDR +#define dmem_vib_dl_size (OMAP_ABE_D_VIB_DL_FIFO_SIZE/4) +#define smem_vib IO_VIBRA_DL_labelID +#define dmem_mm_ext_out OMAP_ABE_D_MM_EXT_OUT_FIFO_ADDR +#define dmem_mm_ext_out_size (OMAP_ABE_D_MM_EXT_OUT_FIFO_SIZE/4) +#define smem_mm_ext_out DL1_GAIN_out_labelID +#define dmem_mm_ext_in OMAP_ABE_D_MM_EXT_IN_FIFO_ADDR +#define dmem_mm_ext_in_size (OMAP_ABE_D_MM_EXT_IN_FIFO_SIZE/4) +/*IO_MM_EXT_IN_ASRC_labelID ASRC input buffer, size 40 */ +#define smem_mm_ext_in_opp100 IO_MM_EXT_IN_ASRC_labelID +/* at OPP 50 without ASRC */ +#define smem_mm_ext_in_opp50 MM_EXT_IN_labelID +#define dmem_bt_vx_dl OMAP_ABE_D_BT_DL_FIFO_ADDR +#define dmem_bt_vx_dl_size (OMAP_ABE_D_BT_DL_FIFO_SIZE/4) +#define smem_bt_vx_dl_opp50 BT_DL_8k_labelID +/*BT_DL_8k_opp100_labelID ASRC output buffer, size 40 */ +#define smem_bt_vx_dl_opp100 BT_DL_8k_opp100_labelID +#define dmem_bt_vx_ul OMAP_ABE_D_BT_UL_FIFO_ADDR +#define dmem_bt_vx_ul_size (OMAP_ABE_D_BT_UL_FIFO_SIZE/4) +#define smem_bt_vx_ul_opp50 BT_UL_8k_labelID +/*IO_BT_UL_ASRC_labelID ASRC input buffer, size 40 */ +#define smem_bt_vx_ul_opp100 IO_BT_UL_ASRC_labelID +/* + * SMEM AREA + */ +/* + * GAIN SMEM on PORT + * int32 smem_G0 [18] : desired gain on the ports + * format of G0 = 6 bits left shifted desired gain in linear 24bits format + * int24 stereo G0 [18] = G0 + * int24 stereo GI [18] current value of the gain in the same format of G0 + * List of smoothed gains : + * 6 DMIC 0 1 2 3 4 5 + * 2 AMIC L R + * 4 PORT1/2_RX L R + * 2 MM_EXT L R + * 2 MM_VX_DL L R + * 2 IHF L R + * --------------- + * 18 = TOTAL + */ +/* + * COEFFICIENTS AREA + */ +/* + * delay coefficients used in the IIR-1 filters + * int24 cmem_gain_delay_iir1[9 x 2] (a, (1-a)) + * + * 3 for 6 DMIC 0 1 2 3 4 5 + * 1 for 2 AMIC L R + * 2 for 4 PORT1/2_RX L R + * 1 for 2 MM_EXT L R + * 1 for 2 MM_VX_DL L R + * 1 for 2 IHF L R + */ +/* + * gain controls + */ +#define GAIN_LEFT_OFFSET 0 +#define GAIN_RIGHT_OFFSET 1 +/* stereo gains */ +#define dmic1_gains_offset 0 +#define dmic2_gains_offset 2 +#define dmic3_gains_offset 4 +#define amic_gains_offset 6 +#define dl1_gains_offset 8 +#define dl2_gains_offset 10 +#define splitters_gains_offset 12 +#define mixer_dl1_offset 14 +#define mixer_dl2_offset 18 +#define mixer_echo_offset 22 +#define mixer_sdt_offset 24 +#define mixer_vxrec_offset 26 +#define mixer_audul_offset 30 +#define btul_gains_offset 34 + +#endif/* _ABE_FW_H_ */ diff --git a/sound/soc/omap/abe/abe_gain.c b/sound/soc/omap/abe/abe_gain.c new file mode 100644 index 0000000..9c148da --- /dev/null +++ b/sound/soc/omap/abe/abe_gain.c @@ -0,0 +1,790 @@ +/* + + This file is provided under a dual BSD/GPLv2 license. When using or + redistributing this file, you may do so under either license. + + GPL LICENSE SUMMARY + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License 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. + The full GNU General Public License is included in this distribution + in the file called LICENSE.GPL. + + BSD LICENSE + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name of Texas Instruments Incorporated nor the names of + its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/err.h> +#include <linux/slab.h> + +#include "abe_dbg.h" +#include "abe.h" +#include "abe_gain.h" +#include "abe_mem.h" + +/* + * ABE CONST AREA FOR PARAMETERS TRANSLATION + */ +#define min_mdb (-12000) +#define max_mdb (3000) +#define sizeof_db2lin_table (1 + ((max_mdb - min_mdb)/100)) + +const u32 abe_db2lin_table[sizeof_db2lin_table] = { + 0x00000000, /* SMEM coding of -120 dB */ + 0x00000000, /* SMEM coding of -119 dB */ + 0x00000000, /* SMEM coding of -118 dB */ + 0x00000000, /* SMEM coding of -117 dB */ + 0x00000000, /* SMEM coding of -116 dB */ + 0x00000000, /* SMEM coding of -115 dB */ + 0x00000000, /* SMEM coding of -114 dB */ + 0x00000000, /* SMEM coding of -113 dB */ + 0x00000000, /* SMEM coding of -112 dB */ + 0x00000000, /* SMEM coding of -111 dB */ + 0x00000000, /* SMEM coding of -110 dB */ + 0x00000000, /* SMEM coding of -109 dB */ + 0x00000001, /* SMEM coding of -108 dB */ + 0x00000001, /* SMEM coding of -107 dB */ + 0x00000001, /* SMEM coding of -106 dB */ + 0x00000001, /* SMEM coding of -105 dB */ + 0x00000001, /* SMEM coding of -104 dB */ + 0x00000001, /* SMEM coding of -103 dB */ + 0x00000002, /* SMEM coding of -102 dB */ + 0x00000002, /* SMEM coding of -101 dB */ + 0x00000002, /* SMEM coding of -100 dB */ + 0x00000002, /* SMEM coding of -99 dB */ + 0x00000003, /* SMEM coding of -98 dB */ + 0x00000003, /* SMEM coding of -97 dB */ + 0x00000004, /* SMEM coding of -96 dB */ + 0x00000004, /* SMEM coding of -95 dB */ + 0x00000005, /* SMEM coding of -94 dB */ + 0x00000005, /* SMEM coding of -93 dB */ + 0x00000006, /* SMEM coding of -92 dB */ + 0x00000007, /* SMEM coding of -91 dB */ + 0x00000008, /* SMEM coding of -90 dB */ + 0x00000009, /* SMEM coding of -89 dB */ + 0x0000000A, /* SMEM coding of -88 dB */ + 0x0000000B, /* SMEM coding of -87 dB */ + 0x0000000D, /* SMEM coding of -86 dB */ + 0x0000000E, /* SMEM coding of -85 dB */ + 0x00000010, /* SMEM coding of -84 dB */ + 0x00000012, /* SMEM coding of -83 dB */ + 0x00000014, /* SMEM coding of -82 dB */ + 0x00000017, /* SMEM coding of -81 dB */ + 0x0000001A, /* SMEM coding of -80 dB */ + 0x0000001D, /* SMEM coding of -79 dB */ + 0x00000021, /* SMEM coding of -78 dB */ + 0x00000025, /* SMEM coding of -77 dB */ + 0x00000029, /* SMEM coding of -76 dB */ + 0x0000002E, /* SMEM coding of -75 dB */ + 0x00000034, /* SMEM coding of -74 dB */ + 0x0000003A, /* SMEM coding of -73 dB */ + 0x00000041, /* SMEM coding of -72 dB */ + 0x00000049, /* SMEM coding of -71 dB */ + 0x00000052, /* SMEM coding of -70 dB */ + 0x0000005D, /* SMEM coding of -69 dB */ + 0x00000068, /* SMEM coding of -68 dB */ + 0x00000075, /* SMEM coding of -67 dB */ + 0x00000083, /* SMEM coding of -66 dB */ + 0x00000093, /* SMEM coding of -65 dB */ + 0x000000A5, /* SMEM coding of -64 dB */ + 0x000000B9, /* SMEM coding of -63 dB */ + 0x000000D0, /* SMEM coding of -62 dB */ + 0x000000E9, /* SMEM coding of -61 dB */ + 0x00000106, /* SMEM coding of -60 dB */ + 0x00000126, /* SMEM coding of -59 dB */ + 0x0000014A, /* SMEM coding of -58 dB */ + 0x00000172, /* SMEM coding of -57 dB */ + 0x0000019F, /* SMEM coding of -56 dB */ + 0x000001D2, /* SMEM coding of -55 dB */ + 0x0000020B, /* SMEM coding of -54 dB */ + 0x0000024A, /* SMEM coding of -53 dB */ + 0x00000292, /* SMEM coding of -52 dB */ + 0x000002E2, /* SMEM coding of -51 dB */ + 0x0000033C, /* SMEM coding of -50 dB */ + 0x000003A2, /* SMEM coding of -49 dB */ + 0x00000413, /* SMEM coding of -48 dB */ + 0x00000492, /* SMEM coding of -47 dB */ + 0x00000521, /* SMEM coding of -46 dB */ + 0x000005C2, /* SMEM coding of -45 dB */ + 0x00000676, /* SMEM coding of -44 dB */ + 0x0000073F, /* SMEM coding of -43 dB */ + 0x00000822, /* SMEM coding of -42 dB */ + 0x00000920, /* SMEM coding of -41 dB */ + 0x00000A3D, /* SMEM coding of -40 dB */ + 0x00000B7D, /* SMEM coding of -39 dB */ + 0x00000CE4, /* SMEM coding of -38 dB */ + 0x00000E76, /* SMEM coding of -37 dB */ + 0x0000103A, /* SMEM coding of -36 dB */ + 0x00001235, /* SMEM coding of -35 dB */ + 0x0000146E, /* SMEM coding of -34 dB */ + 0x000016EC, /* SMEM coding of -33 dB */ + 0x000019B8, /* SMEM coding of -32 dB */ + 0x00001CDC, /* SMEM coding of -31 dB */ + 0x00002061, /* SMEM coding of -30 dB */ + 0x00002455, /* SMEM coding of -29 dB */ + 0x000028C4, /* SMEM coding of -28 dB */ + 0x00002DBD, /* SMEM coding of -27 dB */ + 0x00003352, /* SMEM coding of -26 dB */ + 0x00003995, /* SMEM coding of -25 dB */ + 0x0000409C, /* SMEM coding of -24 dB */ + 0x0000487E, /* SMEM coding of -23 dB */ + 0x00005156, /* SMEM coding of -22 dB */ + 0x00005B43, /* SMEM coding of -21 dB */ + 0x00006666, /* SMEM coding of -20 dB */ + 0x000072E5, /* SMEM coding of -19 dB */ + 0x000080E9, /* SMEM coding of -18 dB */ + 0x000090A4, /* SMEM coding of -17 dB */ + 0x0000A24B, /* SMEM coding of -16 dB */ + 0x0000B618, /* SMEM coding of -15 dB */ + 0x0000CC50, /* SMEM coding of -14 dB */ + 0x0000E53E, /* SMEM coding of -13 dB */ + 0x00010137, /* SMEM coding of -12 dB */ + 0x0001209A, /* SMEM coding of -11 dB */ + 0x000143D1, /* SMEM coding of -10 dB */ + 0x00016B54, /* SMEM coding of -9 dB */ + 0x000197A9, /* SMEM coding of -8 dB */ + 0x0001C967, /* SMEM coding of -7 dB */ + 0x00020137, /* SMEM coding of -6 dB */ + 0x00023FD6, /* SMEM coding of -5 dB */ + 0x00028619, /* SMEM coding of -4 dB */ + 0x0002D4EF, /* SMEM coding of -3 dB */ + 0x00032D64, /* SMEM coding of -2 dB */ + 0x000390A4, /* SMEM coding of -1 dB */ + 0x00040000, /* SMEM coding of 0 dB */ + 0x00047CF2, /* SMEM coding of 1 dB */ + 0x00050923, /* SMEM coding of 2 dB */ + 0x0005A670, /* SMEM coding of 3 dB */ + 0x000656EE, /* SMEM coding of 4 dB */ + 0x00071CF5, /* SMEM coding of 5 dB */ + 0x0007FB26, /* SMEM coding of 6 dB */ + 0x0008F473, /* SMEM coding of 7 dB */ + 0x000A0C2B, /* SMEM coding of 8 dB */ + 0x000B4606, /* SMEM coding of 9 dB */ + 0x000CA62C, /* SMEM coding of 10 dB */ + 0x000E314A, /* SMEM coding of 11 dB */ + 0x000FEC9E, /* SMEM coding of 12 dB */ + 0x0011DE0A, /* SMEM coding of 13 dB */ + 0x00140C28, /* SMEM coding of 14 dB */ + 0x00167E60, /* SMEM coding of 15 dB */ + 0x00193D00, /* SMEM coding of 16 dB */ + 0x001C515D, /* SMEM coding of 17 dB */ + 0x001FC5EB, /* SMEM coding of 18 dB */ + 0x0023A668, /* SMEM coding of 19 dB */ + 0x00280000, /* SMEM coding of 20 dB */ + 0x002CE178, /* SMEM coding of 21 dB */ + 0x00325B65, /* SMEM coding of 22 dB */ + 0x00388062, /* SMEM coding of 23 dB */ + 0x003F654E, /* SMEM coding of 24 dB */ + 0x00472194, /* SMEM coding of 25 dB */ + 0x004FCF7C, /* SMEM coding of 26 dB */ + 0x00598C81, /* SMEM coding of 27 dB */ + 0x006479B7, /* SMEM coding of 28 dB */ + 0x0070BC3D, /* SMEM coding of 29 dB */ + 0x007E7DB9, /* SMEM coding of 30 dB */ +}; + +const u32 abe_1_alpha_iir[64] = { + 0x040002, 0x040002, 0x040002, 0x040002, /* 0 */ + 0x50E955, 0x48CA65, 0x40E321, 0x72BE78, /* 1 [ms] */ + 0x64BA68, 0x57DF14, 0x4C3D60, 0x41D690, /* 2 */ + 0x38A084, 0x308974, 0x297B00, 0x235C7C, /* 4 */ + 0x1E14B0, 0x198AF0, 0x15A800, 0x125660, /* 8 */ + 0x0F82A0, 0x0D1B5C, 0x0B113C, 0x0956CC, /* 16 */ + 0x07E054, 0x06A3B8, 0x059844, 0x04B680, /* 32 */ + 0x03F80C, 0x035774, 0x02D018, 0x025E0C, /* 64 */ + 0x7F8057, 0x6B482F, 0x5A4297, 0x4BEECB, /* 128 */ + 0x3FE00B, 0x35BAA7, 0x2D3143, 0x2602AF, /* 256 */ + 0x1FF803, 0x1AE2FB, 0x169C9F, 0x13042B, /* 512 */ + 0x0FFE03, 0x0D72E7, 0x0B4F4F, 0x0982CB, /* 1.024 [s] */ + 0x07FF83, 0x06B9CF, 0x05A7E7, 0x04C193, /* 2.048 */ + 0x03FFE3, 0x035CFF, 0x02D403, 0x0260D7, /* 4.096 */ + 0x01FFFB, 0x01AE87, 0x016A07, 0x01306F, /* 8.192 */ + 0x00FFFF, 0x00D743, 0x00B503, 0x009837, +}; + +const u32 abe_alpha_iir[64] = { + 0x000000, 0x000000, 0x000000, 0x000000, /* 0 */ + 0x5E2D58, 0x6E6B3C, 0x7E39C0, 0x46A0C5, /* 1 [ms] */ + 0x4DA2CD, 0x541079, 0x59E151, 0x5F14B9, /* 2 */ + 0x63AFC1, 0x67BB45, 0x6B4281, 0x6E51C1, /* 4 */ + 0x70F5A9, 0x733A89, 0x752C01, 0x76D4D1, /* 8 */ + 0x783EB1, 0x797251, 0x7A7761, 0x7B549D, /* 16 */ + 0x7C0FD5, 0x7CAE25, 0x7D33DD, 0x7DA4C1, /* 32 */ + 0x7E03FD, 0x7E5449, 0x7E97F5, 0x7ED0F9, /* 64 */ + 0x7F0101, 0x7F2971, 0x7F4B7D, 0x7F6825, /* 128 */ + 0x7F8041, 0x7F948D, 0x7FA59D, 0x7FB3FD, /* 256 */ + 0x7FC011, 0x7FCA3D, 0x7FD2C9, 0x7FD9F9, /* 512 */ + 0x7FE005, 0x7FE51D, 0x7FE961, 0x7FECFD, /* 1.024 [s] */ + 0x7FF001, 0x7FF28D, 0x7FF4B1, 0x7FF67D, /* 2.048 */ + 0x7FF801, 0x7FF949, 0x7FFA59, 0x7FFB41, /* 4.096 */ + 0x7FFC01, 0x7FFCA5, 0x7FFD2D, 0x7FFDA1, /* 8.192 */ + 0x7FFE01, 0x7FFE51, 0x7FFE95, 0x7FFED1, +}; + +/** + * abe_int_2_float + * returns a mantissa on 16 bits and the exponent + * 0x4000.0000 leads to M=0x4000 X=15 + * 0x0004.0000 leads to M=0x4000 X=4 + * 0x0000.0001 leads to M=0x4000 X=-14 + * + */ +void abe_int_2_float16(u32 data, u32 *mantissa, u32 *exp) +{ + u32 i; + *exp = 0; + *mantissa = 0; + for (i = 0; i < 32; i++) { + if ((1 << i) > data) + break; + } + *exp = i - 15; + *mantissa = (*exp > 0) ? data >> (*exp) : data << (*exp); +} + +/** + * abe_use_compensated_gain + * @on_off: + * + * Selects the automatic Mixer's gain management + * on_off = 1 allows the "abe_write_gain" to adjust the overall + * gains of the mixer to be tuned not to create saturation + */ +int omap_abe_use_compensated_gain(struct omap_abe *abe, int on_off) +{ + abe->compensated_mixer_gain = on_off; + return 0; +} +EXPORT_SYMBOL(omap_abe_use_compensated_gain); + +/** + * omap_abe_gain_offset + * returns the offset to firmware data structures + * + */ +void omap_abe_gain_offset(struct omap_abe *abe, u32 id, u32 *mixer_offset) +{ + switch (id) { + default: + case GAINS_DMIC1: + *mixer_offset = dmic1_gains_offset; + break; + case GAINS_DMIC2: + *mixer_offset = dmic2_gains_offset; + break; + case GAINS_DMIC3: + *mixer_offset = dmic3_gains_offset; + break; + case GAINS_AMIC: + *mixer_offset = amic_gains_offset; + break; + case GAINS_DL1: + *mixer_offset = dl1_gains_offset; + break; + case GAINS_DL2: + *mixer_offset = dl2_gains_offset; + break; + case GAINS_SPLIT: + *mixer_offset = splitters_gains_offset; + break; + case MIXDL1: + *mixer_offset = mixer_dl1_offset; + break; + case MIXDL2: + *mixer_offset = mixer_dl2_offset; + break; + case MIXECHO: + *mixer_offset = mixer_echo_offset; + break; + case MIXSDT: + *mixer_offset = mixer_sdt_offset; + break; + case MIXVXREC: + *mixer_offset = mixer_vxrec_offset; + break; + case MIXAUDUL: + *mixer_offset = mixer_audul_offset; + break; + case GAINS_BTUL: + *mixer_offset = btul_gains_offset; + break; + } +} + +/** + * oamp_abe_write_equalizer + * @abe: Pointer on abe handle + * @id: name of the equalizer + * @param : equalizer coefficients + * + * Load the coefficients in CMEM. + */ +int omap_abe_write_equalizer(struct omap_abe *abe, + u32 id, struct omap_abe_equ *param) +{ + u32 eq_offset, length, *src, eq_mem, eq_mem_len; + _log(ABE_ID_WRITE_EQUALIZER, id, 0, 0); + switch (id) { + default: + case EQ1: + eq_offset = OMAP_ABE_C_DL1_COEFS_ADDR; + eq_mem = OMAP_ABE_S_DL1_M_EQ_DATA_ADDR; + eq_mem_len = OMAP_ABE_S_DL1_M_EQ_DATA_SIZE; + break; + case EQ2L: + eq_offset = OMAP_ABE_C_DL2_L_COEFS_ADDR; + eq_mem = OMAP_ABE_S_DL2_M_LR_EQ_DATA_ADDR; + eq_mem_len = OMAP_ABE_S_DL2_M_LR_EQ_DATA_SIZE; + break; + case EQ2R: + eq_offset = OMAP_ABE_C_DL2_R_COEFS_ADDR; + eq_mem = OMAP_ABE_S_DL2_M_LR_EQ_DATA_ADDR; + eq_mem_len = OMAP_ABE_S_DL2_M_LR_EQ_DATA_SIZE; + break; + case EQSDT: + eq_offset = OMAP_ABE_C_SDT_COEFS_ADDR; + eq_mem = OMAP_ABE_S_SDT_F_DATA_ADDR; + eq_mem_len = OMAP_ABE_S_SDT_F_DATA_SIZE; + break; + case EQAMIC: + eq_offset = OMAP_ABE_C_96_48_AMIC_COEFS_ADDR; + eq_mem = OMAP_ABE_S_AMIC_96_48_DATA_ADDR; + eq_mem_len = OMAP_ABE_S_AMIC_96_48_DATA_SIZE; + break; + case EQDMIC: + eq_offset = OMAP_ABE_C_96_48_DMIC_COEFS_ADDR; + eq_mem = OMAP_ABE_S_DMIC0_96_48_DATA_ADDR; + eq_mem_len = OMAP_ABE_S_DMIC0_96_48_DATA_SIZE; + /* three DMIC are clear at the same time DMIC0 DMIC1 DMIC2 */ + eq_mem_len *= 3; + break; + } + /* reset SMEM buffers before the coefficients are loaded */ + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, eq_mem, eq_mem_len); + + length = param->equ_length; + src = (u32 *) ((param->coef).type1); + /* translate in bytes */ + length <<= 2; + omap_abe_mem_write(abe, OMAP_ABE_CMEM, eq_offset, src, length); + + /* reset SMEM buffers after the coefficients are loaded */ + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, eq_mem, eq_mem_len); + return 0; +} +EXPORT_SYMBOL(omap_abe_write_equalizer); + +/** + * omap_abe_disable_gain + * @abe: Pointer on abe handle + * Parameters: + * mixer id + * sub-port id + * + */ +int omap_abe_disable_gain(struct omap_abe *abe, u32 id, u32 p) +{ + u32 mixer_offset, f_g, ramp; + omap_abe_gain_offset(abe, id, &mixer_offset); + /* save the input parameters for mute/unmute */ + ramp = abe->desired_ramp_delay_ms[mixer_offset + p]; + f_g = GAIN_MUTE; + if (!(abe->muted_gains_indicator[mixer_offset + p] & + OMAP_ABE_GAIN_DISABLED)) { + /* Check if we are in mute */ + if (!(abe->muted_gains_indicator[mixer_offset + p] & + OMAP_ABE_GAIN_MUTED)) { + abe->muted_gains_decibel[mixer_offset + p] = + abe->desired_gains_decibel[mixer_offset + p]; + /* mute the gain */ + omap_abe_write_gain(abe, id, f_g, ramp, p); + } + abe->muted_gains_indicator[mixer_offset + p] |= + OMAP_ABE_GAIN_DISABLED; + } + return 0; +} +EXPORT_SYMBOL(omap_abe_disable_gain); + +/** + * omap_abe_enable_gain + * Parameters: + * mixer id + * sub-port id + * + */ +int omap_abe_enable_gain(struct omap_abe *abe, u32 id, u32 p) +{ + u32 mixer_offset, f_g, ramp; + omap_abe_gain_offset(abe, id, &mixer_offset); + if ((abe->muted_gains_indicator[mixer_offset + p] & + OMAP_ABE_GAIN_DISABLED)) { + /* restore the input parameters for mute/unmute */ + f_g = abe->muted_gains_decibel[mixer_offset + p]; + ramp = abe->desired_ramp_delay_ms[mixer_offset + p]; + abe->muted_gains_indicator[mixer_offset + p] &= + ~OMAP_ABE_GAIN_DISABLED; + /* unmute the gain */ + omap_abe_write_gain(abe, id, f_g, ramp, p); + } + return 0; +} +EXPORT_SYMBOL(omap_abe_enable_gain); +/** + * omap_abe_mute_gain + * Parameters: + * mixer id + * sub-port id + * + */ +int omap_abe_mute_gain(struct omap_abe *abe, u32 id, u32 p) +{ + u32 mixer_offset, f_g, ramp; + omap_abe_gain_offset(abe, id, &mixer_offset); + /* save the input parameters for mute/unmute */ + ramp = abe->desired_ramp_delay_ms[mixer_offset + p]; + f_g = GAIN_MUTE; + if (!abe->muted_gains_indicator[mixer_offset + p]) { + abe->muted_gains_decibel[mixer_offset + p] = + abe->desired_gains_decibel[mixer_offset + p]; + /* mute the gain */ + omap_abe_write_gain(abe, id, f_g, ramp, p); + } + abe->muted_gains_indicator[mixer_offset + p] |= OMAP_ABE_GAIN_MUTED; + return 0; +} +EXPORT_SYMBOL(omap_abe_mute_gain); +/** + * omap_abe_unmute_gain + * Parameters: + * mixer id + * sub-port id + * + */ +int omap_abe_unmute_gain(struct omap_abe *abe, u32 id, u32 p) +{ + u32 mixer_offset, f_g, ramp; + omap_abe_gain_offset(abe, id, &mixer_offset); + if ((abe->muted_gains_indicator[mixer_offset + p] & + OMAP_ABE_GAIN_MUTED)) { + /* restore the input parameters for mute/unmute */ + f_g = abe->muted_gains_decibel[mixer_offset + p]; + ramp = abe->desired_ramp_delay_ms[mixer_offset + p]; + abe->muted_gains_indicator[mixer_offset + p] &= + ~OMAP_ABE_GAIN_MUTED; + /* unmute the gain */ + omap_abe_write_gain(abe, id, f_g, ramp, p); + } + return 0; +} +EXPORT_SYMBOL(omap_abe_unmute_gain); + +/** + * omap_abe_write_gain + * @id: gain name or mixer name + * @f_g: list of input gains of the mixer + * @ramp: gain ramp speed factor + * @p: list of ports corresponding to the above gains + * + * Loads the gain coefficients to FW memory. This API can be called when + * the corresponding MIXER is not activated. After reloading the firmware + * the default coefficients corresponds to "all input and output mixer's gain + * in mute state". A mixer is disabled with a network reconfiguration + * corresponding to an OPP value. + */ +int omap_abe_write_gain(struct omap_abe *abe, + u32 id, s32 f_g, u32 ramp, u32 p) +{ + u32 lin_g, sum_g, mixer_target, mixer_offset, i, mean_gain, mean_exp; + u32 new_gain_linear[4]; + s32 gain_index; + u32 alpha, beta; + u32 ramp_index; + + _log(ABE_ID_WRITE_GAIN, id, f_g, p); + gain_index = ((f_g - min_mdb) / 100); + gain_index = maximum(gain_index, 0); + gain_index = minimum(gain_index, sizeof_db2lin_table); + lin_g = abe_db2lin_table[gain_index]; + omap_abe_gain_offset(abe, id, &mixer_offset); + /* save the input parameters for mute/unmute */ + abe->desired_gains_linear[mixer_offset + p] = lin_g; + abe->desired_gains_decibel[mixer_offset + p] = f_g; + abe->desired_ramp_delay_ms[mixer_offset + p] = ramp; + /* SMEM address in bytes */ + mixer_target = OMAP_ABE_S_GTARGET1_ADDR; + mixer_target += (mixer_offset<<2); + mixer_target += (p<<2); + + if (abe->compensated_mixer_gain) { + switch (id) { + case MIXDL1: + case MIXDL2: + case MIXVXREC: + case MIXAUDUL: + /* compute the sum of the gain of the mixer */ + for (sum_g = i = 0; i < 4; i++) + sum_g += abe->desired_gains_linear[mixer_offset + + i]; + /* lets avoid a division by 0 */ + if (sum_g == 0) + break; + /* if the sum is OK with less than 1, then + do not weight the gains */ + if (sum_g < 0x00040000) { /* REMOVE HARD CONST */ + /* recompute all gains from original + desired values */ + sum_g = 0x00040000; + } + /* translate it in Q16 format for the later division */ + abe_int_2_float16(sum_g, &mean_gain, &mean_exp); + mean_exp = 10 - mean_exp; + for (i = 0; i < 4; i++) { + /* new gain = desired gain divided by sum of gains */ + new_gain_linear[i] = + (abe->desired_gains_linear + [mixer_offset + i] + << 8) / mean_gain; + new_gain_linear[i] = (mean_exp > 0) ? + new_gain_linear[i] << mean_exp : + new_gain_linear[i] >> mean_exp; + } + /* load the whole adpated S_G_Target SMEM MIXER table */ + omap_abe_mem_write(abe, OMAP_ABE_SMEM, + mixer_target - (p << 2), + new_gain_linear, (4 * sizeof(lin_g))); + break; + default: + /* load the S_G_Target SMEM table */ + omap_abe_mem_write(abe, OMAP_ABE_SMEM, + mixer_target, + (u32 *) &lin_g, sizeof(lin_g)); + break; + } + } else { + if (!abe->muted_gains_indicator[mixer_offset + p]) + /* load the S_G_Target SMEM table */ + omap_abe_mem_write(abe, OMAP_ABE_SMEM, + mixer_target, (u32 *) &lin_g, + sizeof(lin_g)); + else + /* update muted gain with new value */ + abe->muted_gains_decibel[mixer_offset + p] = f_g; + } + ramp = maximum(minimum(RAMP_MAXLENGTH, ramp), RAMP_MINLENGTH); + /* ramp data should be interpolated in the table instead */ + ramp_index = 3; + if ((RAMP_2MS <= ramp) && (ramp < RAMP_5MS)) + ramp_index = 8; + if ((RAMP_5MS <= ramp) && (ramp < RAMP_50MS)) + ramp_index = 24; + if ((RAMP_50MS <= ramp) && (ramp < RAMP_500MS)) + ramp_index = 36; + if (ramp > RAMP_500MS) + ramp_index = 48; + beta = abe_alpha_iir[ramp_index]; + alpha = abe_1_alpha_iir[ramp_index]; + /* CMEM bytes address */ + mixer_target = OMAP_ABE_C_1_ALPHA_ADDR; + /* a pair of gains is updated once in the firmware */ + mixer_target += ((p + mixer_offset) >> 1) << 2; + /* load the ramp delay data */ + omap_abe_mem_write(abe, OMAP_ABE_CMEM, mixer_target, + (u32 *) &alpha, sizeof(alpha)); + /* CMEM bytes address */ + mixer_target = OMAP_ABE_C_ALPHA_ADDR; + /* a pair of gains is updated once in the firmware */ + mixer_target += ((p + mixer_offset) >> 1) << 2; + omap_abe_mem_write(abe, OMAP_ABE_CMEM, mixer_target, + (u32 *) &beta, sizeof(beta)); + return 0; +} +EXPORT_SYMBOL(omap_abe_write_gain); +/** + * omap_abe_write_mixer + * @id: name of the mixer + * @param: input gains and delay ramp of the mixer + * @p: port corresponding to the above gains + * + * Load the gain coefficients in FW memory. This API can be called when + * the corresponding MIXER is not activated. After reloading the firmware + * the default coefficients corresponds to "all input and output mixer's + * gain in mute state". A mixer is disabled with a network reconfiguration + * corresponding to an OPP value. + */ +int omap_abe_write_mixer(struct omap_abe *abe, + u32 id, s32 f_g, u32 f_ramp, u32 p) +{ + _log(ABE_ID_WRITE_MIXER, id, f_ramp, p); + omap_abe_write_gain(abe, id, f_g, f_ramp, p); + return 0; +} +EXPORT_SYMBOL(omap_abe_write_mixer); + +/** + * omap_abe_read_gain + * @id: name of the mixer + * @param: list of input gains of the mixer + * @p: list of port corresponding to the above gains + * + */ +int omap_abe_read_gain(struct omap_abe *abe, + u32 id, u32 *f_g, u32 p) +{ + u32 mixer_target, mixer_offset, i; + _log(ABE_ID_READ_GAIN, id, (u32) f_g, p); + omap_abe_gain_offset(abe, id, &mixer_offset); + /* SMEM bytes address */ + mixer_target = OMAP_ABE_S_GTARGET1_ADDR; + mixer_target += (mixer_offset<<2); + mixer_target += (p<<2); + if (!abe->muted_gains_indicator[mixer_offset + p]) { + /* load the S_G_Target SMEM table */ + omap_abe_mem_read(abe, OMAP_ABE_SMEM, mixer_target, + (u32 *) f_g, sizeof(*f_g)); + for (i = 0; i < sizeof_db2lin_table; i++) { + if (abe_db2lin_table[i] == *f_g) + goto found; + } + *f_g = 0; + return -1; + found: + *f_g = (i * 100) + min_mdb; + } else { + /* update muted gain with new value */ + *f_g = abe->muted_gains_decibel[mixer_offset + p]; + } + return 0; +} +EXPORT_SYMBOL(omap_abe_read_gain); + +/** + * abe_read_mixer + * @id: name of the mixer + * @param: gains of the mixer + * @p: port corresponding to the above gains + * + * Load the gain coefficients in FW memory. This API can be called when + * the corresponding MIXER is not activated. After reloading the firmware + * the default coefficients corresponds to "all input and output mixer's + * gain in mute state". A mixer is disabled with a network reconfiguration + * corresponding to an OPP value. + */ +int omap_abe_read_mixer(struct omap_abe *abe, + u32 id, u32 *f_g, u32 p) +{ + _log(ABE_ID_READ_MIXER, id, 0, p); + omap_abe_read_gain(abe, id, f_g, p); + return 0; +} +EXPORT_SYMBOL(omap_abe_read_mixer); + +/** + * abe_reset_gain_mixer + * @id: name of the mixer + * @p: list of port corresponding to the above gains + * + * restart the working gain value of the mixers when a port is enabled + */ +void omap_abe_reset_gain_mixer(struct omap_abe *abe, u32 id, u32 p) +{ + u32 lin_g, mixer_target, mixer_offset; + switch (id) { + default: + case GAINS_DMIC1: + mixer_offset = dmic1_gains_offset; + break; + case GAINS_DMIC2: + mixer_offset = dmic2_gains_offset; + break; + case GAINS_DMIC3: + mixer_offset = dmic3_gains_offset; + break; + case GAINS_AMIC: + mixer_offset = amic_gains_offset; + break; + case GAINS_DL1: + mixer_offset = dl1_gains_offset; + break; + case GAINS_DL2: + mixer_offset = dl2_gains_offset; + break; + case GAINS_SPLIT: + mixer_offset = splitters_gains_offset; + break; + case MIXDL1: + mixer_offset = mixer_dl1_offset; + break; + case MIXDL2: + mixer_offset = mixer_dl2_offset; + break; + case MIXECHO: + mixer_offset = mixer_echo_offset; + break; + case MIXSDT: + mixer_offset = mixer_sdt_offset; + break; + case MIXVXREC: + mixer_offset = mixer_vxrec_offset; + break; + case MIXAUDUL: + mixer_offset = mixer_audul_offset; + break; + case GAINS_BTUL: + mixer_offset = btul_gains_offset; + break; + } + /* SMEM bytes address for the CURRENT gain values */ + mixer_target = OMAP_ABE_S_GCURRENT_ADDR; + mixer_target += (mixer_offset<<2); + mixer_target += (p<<2); + lin_g = 0; + /* load the S_G_Target SMEM table */ + omap_abe_mem_write(abe, OMAP_ABE_SMEM, mixer_target, + (u32 *) &lin_g, sizeof(lin_g)); +} diff --git a/sound/soc/omap/abe/abe_gain.h b/sound/soc/omap/abe/abe_gain.h new file mode 100644 index 0000000..f332837 --- /dev/null +++ b/sound/soc/omap/abe/abe_gain.h @@ -0,0 +1,111 @@ +/* + + This file is provided under a dual BSD/GPLv2 license. When using or + redistributing this file, you may do so under either license. + + GPL LICENSE SUMMARY + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License 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. + The full GNU General Public License is included in this distribution + in the file called LICENSE.GPL. + + BSD LICENSE + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name of Texas Instruments Incorporated nor the names of + its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef _ABE_GAIN_H_ +#define _ABE_GAIN_H_ + +#include "abe_typ.h" +#include "abe_dm_addr.h" +#include "abe_sm_addr.h" +#include "abe_cm_addr.h" + +#define OMAP_ABE_GAIN_MUTED (0x0001<<0) +#define OMAP_ABE_GAIN_DISABLED (0x0001<<1) + +#define OMAP_ABE_GAIN_DMIC1_LEFT 0 +#define OMAP_ABE_GAIN_DMIC1_RIGTH 1 +#define OMAP_ABE_GAIN_DMIC2_LEFT 2 +#define OMAP_ABE_GAIN_DMIC2_RIGTH 3 +#define OMAP_ABE_GAIN_DMIC3_LEFT 4 +#define OMAP_ABE_GAIN_DMIC3_RIGTH 5 +#define OMAP_ABE_GAIN_AMIC_LEFT 6 +#define OMAP_ABE_GAIN_AMIC_RIGTH 7 +#define OMAP_ABE_GAIN_DL1_LEFT 8 +#define OMAP_ABE_GAIN_DL1_RIGTH 9 +#define OMAP_ABE_GAIN_DL2_LEFT 10 +#define OMAP_ABE_GAIN_DL2_RIGTH 11 +#define OMAP_ABE_GAIN_SPLIT_LEFT 12 +#define OMAP_ABE_GAIN_SPLIT_RIGTH 13 +#define OMAP_ABE_MIXDL1_MM_DL 14 +#define OMAP_ABE_MIXDL1_MM_UL2 15 +#define OMAP_ABE_MIXDL1_VX_DL 16 +#define OMAP_ABE_MIXDL1_TONES 17 +#define OMAP_ABE_MIXDL2_MM_DL 18 +#define OMAP_ABE_MIXDL2_MM_UL2 19 +#define OMAP_ABE_MIXDL2_VX_DL 20 +#define OMAP_ABE_MIXDL2_TONES 21 +#define OMAP_ABE_MIXECHO_DL1 22 +#define OMAP_ABE_MIXECHO_DL2 23 +#define OMAP_ABE_MIXSDT_UL 24 +#define OMAP_ABE_MIXECHO_DL 25 +#define OMAP_ABE_MIXVXREC_MM_DL 26 +#define OMAP_ABE_MIXVXREC_TONES 27 +#define OMAP_ABE_MIXVXREC_VX_UL 28 +#define OMAP_ABE_MIXVXREC_VX_DL 29 +#define OMAP_ABE_MIXAUDUL_MM_DL 30 +#define OMAP_ABE_MIXAUDUL_TONES 31 +#define OMAP_ABE_MIXAUDUL_UPLINK 32 +#define OMAP_ABE_MIXAUDUL_VX_DL 33 +#define OMAP_ABE_GAIN_BTUL_LEFT 34 +#define OMAP_ABE_GAIN_BTUL_RIGTH 35 + +void omap_abe_reset_gain_mixer(struct omap_abe *abe, u32 id, u32 p); + +void abe_int_2_float16(u32 data, u32 *mantissa, u32 *exp); + +#endif /* _ABE_GAIN_H_ */ diff --git a/sound/soc/omap/abe/abe_ini.c b/sound/soc/omap/abe/abe_ini.c new file mode 100644 index 0000000..a126e23 --- /dev/null +++ b/sound/soc/omap/abe/abe_ini.c @@ -0,0 +1,455 @@ +/* + + This file is provided under a dual BSD/GPLv2 license. When using or + redistributing this file, you may do so under either license. + + GPL LICENSE SUMMARY + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License 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. + The full GNU General Public License is included in this distribution + in the file called LICENSE.GPL. + + BSD LICENSE + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name of Texas Instruments Incorporated nor the names of + its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/err.h> +#include <linux/slab.h> + +#include "abe_dbg.h" +#include "abe.h" +#include "abe_aess.h" +#include "abe_gain.h" +#include "abe_mem.h" +#include "abe_port.h" +#include "abe_seq.h" + +#include "abe_taskid.h" + + +#define ABE_TASK_ID(ID) (OMAP_ABE_D_TASKSLIST_ADDR + sizeof(ABE_STask)*(ID)) +void omap_abe_build_scheduler_table(struct omap_abe *abe); +void omap_abe_reset_all_ports(struct omap_abe *abe); + +const u32 abe_firmware_array[ABE_FIRMWARE_MAX_SIZE] = { +#include "abe_firmware.c" +}; + + +/* + * initialize the default values for call-backs to subroutines + * - FIFO IRQ call-backs for sequenced tasks + * - FIFO IRQ call-backs for audio player/recorders (ping-pong protocols) + * - Remote debugger interface + * - Error monitoring + * - Activity Tracing + */ + +/** + * abe_init_mem - Allocate Kernel space memory map for ABE + * + * Memory map of ABE memory space for PMEM/DMEM/SMEM/DMEM + */ +void abe_init_mem(void __iomem **_io_base) +{ + int i; + + abe = kzalloc(sizeof(struct omap_abe), GFP_KERNEL); + if (abe == NULL) + printk(KERN_ERR "ABE Allocation ERROR "); + + for (i = 0; i < 5; i++) + abe->io_base[i] = _io_base[i]; + + mutex_init(&abe->mutex); + +} +EXPORT_SYMBOL(abe_init_mem); + +/** + * abe_load_fw_param - Load ABE Firmware memories + * @PMEM: Pointer of Program memory data + * @PMEM_SIZE: Size of PMEM data + * @CMEM: Pointer of Coeffients memory data + * @CMEM_SIZE: Size of CMEM data + * @SMEM: Pointer of Sample memory data + * @SMEM_SIZE: Size of SMEM data + * @DMEM: Pointer of Data memory data + * @DMEM_SIZE: Size of DMEM data + * + */ +int abe_load_fw_param(u32 *ABE_FW) +{ + u32 pmem_size, dmem_size, smem_size, cmem_size; + u32 *pmem_ptr, *dmem_ptr, *smem_ptr, *cmem_ptr, *fw_ptr; + /* fast counter timer set at 4096 * 250us = 1,024s */ + u32 data = 0x10001000; + + _log(ABE_ID_LOAD_FW_param, 0, 0, 0); +#define ABE_FW_OFFSET 5 + fw_ptr = ABE_FW; + abe->firmware_version_number = *fw_ptr++; + pmem_size = *fw_ptr++; + cmem_size = *fw_ptr++; + dmem_size = *fw_ptr++; + smem_size = *fw_ptr++; + pmem_ptr = fw_ptr; + cmem_ptr = pmem_ptr + (pmem_size >> 2); + dmem_ptr = cmem_ptr + (cmem_size >> 2); + smem_ptr = dmem_ptr + (dmem_size >> 2); + /* do not load PMEM */ + if (abe->warm_boot) { + /* Stop the event Generator */ + omap_abe_stop_event_generator(abe); + + /* Now we are sure the firmware is stalled */ + omap_abe_mem_write(abe, OMAP_ABE_CMEM, 0, cmem_ptr, + cmem_size); + omap_abe_mem_write(abe, OMAP_ABE_SMEM, 0, smem_ptr, + smem_size); + omap_abe_mem_write(abe, OMAP_ABE_DMEM, 0, dmem_ptr, + dmem_size); + + /* Restore the event Generator status */ + omap_abe_start_event_generator(abe); + } else { + omap_abe_mem_write(abe, OMAP_ABE_PMEM, 0, pmem_ptr, + pmem_size); + omap_abe_mem_write(abe, OMAP_ABE_CMEM, 0, cmem_ptr, + cmem_size); + omap_abe_mem_write(abe, OMAP_ABE_SMEM, 0, smem_ptr, + smem_size); + omap_abe_mem_write(abe, OMAP_ABE_DMEM, 0, dmem_ptr, + dmem_size); + } + omap_abe_mem_write(abe, OMAP_ABE_DMEM, + OMAP_ABE_D_FASTCOUNTER_ADDR, + &data, + OMAP_ABE_D_FASTCOUNTER_SIZE); + + /* Update Saturation threshold */ + data = 0x00700000; + omap_abe_mem_write(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_SATURATION_EQ_ADDR, + &data, 4); + data = 0x00900000; + omap_abe_mem_write(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_SATURATION_EQ_ADDR + 4, + &data, 4); + + abe->warm_boot = 1; + return 0; +} +EXPORT_SYMBOL(abe_load_fw_param); + +/** + * omap_abe_load_fw - Load ABE Firmware and initialize memories + * @abe: Pointer on abe handle + * + */ +int omap_abe_load_fw(struct omap_abe *abe, u32 *firmware) +{ + _log(ABE_ID_LOAD_FW, 0, 0, 0); + abe_load_fw_param(firmware); + omap_abe_reset_all_ports(abe); + omap_abe_build_scheduler_table(abe); + omap_abe_reset_all_sequence(abe); + omap_abe_select_main_port(OMAP_ABE_PDM_DL_PORT); + return 0; +} +EXPORT_SYMBOL(omap_abe_load_fw); + +/** + * abe_reload_fw - Reload ABE Firmware after OFF mode + */ +int omap_abe_reload_fw(struct omap_abe *abe, u32 *firmware) +{ + abe->warm_boot = 0; + abe_load_fw_param(firmware); + omap_abe_build_scheduler_table(abe); + omap_abe_dbg_reset(&abe->dbg); + /* IRQ circular read pointer in DMEM */ + abe->irq_dbg_read_ptr = 0; + /* Restore Gains not managed by the drivers */ + omap_abe_write_gain(abe, GAINS_SPLIT, GAIN_0dB, + RAMP_2MS, GAIN_LEFT_OFFSET); + omap_abe_write_gain(abe, GAINS_SPLIT, GAIN_0dB, + RAMP_2MS, GAIN_RIGHT_OFFSET); + + return 0; +} +EXPORT_SYMBOL(omap_abe_reload_fw); + +/** + * omap_abe_get_default_fw + * + * Get default ABE firmware + */ +u32 *omap_abe_get_default_fw(struct omap_abe *abe) +{ + return (u32 *)abe_firmware_array; +} + +/** + * abe_build_scheduler_table + * + */ +void omap_abe_build_scheduler_table(struct omap_abe *abe) +{ + u16 i, n; + u8 *ptr; + u16 aUplinkMuxing[NBROUTE_UL]; + + /* LOAD OF THE TASKS' MULTIFRAME */ + /* WARNING ON THE LOCATION OF IO_MM_DL WHICH IS PATCHED + IN "abe_init_io_tasks" */ + for (ptr = (u8 *) &(abe->MultiFrame[0][0]), i = 0; + i < sizeof(abe->MultiFrame); i++) + *ptr++ = 0; + + abe->MultiFrame[0][2] = 0/*ABE_TASK_ID(C_ABE_FW_TASK_IO_VX_DL)*/; + abe->MultiFrame[0][3] = ABE_TASK_ID(C_ABE_FW_TASK_ASRC_VX_DL_8); + + abe->MultiFrame[1][3] = ABE_TASK_ID(C_ABE_FW_TASK_VX_DL_8_48_FIR); + abe->MultiFrame[1][6] = ABE_TASK_ID(C_ABE_FW_TASK_DL2Mixer); + abe->MultiFrame[1][7] = 0/*ABE_TASK_ID(C_ABE_FW_TASK_IO_VIB_DL)*/; + + abe->MultiFrame[2][0] = ABE_TASK_ID(C_ABE_FW_TASK_DL1Mixer); + abe->MultiFrame[2][1] = ABE_TASK_ID(C_ABE_FW_TASK_SDTMixer); + abe->MultiFrame[2][5] = 0/*ABE_TASK_ID(C_ABE_FW_TASK_IO_DMIC)*/; + + abe->MultiFrame[3][0] = ABE_TASK_ID(C_ABE_FW_TASK_DL1_GAIN); + abe->MultiFrame[3][6] = ABE_TASK_ID(C_ABE_FW_TASK_DL2_GAIN); + abe->MultiFrame[3][7] = ABE_TASK_ID(C_ABE_FW_TASK_DL2_EQ); + + abe->MultiFrame[4][0] = ABE_TASK_ID(C_ABE_FW_TASK_DL1_EQ); + abe->MultiFrame[4][2] = ABE_TASK_ID(C_ABE_FW_TASK_VXRECMixer); + abe->MultiFrame[4][3] = ABE_TASK_ID(C_ABE_FW_TASK_VXREC_SPLIT); + abe->MultiFrame[4][6] = ABE_TASK_ID(C_ABE_FW_TASK_VIBRA1); + abe->MultiFrame[4][7] = ABE_TASK_ID(C_ABE_FW_TASK_VIBRA2); + + abe->MultiFrame[5][0] = 0; + abe->MultiFrame[5][1] = ABE_TASK_ID(C_ABE_FW_TASK_EARP_48_96_LP); + abe->MultiFrame[5][2] = 0/*ABE_TASK_ID(C_ABE_FW_TASK_IO_PDM_UL)*/; + abe->MultiFrame[5][7] = ABE_TASK_ID(C_ABE_FW_TASK_VIBRA_SPLIT); + + abe->MultiFrame[6][0] = ABE_TASK_ID(C_ABE_FW_TASK_EARP_48_96_LP); + abe->MultiFrame[6][4] = ABE_TASK_ID(C_ABE_FW_TASK_EchoMixer); + abe->MultiFrame[6][5] = ABE_TASK_ID(C_ABE_FW_TASK_BT_UL_SPLIT); + + abe->MultiFrame[7][0] = 0/*ABE_TASK_ID(C_ABE_FW_TASK_IO_PDM_DL)*/; + abe->MultiFrame[7][3] = ABE_TASK_ID(C_ABE_FW_TASK_DBG_SYNC); + abe->MultiFrame[7][5] = ABE_TASK_ID(C_ABE_FW_TASK_ECHO_REF_SPLIT); + + abe->MultiFrame[9][2] = ABE_TASK_ID(C_ABE_FW_TASK_CHECK_IIR_RIGHT); + + abe->MultiFrame[9][6] = 0; + abe->MultiFrame[9][7] = ABE_TASK_ID(C_ABE_FW_TASK_IHF_48_96_LP); + + abe->MultiFrame[10][7] = ABE_TASK_ID(C_ABE_FW_TASK_IHF_48_96_LP); + + abe->MultiFrame[11][2] = ABE_TASK_ID(C_ABE_FW_TASK_AMIC_96_48_LP); + abe->MultiFrame[11][4] = ABE_TASK_ID(C_ABE_FW_TASK_AMIC_SPLIT); + abe->MultiFrame[11][7] = ABE_TASK_ID(C_ABE_FW_TASK_VIBRA_PACK); + + abe->MultiFrame[12][3] = ABE_TASK_ID(C_ABE_FW_TASK_VX_UL_ROUTING); + abe->MultiFrame[12][4] = ABE_TASK_ID(C_ABE_FW_TASK_ULMixer); + abe->MultiFrame[12][5] = ABE_TASK_ID(C_ABE_FW_TASK_VX_UL_48_8); + + abe->MultiFrame[13][2] = ABE_TASK_ID(C_ABE_FW_TASK_MM_UL2_ROUTING); + abe->MultiFrame[13][3] = ABE_TASK_ID(C_ABE_FW_TASK_SideTone); + abe->MultiFrame[13][5] = 0/*ABE_TASK_ID(C_ABE_FW_TASK_IO_BT_VX_DL)*/; + + abe->MultiFrame[14][3] = 0/*ABE_TASK_ID(C_ABE_FW_TASK_IO_DMIC)*/; + abe->MultiFrame[14][4] = ABE_TASK_ID(C_ABE_FW_TASK_BT_DL_48_8_FIR); + + abe->MultiFrame[15][0] = 0/*ABE_TASK_ID(C_ABE_FW_TASK_IO_MM_EXT_OUT)*/; + abe->MultiFrame[15][3] = 0/*ABE_TASK_ID(C_ABE_FW_TASK_IO_BT_VX_UL)*/; + abe->MultiFrame[15][6] = 0/*ABE_TASK_ID(C_ABE_FW_TASK_ASRC_BT_UL_8)*/; + + abe->MultiFrame[16][2] = ABE_TASK_ID(C_ABE_FW_TASK_ASRC_VX_UL_8); + abe->MultiFrame[16][3] = 0/*ABE_TASK_ID(C_ABE_FW_TASK_IO_VX_UL)*/; + + abe->MultiFrame[17][2] = ABE_TASK_ID(C_ABE_FW_TASK_BT_UL_8_48); + abe->MultiFrame[17][3] = 0/*ABE_TASK_ID(C_ABE_FW_TASK_IO_MM_UL2)*/; + + abe->MultiFrame[18][0] = 0/*ABE_TASK_ID(C_ABE_FW_TASK_IO_MM_DL)*/; + abe->MultiFrame[18][6] = 0/*ABE_TASK_ID(C_ABE_FW_TASK_ASRC_BT_DL_8)*/; + + abe->MultiFrame[19][0] = 0/*ABE_TASK_ID(C_ABE_FW_TASK_IO_PDM_DL)*/; + + /* MM_UL is moved to OPP 100% */ + abe->MultiFrame[19][6] = 0/*ABE_TASK_ID(C_ABE_FW_TASK_IO_MM_UL)*/; + + abe->MultiFrame[20][0] = 0/*ABE_TASK_ID(C_ABE_FW_TASK_IO_TONES_DL)*/; + abe->MultiFrame[20][6] = 0/*ABE_TASK_ID(C_ABE_FW_TASK_ASRC_MM_EXT_IN)*/; + + abe->MultiFrame[21][1] = ABE_TASK_ID(C_ABE_FW_TASK_DEBUGTRACE_VX_ASRCs); + abe->MultiFrame[21][3] = 0/*ABE_TASK_ID(C_ABE_FW_TASK_IO_MM_EXT_IN)*/; + /* MUST STAY ON SLOT 22 */ + abe->MultiFrame[22][0] = ABE_TASK_ID(C_ABE_FW_TASK_DEBUG_IRQFIFO); + abe->MultiFrame[22][1] = ABE_TASK_ID(C_ABE_FW_TASK_INIT_FW_MEMORY); + abe->MultiFrame[22][2] = 0; + /* MM_EXT_IN_SPLIT task must be after IO_MM_EXT_IN and before + ASRC_MM_EXT_IN in order to manage OPP50 <-> transitions */ + abe->MultiFrame[22][4] = ABE_TASK_ID(C_ABE_FW_TASK_MM_EXT_IN_SPLIT); + + abe->MultiFrame[23][0] = ABE_TASK_ID(C_ABE_FW_TASK_GAIN_UPDATE); + abe->MultiFrame[23][2] = ABE_TASK_ID(C_ABE_FW_TASK_CHECK_IIR_LEFT); + + omap_abe_mem_write(abe, OMAP_ABE_DMEM, OMAP_ABE_D_MULTIFRAME_ADDR, + (u32 *) abe->MultiFrame, sizeof(abe->MultiFrame)); + /* reset the uplink router */ + n = (OMAP_ABE_D_AUPLINKROUTING_SIZE) >> 1; + for (i = 0; i < n; i++) + aUplinkMuxing[i] = ZERO_labelID; + + omap_abe_mem_write(abe, OMAP_ABE_DMEM, OMAP_ABE_D_AUPLINKROUTING_ADDR, + (u32 *) aUplinkMuxing, sizeof(aUplinkMuxing)); +} + +/** + * omap_abe_reset_port + * @id: ABE port ID + * + * stop the port activity and reload default parameters on the associated + * processing features. + * Clears the internal AE buffers. + */ +int omap_abe_reset_port(u32 id) +{ + _log(ABE_ID_RESET_PORT, id, 0, 0); + abe_port[id] = ((abe_port_t *) abe_port_init)[id]; + return 0; +} + +/** + * abe_reset_all_ports + * + * load default configuration for all features + */ +void omap_abe_reset_all_ports(struct omap_abe *abe) +{ + u16 i; + for (i = 0; i < LAST_PORT_ID; i++) + omap_abe_reset_port(i); + /* mixers' configuration */ + omap_abe_write_mixer(abe, MIXDL1, MUTE_GAIN, + RAMP_2MS, MIX_DL1_INPUT_MM_DL); + omap_abe_write_mixer(abe, MIXDL1, MUTE_GAIN, + RAMP_2MS, MIX_DL1_INPUT_MM_UL2); + omap_abe_write_mixer(abe, MIXDL1, MUTE_GAIN, + RAMP_2MS, MIX_DL1_INPUT_VX_DL); + omap_abe_write_mixer(abe, MIXDL1, MUTE_GAIN, + RAMP_2MS, MIX_DL1_INPUT_TONES); + omap_abe_write_mixer(abe, MIXDL2, MUTE_GAIN, + RAMP_2MS, MIX_DL2_INPUT_TONES); + omap_abe_write_mixer(abe, MIXDL2, MUTE_GAIN, + RAMP_2MS, MIX_DL2_INPUT_VX_DL); + omap_abe_write_mixer(abe, MIXDL2, MUTE_GAIN, + RAMP_2MS, MIX_DL2_INPUT_MM_DL); + omap_abe_write_mixer(abe, MIXDL2, MUTE_GAIN, + RAMP_2MS, MIX_DL2_INPUT_MM_UL2); + omap_abe_write_mixer(abe, MIXSDT, MUTE_GAIN, + RAMP_2MS, MIX_SDT_INPUT_UP_MIXER); + omap_abe_write_mixer(abe, MIXSDT, GAIN_0dB, + RAMP_2MS, MIX_SDT_INPUT_DL1_MIXER); + omap_abe_write_mixer(abe, MIXECHO, MUTE_GAIN, + RAMP_2MS, MIX_ECHO_DL1); + omap_abe_write_mixer(abe, MIXECHO, MUTE_GAIN, + RAMP_2MS, MIX_ECHO_DL2); + omap_abe_write_mixer(abe, MIXAUDUL, MUTE_GAIN, + RAMP_2MS, MIX_AUDUL_INPUT_MM_DL); + omap_abe_write_mixer(abe, MIXAUDUL, MUTE_GAIN, + RAMP_2MS, MIX_AUDUL_INPUT_TONES); + omap_abe_write_mixer(abe, MIXAUDUL, GAIN_0dB, + RAMP_2MS, MIX_AUDUL_INPUT_UPLINK); + omap_abe_write_mixer(abe, MIXAUDUL, MUTE_GAIN, + RAMP_2MS, MIX_AUDUL_INPUT_VX_DL); + omap_abe_write_mixer(abe, MIXVXREC, MUTE_GAIN, + RAMP_2MS, MIX_VXREC_INPUT_TONES); + omap_abe_write_mixer(abe, MIXVXREC, MUTE_GAIN, + RAMP_2MS, MIX_VXREC_INPUT_VX_DL); + omap_abe_write_mixer(abe, MIXVXREC, MUTE_GAIN, + RAMP_2MS, MIX_VXREC_INPUT_MM_DL); + omap_abe_write_mixer(abe, MIXVXREC, MUTE_GAIN, + RAMP_2MS, MIX_VXREC_INPUT_VX_UL); + omap_abe_write_gain(abe, GAINS_DMIC1, GAIN_0dB, + RAMP_2MS, GAIN_LEFT_OFFSET); + omap_abe_write_gain(abe, GAINS_DMIC1, GAIN_0dB, + RAMP_2MS, GAIN_RIGHT_OFFSET); + omap_abe_write_gain(abe, GAINS_DMIC2, GAIN_0dB, + RAMP_2MS, GAIN_LEFT_OFFSET); + omap_abe_write_gain(abe, GAINS_DMIC2, GAIN_0dB, + RAMP_2MS, GAIN_RIGHT_OFFSET); + omap_abe_write_gain(abe, GAINS_DMIC3, GAIN_0dB, + RAMP_2MS, GAIN_LEFT_OFFSET); + omap_abe_write_gain(abe, GAINS_DMIC3, GAIN_0dB, + RAMP_2MS, GAIN_RIGHT_OFFSET); + omap_abe_write_gain(abe, GAINS_AMIC, GAIN_0dB, + RAMP_2MS, GAIN_LEFT_OFFSET); + omap_abe_write_gain(abe, GAINS_AMIC, GAIN_0dB, + RAMP_2MS, GAIN_RIGHT_OFFSET); + omap_abe_write_gain(abe, GAINS_SPLIT, GAIN_0dB, + RAMP_2MS, GAIN_LEFT_OFFSET); + omap_abe_write_gain(abe, GAINS_SPLIT, GAIN_0dB, + RAMP_2MS, GAIN_RIGHT_OFFSET); + omap_abe_write_gain(abe, GAINS_DL1, GAIN_0dB, + RAMP_2MS, GAIN_LEFT_OFFSET); + omap_abe_write_gain(abe, GAINS_DL1, GAIN_0dB, + RAMP_2MS, GAIN_RIGHT_OFFSET); + omap_abe_write_gain(abe, GAINS_DL2, GAIN_0dB, + RAMP_2MS, GAIN_LEFT_OFFSET); + omap_abe_write_gain(abe, GAINS_DL2, GAIN_0dB, + RAMP_2MS, GAIN_RIGHT_OFFSET); + omap_abe_write_gain(abe, GAINS_BTUL, GAIN_0dB, + RAMP_2MS, GAIN_LEFT_OFFSET); + omap_abe_write_gain(abe, GAINS_BTUL, GAIN_0dB, + RAMP_2MS, GAIN_RIGHT_OFFSET); +} diff --git a/sound/soc/omap/abe/abe_initxxx_labels.h b/sound/soc/omap/abe/abe_initxxx_labels.h new file mode 100644 index 0000000..823f2f3 --- /dev/null +++ b/sound/soc/omap/abe/abe_initxxx_labels.h @@ -0,0 +1,460 @@ +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2010-2011 Texas Instruments Incorporated, + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License 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. + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * BSD LICENSE + * + * Copyright(c) 2010-2011 Texas Instruments Incorporated, + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef _ABE_INITXXX_LABELS_H_ +#define _ABE_INITXXX_LABELS_H_ +#define Dummy_Regs_labelID 0 +#define Dummy_AM_labelID 1 +#define Voice_8k_UL_labelID 2 +#define Voice_8k_DL_labelID 3 +#define ECHO_REF_8K_labelID 4 +#define Voice_16k_UL_labelID 5 +#define Voice_16k_DL_labelID 6 +#define ECHO_REF_16K_labelID 7 +#define MM_DL_labelID 8 +#define IO_VX_DL_ASRC_labelID 9 +#define IO_MM_EXT_IN_ASRC_labelID 10 +#define IO_VIBRA_DL_labelID 11 +#define ZERO_labelID 12 +#define GTarget_labelID 13 +#define GCurrent_labelID 14 +#define Gr_1_labelID 15 +#define Gr_2_labelID 16 +#define Gr_Regs_labelID 17 +#define DMIC0_Gain_labelID 18 +#define DMIC1_Gain_labelID 19 +#define DMIC2_Gain_labelID 20 +#define DMIC3_Gain_labelID 21 +#define AMIC_Gain_labelID 22 +#define MIXDL1_Gain_labelID 23 +#define MIXDL2_Gain_labelID 24 +#define DEFAULT_Gain_labelID 25 +#define DL1_M_G_Tones_labelID 26 +#define DL2_M_G_Tones_labelID 27 +#define Echo_M_G_labelID 28 +#define SDT_M_G_labelID 29 +#define VXREC_M_G_VX_DL_labelID 30 +#define UL_M_G_VX_DL_labelID 31 +#define BTUL_Gain_labelID 32 +#define DL1_M_labelID 33 +#define DL2_M_labelID 34 +#define MM_UL2_labelID 35 +#define VX_DL_labelID 36 +#define Tones_labelID 37 +#define DL_M_MM_UL2_VX_DL_labelID 38 +#define Echo_M_labelID 39 +#define VX_UL_labelID 40 +#define VX_UL_M_labelID 41 +#define SDT_F_labelID 42 +#define SDT_F_data_labelID 43 +#define SDT_Coef_labelID 44 +#define SDT_Regs_labelID 45 +#define SDT_M_labelID 46 +#define DL1_EQ_labelID 47 +#define DL2_EQ_labelID 48 +#define DL1_GAIN_out_labelID 49 +#define DL2_GAIN_out_labelID 50 +#define DMIC1_labelID 51 +#define DMIC1_L_labelID 52 +#define DMIC1_R_labelID 53 +#define DMIC2_labelID 54 +#define DMIC2_L_labelID 55 +#define DMIC2_R_labelID 56 +#define DMIC3_labelID 57 +#define DMIC3_L_labelID 58 +#define DMIC3_R_labelID 59 +#define SaturationMinMax_labelID 60 +#define TEMPORARY0_labelID 61 +#define TEMPORARY1_labelID 62 +#define BT_UL_L_labelID 63 +#define BT_UL_R_labelID 64 +#define AMIC_labelID 65 +#define AMIC_L_labelID 66 +#define AMIC_R_labelID 67 +#define EchoRef_L_labelID 68 +#define EchoRef_R_labelID 69 +#define MM_DL_L_labelID 70 +#define MM_DL_R_labelID 71 +#define MM_UL_labelID 72 +#define AMIC_96_labelID 73 +#define DMIC0_96_labelID 74 +#define DMIC1_96_labelID 75 +#define DMIC2_96_labelID 76 +#define MM_DL_44P1_WPTR_labelID 77 +#define EQ_DL_48K_labelID 78 +#define EQ_48K_labelID 79 +#define McPDM_Out1_labelID 80 +#define McPDM_Out2_labelID 81 +#define McPDM_Out3_labelID 82 +#define VX_UL_MUX_labelID 83 +#define MM_UL2_MUX_labelID 84 +#define MM_UL_MUX_labelID 85 +#define XinASRC_DL_VX_labelID 86 +#define ASRC_DL_VX_Coefs_labelID 87 +#define ASRC_DL_VX_Alpha_labelID 88 +#define ASRC_DL_VX_VarsBeta_labelID 89 +#define ASRC_DL_VX_8k_Regs_labelID 90 +#define XinASRC_UL_VX_labelID 91 +#define ASRC_UL_VX_Coefs_labelID 92 +#define ASRC_UL_VX_Alpha_labelID 93 +#define ASRC_UL_VX_VarsBeta_labelID 94 +#define ASRC_UL_VX_8k_Regs_labelID 95 +#define UL_48_8_DEC_labelID 96 +#define ASRC_DL_VX_16k_Regs_labelID 97 +#define ASRC_UL_VX_16k_Regs_labelID 98 +#define UL_48_16_DEC_labelID 99 +#define XinASRC_MM_EXT_IN_labelID 100 +#define ASRC_MM_EXT_IN_Coefs_labelID 101 +#define ASRC_MM_EXT_IN_Alpha_labelID 102 +#define ASRC_MM_EXT_IN_VarsBeta_labelID 103 +#define ASRC_MM_EXT_IN_Regs_labelID 104 +#define VX_REC_labelID 105 +#define VXREC_UL_M_Tones_VX_UL_labelID 106 +#define VX_REC_L_labelID 107 +#define VX_REC_R_labelID 108 +#define DL2_M_L_labelID 109 +#define DL2_M_R_labelID 110 +#define DL1_M_data_labelID 111 +#define DL1_M_Coefs_labelID 112 +#define DL2_M_LR_data_labelID 113 +#define DL2_M_LR_Coefs_labelID 114 +#define SRC_6_LP_COEFS_labelID 115 +#define SRC_6_LP_GAIN_COEFS_labelID 116 +#define SRC_6_HP_COEFS_labelID 117 +#define SRC_3_LP_COEFS_labelID 118 +#define SRC_3_LP_GAIN_COEFS_labelID 119 +#define SRC_3_HP_COEFS_labelID 120 +#define VX_DL_8_48_LP_DATA_labelID 121 +#define VX_DL_8_48_HP_DATA_labelID 122 +#define VX_DL_16_48_LP_DATA_labelID 123 +#define VX_DL_16_48_HP_DATA_labelID 124 +#define VX_UL_48_8_LP_DATA_labelID 125 +#define VX_UL_48_8_HP_DATA_labelID 126 +#define VX_UL_48_16_LP_DATA_labelID 127 +#define VX_UL_48_16_HP_DATA_labelID 128 +#define BT_UL_8_48_LP_DATA_labelID 129 +#define BT_UL_8_48_HP_DATA_labelID 130 +#define BT_UL_16_48_LP_DATA_labelID 131 +#define BT_UL_16_48_HP_DATA_labelID 132 +#define BT_DL_48_8_LP_DATA_labelID 133 +#define BT_DL_48_8_HP_DATA_labelID 134 +#define BT_DL_48_16_LP_DATA_labelID 135 +#define BT_DL_48_16_HP_DATA_labelID 136 +#define ECHO_REF_48_16_LP_DATA_labelID 137 +#define ECHO_REF_48_16_HP_DATA_labelID 138 +#define ECHO_REF_48_8_LP_DATA_labelID 139 +#define ECHO_REF_48_8_HP_DATA_labelID 140 +#define ECHO_REF_DEC_labelID 141 +#define VX_UL_8_TEMP_labelID 142 +#define VX_UL_16_TEMP_labelID 143 +#define UP_DOWN_8_48_labelID 144 +#define UP_DOWN_16_48_labelID 145 +#define SRC_6_LP_48k_labelID 146 +#define SRC_6_HP_labelID 147 +#define SRC_3_LP_48k_labelID 148 +#define SRC_3_HP_labelID 149 +#define EARP_48_96_LP_DATA_labelID 150 +#define SRC_48_96_LP_labelID 151 +#define IHF_48_96_LP_DATA_labelID 152 +#define EQ_VX_UL_16K_labelID 153 +#define AB0_labelID 154 +#define AC0_labelID 155 +#define MM_DL_C_labelID 156 +#define TONES_C_labelID 157 +#define MM_DL_44P1_REGS_labelID 158 +#define TONES_44P1_REGS_labelID 159 +#define MM_DL_44P1_DRIFT_labelID 160 +#define MM_DL_44P1_XK_labelID 161 +#define TONES_44P1_DRIFT_labelID 162 +#define TONES_44P1_XK_labelID 163 +#define SRC_44P1_MULFAC1_2_labelID 164 +#define A00_labelID 165 +#define MM_DL_44P1_WPTR1_labelID 166 +#define MM_DL_44P1_RPTR_labelID 167 +#define TONES_44P1_WPTR_labelID 168 +#define TONES_44P1_RPTR_labelID 169 +#define C_0DB_SAT_labelID 170 +#define UL_MIC_48K_labelID 171 +#define MM_DL_44P1_PP_REGS_labelID 172 +#define SRC_6_HP_NEW_COEFS_labelID 173 +#define AF_labelID 174 +#define AG_labelID 175 +#define AH_labelID 176 +#define AI_labelID 177 +#define AJ_labelID 178 +#define AK_labelID 179 +#define AL_labelID 180 +#define AM_labelID 181 +#define AN_labelID 182 +#define AO_labelID 183 +#define AP_labelID 184 +#define AQ_labelID 185 +#define AR_labelID 186 +#define AS_labelID 187 +#define AT_labelID 188 +#define AU_labelID 189 +#define AV_labelID 190 +#define SaturationMinMaxEQ_labelID 191 +#define pVIBRA1_p0_labelID 192 +#define pVIBRA1_p1_labelID 193 +#define pVIBRA1_p23_labelID 194 +#define pVIBRA1_p45_labelID 195 +#define pVibra1_pR1_labelID 196 +#define pVibra1_pR2_labelID 197 +#define pVibra1_pR3_labelID 198 +#define pVIBRA1_r_labelID 199 +#define pVIBRA2_p0_0_labelID 200 +#define pVIBRA2_p0_labelID 201 +#define pVIBRA2_p1_labelID 202 +#define pVIBRA2_p23_labelID 203 +#define pVIBRA2_p45_labelID 204 +#define pCtrl_p67_labelID 205 +#define pVIBRA2_r_labelID 206 +#define VIBRA_labelID 207 +#define UP_48_96_LP_COEFS_DC_HF_labelID 208 +#define AX_labelID 209 +#define UP_48_96_LP_COEFS_DC_HS_labelID 210 +#define AMIC_96_48_data_labelID 211 +#define DOWN_96_48_AMIC_Coefs_labelID 212 +#define DOWN_96_48_DMIC_Coefs_labelID 213 +#define DOWN_96_48_AMIC_Regs_labelID 214 +#define DOWN_96_48_DMIC_Regs_labelID 215 +#define DMIC0_96_48_data_labelID 216 +#define DMIC1_96_48_data_labelID 217 +#define DMIC2_96_48_data_labelID 218 +#define SIO_DMIC_labelID 219 +#define SIO_PDM_UL_labelID 220 +#define SIO_BT_VX_UL_labelID 221 +#define SIO_MM_UL_labelID 222 +#define SIO_MM_UL2_labelID 223 +#define SIO_VX_UL_labelID 224 +#define SIO_MM_DL_labelID 225 +#define SIO_VX_DL_labelID 226 +#define SIO_TONES_DL_labelID 227 +#define SIO_VIB_DL_labelID 228 +#define SIO_BT_VX_DL_labelID 229 +#define SIO_PDM_DL_labelID 230 +#define SIO_MM_EXT_OUT_labelID 231 +#define SIO_MM_EXT_IN_labelID 232 +#define SIO_TDM_OUT_labelID 233 +#define SIO_TDM_IN_labelID 234 +#define DMIC_ATC_PTR_labelID 235 +#define MCPDM_UL_ATC_PTR_labelID 236 +#define BT_VX_UL_ATC_PTR_labelID 237 +#define MM_UL_ATC_PTR_labelID 238 +#define MM_UL2_ATC_PTR_labelID 239 +#define VX_UL_ATC_PTR_labelID 240 +#define MM_DL_ATC_PTR_labelID 241 +#define VX_DL_ATC_PTR_labelID 242 +#define TONES_DL_ATC_PTR_labelID 243 +#define VIB_DL_ATC_PTR_labelID 244 +#define BT_VX_DL_ATC_PTR_labelID 245 +#define PDM_DL_ATC_PTR_labelID 246 +#define MM_EXT_OUT_ATC_PTR_labelID 247 +#define MM_EXT_IN_ATC_PTR_labelID 248 +#define TDM_OUT_ATC_PTR_labelID 249 +#define TDM_IN_ATC_PTR_labelID 250 +#define MCU_IRQ_FIFO_ptr_labelID 251 +#define DEBUG_IRQ_FIFO_reg_labelID 252 +#define UP_DOWN_48_96_labelID 253 +#define OSR96_2_labelID 254 +#define DEBUG_GAINS_labelID 255 +#define DBG_8K_PATTERN_labelID 256 +#define DBG_16K_PATTERN_labelID 257 +#define DBG_24K_PATTERN_labelID 258 +#define DBG_48K_PATTERN_labelID 259 +#define DBG_96K_PATTERN_labelID 260 +#define UL_VX_UL_48_8K_labelID 261 +#define UL_VX_UL_48_16K_labelID 262 +#define BT_DL_labelID 263 +#define BT_UL_labelID 264 +#define BT_DL_8k_labelID 265 +#define BT_DL_16k_labelID 266 +#define BT_UL_8k_labelID 267 +#define BT_UL_16k_labelID 268 +#define MM_EXT_IN_labelID 269 +#define MM_EXT_IN_L_labelID 270 +#define MM_EXT_IN_R_labelID 271 +#define ECHO_REF_48_16_WRAP_labelID 272 +#define ECHO_REF_48_8_WRAP_labelID 273 +#define BT_UL_16_48_WRAP_labelID 274 +#define BT_UL_8_48_WRAP_labelID 275 +#define BT_DL_48_16_WRAP_labelID 276 +#define BT_DL_48_8_WRAP_labelID 277 +#define VX_DL_16_48_WRAP_labelID 278 +#define VX_DL_8_48_WRAP_labelID 279 +#define VX_UL_48_16_WRAP_labelID 280 +#define VX_UL_48_8_WRAP_labelID 281 +#define ATC_NULL_BUFFER_labelID 282 +#define MEM_INIT_hal_mem_labelID 283 +#define MEM_INIT_write_mem_labelID 284 +#define MEM_INIT_regs_labelID 285 +#define GAIN_0DB_labelID 286 +#define XinASRC_BT_UL_labelID 287 +#define IO_BT_UL_ASRC_labelID 288 +#define ASRC_BT_UL_Coefs_labelID 289 +#define ASRC_BT_UL_Alpha_labelID 290 +#define ASRC_BT_UL_VarsBeta_labelID 291 +#define ASRC_BT_UL_8k_Regs_labelID 292 +#define ASRC_BT_UL_16k_Regs_labelID 293 +#define XinASRC_BT_DL_labelID 294 +#define DL_48_8_DEC_labelID 295 +#define DL_48_16_DEC_labelID 296 +#define BT_DL_8k_TEMP_labelID 297 +#define BT_DL_16k_TEMP_labelID 298 +#define BT_DL_8k_opp100_labelID 299 +#define BT_DL_16k_opp100_labelID 300 +#define ASRC_BT_DL_Coefs_labelID 301 +#define ASRC_BT_DL_Alpha_labelID 302 +#define ASRC_BT_DL_VarsBeta_labelID 303 +#define ASRC_BT_DL_8k_Regs_labelID 304 +#define ASRC_BT_DL_16k_Regs_labelID 305 +#define BT_DL_48_8_OPP100_WRAP_labelID 306 +#define BT_DL_48_16_OPP100_WRAP_labelID 307 +#define VX_DL_8_48_OSR_LP_labelID 308 +#define SRC_FIR6_OSR_LP_labelID 309 +#define VX_DL_8_48_FIR_WRAP_labelID 310 +#define PING_labelID 311 +#define PING_Regs_labelID 312 +#define BT_UL_8_48_FIR_WRAP_labelID 313 +#define BT_UL_8_48_OSR_LP_labelID 314 +#define SRC_6_LP_NEW_48k_labelID 315 +#define BT_DL_8_48_OSR_LP_labelID 316 +#define SRC_FIR12_OSR_LP_labelID 317 +#define BT_DL_48_8_FIR_WRAP_labelID 318 +#define BT_DL_48_8_FIR_OPP100_WRAP_labelID 319 +#define VX_UL_48_8_FIR_WRAP_labelID 320 +#define VX_UL_8_48_OSR_LP_labelID 321 +#define Dummy_322_labelID 322 +#define Dummy_323_labelID 323 +#define Dummy_324_labelID 324 +#define Dummy_325_labelID 325 +#define Dummy_326_labelID 326 +#define Dummy_327_labelID 327 +#define Dummy_328_labelID 328 +#define Dummy_329_labelID 329 +#define Dummy_330_labelID 330 +#define Dummy_331_labelID 331 +#define Dummy_332_labelID 332 +#define Dummy_333_labelID 333 +#define Dummy_334_labelID 334 +#define Dummy_335_labelID 335 +#define Dummy_336_labelID 336 +#define Dummy_337_labelID 337 +#define Dummy_338_labelID 338 +#define Dummy_339_labelID 339 +#define Dummy_340_labelID 340 +#define Dummy_341_labelID 341 +#define Dummy_342_labelID 342 +#define Dummy_343_labelID 343 +#define Dummy_344_labelID 344 +#define Dummy_345_labelID 345 +#define Dummy_346_labelID 346 +#define Dummy_347_labelID 347 +#define Dummy_348_labelID 348 +#define Dummy_349_labelID 349 +#define Dummy_350_labelID 350 +#define Dummy_351_labelID 351 +#define Dummy_352_labelID 352 +#define Dummy_353_labelID 353 +#define Dummy_354_labelID 354 +#define Dummy_355_labelID 355 +#define Dummy_356_labelID 356 +#define Dummy_357_labelID 357 +#define Dummy_358_labelID 358 +#define Dummy_359_labelID 359 +#define Dummy_360_labelID 360 +#define Dummy_361_labelID 361 +#define Dummy_362_labelID 362 +#define Dummy_363_labelID 363 +#define Dummy_364_labelID 364 +#define Dummy_365_labelID 365 +#define Dummy_366_labelID 366 +#define Dummy_367_labelID 367 +#define Dummy_368_labelID 368 +#define Dummy_369_labelID 369 +#define Dummy_370_labelID 370 +#define Dummy_371_labelID 371 +#define Dummy_372_labelID 372 +#define Dummy_373_labelID 373 +#define Dummy_374_labelID 374 +#define Dummy_375_labelID 375 +#define Dummy_376_labelID 376 +#define Dummy_377_labelID 377 +#define Dummy_378_labelID 378 +#define Dummy_379_labelID 379 +#define Dummy_380_labelID 380 +#define Dummy_381_labelID 381 +#define Dummy_382_labelID 382 +#define Dummy_383_labelID 383 +#define Dummy_384_labelID 384 +#define Dummy_385_labelID 385 +#define Dummy_386_labelID 386 +#define Dummy_387_labelID 387 +#define Dummy_388_labelID 388 +#define Dummy_389_labelID 389 +#define Dummy_390_labelID 390 +#define Dummy_391_labelID 391 +#define Dummy_392_labelID 392 +#define Dummy_393_labelID 393 +#define Dummy_394_labelID 394 +#define Dummy_395_labelID 395 +#define Dummy_396_labelID 396 +#define Dummy_397_labelID 397 +#define Dummy_398_labelID 398 +#define Dummy_399_labelID 399 +#endif /* _ABE_INITXXXX_LABELS_H_ */ diff --git a/sound/soc/omap/abe/abe_irq.c b/sound/soc/omap/abe/abe_irq.c new file mode 100644 index 0000000..7749d46 --- /dev/null +++ b/sound/soc/omap/abe/abe_irq.c @@ -0,0 +1,113 @@ +/* + + This file is provided under a dual BSD/GPLv2 license. When using or + redistributing this file, you may do so under either license. + + GPL LICENSE SUMMARY + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License 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. + The full GNU General Public License is included in this distribution + in the file called LICENSE.GPL. + + BSD LICENSE + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name of Texas Instruments Incorporated nor the names of + its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include "abe_legacy.h" + +extern u32 abe_irq_pingpong_player_id; + +/* + * initialize the default values for call-backs to subroutines + * - FIFO IRQ call-backs for sequenced tasks + * - FIFO IRQ call-backs for audio player/recorders (ping-pong protocols) + * - Remote debugger interface + * - Error monitoring + * - Activity Tracing + */ +/** + * abe_irq_ping_pong + * + * Call the respective subroutine depending on the IRQ FIFO content: + * APS interrupts : IRQ_FIFO[31:28] = IRQtag_APS, + * IRQ_FIFO[27:16] = APS_IRQs, IRQ_FIFO[15:0] = loopCounter + * SEQ interrupts : IRQ_FIFO[31:28] = IRQtag_COUNT, + * IRQ_FIFO[27:16] = Count_IRQs, IRQ_FIFO[15:0] = loopCounter + * Ping-Pong Interrupts : IRQ_FIFO[31:28] = IRQtag_PP, + * IRQ_FIFO[27:16] = PP_MCU_IRQ, IRQ_FIFO[15:0] = loopCounter + */ +void abe_irq_ping_pong(void) +{ + /* first IRQ doesn't represent a buffer transference completion */ + if (abe->pp_first_irq) + abe->pp_first_irq = 0; + else + abe->pp_buf_id = (abe->pp_buf_id + 1) & 0x03; + + abe_call_subroutine(abe_irq_pingpong_player_id, NOPARAMETER, + NOPARAMETER, NOPARAMETER, NOPARAMETER); +} +/** + * abe_irq_check_for_sequences +* @i: sequence ID + * + * check the active sequence list + * + */ +void abe_irq_check_for_sequences(u32 i) +{ +} +/** + * abe_irq_aps + * + * call the application subroutines that updates + * the acoustics protection filters + */ +void abe_irq_aps(u32 aps_info) +{ + abe_call_subroutine(abe_irq_aps_adaptation_id, NOPARAMETER, NOPARAMETER, + NOPARAMETER, NOPARAMETER); +} diff --git a/sound/soc/omap/abe/abe_legacy.h b/sound/soc/omap/abe/abe_legacy.h new file mode 100644 index 0000000..ca73dc2 --- /dev/null +++ b/sound/soc/omap/abe/abe_legacy.h @@ -0,0 +1,98 @@ +/* + + This file is provided under a dual BSD/GPLv2 license. When using or + redistributing this file, you may do so under either license. + + GPL LICENSE SUMMARY + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License 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. + The full GNU General Public License is included in this distribution + in the file called LICENSE.GPL. + + BSD LICENSE + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name of Texas Instruments Incorporated nor the names of + its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef _ABE_MAIN_H_ +#define _ABE_MAIN_H_ + +#include <linux/io.h> + +#include "abe_dm_addr.h" +#include "abe_sm_addr.h" +#include "abe_cm_addr.h" +#include "abe_define.h" +#include "abe_fw.h" +#include "abe_def.h" +#include "abe_typ.h" +#include "abe_ext.h" +#include "abe_dbg.h" +#include "abe_ref.h" +#include "abe_api.h" +#include "abe_typedef.h" +#include "abe_functionsid.h" +#include "abe_taskid.h" +#include "abe_initxxx_labels.h" +#include "abe_fw.h" + +/* pipe connection to the TARGET simulator */ +#define ABE_DEBUG_CHECKERS 0 +/* simulator data extracted from a text-file */ +#define ABE_DEBUG_HWFILE 0 +/* low-level log files */ +#define ABE_DEBUG_LL_LOG 0 + +extern struct omap_abe *abe; + +void omap_abe_dbg_log(struct omap_abe *abe, u32 x, u32 y, u32 z, u32 t); +void omap_abe_dbg_error(struct omap_abe *abe, int level, int error); + +/* + * MACROS + */ +#define _log(x, y, z, t) { if (x & abe->dbg.mask) omap_abe_dbg_log(abe, x, y, z, t); } + +#endif /* _ABE_MAIN_H_ */ diff --git a/sound/soc/omap/abe/abe_main.c b/sound/soc/omap/abe/abe_main.c new file mode 100644 index 0000000..4f35e7f --- /dev/null +++ b/sound/soc/omap/abe/abe_main.c @@ -0,0 +1,847 @@ +/* + + This file is provided under a dual BSD/GPLv2 license. When using or + redistributing this file, you may do so under either license. + + GPL LICENSE SUMMARY + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License 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. + The full GNU General Public License is included in this distribution + in the file called LICENSE.GPL. + + BSD LICENSE + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name of Texas Instruments Incorporated nor the names of + its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/slab.h> + +#include "abe_legacy.h" +#include "abe_dbg.h" +#include "abe_port.h" + + +struct omap_abe_equ { + /* type of filter */ + u32 equ_type; + /* filter length */ + u32 equ_length; + union { + /* parameters are the direct and recursive coefficients in */ + /* Q6.26 integer fixed-point format. */ + s32 type1[NBEQ1]; + struct { + /* center frequency of the band [Hz] */ + s32 freq[NBEQ2]; + /* gain of each band. [dB] */ + s32 gain[NBEQ2]; + /* Q factor of this band [dB] */ + s32 q[NBEQ2]; + } type2; + } coef; + s32 equ_param3; +}; + +#include "abe_gain.h" +#include "abe_aess.h" +#include "abe_seq.h" + + +int omap_abe_connect_debug_trace(struct omap_abe *abe, + struct omap_abe_dma *dma2); + +int omap_abe_reset_hal(struct omap_abe *abe); +int omap_abe_load_fw(struct omap_abe *abe, u32 *firmware); +int omap_abe_reload_fw(struct omap_abe *abe, u32 *firmware); +u32* omap_abe_get_default_fw(struct omap_abe *abe); +int omap_abe_wakeup(struct omap_abe *abe); +int omap_abe_irq_processing(struct omap_abe *abe); +int omap_abe_clear_irq(struct omap_abe *abe); +int omap_abe_disable_irq(struct omap_abe *abe); +int omap_abe_set_debug_trace(struct omap_abe_dbg *dbg, int debug); +int omap_abe_set_ping_pong_buffer(struct omap_abe *abe, + u32 port, u32 n_bytes); +int omap_abe_read_next_ping_pong_buffer(struct omap_abe *abe, + u32 port, u32 *p, u32 *n); +int omap_abe_init_ping_pong_buffer(struct omap_abe *abe, + u32 id, u32 size_bytes, u32 n_buffers, + u32 *p); +int omap_abe_read_offset_from_ping_buffer(struct omap_abe *abe, + u32 id, u32 *n); +int omap_abe_set_router_configuration(struct omap_abe *abe, + u32 id, u32 k, u32 *param); +int omap_abe_set_opp_processing(struct omap_abe *abe, u32 opp); +int omap_abe_disable_data_transfer(struct omap_abe *abe, u32 id); +int omap_abe_enable_data_transfer(struct omap_abe *abe, u32 id); +int omap_abe_connect_cbpr_dmareq_port(struct omap_abe *abe, + u32 id, abe_data_format_t *f, + u32 d, + abe_dma_t *returned_dma_t); +int omap_abe_connect_irq_ping_pong_port(struct omap_abe *abe, + u32 id, abe_data_format_t *f, + u32 subroutine_id, u32 size, + u32 *sink, u32 dsp_mcu_flag); +int omap_abe_connect_serial_port(struct omap_abe *abe, + u32 id, abe_data_format_t *f, + u32 mcbsp_id); +int omap_abe_read_port_address(struct omap_abe *abe, + u32 port, abe_dma_t *dma2); +int omap_abe_check_activity(struct omap_abe *abe); + +int omap_abe_use_compensated_gain(struct omap_abe *abe, int on_off); +int omap_abe_write_equalizer(struct omap_abe *abe, + u32 id, struct omap_abe_equ *param); + +int omap_abe_disable_gain(struct omap_abe *abe, u32 id, u32 p); +int omap_abe_enable_gain(struct omap_abe *abe, u32 id, u32 p); +int omap_abe_mute_gain(struct omap_abe *abe, u32 id, u32 p); +int omap_abe_unmute_gain(struct omap_abe *abe, u32 id, u32 p); + +int omap_abe_write_gain(struct omap_abe *abe, + u32 id, s32 f_g, u32 ramp, u32 p); +int omap_abe_write_mixer(struct omap_abe *abe, + u32 id, s32 f_g, u32 f_ramp, u32 p); +int omap_abe_read_gain(struct omap_abe *abe, + u32 id, u32 *f_g, u32 p); +int omap_abe_read_mixer(struct omap_abe *abe, + u32 id, u32 *f_g, u32 p); +int omap_abe_mono_mixer(struct omap_abe *abe, u32 id, u32 on_off); + +int omap_abe_reset_vx_ul_src_filters(struct omap_abe *abe); +int omap_abe_reset_mic_ul_src_filters(struct omap_abe *abe); +int omap_abe_reset_vx_dl_src_filters(struct omap_abe *abe); +int omap_abe_reset_dl1_src_filters(struct omap_abe *abe); +int omap_abe_reset_dl2_src_filters(struct omap_abe *abe); +int omap_abe_reset_bt_dl_src_filters(struct omap_abe *abe); +void omap_abe_src_filters_saturation_monitoring(struct omap_abe *abe); + +extern struct omap_abe *abe; + +#if 0 +/** + * abe_init_mem - Allocate Kernel space memory map for ABE + * + * Memory map of ABE memory space for PMEM/DMEM/SMEM/DMEM + */ +void abe_init_mem(void __iomem *_io_base) +{ + omap_abe_init_mem(abe, _io_base); +} +EXPORT_SYMBOL(abe_init_mem); + +struct omap_abe* abe_probe_aess(void) +{ + return omap_abe_probe_aess(abe); +} +EXPORT_SYMBOL(abe_probe_aess); + +void abe_remove_aess(void) +{ + omap_abe_remove_aess(abe); +} +EXPORT_SYMBOL(abe_remove_aess); + +void abe_add_subroutine(u32 *id, abe_subroutine2 f, + u32 nparam, u32 *params) +{ + omap_abe_add_subroutine(abe, id, f, nparam, params); +} +EXPORT_SYMBOL(abe_add_subroutine); + +#endif + +/** + * abe_reset_hal - reset the ABE/HAL + * @rdev: regulator source + * @constraints: constraints to apply + * + * Operations : reset the HAL by reloading the static variables and + * default AESS registers. + * Called after a PRCM cold-start reset of ABE + */ +u32 abe_reset_hal(void) +{ + omap_abe_reset_hal(abe); + return 0; +} +EXPORT_SYMBOL(abe_reset_hal); + +/** + * abe_load_fw - Load ABE Firmware and initialize memories + * + */ +u32 abe_load_fw(u32 *firmware) +{ + omap_abe_load_fw(abe, firmware); + return 0; +} +EXPORT_SYMBOL(abe_load_fw); + +/** + * abe_reload_fw - Reload ABE Firmware and initialize memories + * + */ +u32 abe_reload_fw(u32 *firmware) +{ + omap_abe_reload_fw(abe, firmware); + return 0; +} +EXPORT_SYMBOL(abe_reload_fw); + +u32* abe_get_default_fw(void) +{ + return omap_abe_get_default_fw(abe); +} +EXPORT_SYMBOL(abe_get_default_fw); + +/** + * abe_wakeup - Wakeup ABE + * + * Wakeup ABE in case of retention + */ +u32 abe_wakeup(void) +{ + omap_abe_wakeup(abe); + return 0; +} +EXPORT_SYMBOL(abe_wakeup); + +/** + * abe_irq_processing - Process ABE interrupt + * + * This subroutine is call upon reception of "MA_IRQ_99 ABE_MPU_IRQ" Audio + * back-end interrupt. This subroutine will check the ATC Hrdware, the + * IRQ_FIFO from the AE and act accordingly. Some IRQ source are originated + * for the delivery of "end of time sequenced tasks" notifications, some are + * originated from the Ping-Pong protocols, some are generated from + * the embedded debugger when the firmware stops on programmable break-points, + * etc ... + */ +u32 abe_irq_processing(void) +{ + omap_abe_irq_processing(abe); + return 0; +} +EXPORT_SYMBOL(abe_irq_processing); + +/** + * abe_clear_irq - clear ABE interrupt + * + * This subroutine is call to clear MCU Irq + */ +u32 abe_clear_irq(void) +{ + omap_abe_clear_irq(abe); + return 0; +} +EXPORT_SYMBOL(abe_clear_irq); + +/** + * abe_disable_irq - disable MCU/DSP ABE interrupt + * + * This subroutine is disabling ABE MCU/DSP Irq + */ +u32 abe_disable_irq(void) +{ + omap_abe_disable_irq(abe); + + return 0; +} +EXPORT_SYMBOL(abe_disable_irq); + +/** + * abe_write_event_generator - Selects event generator source + * @e: Event Generation Counter, McPDM, DMIC or default. + * + * Loads the AESS event generator hardware source. + * Loads the firmware parameters accordingly. + * Indicates to the FW which data stream is the most important to preserve + * in case all the streams are asynchronous. + * If the parameter is "default", then HAL decides which Event source + * is the best appropriate based on the opened ports. + * + * When neither the DMIC and the McPDM are activated, the AE will have + * its EVENT generator programmed with the EVENT_COUNTER. + * The event counter will be tuned in order to deliver a pulse frequency higher + * than 96 kHz. + * The DPLL output at 100% OPP is MCLK = (32768kHz x6000) = 196.608kHz + * The ratio is (MCLK/96000)+(1<<1) = 2050 + * (1<<1) in order to have the same speed at 50% and 100% OPP + * (only 15 MSB bits are used at OPP50%) + */ +u32 abe_write_event_generator(u32 e) // should integarte abe as parameter +{ + omap_abe_write_event_generator(abe, e); + return 0; +} +EXPORT_SYMBOL(abe_write_event_generator); + +/** + * abe_start_event_generator - Starts event generator source + * + * Start the event genrator of AESS. No more event will be send to AESS engine. + * Upper layer must wait 1/96kHz to be sure that engine reaches + * the IDLE instruction. + */ +u32 abe_stop_event_generator(void) +{ + omap_abe_stop_event_generator(abe); + return 0; +} +EXPORT_SYMBOL(abe_stop_event_generator); + +/** + * abe_connect_debug_trace + * @dma2:pointer to the DMEM trace buffer + * + * returns the address and size of the real-time debug trace buffer, + * the content of which will vary from one firmware release to another + */ +u32 abe_connect_debug_trace(abe_dma_t *dma2) +{ + omap_abe_connect_debug_trace(abe, (struct omap_abe_dma *)dma2); + return 0; +} +EXPORT_SYMBOL(abe_connect_debug_trace); + +/** + * abe_set_debug_trace + * @debug: debug ID from a list to be defined + * + * loads a mask which filters the debug trace to dedicated types of data + */ +u32 abe_set_debug_trace(abe_dbg_t debug) +{ + omap_abe_set_debug_trace(&abe->dbg, (int)(debug)); + return 0; +} +EXPORT_SYMBOL(abe_set_debug_trace); + +/** + * abe_set_ping_pong_buffer + * @port: ABE port ID + * @n_bytes: Size of Ping/Pong buffer + * + * Updates the next ping-pong buffer with "size" bytes copied from the + * host processor. This API notifies the FW that the data transfer is done. + */ +u32 abe_set_ping_pong_buffer(u32 port, u32 n_bytes) +{ + omap_abe_set_ping_pong_buffer(abe, port, n_bytes); + return 0; +} +EXPORT_SYMBOL(abe_set_ping_pong_buffer); + +/** + * abe_read_next_ping_pong_buffer + * @port: ABE portID + * @p: Next buffer address (pointer) + * @n: Next buffer size (pointer) + * + * Tell the next base address of the next ping_pong Buffer and its size + */ +u32 abe_read_next_ping_pong_buffer(u32 port, u32 *p, u32 *n) +{ + omap_abe_read_next_ping_pong_buffer(abe, port, p, n); + return 0; +} +EXPORT_SYMBOL(abe_read_next_ping_pong_buffer); + +/** + * abe_init_ping_pong_buffer + * @id: ABE port ID + * @size_bytes:size of the ping pong + * @n_buffers:number of buffers (2 = ping/pong) + * @p:returned address of the ping-pong list of base addresses + * (byte offset from DMEM start) + * + * Computes the base address of the ping_pong buffers + */ +u32 abe_init_ping_pong_buffer(u32 id, u32 size_bytes, u32 n_buffers, + u32 *p) +{ + omap_abe_init_ping_pong_buffer(abe, id, size_bytes, n_buffers, p); + return 0; +} +EXPORT_SYMBOL(abe_init_ping_pong_buffer); + +/** + * abe_read_offset_from_ping_buffer + * @id: ABE port ID + * @n: returned address of the offset + * from the ping buffer start address (in samples) + * + * Computes the current firmware ping pong read pointer location, + * expressed in samples, as the offset from the start address of ping buffer. + */ +u32 abe_read_offset_from_ping_buffer(u32 id, u32 *n) +{ + omap_abe_read_offset_from_ping_buffer(abe, id, n); + return 0; +} +EXPORT_SYMBOL(abe_read_offset_from_ping_buffer); + +/** + * abe_write_equalizer + * @id: name of the equalizer + * @param : equalizer coefficients + * + * Load the coefficients in CMEM. + */ +u32 abe_write_equalizer(u32 id, abe_equ_t *param) +{ + omap_abe_write_equalizer(abe, id, (struct omap_abe_equ *)param); + return 0; +} +EXPORT_SYMBOL(abe_write_equalizer); +/** + * abe_disable_gain + * Parameters: + * mixer id + * sub-port id + * + */ +u32 abe_disable_gain(u32 id, u32 p) +{ + omap_abe_disable_gain(abe, id, p); + return 0; +} +EXPORT_SYMBOL(abe_disable_gain); +/** + * abe_enable_gain + * Parameters: + * mixer id + * sub-port id + * + */ +u32 abe_enable_gain(u32 id, u32 p) +{ + omap_abe_enable_gain(abe, id, p); + return 0; +} +EXPORT_SYMBOL(abe_enable_gain); + +/** + * abe_mute_gain + * Parameters: + * mixer id + * sub-port id + * + */ +u32 abe_mute_gain(u32 id, u32 p) +{ + omap_abe_mute_gain(abe, id, p); + return 0; +} +EXPORT_SYMBOL(abe_mute_gain); + +/** + * abe_unmute_gain + * Parameters: + * mixer id + * sub-port id + * + */ +u32 abe_unmute_gain(u32 id, u32 p) +{ + omap_abe_unmute_gain(abe, id, p); + return 0; +} +EXPORT_SYMBOL(abe_unmute_gain); + +/** + * abe_write_gain + * @id: gain name or mixer name + * @f_g: list of input gains of the mixer + * @ramp: gain ramp speed factor + * @p: list of ports corresponding to the above gains + * + * Loads the gain coefficients to FW memory. This API can be called when + * the corresponding MIXER is not activated. After reloading the firmware + * the default coefficients corresponds to "all input and output mixer's gain + * in mute state". A mixer is disabled with a network reconfiguration + * corresponding to an OPP value. + */ +u32 abe_write_gain(u32 id, s32 f_g, u32 ramp, u32 p) +{ + omap_abe_write_gain(abe, id, f_g, ramp, p); + return 0; +} +EXPORT_SYMBOL(abe_write_gain); + +/** + * abe_write_mixer + * @id: name of the mixer + * @param: input gains and delay ramp of the mixer + * @p: port corresponding to the above gains + * + * Load the gain coefficients in FW memory. This API can be called when + * the corresponding MIXER is not activated. After reloading the firmware + * the default coefficients corresponds to "all input and output mixer's + * gain in mute state". A mixer is disabled with a network reconfiguration + * corresponding to an OPP value. + */ +u32 abe_write_mixer(u32 id, s32 f_g, u32 f_ramp, u32 p) +{ + omap_abe_write_gain(abe, id, f_g, f_ramp, p); + return 0; +} +EXPORT_SYMBOL(abe_write_mixer); + +/** + * abe_read_gain + * @id: name of the mixer + * @param: list of input gains of the mixer + * @p: list of port corresponding to the above gains + * + */ +u32 abe_read_gain(u32 id, u32 *f_g, u32 p) +{ + omap_abe_read_gain(abe, id, f_g, p); + return 0; +} +EXPORT_SYMBOL(abe_read_gain); + +/** + * abe_read_mixer + * @id: name of the mixer + * @param: gains of the mixer + * @p: port corresponding to the above gains + * + * Load the gain coefficients in FW memory. This API can be called when + * the corresponding MIXER is not activated. After reloading the firmware + * the default coefficients corresponds to "all input and output mixer's + * gain in mute state". A mixer is disabled with a network reconfiguration + * corresponding to an OPP value. + */ +u32 abe_read_mixer(u32 id, u32 *f_g, u32 p) +{ + omap_abe_read_gain(abe, id, f_g, p); + return 0; +} +EXPORT_SYMBOL(abe_read_mixer); + +/** + * abe_set_router_configuration + * @Id: name of the router + * @Conf: id of the configuration + * @param: list of output index of the route + * + * The uplink router takes its input from DMIC (6 samples), AMIC (2 samples) + * and PORT1/2 (2 stereo ports). Each sample will be individually stored in + * an intermediate table of 10 elements. + * + * Example of router table parameter for voice uplink with phoenix microphones + * + * indexes 0 .. 9 = MM_UL description (digital MICs and MMEXTIN) + * DMIC1_L_labelID, DMIC1_R_labelID, DMIC2_L_labelID, DMIC2_R_labelID, + * MM_EXT_IN_L_labelID, MM_EXT_IN_R_labelID, ZERO_labelID, ZERO_labelID, + * ZERO_labelID, ZERO_labelID, + * indexes 10 .. 11 = MM_UL2 description (recording on DMIC3) + * DMIC3_L_labelID, DMIC3_R_labelID, + * indexes 12 .. 13 = VX_UL description (VXUL based on PDMUL data) + * AMIC_L_labelID, AMIC_R_labelID, + * indexes 14 .. 15 = RESERVED (NULL) + * ZERO_labelID, ZERO_labelID, + */ +u32 abe_set_router_configuration(u32 id, u32 k, u32 *param) +{ + omap_abe_set_router_configuration(abe, id, k, param); + return 0; +} +EXPORT_SYMBOL(abe_set_router_configuration); + +/** + * abe_set_opp_processing - Set OPP mode for ABE Firmware + * @opp: OOPP mode + * + * New processing network and OPP: + * 0: Ultra Lowest power consumption audio player (no post-processing, no mixer) + * 1: OPP 25% (simple multimedia features, including low-power player) + * 2: OPP 50% (multimedia and voice calls) + * 3: OPP100% ( multimedia complex use-cases) + * + * Rearranges the FW task network to the corresponding OPP list of features. + * The corresponding AE ports are supposed to be set/reset accordingly before + * this switch. + * + */ +u32 abe_set_opp_processing(u32 opp) +{ + omap_abe_set_opp_processing(abe, opp); + return 0; +} +EXPORT_SYMBOL(abe_set_opp_processing); + +/** + * abe_disable_data_transfer + * @id: ABE port id + * + * disables the ATC descriptor and stop IO/port activities + * disable the IO task (@f = 0) + * clear ATC DMEM buffer, ATC enabled + */ +u32 abe_disable_data_transfer(u32 id) +{ + omap_abe_disable_data_transfer(abe, id); + return 0; +} +EXPORT_SYMBOL(abe_disable_data_transfer); + +/** + * abe_enable_data_transfer + * @ip: ABE port id + * + * enables the ATC descriptor + * reset ATC pointers + * enable the IO task (@f <> 0) + */ +u32 abe_enable_data_transfer(u32 id) +{ + omap_abe_enable_data_transfer(abe, id); + return 0; +} +EXPORT_SYMBOL(abe_enable_data_transfer); + +/** + * abe_connect_cbpr_dmareq_port + * @id: port name + * @f: desired data format + * @d: desired dma_request line (0..7) + * @a: returned pointer to the base address of the CBPr register and number of + * samples to exchange during a DMA_request. + * + * enables the data echange between a DMA and the ABE through the + * CBPr registers of AESS. + */ +u32 abe_connect_cbpr_dmareq_port(u32 id, abe_data_format_t *f, u32 d, + abe_dma_t *returned_dma_t) +{ + omap_abe_connect_cbpr_dmareq_port(abe, id, f, d, returned_dma_t); + return 0; +} +EXPORT_SYMBOL(abe_connect_cbpr_dmareq_port); + +/** + * abe_connect_irq_ping_pong_port + * @id: port name + * @f: desired data format + * @I: index of the call-back subroutine to call + * @s: half-buffer (ping) size + * @p: returned base address of the first (ping) buffer) + * + * enables the data echanges between a direct access to the DMEM + * memory of ABE using cache flush. On each IRQ activation a subroutine + * registered with "abe_plug_subroutine" will be called. This subroutine + * will generate an amount of samples, send them to DMEM memory and call + * "abe_set_ping_pong_buffer" to notify the new amount of samples in the + * pong buffer. + */ +u32 abe_connect_irq_ping_pong_port(u32 id, abe_data_format_t *f, + u32 subroutine_id, u32 size, + u32 *sink, u32 dsp_mcu_flag) +{ + omap_abe_connect_irq_ping_pong_port(abe, id, f, subroutine_id, size, + sink, dsp_mcu_flag); + return 0; +} +EXPORT_SYMBOL(abe_connect_irq_ping_pong_port); + +/** + * abe_connect_serial_port() + * @id: port name + * @f: data format + * @i: peripheral ID (McBSP #1, #2, #3) + * + * Operations : enables the data echanges between a McBSP and an ATC buffer in + * DMEM. This API is used connect 48kHz McBSP streams to MM_DL and 8/16kHz + * voice streams to VX_UL, VX_DL, BT_VX_UL, BT_VX_DL. It abstracts the + * abe_write_port API. + */ +u32 abe_connect_serial_port(u32 id, abe_data_format_t *f, + u32 mcbsp_id) +{ + omap_abe_connect_serial_port(abe, id, f, mcbsp_id); + return 0; +} +EXPORT_SYMBOL(abe_connect_serial_port); + +/** + * abe_read_port_address + * @dma: output pointer to the DMA iteration and data destination pointer + * + * This API returns the address of the DMA register used on this audio port. + * Depending on the protocol being used, adds the base address offset L3 + * (DMA) or MPU (ARM) + */ +u32 abe_read_port_address(u32 port, abe_dma_t *dma2) +{ + omap_abe_read_port_address(abe, port, dma2); + return 0; +} +EXPORT_SYMBOL(abe_read_port_address); + +/** + * abe_check_activity - Check if some ABE activity. + * + * Check if any ABE ports are running. + * return 1: still activity on ABE + * return 0: no more activity on ABE. Event generator can be stopped + * + */ +u32 abe_check_activity(void) +{ + return (u32)omap_abe_check_activity(abe); +} +EXPORT_SYMBOL(abe_check_activity); +/** + * abe_use_compensated_gain + * @on_off: + * + * Selects the automatic Mixer's gain management + * on_off = 1 allows the "abe_write_gain" to adjust the overall + * gains of the mixer to be tuned not to create saturation + */ +abehal_status abe_use_compensated_gain(u32 on_off) +{ + omap_abe_use_compensated_gain(abe, (int)(on_off)); + return 0; +} + +/** + * abe_mono_mixer + * @id: name of the mixer (MIXDL1, MIXDL2, MIXAUDUL) + * on_off: enable\disable flag + * + * This API Programs DL1Mixer or DL2Mixer to output mono data + * on both left and right data paths. + */ +int abe_mono_mixer(u32 id, u32 on_off) +{ + return omap_abe_mono_mixer(abe, id, on_off); +} +EXPORT_SYMBOL(abe_mono_mixer); + +EXPORT_SYMBOL(abe_use_compensated_gain); + +/** +* abe_reset_vx_ul_src_filters - reset VX UL path filters +* +* it is assumed that filters are located in SMEM +*/ +u32 abe_reset_vx_ul_src_filters(void) +{ + return (u32)omap_abe_reset_vx_ul_src_filters(abe); +} +EXPORT_SYMBOL(abe_reset_vx_ul_src_filters); + +/** +* abe_reset_mic_ul_src_filters - reset mic path filters +* +* it is assumed that filters are located in SMEM +*/ +u32 abe_reset_mic_ul_src_filters(void) +{ + return (u32)omap_abe_reset_mic_ul_src_filters(abe); +} +EXPORT_SYMBOL(abe_reset_mic_ul_src_filters); + +/** +* abe_reset_vx_dl_src_filters - reset VX DL path filters +* +* it is assumed that filters are located in SMEM +*/ +u32 abe_reset_vx_dl_src_filters(void) +{ + return (u32)omap_abe_reset_vx_dl_src_filters(abe); +} +EXPORT_SYMBOL(abe_reset_vx_dl_src_filters); + +/** +* abe_reset_dl1_src_filters - reset DL1 path filters +* +* it is assumed that filters are located in SMEM +*/ +u32 abe_reset_dl1_src_filters(void) +{ + return (u32)omap_abe_reset_dl1_src_filters(abe); +} +EXPORT_SYMBOL(abe_reset_dl1_src_filters); + +/** +* abe_reset_dl2_src_filters - reset DL2 path filters +* +* it is assumed that filters are located in SMEM +*/ +u32 abe_reset_dl2_src_filters(void) +{ + return (u32)omap_abe_reset_dl2_src_filters(abe); +} +EXPORT_SYMBOL(abe_reset_dl2_src_filters); + +/** +* abe_reset_bt_dl_src_filters - reset BT DL path filters +* +* it is assumed that filters are located in SMEM +*/ +u32 abe_reset_bt_dl_src_filters(void) +{ + return (u32)omap_abe_reset_bt_dl_src_filters(abe); +} +EXPORT_SYMBOL(abe_reset_bt_dl_src_filters); + +/** +* abe_src_ilters_saturation_monitoring - monitor for saturation +* in abe filters +*/ +void abe_src_filters_saturation_monitoring(void) +{ + omap_abe_src_filters_saturation_monitoring(abe); +} +EXPORT_SYMBOL(abe_src_filters_saturation_monitoring); diff --git a/sound/soc/omap/abe/abe_main.h b/sound/soc/omap/abe/abe_main.h new file mode 100644 index 0000000..e019541 --- /dev/null +++ b/sound/soc/omap/abe/abe_main.h @@ -0,0 +1,676 @@ +/* + + This file is provided under a dual BSD/GPLv2 license. When using or + redistributing this file, you may do so under either license. + + GPL LICENSE SUMMARY + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License 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. + The full GNU General Public License is included in this distribution + in the file called LICENSE.GPL. + + BSD LICENSE + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name of Texas Instruments Incorporated nor the names of + its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef _ABE_MAIN_H_ +#define _ABE_MAIN_H_ + +#include <linux/io.h> + +#include "abe_initxxx_labels.h" + +#define D_DEBUG_FIFO_ADDR 8160 +#define D_DEBUG_FIFO_ADDR_END 8255 + +#define SUB_0_PARAM 0 +#define SUB_1_PARAM 1 + +#define ABE_DEFAULT_BASE_ADDRESS_L3 0x49000000L +#define ABE_DMEM_BASE_ADDRESS_MPU 0x40180000L +#define ABE_DMEM_BASE_OFFSET_MPU 0x00080000L +#define ABE_DMEM_BASE_ADDRESS_L3 (ABE_DEFAULT_BASE_ADDRESS_L3 + \ + ABE_DMEM_BASE_OFFSET_MPU) + +/* + * HARDWARE AND PERIPHERAL DEFINITIONS + */ +/* MM_DL */ +#define ABE_CBPR0_IDX 0 +/* VX_DL */ +#define ABE_CBPR1_IDX 1 +/* VX_UL */ +#define ABE_CBPR2_IDX 2 +/* MM_UL */ +#define ABE_CBPR3_IDX 3 +/* MM_UL2 */ +#define ABE_CBPR4_IDX 4 +/* TONES */ +#define ABE_CBPR5_IDX 5 +/* VIB */ +#define ABE_CBPR6_IDX 6 +/* DEBUG/CTL */ +#define ABE_CBPR7_IDX 7 + +/* + * OPP TYPE + * + * 0: Ultra Lowest power consumption audio player + * 1: OPP 25% (simple multimedia features) + * 2: OPP 50% (multimedia and voice calls) + * 3: OPP100% (multimedia complex use-cases) + */ +#define ABE_OPP0 0 +#define ABE_OPP25 1 +#define ABE_OPP50 2 +#define ABE_OPP100 3 +/* + * SAMPLES TYPE + * + * mono 16 bit sample LSB aligned, 16 MSB bits are unused; + * mono right shifted to 16bits LSBs on a 32bits DMEM FIFO for McBSP + * TX purpose; + * mono sample MSB aligned (16/24/32bits); + * two successive mono samples in one 32bits container; + * Two L/R 16bits samples in a 32bits container; + * Two channels defined with two MSB aligned samples; + * Three channels defined with three MSB aligned samples (MIC); + * Four channels defined with four MSB aligned samples (MIC); + * . . . + * Eight channels defined with eight MSB aligned samples (MIC); + */ +#define MONO_MSB 1 +#define MONO_RSHIFTED_16 2 +#define STEREO_RSHIFTED_16 3 +#define STEREO_16_16 4 +#define STEREO_MSB 5 +#define THREE_MSB 6 +#define FOUR_MSB 7 +#define FIVE_MSB 8 +#define SIX_MSB 9 +#define SEVEN_MSB 10 +#define EIGHT_MSB 11 +#define NINE_MSB 12 +#define TEN_MSB 13 +/* + * PORT PROTOCOL TYPE - abe_port_protocol_switch_id + */ +#define SLIMBUS_PORT_PROT 1 +#define SERIAL_PORT_PROT 2 +#define TDM_SERIAL_PORT_PROT 3 +#define DMIC_PORT_PROT 4 +#define MCPDMDL_PORT_PROT 5 +#define MCPDMUL_PORT_PROT 6 +#define PINGPONG_PORT_PROT 7 +#define DMAREQ_PORT_PROT 8 +/* + * PORT IDs, this list is aligned with the FW data mapping + */ +#define DMIC_PORT 0 +#define PDM_UL_PORT 1 +#define BT_VX_UL_PORT 2 +#define MM_UL_PORT 3 +#define MM_UL2_PORT 4 +#define VX_UL_PORT 5 +#define MM_DL_PORT 6 +#define VX_DL_PORT 7 +#define TONES_DL_PORT 8 +#define VIB_DL_PORT 9 +#define BT_VX_DL_PORT 10 +#define PDM_DL_PORT 11 +#define MM_EXT_OUT_PORT 12 +#define MM_EXT_IN_PORT 13 +#define TDM_DL_PORT 14 +#define TDM_UL_PORT 15 +#define DEBUG_PORT 16 +#define LAST_PORT_ID 17 +/* definitions for the compatibility with HAL05xx */ +#define PDM_DL1_PORT 18 +#define PDM_DL2_PORT 19 +#define PDM_VIB_PORT 20 +/* There is only one DMIC port, always used with 6 samples + per 96kHz periods */ +#define DMIC_PORT1 DMIC_PORT +#define DMIC_PORT2 DMIC_PORT +#define DMIC_PORT3 DMIC_PORT +/* + * Signal processing module names - EQ APS MIX ROUT + */ +/* equalizer downlink path headset + earphone */ +#define FEAT_EQ1 1 +/* equalizer downlink path integrated handsfree LEFT */ +#define FEAT_EQ2L (FEAT_EQ1+1) +/* equalizer downlink path integrated handsfree RIGHT */ +#define FEAT_EQ2R (FEAT_EQ2L+1) +/* equalizer downlink path side-tone */ +#define FEAT_EQSDT (FEAT_EQ2R+1) +/* equalizer uplink path AMIC */ +#define FEAT_EQAMIC (FEAT_EQSDT+1) +/* equalizer uplink path DMIC */ +#define FEAT_EQDMIC (FEAT_EQAMIC+1) +/* Acoustic protection for headset */ +#define FEAT_APS1 (FEAT_EQDMIC+1) +/* acoustic protection high-pass filter for handsfree "Left" */ +#define FEAT_APS2 (FEAT_APS1+1) +/* acoustic protection high-pass filter for handsfree "Right" */ +#define FEAT_APS3 (FEAT_APS2+1) +/* asynchronous sample-rate-converter for the downlink voice path */ +#define FEAT_ASRC1 (FEAT_APS3+1) +/* asynchronous sample-rate-converter for the uplink voice path */ +#define FEAT_ASRC2 (FEAT_ASRC1+1) +/* asynchronous sample-rate-converter for the multimedia player */ +#define FEAT_ASRC3 (FEAT_ASRC2+1) +/* asynchronous sample-rate-converter for the echo reference */ +#define FEAT_ASRC4 (FEAT_ASRC3+1) +/* mixer of the headset and earphone path */ +#define FEAT_MIXDL1 (FEAT_ASRC4+1) +/* mixer of the hands-free path */ +#define FEAT_MIXDL2 (FEAT_MIXDL1+1) +/* mixer for audio being sent on the voice_ul path */ +#define FEAT_MIXAUDUL (FEAT_MIXDL2+1) +/* mixer for voice communication recording */ +#define FEAT_MIXVXREC (FEAT_MIXAUDUL+1) +/* mixer for side-tone */ +#define FEAT_MIXSDT (FEAT_MIXVXREC+1) +/* mixer for echo reference */ +#define FEAT_MIXECHO (FEAT_MIXSDT+1) +/* router of the uplink path */ +#define FEAT_UPROUTE (FEAT_MIXECHO+1) +/* all gains */ +#define FEAT_GAINS (FEAT_UPROUTE+1) +#define FEAT_GAINS_DMIC1 (FEAT_GAINS+1) +#define FEAT_GAINS_DMIC2 (FEAT_GAINS_DMIC1+1) +#define FEAT_GAINS_DMIC3 (FEAT_GAINS_DMIC2+1) +#define FEAT_GAINS_AMIC (FEAT_GAINS_DMIC3+1) +#define FEAT_GAINS_SPLIT (FEAT_GAINS_AMIC+1) +#define FEAT_GAINS_DL1 (FEAT_GAINS_SPLIT+1) +#define FEAT_GAINS_DL2 (FEAT_GAINS_DL1+1) +#define FEAT_GAIN_BTUL (FEAT_GAINS_DL2+1) +/* sequencing queue of micro tasks */ +#define FEAT_SEQ (FEAT_GAIN_BTUL+1) +/* Phoenix control queue through McPDM */ +#define FEAT_CTL (FEAT_SEQ+1) +/* list of features of the firmware -------------------------------*/ +#define MAXNBFEATURE FEAT_CTL +/* abe_equ_id */ +/* equalizer downlink path headset + earphone */ +#define EQ1 FEAT_EQ1 +/* equalizer downlink path integrated handsfree LEFT */ +#define EQ2L FEAT_EQ2L +#define EQ2R FEAT_EQ2R +/* equalizer downlink path side-tone */ +#define EQSDT FEAT_EQSDT +#define EQAMIC FEAT_EQAMIC +#define EQDMIC FEAT_EQDMIC +/* abe_aps_id */ +/* Acoustic protection for headset */ +#define APS1 FEAT_APS1 +#define APS2L FEAT_APS2 +#define APS2R FEAT_APS3 +/* abe_asrc_id */ +/* asynchronous sample-rate-converter for the downlink voice path */ +#define ASRC1 FEAT_ASRC1 +/* asynchronous sample-rate-converter for the uplink voice path */ +#define ASRC2 FEAT_ASRC2 +/* asynchronous sample-rate-converter for the multimedia player */ +#define ASRC3 FEAT_ASRC3 +/* asynchronous sample-rate-converter for the voice uplink echo_reference */ +#define ASRC4 FEAT_ASRC4 +/* abe_mixer_id */ +#define MIXDL1 FEAT_MIXDL1 +#define MIXDL2 FEAT_MIXDL2 +#define MIXSDT FEAT_MIXSDT +#define MIXECHO FEAT_MIXECHO +#define MIXAUDUL FEAT_MIXAUDUL +#define MIXVXREC FEAT_MIXVXREC +/* abe_router_id */ +/* there is only one router up to now */ +#define UPROUTE FEAT_UPROUTE +/* + * gain controls + */ +#define GAIN_LEFT_OFFSET 0 +#define GAIN_RIGHT_OFFSET 1 +/* + * GAIN IDs + */ +#define GAINS_DMIC1 FEAT_GAINS_DMIC1 +#define GAINS_DMIC2 FEAT_GAINS_DMIC2 +#define GAINS_DMIC3 FEAT_GAINS_DMIC3 +#define GAINS_AMIC FEAT_GAINS_AMIC +#define GAINS_SPLIT FEAT_GAINS_SPLIT +#define GAINS_DL1 FEAT_GAINS_DL1 +#define GAINS_DL2 FEAT_GAINS_DL2 +#define GAINS_BTUL FEAT_GAIN_BTUL +/* + * ABE CONST AREA FOR PARAMETERS TRANSLATION + */ +#define sizeof_alpha_iir_table 61 +#define sizeof_beta_iir_table 61 +#define GAIN_MAXIMUM 3000L +#define GAIN_24dB 2400L +#define GAIN_18dB 1800L +#define GAIN_12dB 1200L +#define GAIN_6dB 600L +/* default gain = 1 */ +#define GAIN_0dB 0L +#define GAIN_M1dB -100L +#define GAIN_M6dB -600L +#define GAIN_M7dB -700L +#define GAIN_M8dB -800L +#define GAIN_M12dB -1200L +#define GAIN_M18dB -1800L +#define GAIN_M24dB -2400L +#define GAIN_M30dB -3000L +#define GAIN_M40dB -4000L +#define GAIN_M50dB -5000L +/* muted gain = -120 decibels */ +#define MUTE_GAIN -12000L +#define GAIN_TOOLOW -13000L +#define GAIN_MUTE MUTE_GAIN +#define RAMP_MINLENGTH 3L +/* ramp_t is in milli- seconds */ +#define RAMP_0MS 0L +#define RAMP_1MS 1L +#define RAMP_2MS 2L +#define RAMP_5MS 5L +#define RAMP_10MS 10L +#define RAMP_20MS 20L +#define RAMP_50MS 50L +#define RAMP_100MS 100L +#define RAMP_200MS 200L +#define RAMP_500MS 500L +#define RAMP_1000MS 1000L +#define RAMP_MAXLENGTH 10000L +/* for abe_translate_gain_format */ +#define LINABE_TO_DECIBELS 1 +#define DECIBELS_TO_LINABE 2 +/* for abe_translate_ramp_format */ +#define IIRABE_TO_MICROS 1 +#define MICROS_TO_IIABE 2 +/* + * EVENT GENERATORS - abe_event_id + */ +#define EVENT_TIMER 0 +#define EVENT_44100 1 +/* + * DMA requests + */ +/*Internal connection doesn't connect at ABE boundary */ +#define External_DMA_0 0 +/*Transmit request digital microphone */ +#define DMIC_DMA_REQ 1 +/*Multichannel PDM downlink */ +#define McPDM_DMA_DL 2 +/*Multichannel PDM uplink */ +#define McPDM_DMA_UP 3 +/*MCBSP module 1 - transmit request */ +#define MCBSP1_DMA_TX 4 +/*MCBSP module 1 - receive request */ +#define MCBSP1_DMA_RX 5 +/*MCBSP module 2 - transmit request */ +#define MCBSP2_DMA_TX 6 +/*MCBSP module 2 - receive request */ +#define MCBSP2_DMA_RX 7 +/*MCBSP module 3 - transmit request */ +#define MCBSP3_DMA_TX 8 +/*MCBSP module 3 - receive request */ +#define MCBSP3_DMA_RX 9 +/* + * SERIAL PORTS IDs - abe_mcbsp_id + */ +#define MCBSP1_TX MCBSP1_DMA_TX +#define MCBSP1_RX MCBSP1_DMA_RX +#define MCBSP2_TX MCBSP2_DMA_TX +#define MCBSP2_RX MCBSP2_DMA_RX +#define MCBSP3_TX MCBSP3_DMA_TX +#define MCBSP3_RX MCBSP3_DMA_RX + +#define PING_PONG_WITH_MCU_IRQ 1 +#define PING_PONG_WITH_DSP_IRQ 2 + +/* + Mixer ID Input port ID Comments + DL1_MIXER 0 MMDL path + 1 MMUL2 path + 2 VXDL path + 3 TONES path + SDT_MIXER 0 Uplink path + 1 Downlink path + ECHO_MIXER 0 DL1_MIXER path + 1 DL2_MIXER path + AUDUL_MIXER 0 TONES_DL path + 1 Uplink path + 2 MM_DL path + VXREC_MIXER 0 TONES_DL path + 1 VX_DL path + 2 MM_DL path + 3 VX_UL path +*/ +#define MIX_VXUL_INPUT_MM_DL 0 +#define MIX_VXUL_INPUT_TONES 1 +#define MIX_VXUL_INPUT_VX_UL 2 +#define MIX_VXUL_INPUT_VX_DL 3 +#define MIX_DL1_INPUT_MM_DL 0 +#define MIX_DL1_INPUT_MM_UL2 1 +#define MIX_DL1_INPUT_VX_DL 2 +#define MIX_DL1_INPUT_TONES 3 +#define MIX_DL2_INPUT_MM_DL 0 +#define MIX_DL2_INPUT_MM_UL2 1 +#define MIX_DL2_INPUT_VX_DL 2 +#define MIX_DL2_INPUT_TONES 3 +#define MIX_SDT_INPUT_UP_MIXER 0 +#define MIX_SDT_INPUT_DL1_MIXER 1 +#define MIX_AUDUL_INPUT_MM_DL 0 +#define MIX_AUDUL_INPUT_TONES 1 +#define MIX_AUDUL_INPUT_UPLINK 2 +#define MIX_AUDUL_INPUT_VX_DL 3 +#define MIX_VXREC_INPUT_MM_DL 0 +#define MIX_VXREC_INPUT_TONES 1 +#define MIX_VXREC_INPUT_VX_UL 2 +#define MIX_VXREC_INPUT_VX_DL 3 +#define MIX_ECHO_DL1 0 +#define MIX_ECHO_DL2 1 +/* nb of samples to route */ +#define NBROUTE_UL 16 +/* 10 routing tables max */ +#define NBROUTE_CONFIG_MAX 10 +/* 5 pre-computed routing tables */ +#define NBROUTE_CONFIG 6 +/* AMIC on VX_UL */ +#define UPROUTE_CONFIG_AMIC 0 +/* DMIC first pair on VX_UL */ +#define UPROUTE_CONFIG_DMIC1 1 +/* DMIC second pair on VX_UL */ +#define UPROUTE_CONFIG_DMIC2 2 +/* DMIC last pair on VX_UL */ +#define UPROUTE_CONFIG_DMIC3 3 +/* BT_UL on VX_UL */ +#define UPROUTE_CONFIG_BT 4 +/* ECHO_REF on MM_UL2 */ +#define UPROUTE_ECHO_MMUL2 5 + +/* + * DMA_T + * + * dma structure for easing programming + */ +typedef struct { + /* OCP L3 pointer to the first address of the */ + void *data; + /* destination buffer (either DMA or Ping-Pong read/write pointers). */ + /* address L3 when addressing the DMEM buffer instead of CBPr */ + void *l3_dmem; + /* address L3 translated to L4 the ARM memory space */ + void *l4_dmem; + /* number of iterations for the DMA data moves. */ + u32 iter; +} abe_dma_t; +typedef u32 abe_dbg_t; +/* + * ROUTER_T + * + * table of indexes in unsigned bytes + */ +typedef u16 abe_router_t; +/* + * DATA_FORMAT_T + * + * used in port declaration + */ +typedef struct { + /* Sampling frequency of the stream */ + u32 f; + /* Sample format type */ + u32 samp_format; +} abe_data_format_t; +/* + * PORT_PROTOCOL_T + * + * port declaration + */ +typedef struct { + /* Direction=0 means input from AESS point of view */ + u32 direction; + /* Protocol type (switch) during the data transfers */ + u32 protocol_switch; + union { + /* Slimbus peripheral connected to ATC */ + struct { + /* Address of ATC Slimbus descriptor's index */ + u32 desc_addr1; + /* DMEM address 1 in bytes */ + u32 buf_addr1; + /* DMEM buffer size size in bytes */ + u32 buf_size; + /* ITERation on each DMAreq signals */ + u32 iter; + /* Second ATC index for SlimBus reception (or NULL) */ + u32 desc_addr2; + /* DMEM address 2 in bytes */ + u32 buf_addr2; + } prot_slimbus; + /* McBSP/McASP peripheral connected to ATC */ + struct { + u32 desc_addr; + /* Address of ATC McBSP/McASP descriptor's in bytes */ + u32 buf_addr; + /* DMEM address in bytes */ + u32 buf_size; + /* ITERation on each DMAreq signals */ + u32 iter; + } prot_serial; + /* DMIC peripheral connected to ATC */ + struct { + /* DMEM address in bytes */ + u32 buf_addr; + /* DMEM buffer size in bytes */ + u32 buf_size; + /* Number of activated DMIC */ + u32 nbchan; + } prot_dmic; + /* McPDMDL peripheral connected to ATC */ + struct { + /* DMEM address in bytes */ + u32 buf_addr; + /* DMEM size in bytes */ + u32 buf_size; + /* Control allowed on McPDM DL */ + u32 control; + } prot_mcpdmdl; + /* McPDMUL peripheral connected to ATC */ + struct { + /* DMEM address size in bytes */ + u32 buf_addr; + /* DMEM buffer size size in bytes */ + u32 buf_size; + } prot_mcpdmul; + /* Ping-Pong interface to the Host using cache-flush */ + struct { + /* Address of ATC descriptor's */ + u32 desc_addr; + /* DMEM buffer base address in bytes */ + u32 buf_addr; + /* DMEM size in bytes for each ping and pong buffers */ + u32 buf_size; + /* IRQ address (either DMA (0) MCU (1) or DSP(2)) */ + u32 irq_addr; + /* IRQ data content loaded in the AESS IRQ register */ + u32 irq_data; + /* Call-back function upon IRQ reception */ + u32 callback; + } prot_pingpong; + /* DMAreq line to CBPr */ + struct { + /* Address of ATC descriptor's */ + u32 desc_addr; + /* DMEM buffer address in bytes */ + u32 buf_addr; + /* DMEM buffer size size in bytes */ + u32 buf_size; + /* ITERation on each DMAreq signals */ + u32 iter; + /* DMAreq address */ + u32 dma_addr; + /* DMA/AESS = 1 << #DMA */ + u32 dma_data; + } prot_dmareq; + /* Circular buffer - direct addressing to DMEM */ + struct { + /* DMEM buffer base address in bytes */ + u32 buf_addr; + /* DMEM buffer size in bytes */ + u32 buf_size; + /* DMAreq address */ + u32 dma_addr; + /* DMA/AESS = 1 << #DMA */ + u32 dma_data; + } prot_circular_buffer; + } p; +} abe_port_protocol_t; + +/* + * EQU_T + * + * coefficients of the equalizer + */ +/* 24 Q6.26 coefficients */ +#define NBEQ1 25 +/* 2x12 Q6.26 coefficients */ +#define NBEQ2 13 + +typedef struct { + /* type of filter */ + u32 equ_type; + /* filter length */ + u32 equ_length; + union { + /* parameters are the direct and recursive coefficients in */ + /* Q6.26 integer fixed-point format. */ + s32 type1[NBEQ1]; + struct { + /* center frequency of the band [Hz] */ + s32 freq[NBEQ2]; + /* gain of each band. [dB] */ + s32 gain[NBEQ2]; + /* Q factor of this band [dB] */ + s32 q[NBEQ2]; + } type2; + } coef; + s32 equ_param3; +} abe_equ_t; + + +/* subroutine with no parameter */ +typedef void (*abe_subroutine0) (void); +/* subroutine with one parameter */ +typedef void (*abe_subroutine1) (u32); +typedef void (*abe_subroutine2) (u32, u32); +typedef void (*abe_subroutine3) (u32, u32, u32); +typedef void (*abe_subroutine4) (u32, u32, u32, u32); + + +extern u32 abe_irq_pingpong_player_id; + + +void abe_init_mem(void __iomem **_io_base); +u32 abe_reset_hal(void); +int abe_load_fw(u32 *firmware); +int abe_reload_fw(u32 *firmware); +u32 *abe_get_default_fw(void); +u32 abe_wakeup(void); +u32 abe_irq_processing(void); +u32 abe_clear_irq(void); +u32 abe_disable_irq(void); +u32 abe_write_event_generator(u32 e); +u32 abe_stop_event_generator(void); +u32 abe_connect_debug_trace(abe_dma_t *dma2); +u32 abe_set_debug_trace(abe_dbg_t debug); +u32 abe_set_ping_pong_buffer(u32 port, u32 n_bytes); +u32 abe_read_next_ping_pong_buffer(u32 port, u32 *p, u32 *n); +u32 abe_init_ping_pong_buffer(u32 id, u32 size_bytes, u32 n_buffers, + u32 *p); +u32 abe_read_offset_from_ping_buffer(u32 id, u32 *n); +u32 abe_write_equalizer(u32 id, abe_equ_t *param); +u32 abe_disable_gain(u32 id, u32 p); +u32 abe_enable_gain(u32 id, u32 p); +u32 abe_mute_gain(u32 id, u32 p); +u32 abe_unmute_gain(u32 id, u32 p); +u32 abe_write_gain(u32 id, s32 f_g, u32 ramp, u32 p); +u32 abe_write_mixer(u32 id, s32 f_g, u32 f_ramp, u32 p); +u32 abe_read_gain(u32 id, u32 *f_g, u32 p); +u32 abe_read_mixer(u32 id, u32 *f_g, u32 p); +int abe_mono_mixer(u32 id, u32 on_off); +u32 abe_set_router_configuration(u32 id, u32 k, u32 *param); +u32 abe_set_opp_processing(u32 opp); +u32 abe_disable_data_transfer(u32 id); +u32 abe_enable_data_transfer(u32 id); +u32 abe_connect_cbpr_dmareq_port(u32 id, abe_data_format_t *f, u32 d, + abe_dma_t *returned_dma_t); +u32 abe_connect_irq_ping_pong_port(u32 id, abe_data_format_t *f, + u32 subroutine_id, u32 size, + u32 *sink, u32 dsp_mcu_flag); +u32 abe_connect_serial_port(u32 id, abe_data_format_t *f, + u32 mcbsp_id); +u32 abe_read_port_address(u32 port, abe_dma_t *dma2); +void abe_add_subroutine(u32 *id, abe_subroutine2 f, u32 nparam, u32 *params); +u32 abe_read_next_ping_pong_buffer(u32 port, u32 *p, u32 *n); +void abe_write_pdmdl_offset(u32 path, u32 offset_left, u32 offset_right); +u32 abe_reset_vx_ul_src_filters(void); +u32 abe_reset_mic_ul_src_filters(void); +u32 abe_reset_vx_dl_src_filters(void); +u32 abe_reset_dl1_src_filters(void); +u32 abe_reset_dl2_src_filters(void); +u32 abe_reset_bt_dl_src_filters(void); +void abe_src_filters_saturation_monitoring(void); +u32 abe_check_activity(void); +void abe_add_subroutine(u32 *id, abe_subroutine2 f, + u32 nparam, u32 *params); + +u32 abe_plug_subroutine(u32 *id, abe_subroutine2 f, u32 n, + u32 *params); + +#endif /* _ABE_MAIN_H_ */ diff --git a/sound/soc/omap/abe/abe_mem.h b/sound/soc/omap/abe/abe_mem.h new file mode 100644 index 0000000..683968e --- /dev/null +++ b/sound/soc/omap/abe/abe_mem.h @@ -0,0 +1,99 @@ +/* + + This file is provided under a dual BSD/GPLv2 license. When using or + redistributing this file, you may do so under either license. + + GPL LICENSE SUMMARY + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License 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. + The full GNU General Public License is included in this distribution + in the file called LICENSE.GPL. + + BSD LICENSE + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name of Texas Instruments Incorporated nor the names of + its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef _ABE_MEM_H_ +#define _ABE_MEM_H_ + +#define OMAP_ABE_DMEM 0 +#define OMAP_ABE_CMEM 1 +#define OMAP_ABE_SMEM 2 +#define OMAP_ABE_PMEM 3 +#define OMAP_ABE_AESS 4 + +/* Distinction between Read and Write from/to ABE memory + * is useful for simulation tool */ +static inline void omap_abe_mem_write(struct omap_abe *abe, int bank, + u32 offset, u32 *src, size_t bytes) +{ + memcpy((abe->io_base[bank] + offset), src, bytes); +} + +static inline void omap_abe_mem_read(struct omap_abe *abe, int bank, + u32 offset, u32 *dest, size_t bytes) +{ + memcpy(dest, (abe->io_base[bank] + offset), bytes); +} + +static inline u32 omap_abe_reg_readl(struct omap_abe *abe, u32 offset) +{ + return __raw_readl(abe->io_base[OMAP_ABE_AESS] + offset); +} + +static inline void omap_abe_reg_writel(struct omap_abe *abe, + u32 offset, u32 val) +{ + __raw_writel(val, (abe->io_base[OMAP_ABE_AESS] + offset)); +} + +static inline void *omap_abe_reset_mem(struct omap_abe *abe, int bank, + u32 offset, size_t bytes) +{ + return memset(abe->io_base[bank] + offset, 0, bytes); +} + +#endif /*_ABE_MEM_H_*/ diff --git a/sound/soc/omap/abe/abe_port.c b/sound/soc/omap/abe/abe_port.c new file mode 100644 index 0000000..724dabd --- /dev/null +++ b/sound/soc/omap/abe/abe_port.c @@ -0,0 +1,1774 @@ +/* + + This file is provided under a dual BSD/GPLv2 license. When using or + redistributing this file, you may do so under either license. + + GPL LICENSE SUMMARY + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License 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. + The full GNU General Public License is included in this distribution + in the file called LICENSE.GPL. + + BSD LICENSE + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name of Texas Instruments Incorporated nor the names of + its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/err.h> +#include <linux/slab.h> + +#include "abe_legacy.h" +#include "abe_port.h" +#include "abe_dbg.h" +#include "abe_mem.h" +#include "abe_gain.h" + +/** + * abe_clean_temporay buffers + * + * clear temporary buffers + */ +void omap_abe_clean_temporary_buffers(struct omap_abe *abe, u32 id) +{ + switch (id) { + case OMAP_ABE_DMIC_PORT: + omap_abe_reset_mem(abe, OMAP_ABE_DMEM, + OMAP_ABE_D_DMIC_UL_FIFO_ADDR, + OMAP_ABE_D_DMIC_UL_FIFO_SIZE); + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_DMIC0_96_48_DATA_ADDR, + OMAP_ABE_S_DMIC0_96_48_DATA_SIZE); + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_DMIC1_96_48_DATA_ADDR, + OMAP_ABE_S_DMIC1_96_48_DATA_SIZE); + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_DMIC2_96_48_DATA_ADDR, + OMAP_ABE_S_DMIC2_96_48_DATA_SIZE); + /* reset working values of the gain, target gain is preserved */ + omap_abe_reset_gain_mixer(abe, GAINS_DMIC1, GAIN_LEFT_OFFSET); + omap_abe_reset_gain_mixer(abe, GAINS_DMIC1, GAIN_RIGHT_OFFSET); + omap_abe_reset_gain_mixer(abe, GAINS_DMIC2, GAIN_LEFT_OFFSET); + omap_abe_reset_gain_mixer(abe, GAINS_DMIC2, GAIN_RIGHT_OFFSET); + omap_abe_reset_gain_mixer(abe, GAINS_DMIC3, GAIN_LEFT_OFFSET); + omap_abe_reset_gain_mixer(abe, GAINS_DMIC3, GAIN_RIGHT_OFFSET); + break; + case OMAP_ABE_PDM_UL_PORT: + omap_abe_reset_mem(abe, OMAP_ABE_DMEM, + OMAP_ABE_D_MCPDM_UL_FIFO_ADDR, + OMAP_ABE_D_MCPDM_UL_FIFO_SIZE); + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_AMIC_96_48_DATA_ADDR, + OMAP_ABE_S_AMIC_96_48_DATA_SIZE); + /* reset working values of the gain, target gain is preserved */ + omap_abe_reset_gain_mixer(abe, GAINS_AMIC, GAIN_LEFT_OFFSET); + omap_abe_reset_gain_mixer(abe, GAINS_AMIC, GAIN_RIGHT_OFFSET); + break; + case OMAP_ABE_BT_VX_UL_PORT: + omap_abe_reset_mem(abe, OMAP_ABE_DMEM, + OMAP_ABE_D_BT_UL_FIFO_ADDR, + OMAP_ABE_D_BT_UL_FIFO_SIZE); + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_BT_UL_ADDR, + OMAP_ABE_S_BT_UL_SIZE); + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_BT_UL_8_48_HP_DATA_ADDR, + OMAP_ABE_S_BT_UL_8_48_HP_DATA_SIZE); + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_BT_UL_8_48_LP_DATA_ADDR, + OMAP_ABE_S_BT_UL_8_48_LP_DATA_SIZE); + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_BT_UL_16_48_HP_DATA_ADDR, + OMAP_ABE_S_BT_UL_16_48_HP_DATA_SIZE); + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_BT_UL_16_48_LP_DATA_ADDR, + OMAP_ABE_S_BT_UL_16_48_LP_DATA_SIZE); + /* reset working values of the gain, target gain is preserved */ + omap_abe_reset_gain_mixer(abe, GAINS_BTUL, GAIN_LEFT_OFFSET); + omap_abe_reset_gain_mixer(abe, GAINS_BTUL, GAIN_RIGHT_OFFSET); + break; + case OMAP_ABE_MM_UL_PORT: + omap_abe_reset_mem(abe, OMAP_ABE_DMEM, + OMAP_ABE_D_MM_UL_FIFO_ADDR, + OMAP_ABE_D_MM_UL_FIFO_SIZE); + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_MM_UL_ADDR, + OMAP_ABE_S_MM_UL_SIZE); + break; + case OMAP_ABE_MM_UL2_PORT: + omap_abe_reset_mem(abe, OMAP_ABE_DMEM, + OMAP_ABE_D_MM_UL2_FIFO_ADDR, + OMAP_ABE_D_MM_UL2_FIFO_SIZE); + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_MM_UL2_ADDR, + OMAP_ABE_S_MM_UL2_SIZE); + break; + case OMAP_ABE_VX_UL_PORT: + omap_abe_reset_mem(abe, OMAP_ABE_DMEM, + OMAP_ABE_D_VX_UL_FIFO_ADDR, + OMAP_ABE_D_VX_UL_FIFO_SIZE); + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_VX_UL_ADDR, + OMAP_ABE_S_VX_UL_SIZE); + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_VX_UL_48_8_HP_DATA_ADDR, + OMAP_ABE_S_VX_UL_48_8_HP_DATA_SIZE); + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_VX_UL_48_8_LP_DATA_ADDR, + OMAP_ABE_S_VX_UL_48_8_LP_DATA_SIZE); + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_VX_UL_48_16_HP_DATA_ADDR, + OMAP_ABE_S_VX_UL_48_16_HP_DATA_SIZE); + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_VX_UL_48_16_LP_DATA_ADDR, + OMAP_ABE_S_VX_UL_48_16_LP_DATA_SIZE); + omap_abe_reset_gain_mixer(abe, MIXAUDUL, MIX_AUDUL_INPUT_UPLINK); + break; + case OMAP_ABE_MM_DL_PORT: + omap_abe_reset_mem(abe, OMAP_ABE_DMEM, + OMAP_ABE_D_MM_DL_FIFO_ADDR, + OMAP_ABE_D_MM_DL_FIFO_SIZE); + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_MM_DL_ADDR, + OMAP_ABE_S_MM_DL_SIZE); + omap_abe_reset_gain_mixer(abe, MIXDL1, MIX_DL1_INPUT_MM_DL); + omap_abe_reset_gain_mixer(abe, MIXDL2, MIX_DL2_INPUT_MM_DL); + break; + case OMAP_ABE_VX_DL_PORT: + omap_abe_reset_mem(abe, OMAP_ABE_DMEM, + OMAP_ABE_D_VX_DL_FIFO_ADDR, + OMAP_ABE_D_VX_DL_FIFO_SIZE); + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_VX_DL_ADDR, + OMAP_ABE_S_VX_DL_SIZE); + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_VX_DL_8_48_HP_DATA_ADDR, + OMAP_ABE_S_VX_DL_8_48_HP_DATA_SIZE); + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_VX_DL_8_48_LP_DATA_ADDR, + OMAP_ABE_S_VX_DL_8_48_LP_DATA_SIZE); + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_VX_DL_8_48_OSR_LP_DATA_ADDR, + OMAP_ABE_S_VX_DL_8_48_OSR_LP_DATA_SIZE); + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_VX_DL_16_48_HP_DATA_ADDR, + OMAP_ABE_S_VX_DL_16_48_HP_DATA_SIZE); + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_VX_DL_16_48_LP_DATA_ADDR, + OMAP_ABE_S_VX_DL_16_48_LP_DATA_SIZE); + omap_abe_reset_gain_mixer(abe, MIXDL1, MIX_DL1_INPUT_VX_DL); + omap_abe_reset_gain_mixer(abe, MIXDL2, MIX_DL2_INPUT_VX_DL); + break; + case OMAP_ABE_TONES_DL_PORT: + omap_abe_reset_mem(abe, OMAP_ABE_DMEM, + OMAP_ABE_D_TONES_DL_FIFO_ADDR, + OMAP_ABE_D_TONES_DL_FIFO_SIZE); + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_TONES_ADDR, + OMAP_ABE_S_TONES_SIZE); + omap_abe_reset_gain_mixer(abe, MIXDL1, MIX_DL1_INPUT_TONES); + omap_abe_reset_gain_mixer(abe, MIXDL2, MIX_DL2_INPUT_TONES); + break; + case OMAP_ABE_VIB_DL_PORT: + omap_abe_reset_mem(abe, OMAP_ABE_DMEM, + OMAP_ABE_D_VIB_DL_FIFO_ADDR, + OMAP_ABE_D_VIB_DL_FIFO_SIZE); + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_VIBRA_ADDR, + OMAP_ABE_S_VIBRA_SIZE); + break; + case OMAP_ABE_BT_VX_DL_PORT: + omap_abe_reset_mem(abe, OMAP_ABE_DMEM, + OMAP_ABE_D_BT_DL_FIFO_ADDR, + OMAP_ABE_D_BT_DL_FIFO_SIZE); + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_BT_DL_ADDR, + OMAP_ABE_S_BT_DL_SIZE); + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_BT_DL_8_48_OSR_LP_DATA_ADDR, + OMAP_ABE_S_BT_DL_8_48_OSR_LP_DATA_SIZE); + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_BT_DL_48_8_HP_DATA_ADDR, + OMAP_ABE_S_BT_DL_48_8_HP_DATA_SIZE); + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_BT_DL_48_8_LP_DATA_ADDR, + OMAP_ABE_S_BT_DL_48_8_LP_DATA_SIZE); + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_BT_DL_48_16_HP_DATA_ADDR, + OMAP_ABE_S_BT_DL_48_16_HP_DATA_SIZE); + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_BT_DL_48_16_LP_DATA_ADDR, + OMAP_ABE_S_BT_DL_48_16_LP_DATA_SIZE); + break; + case OMAP_ABE_PDM_DL_PORT: + omap_abe_reset_mem(abe, OMAP_ABE_DMEM, + OMAP_ABE_D_MCPDM_DL_FIFO_ADDR, + OMAP_ABE_D_MCPDM_DL_FIFO_SIZE); + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_DL2_M_LR_EQ_DATA_ADDR, + OMAP_ABE_S_DL2_M_LR_EQ_DATA_SIZE); + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_DL1_M_EQ_DATA_ADDR, + OMAP_ABE_S_DL1_M_EQ_DATA_SIZE); + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_EARP_48_96_LP_DATA_ADDR, + OMAP_ABE_S_EARP_48_96_LP_DATA_SIZE); + omap_abe_reset_mem(abe, OMAP_ABE_SMEM, + OMAP_ABE_S_IHF_48_96_LP_DATA_ADDR, + OMAP_ABE_S_IHF_48_96_LP_DATA_SIZE); + omap_abe_reset_gain_mixer(abe, GAINS_DL1, GAIN_LEFT_OFFSET); + omap_abe_reset_gain_mixer(abe, GAINS_DL1, GAIN_RIGHT_OFFSET); + omap_abe_reset_gain_mixer(abe, GAINS_DL2, GAIN_LEFT_OFFSET); + omap_abe_reset_gain_mixer(abe, GAINS_DL2, GAIN_RIGHT_OFFSET); + omap_abe_reset_gain_mixer(abe, MIXSDT, MIX_SDT_INPUT_UP_MIXER); + omap_abe_reset_gain_mixer(abe, MIXSDT, MIX_SDT_INPUT_DL1_MIXER); + break; + case OMAP_ABE_MM_EXT_OUT_PORT: + omap_abe_reset_mem(abe, OMAP_ABE_DMEM, + OMAP_ABE_D_MM_EXT_OUT_FIFO_ADDR, + OMAP_ABE_D_MM_EXT_OUT_FIFO_SIZE); + break; + case OMAP_ABE_MM_EXT_IN_PORT: + omap_abe_reset_mem(abe, OMAP_ABE_DMEM, + OMAP_ABE_D_MM_EXT_IN_FIFO_ADDR, + OMAP_ABE_D_MM_EXT_IN_FIFO_SIZE); + break; + } +} + +/** + * omap_abe_disable_enable_dma_request + * Parameter: + * Operations: + * Return value: + */ +void omap_abe_disable_enable_dma_request(struct omap_abe *abe, u32 id, + u32 on_off) +{ + u8 desc_third_word[4], irq_dmareq_field; + u32 sio_desc_address; + u32 struct_offset; + struct ABE_SIODescriptor sio_desc; + struct ABE_SPingPongDescriptor desc_pp; + + if (abe_port[id].protocol.protocol_switch == PINGPONG_PORT_PROT) { + irq_dmareq_field = + (u8) (on_off * + abe_port[id].protocol.p.prot_pingpong.irq_data); + sio_desc_address = OMAP_ABE_D_PINGPONGDESC_ADDR; + struct_offset = (u32) &(desc_pp.data_size) - (u32) &(desc_pp); + omap_abe_mem_read(abe, OMAP_ABE_DMEM, + sio_desc_address + struct_offset, + (u32 *) desc_third_word, 4); + desc_third_word[2] = irq_dmareq_field; + omap_abe_mem_write(abe, OMAP_ABE_DMEM, + sio_desc_address + struct_offset, + (u32 *) desc_third_word, 4); + } else { + /* serial interface: sync ATC with Firmware activity */ + sio_desc_address = + OMAP_ABE_D_IODESCR_ADDR + + (id * sizeof(struct ABE_SIODescriptor)); + omap_abe_mem_read(abe, OMAP_ABE_DMEM, + sio_desc_address, (u32 *) &sio_desc, + sizeof(sio_desc)); + if (on_off) { + if (abe_port[id].protocol.protocol_switch != SERIAL_PORT_PROT) + sio_desc.atc_irq_data = + (u8) abe_port[id].protocol.p.prot_dmareq. + dma_data; + sio_desc.on_off = 0x80; + } else { + sio_desc.atc_irq_data = 0; + sio_desc.on_off = 0; + } + omap_abe_mem_write(abe, OMAP_ABE_DMEM, + sio_desc_address, (u32 *) &sio_desc, + sizeof(sio_desc)); + } + +} + +/** + * omap_abe_enable_dma_request + * + * Parameter: + * Operations: + * Return value: + * + */ +void omap_abe_enable_dma_request(struct omap_abe *abe, u32 id) +{ + omap_abe_disable_enable_dma_request(abe, id, 1); +} + +/** + * omap_abe_disable_dma_request + * + * Parameter: + * Operations: + * Return value: + * + */ +void omap_abe_disable_dma_request(struct omap_abe *abe, u32 id) +{ + omap_abe_disable_enable_dma_request(abe, id, 0); +} + +/** + * abe_init_atc + * @id: ABE port ID + * + * load the DMEM ATC/AESS descriptors + */ +void omap_abe_init_atc(struct omap_abe *abe, u32 id) +{ + u8 iter; + s32 datasize; + struct omap_abe_atc_desc atc_desc; + +#define JITTER_MARGIN 4 + /* load default values of the descriptor */ + atc_desc.rdpt = 0; + atc_desc.wrpt = 0; + atc_desc.irqdest = 0; + atc_desc.cberr = 0; + atc_desc.desen = 0; + atc_desc.nw = 0; + atc_desc.reserved0 = 0; + atc_desc.reserved1 = 0; + atc_desc.reserved2 = 0; + atc_desc.srcid = 0; + atc_desc.destid = 0; + atc_desc.badd = 0; + atc_desc.iter = 0; + atc_desc.cbsize = 0; + datasize = abe_dma_port_iter_factor(&((abe_port[id]).format)); + iter = (u8) abe_dma_port_iteration(&((abe_port[id]).format)); + /* if the ATC FIFO is too small there will be two ABE firmware + utasks to do the copy this happems on DMIC and MCPDMDL */ + /* VXDL_8kMono = 4 = 2 + 2x1 */ + /* VXDL_16kstereo = 12 = 8 + 2x2 */ + /* MM_DL_1616 = 14 = 12 + 2x1 */ + /* DMIC = 84 = 72 + 2x6 */ + /* VXUL_8kMono = 2 */ + /* VXUL_16kstereo = 4 */ + /* MM_UL2_Stereo = 4 */ + /* PDMDL = 12 */ + /* IN from AESS point of view */ + if (abe_port[id].protocol.direction == ABE_ATC_DIRECTION_IN) + if (iter + 2 * datasize > 126) + atc_desc.wrpt = (iter >> 1) + + ((JITTER_MARGIN-1) * datasize); + else + atc_desc.wrpt = iter + ((JITTER_MARGIN-1) * datasize); + else + atc_desc.wrpt = 0 + ((JITTER_MARGIN+1) * datasize); + switch ((abe_port[id]).protocol.protocol_switch) { + case SLIMBUS_PORT_PROT: + atc_desc.cbdir = (abe_port[id]).protocol.direction; + atc_desc.cbsize = + (abe_port[id]).protocol.p.prot_slimbus.buf_size; + atc_desc.badd = + ((abe_port[id]).protocol.p.prot_slimbus.buf_addr1) >> 4; + atc_desc.iter = (abe_port[id]).protocol.p.prot_slimbus.iter; + atc_desc.srcid = + abe_atc_srcid[(abe_port[id]).protocol.p.prot_slimbus. + desc_addr1 >> 3]; + omap_abe_mem_write(abe, OMAP_ABE_DMEM, + (abe_port[id]).protocol.p.prot_slimbus. + desc_addr1, (u32 *) &atc_desc, sizeof(atc_desc)); + atc_desc.badd = + (abe_port[id]).protocol.p.prot_slimbus.buf_addr2; + atc_desc.srcid = + abe_atc_srcid[(abe_port[id]).protocol.p.prot_slimbus. + desc_addr2 >> 3]; + omap_abe_mem_write(abe, OMAP_ABE_DMEM, + (abe_port[id]).protocol.p.prot_slimbus. + desc_addr2, (u32 *) &atc_desc, sizeof(atc_desc)); + break; + case SERIAL_PORT_PROT: + atc_desc.cbdir = (abe_port[id]).protocol.direction; + atc_desc.cbsize = + (abe_port[id]).protocol.p.prot_serial.buf_size; + atc_desc.badd = + ((abe_port[id]).protocol.p.prot_serial.buf_addr) >> 4; + atc_desc.iter = (abe_port[id]).protocol.p.prot_serial.iter; + atc_desc.srcid = + abe_atc_srcid[(abe_port[id]).protocol.p.prot_serial. + desc_addr >> 3]; + atc_desc.destid = + abe_atc_dstid[(abe_port[id]).protocol.p.prot_serial. + desc_addr >> 3]; + omap_abe_mem_write(abe, OMAP_ABE_DMEM, + (abe_port[id]).protocol.p.prot_serial.desc_addr, + (u32 *) &atc_desc, sizeof(atc_desc)); + break; + case DMIC_PORT_PROT: + atc_desc.cbdir = ABE_ATC_DIRECTION_IN; + atc_desc.cbsize = (abe_port[id]).protocol.p.prot_dmic.buf_size; + atc_desc.badd = + ((abe_port[id]).protocol.p.prot_dmic.buf_addr) >> 4; + atc_desc.iter = DMIC_ITER; + atc_desc.srcid = abe_atc_srcid[ABE_ATC_DMIC_DMA_REQ]; + omap_abe_mem_write(abe, OMAP_ABE_DMEM, + (ABE_ATC_DMIC_DMA_REQ*ATC_SIZE), + (u32 *) &atc_desc, sizeof(atc_desc)); + break; + case MCPDMDL_PORT_PROT: + atc_desc.cbdir = ABE_ATC_DIRECTION_OUT; + atc_desc.cbsize = + (abe_port[id]).protocol.p.prot_mcpdmdl.buf_size; + atc_desc.badd = + ((abe_port[id]).protocol.p.prot_mcpdmdl.buf_addr) >> 4; + atc_desc.iter = MCPDM_DL_ITER; + atc_desc.destid = abe_atc_dstid[ABE_ATC_MCPDMDL_DMA_REQ]; + omap_abe_mem_write(abe, OMAP_ABE_DMEM, + (ABE_ATC_MCPDMDL_DMA_REQ*ATC_SIZE), + (u32 *) &atc_desc, sizeof(atc_desc)); + break; + case MCPDMUL_PORT_PROT: + atc_desc.cbdir = ABE_ATC_DIRECTION_IN; + atc_desc.cbsize = + (abe_port[id]).protocol.p.prot_mcpdmul.buf_size; + atc_desc.badd = + ((abe_port[id]).protocol.p.prot_mcpdmul.buf_addr) >> 4; + atc_desc.iter = MCPDM_UL_ITER; + atc_desc.srcid = abe_atc_srcid[ABE_ATC_MCPDMUL_DMA_REQ]; + omap_abe_mem_write(abe, OMAP_ABE_DMEM, + (ABE_ATC_MCPDMUL_DMA_REQ*ATC_SIZE), + (u32 *) &atc_desc, sizeof(atc_desc)); + break; + case PINGPONG_PORT_PROT: + /* software protocol, nothing to do on ATC */ + break; + case DMAREQ_PORT_PROT: + atc_desc.cbdir = (abe_port[id]).protocol.direction; + atc_desc.cbsize = + (abe_port[id]).protocol.p.prot_dmareq.buf_size; + atc_desc.badd = + ((abe_port[id]).protocol.p.prot_dmareq.buf_addr) >> 4; + /* CBPr needs ITER=1. + It is the job of eDMA to do the iterations */ + atc_desc.iter = 1; + /* input from ABE point of view */ + if (abe_port[id].protocol.direction == ABE_ATC_DIRECTION_IN) { + /* atc_atc_desc.rdpt = 127; */ + /* atc_atc_desc.wrpt = 0; */ + atc_desc.srcid = abe_atc_srcid + [(abe_port[id]).protocol.p.prot_dmareq. + desc_addr >> 3]; + } else { + /* atc_atc_desc.rdpt = 0; */ + /* atc_atc_desc.wrpt = 127; */ + atc_desc.destid = abe_atc_dstid + [(abe_port[id]).protocol.p.prot_dmareq. + desc_addr >> 3]; + } + omap_abe_mem_write(abe, OMAP_ABE_DMEM, + (abe_port[id]).protocol.p.prot_dmareq.desc_addr, + (u32 *) &atc_desc, sizeof(atc_desc)); + break; + } +} + +/** + * omap_abe_enable_pp_io_task + * @id: port_id + * + * + */ +void omap_abe_enable_pp_io_task(struct omap_abe *abe, u32 id) +{ + if (OMAP_ABE_MM_DL_PORT == id) { + /* MM_DL managed in ping-pong */ + abe->MultiFrame[TASK_IO_MM_DL_SLT][TASK_IO_MM_DL_IDX] = + ABE_TASK_ID(C_ABE_FW_TASK_IO_PING_PONG); + omap_abe_mem_write(abe, OMAP_ABE_DMEM, + OMAP_ABE_D_MULTIFRAME_ADDR, (u32 *) abe->MultiFrame, + sizeof(abe->MultiFrame)); + } else { + /* ping_pong is only supported on MM_DL */ + omap_abe_dbg_error(abe, OMAP_ABE_ERR_API, + ABE_PARAMETER_ERROR); + } +} +/** + * omap_abe_disable_pp_io_task + * @id: port_id + * + * + */ +void omap_abe_disable_pp_io_task(struct omap_abe *abe, u32 id) +{ + if (OMAP_ABE_MM_DL_PORT == id) { + /* MM_DL managed in ping-pong */ + abe->MultiFrame[TASK_IO_MM_DL_SLT][TASK_IO_MM_DL_IDX] = 0; + omap_abe_mem_write(abe, OMAP_ABE_DMEM, + OMAP_ABE_D_MULTIFRAME_ADDR, (u32 *) abe->MultiFrame, + sizeof(abe->MultiFrame)); + } else { + /* ping_pong is only supported on MM_DL */ + omap_abe_dbg_error(abe, OMAP_ABE_ERR_API, + ABE_PARAMETER_ERROR); + } +} + +/** + * omap_abe_disable_data_transfer + * @id: ABE port id + * + * disables the ATC descriptor and stop IO/port activities + * disable the IO task (@f = 0) + * clear ATC DMEM buffer, ATC enabled + */ +int omap_abe_disable_data_transfer(struct omap_abe *abe, u32 id) +{ + + _log(ABE_ID_DISABLE_DATA_TRANSFER, id, 0, 0); + + /* MM_DL managed in ping-pong */ + if (id == OMAP_ABE_MM_DL_PORT) { + if (abe_port[OMAP_ABE_MM_DL_PORT].protocol.protocol_switch == PINGPONG_PORT_PROT) + omap_abe_disable_pp_io_task(abe, OMAP_ABE_MM_DL_PORT); + } + /* local host variable status= "port is running" */ + abe_port[id].status = OMAP_ABE_PORT_ACTIVITY_IDLE; + /* disable DMA requests */ + omap_abe_disable_dma_request(abe, id); + /* disable ATC transfers */ + omap_abe_init_atc(abe, id); + omap_abe_clean_temporary_buffers(abe, id); + /* select the main port based on the desactivation of this port */ + abe_decide_main_port(); + + return 0; +} +EXPORT_SYMBOL(omap_abe_disable_data_transfer); + +/** + * omap_abe_enable_data_transfer + * @ip: ABE port id + * + * enables the ATC descriptor + * reset ATC pointers + * enable the IO task (@f <> 0) + */ +int omap_abe_enable_data_transfer(struct omap_abe *abe, u32 id) +{ + abe_port_protocol_t *protocol; + abe_data_format_t format; + + _log(ABE_ID_ENABLE_DATA_TRANSFER, id, 0, 0); + omap_abe_clean_temporary_buffers(abe, id); + + switch (id) { + case OMAP_ABE_PDM_UL_PORT: + case OMAP_ABE_PDM_DL_PORT: + case OMAP_ABE_DMIC_PORT: + /* initializes the ABE ATC descriptors in DMEM for BE ports */ + protocol = &(abe_port[id].protocol); + format = abe_port[id].format; + omap_abe_init_atc(abe, id); + abe_init_io_tasks(id, &format, protocol); + break; + + case OMAP_ABE_MM_DL_PORT: + protocol = &(abe_port[OMAP_ABE_MM_DL_PORT].protocol); + if (protocol->protocol_switch == PINGPONG_PORT_PROT) + abe->MultiFrame[TASK_IO_MM_DL_SLT][TASK_IO_MM_DL_IDX] = ABE_TASK_ID(C_ABE_FW_TASK_IO_PING_PONG); + else + abe->MultiFrame[TASK_IO_MM_DL_SLT][TASK_IO_MM_DL_IDX] = ABE_TASK_ID(C_ABE_FW_TASK_IO_MM_DL); + break; + case OMAP_ABE_VX_UL_PORT: + break; + case OMAP_ABE_VX_DL_PORT: + break; + case OMAP_ABE_MM_UL2_PORT: + abe->MultiFrame[17][3] = ABE_TASK_ID(C_ABE_FW_TASK_IO_MM_UL2); + break; + case OMAP_ABE_TONES_DL_PORT: + abe->MultiFrame[20][0] = ABE_TASK_ID(C_ABE_FW_TASK_IO_TONES_DL); + break; + case OMAP_ABE_MM_UL_PORT: + abe->MultiFrame[19][6] = ABE_TASK_ID(C_ABE_FW_TASK_IO_MM_UL); + break; + case OMAP_ABE_BT_VX_DL_PORT: + abe->MultiFrame[13][5] = ABE_TASK_ID(C_ABE_FW_TASK_IO_BT_VX_DL); + break; + case OMAP_ABE_BT_VX_UL_PORT: + abe->MultiFrame[15][3] = ABE_TASK_ID(C_ABE_FW_TASK_IO_BT_VX_UL); + break; + case OMAP_ABE_MM_EXT_IN_PORT: + abe->MultiFrame[21][3] = ABE_TASK_ID(C_ABE_FW_TASK_IO_MM_EXT_IN); + break; + case OMAP_ABE_MM_EXT_OUT_PORT: + abe->MultiFrame[15][0] = ABE_TASK_ID(C_ABE_FW_TASK_IO_MM_EXT_OUT); + break; + default: + break; + } + + omap_abe_mem_write(abe, OMAP_ABE_DMEM, OMAP_ABE_D_MULTIFRAME_ADDR, + (u32 *) abe->MultiFrame, sizeof(abe->MultiFrame)); + + /* local host variable status= "port is running" */ + abe_port[id].status = OMAP_ABE_PORT_ACTIVITY_RUNNING; + /* enable DMA requests */ + omap_abe_enable_dma_request(abe, id); + /* select the main port based on the activation of this new port */ + abe_decide_main_port(); + + return 0; +} +EXPORT_SYMBOL(omap_abe_enable_data_transfer); + +/** + * omap_abe_connect_cbpr_dmareq_port + * @id: port name + * @f: desired data format + * @d: desired dma_request line (0..7) + * @a: returned pointer to the base address of the CBPr register and number of + * samples to exchange during a DMA_request. + * + * enables the data echange between a DMA and the ABE through the + * CBPr registers of AESS. + */ +int omap_abe_connect_cbpr_dmareq_port(struct omap_abe *abe, + u32 id, abe_data_format_t *f, + u32 d, + abe_dma_t *returned_dma_t) +{ + _log(ABE_ID_CONNECT_CBPR_DMAREQ_PORT, id, f->f, f->samp_format); + + abe_port[id] = ((abe_port_t *) abe_port_init)[id]; + (abe_port[id]).format = (*f); + abe_port[id].protocol.protocol_switch = DMAREQ_PORT_PROT; + abe_port[id].protocol.p.prot_dmareq.iter = abe_dma_port_iteration(f); + abe_port[id].protocol.p.prot_dmareq.dma_addr = ABE_DMASTATUS_RAW; + abe_port[id].protocol.p.prot_dmareq.dma_data = (1 << d); + /* load the dma_t with physical information from AE memory mapping */ + abe_init_dma_t(id, &((abe_port[id]).protocol)); + + /* load the ATC descriptors - disabled */ + omap_abe_init_atc(abe, id); + + /* load the micro-task parameters */ + abe_init_io_tasks(id, &((abe_port[id]).format), + &((abe_port[id]).protocol)); + abe_port[id].status = OMAP_ABE_PORT_INITIALIZED; + + /* return the dma pointer address */ + abe_read_port_address(id, returned_dma_t); + return 0; +} +EXPORT_SYMBOL(omap_abe_connect_cbpr_dmareq_port); + +/** + * omap_abe_connect_irq_ping_pong_port + * @id: port name + * @f: desired data format + * @I: index of the call-back subroutine to call + * @s: half-buffer (ping) size + * @p: returned base address of the first (ping) buffer) + * + * enables the data echanges between a direct access to the DMEM + * memory of ABE using cache flush. On each IRQ activation a subroutine + * registered with "abe_plug_subroutine" will be called. This subroutine + * will generate an amount of samples, send them to DMEM memory and call + * "abe_set_ping_pong_buffer" to notify the new amount of samples in the + * pong buffer. + */ +int omap_abe_connect_irq_ping_pong_port(struct omap_abe *abe, + u32 id, abe_data_format_t *f, + u32 subroutine_id, u32 size, + u32 *sink, u32 dsp_mcu_flag) +{ + _log(ABE_ID_CONNECT_IRQ_PING_PONG_PORT, id, f->f, f->samp_format); + + /* ping_pong is only supported on MM_DL */ + if (id != OMAP_ABE_MM_DL_PORT) { + omap_abe_dbg_error(abe, OMAP_ABE_ERR_API, + ABE_PARAMETER_ERROR); + } + abe_port[id] = ((abe_port_t *) abe_port_init)[id]; + (abe_port[id]).format = (*f); + (abe_port[id]).protocol.protocol_switch = PINGPONG_PORT_PROT; + (abe_port[id]).protocol.p.prot_pingpong.buf_addr = + OMAP_ABE_D_PING_ADDR; + (abe_port[id]).protocol.p.prot_pingpong.buf_size = size; + (abe_port[id]).protocol.p.prot_pingpong.irq_data = (1); + abe_init_ping_pong_buffer(OMAP_ABE_MM_DL_PORT, size, 2, sink); + if (dsp_mcu_flag == PING_PONG_WITH_MCU_IRQ) + (abe_port[id]).protocol.p.prot_pingpong.irq_addr = + ABE_MCU_IRQSTATUS_RAW; + if (dsp_mcu_flag == PING_PONG_WITH_DSP_IRQ) + (abe_port[id]).protocol.p.prot_pingpong.irq_addr = + ABE_DSP_IRQSTATUS_RAW; + abe_port[id].status = OMAP_ABE_PORT_INITIALIZED; + + /* load the ATC descriptors - disabled */ + omap_abe_init_atc(abe, id); + /* load the micro-task parameters */ + abe_init_io_tasks(id, &((abe_port[id]).format), + &((abe_port[id]).protocol)); + + *sink = (abe_port[id]).protocol.p.prot_pingpong.buf_addr; + return 0; +} +EXPORT_SYMBOL(omap_abe_connect_irq_ping_pong_port); + +/** + * omap_abe_connect_serial_port() + * @id: port name + * @f: data format + * @i: peripheral ID (McBSP #1, #2, #3) + * + * Operations : enables the data echanges between a McBSP and an ATC buffer in + * DMEM. This API is used connect 48kHz McBSP streams to MM_DL and 8/16kHz + * voice streams to VX_UL, VX_DL, BT_VX_UL, BT_VX_DL. It abstracts the + * abe_write_port API. + */ +int omap_abe_connect_serial_port(struct omap_abe *abe, + u32 id, abe_data_format_t *f, + u32 mcbsp_id) +{ + _log(ABE_ID_CONNECT_SERIAL_PORT, id, f->samp_format, mcbsp_id); + + abe_port[id] = ((abe_port_t *) abe_port_init)[id]; + (abe_port[id]).format = (*f); + (abe_port[id]).protocol.protocol_switch = SERIAL_PORT_PROT; + /* McBSP peripheral connected to ATC */ + (abe_port[id]).protocol.p.prot_serial.desc_addr = mcbsp_id*ATC_SIZE; + /* check the iteration of ATC */ + (abe_port[id]).protocol.p.prot_serial.iter = + abe_dma_port_iter_factor(f); + + /* load the ATC descriptors - disabled */ + omap_abe_init_atc(abe, id); + /* load the micro-task parameters */ + abe_init_io_tasks(id, &((abe_port[id]).format), + &((abe_port[id]).protocol)); + abe_port[id].status = OMAP_ABE_PORT_INITIALIZED; + + return 0; +} +EXPORT_SYMBOL(omap_abe_connect_serial_port); + +/** + * omap_abe_read_port_address + * @dma: output pointer to the DMA iteration and data destination pointer + * + * This API returns the address of the DMA register used on this audio port. + * Depending on the protocol being used, adds the base address offset L3 + * (DMA) or MPU (ARM) + */ +int omap_abe_read_port_address(struct omap_abe *abe, + u32 port, abe_dma_t *dma2) +{ + abe_dma_t_offset dma1; + u32 protocol_switch; + + _log(ABE_ID_READ_PORT_ADDRESS, port, 0, 0); + + dma1 = (abe_port[port]).dma; + protocol_switch = abe_port[port].protocol.protocol_switch; + switch (protocol_switch) { + case PINGPONG_PORT_PROT: + /* return the base address of the buffer in L3 and L4 spaces */ + (*dma2).data = (void *)(dma1.data + + ABE_DEFAULT_BASE_ADDRESS_L3 + ABE_DMEM_BASE_OFFSET_MPU); + (*dma2).l3_dmem = (void *)(dma1.data + + ABE_DEFAULT_BASE_ADDRESS_L3 + ABE_DMEM_BASE_OFFSET_MPU); + (*dma2).l4_dmem = (void *)(dma1.data + + ABE_DEFAULT_BASE_ADDRESS_L4 + ABE_DMEM_BASE_OFFSET_MPU); + break; + case DMAREQ_PORT_PROT: + /* return the CBPr(L3), DMEM(L3), DMEM(L4) address */ + (*dma2).data = (void *)(dma1.data + + ABE_DEFAULT_BASE_ADDRESS_L3 + ABE_ATC_BASE_OFFSET_MPU); + (*dma2).l3_dmem = + (void *)((abe_port[port]).protocol.p.prot_dmareq.buf_addr + + ABE_DEFAULT_BASE_ADDRESS_L3 + ABE_DMEM_BASE_OFFSET_MPU); + (*dma2).l4_dmem = + (void *)((abe_port[port]).protocol.p.prot_dmareq.buf_addr + + ABE_DEFAULT_BASE_ADDRESS_L4 + ABE_DMEM_BASE_OFFSET_MPU); + break; + default: + break; + } + (*dma2).iter = (dma1.iter); + + return 0; +} +EXPORT_SYMBOL(omap_abe_read_port_address); + +/** + * abe_init_dma_t + * @ id: ABE port ID + * @ prot: protocol being used + * + * load the dma_t with physical information from AE memory mapping + */ +void abe_init_dma_t(u32 id, abe_port_protocol_t *prot) +{ + abe_dma_t_offset dma; + u32 idx; + /* default dma_t points to address 0000... */ + dma.data = 0; + dma.iter = 0; + switch (prot->protocol_switch) { + case PINGPONG_PORT_PROT: + for (idx = 0; idx < 32; idx++) { + if (((prot->p).prot_pingpong.irq_data) == + (u32) (1 << idx)) + break; + } + (prot->p).prot_dmareq.desc_addr = + ((CBPr_DMA_RTX0 + idx)*ATC_SIZE); + /* translate byte address/size in DMEM words */ + dma.data = (prot->p).prot_pingpong.buf_addr >> 2; + dma.iter = (prot->p).prot_pingpong.buf_size >> 2; + break; + case DMAREQ_PORT_PROT: + for (idx = 0; idx < 32; idx++) { + if (((prot->p).prot_dmareq.dma_data) == + (u32) (1 << idx)) + break; + } + dma.data = (CIRCULAR_BUFFER_PERIPHERAL_R__0 + (idx << 2)); + dma.iter = (prot->p).prot_dmareq.iter; + (prot->p).prot_dmareq.desc_addr = + ((CBPr_DMA_RTX0 + idx)*ATC_SIZE); + break; + case SLIMBUS_PORT_PROT: + case SERIAL_PORT_PROT: + case DMIC_PORT_PROT: + case MCPDMDL_PORT_PROT: + case MCPDMUL_PORT_PROT: + default: + break; + } + /* upload the dma type */ + abe_port[id].dma = dma; +} + +/** + * abe_enable_atc + * Parameter: + * Operations: + * Return value: + */ +void abe_enable_atc(u32 id) +{ + struct omap_abe_atc_desc atc_desc; + + omap_abe_mem_read(abe, OMAP_ABE_DMEM, + (abe_port[id]).protocol.p.prot_dmareq.desc_addr, + (u32 *) &atc_desc, sizeof(atc_desc)); + atc_desc.desen = 1; + omap_abe_mem_write(abe, OMAP_ABE_DMEM, + (abe_port[id]).protocol.p.prot_dmareq.desc_addr, + (u32 *) &atc_desc, sizeof(atc_desc)); + +} +/** + * abe_disable_atc + * Parameter: + * Operations: + * Return value: + */ +void abe_disable_atc(u32 id) +{ + struct omap_abe_atc_desc atc_desc; + + omap_abe_mem_read(abe, OMAP_ABE_DMEM, + (abe_port[id]).protocol.p.prot_dmareq.desc_addr, + (u32 *) &atc_desc, sizeof(atc_desc)); + atc_desc.desen = 0; + omap_abe_mem_write(abe, OMAP_ABE_DMEM, + (abe_port[id]).protocol.p.prot_dmareq.desc_addr, + (u32 *) &atc_desc, sizeof(atc_desc)); + +} +/** + * abe_init_io_tasks + * @prot : protocol being used + * + * load the micro-task parameters doing to DMEM <==> SMEM data moves + * + * I/O descriptors input parameters : + * For Read from DMEM usually THR1/THR2 = X+1/X-1 + * For Write to DMEM usually THR1/THR2 = 2/0 + * UP_1/2 =X+1/X-1 + */ +void abe_init_io_tasks(u32 id, abe_data_format_t *format, + abe_port_protocol_t *prot) +{ + u32 x_io, direction, iter_samples, smem1, smem2, smem3, io_sub_id, + io_flag; + u32 copy_func_index, before_func_index, after_func_index; + u32 dmareq_addr, dmareq_field; + u32 sio_desc_address, datasize, iter, nsamp, datasize2, dOppMode32; + u32 atc_ptr_saved, atc_ptr_saved2, copy_func_index1; + u32 copy_func_index2, atc_desc_address1, atc_desc_address2; + struct ABE_SPingPongDescriptor desc_pp; + struct ABE_SIODescriptor sio_desc; + + if (prot->protocol_switch == PINGPONG_PORT_PROT) { + /* ping_pong is only supported on MM_DL */ + if (OMAP_ABE_MM_DL_PORT != id) { + omap_abe_dbg_error(abe, OMAP_ABE_ERR_API, + ABE_PARAMETER_ERROR); + } + smem1 = smem_mm_dl; + copy_func_index = (u8) abe_dma_port_copy_subroutine_id(id); + dmareq_addr = abe_port[id].protocol.p.prot_pingpong.irq_addr; + dmareq_field = abe_port[id].protocol.p.prot_pingpong.irq_data; + datasize = abe_dma_port_iter_factor(format); + /* number of "samples" either mono or stereo */ + iter = abe_dma_port_iteration(format); + iter_samples = (iter / datasize); + /* load the IO descriptor */ + /* no drift */ + desc_pp.drift_ASRC = 0; + /* no drift */ + desc_pp.drift_io = 0; + desc_pp.hw_ctrl_addr = (u16) dmareq_addr; + desc_pp.copy_func_index = (u8) copy_func_index; + desc_pp.smem_addr = (u8) smem1; + /* DMA req 0 is used for CBPr0 */ + desc_pp.atc_irq_data = (u8) dmareq_field; + /* size of block transfer */ + desc_pp.x_io = (u8) iter_samples; + desc_pp.data_size = (u8) datasize; + /* address comunicated in Bytes */ + desc_pp.workbuff_BaseAddr = + (u16) (abe_base_address_pingpong[1]); + /* size comunicated in XIO sample */ + desc_pp.workbuff_Samples = 0; + desc_pp.nextbuff0_BaseAddr = + (u16) (abe_base_address_pingpong[0]); + desc_pp.nextbuff1_BaseAddr = + (u16) (abe_base_address_pingpong[1]); + if (dmareq_addr == ABE_DMASTATUS_RAW) { + desc_pp.nextbuff0_Samples = + (u16) ((abe_size_pingpong >> 2) / datasize); + desc_pp.nextbuff1_Samples = + (u16) ((abe_size_pingpong >> 2) / datasize); + } else { + desc_pp.nextbuff0_Samples = 0; + desc_pp.nextbuff1_Samples = 0; + } + /* next buffer to send is B1, first IRQ fills B0 */ + desc_pp.counter = 0; + /* send a DMA req to fill B0 with N samples + abe_block_copy (COPY_FROM_HOST_TO_ABE, + ABE_ATC, + ABE_DMASTATUS_RAW, + &(abe_port[id].protocol.p.prot_pingpong.irq_data), + 4); */ + sio_desc_address = OMAP_ABE_D_PINGPONGDESC_ADDR; + omap_abe_mem_write(abe, OMAP_ABE_DMEM, + sio_desc_address, (u32 *) &desc_pp, + sizeof(desc_pp)); + } else { + io_sub_id = dmareq_addr = ABE_DMASTATUS_RAW; + dmareq_field = 0; + atc_desc_address1 = atc_desc_address2 = 0; + /* default: repeat of the last downlink samples in case of + DMA errors, (disable=0x00) */ + io_flag = 0xFF; + datasize2 = datasize = abe_dma_port_iter_factor(format); + x_io = (u8) abe_dma_port_iteration(format); + nsamp = (x_io / datasize); + atc_ptr_saved2 = atc_ptr_saved = DMIC_ATC_PTR_labelID + id; + smem1 = abe_port[id].smem_buffer1; + smem3 = smem2 = abe_port[id].smem_buffer2; + copy_func_index1 = (u8) abe_dma_port_copy_subroutine_id(id); + before_func_index = after_func_index = + copy_func_index2 = NULL_COPY_CFPID; + switch (prot->protocol_switch) { + case DMIC_PORT_PROT: + /* DMIC port is read in two steps */ + x_io = x_io >> 1; + nsamp = nsamp >> 1; + atc_desc_address1 = (ABE_ATC_DMIC_DMA_REQ*ATC_SIZE); + io_sub_id = IO_IP_CFPID; + break; + case MCPDMDL_PORT_PROT: + /* PDMDL port is written to in two steps */ + x_io = x_io >> 1; + atc_desc_address1 = + (ABE_ATC_MCPDMDL_DMA_REQ*ATC_SIZE); + io_sub_id = IO_IP_CFPID; + break; + case MCPDMUL_PORT_PROT: + atc_desc_address1 = + (ABE_ATC_MCPDMUL_DMA_REQ*ATC_SIZE); + io_sub_id = IO_IP_CFPID; + break; + case SLIMBUS_PORT_PROT: + atc_desc_address1 = + abe_port[id].protocol.p.prot_slimbus.desc_addr1; + atc_desc_address2 = + abe_port[id].protocol.p.prot_slimbus.desc_addr2; + copy_func_index2 = NULL_COPY_CFPID; + /* @@@@@@ + #define SPLIT_SMEM_CFPID 9 + #define MERGE_SMEM_CFPID 10 + #define SPLIT_TDM_12_CFPID 11 + #define MERGE_TDM_12_CFPID 12 + */ + io_sub_id = IO_IP_CFPID; + break; + case SERIAL_PORT_PROT: /* McBSP/McASP */ + atc_desc_address1 = + (s16) abe_port[id].protocol.p.prot_serial. + desc_addr; + io_sub_id = IO_IP_CFPID; + break; + case DMAREQ_PORT_PROT: /* DMA w/wo CBPr */ + dmareq_addr = + abe_port[id].protocol.p.prot_dmareq.dma_addr; + dmareq_field = 0; + atc_desc_address1 = + abe_port[id].protocol.p.prot_dmareq.desc_addr; + io_sub_id = IO_IP_CFPID; + break; + } + /* special situation of the PING_PONG protocol which + has its own SIO descriptor format */ + /* + Sequence of operations on ping-pong buffers B0/B1 + -------------- time ---------------------------->>>> + Host Application is ready to send data from DDR to B0 + SDMA is initialized from "abe_connect_irq_ping_pong_port" to B0 + FIRMWARE starts with #12 B1 data, + sends IRQ/DMAreq, sends #pong B1 data, + sends IRQ/DMAreq, sends #ping B0, + sends B1 samples + ARM / SDMA | fills B0 | fills B1 ... | fills B0 ... + Counter 0 1 2 3 + */ + switch (id) { + case OMAP_ABE_PDM_DL_PORT: + abe->MultiFrame[7][0] = ABE_TASK_ID(C_ABE_FW_TASK_IO_PDM_DL); + abe->MultiFrame[19][0] = ABE_TASK_ID(C_ABE_FW_TASK_IO_PDM_DL); + break; + case OMAP_ABE_TONES_DL_PORT: + break; + case OMAP_ABE_PDM_UL_PORT: + abe->MultiFrame[5][2] = ABE_TASK_ID(C_ABE_FW_TASK_IO_PDM_UL); + break; + case OMAP_ABE_DMIC_PORT: + abe->MultiFrame[2][5] = ABE_TASK_ID(C_ABE_FW_TASK_IO_DMIC); + abe->MultiFrame[14][3] = ABE_TASK_ID(C_ABE_FW_TASK_IO_DMIC); + break; + case OMAP_ABE_MM_UL_PORT: + copy_func_index1 = COPY_MM_UL_CFPID; + before_func_index = ROUTE_MM_UL_CFPID; + break; + case OMAP_ABE_MM_UL2_PORT: + break; + case OMAP_ABE_VX_DL_PORT: + abe->MultiFrame[0][2] = ABE_TASK_ID(C_ABE_FW_TASK_IO_VX_DL); + /* check for 8kHz/16kHz */ + if (abe_port[id].format.f == 8000) { + abe->MultiFrame[TASK_VX_DL_SLT][TASK_VX_DL_IDX] = + ABE_TASK_ID(C_ABE_FW_TASK_VX_DL_8_48_FIR); + /*Voice_8k_DL_labelID */ + smem1 = IO_VX_DL_ASRC_labelID; + + if ((abe_port[OMAP_ABE_VX_DL_PORT].status == + OMAP_ABE_PORT_ACTIVITY_IDLE) && + (abe_port[OMAP_ABE_VX_UL_PORT].status == + OMAP_ABE_PORT_ACTIVITY_IDLE)) { + /* the 1st opened port is VX_DL_PORT + * both VX_UL ASRC and VX_DL ASRC will add/remove sample + * referring to VX_DL flow_counter */ + abe->MultiFrame[TASK_ASRC_VX_DL_SLT][TASK_ASRC_VX_DL_IDX] = + ABE_TASK_ID(C_ABE_FW_TASK_ASRC_VX_DL_8); + abe->MultiFrame[TASK_ASRC_VX_UL_SLT][TASK_ASRC_VX_UL_IDX] = + ABE_TASK_ID(C_ABE_FW_TASK_ASRC_VX_UL_8_SIB); + /* Init VX_UL ASRC & VX_DL ASRC and enable its adaptation */ + abe_init_asrc_vx_ul(-250); + abe_init_asrc_vx_dl(250); + } else { + /* Do nothing, Scheduling Table has already been patched */ + } + } else { + abe->MultiFrame[TASK_VX_DL_SLT][TASK_VX_DL_IDX] = + ABE_TASK_ID(C_ABE_FW_TASK_VX_DL_16_48); + /* Voice_16k_DL_labelID */ + smem1 = IO_VX_DL_ASRC_labelID; + + if ((abe_port[OMAP_ABE_VX_DL_PORT].status == + OMAP_ABE_PORT_ACTIVITY_IDLE) && + (abe_port[OMAP_ABE_VX_UL_PORT].status == + OMAP_ABE_PORT_ACTIVITY_IDLE)) { + /* the 1st opened port is VX_DL_PORT + * both VX_UL ASRC and VX_DL ASRC will add/remove sample + * referring to VX_DL flow_counter */ + abe->MultiFrame[TASK_ASRC_VX_DL_SLT][TASK_ASRC_VX_DL_IDX] = + ABE_TASK_ID(C_ABE_FW_TASK_ASRC_VX_DL_16); + abe->MultiFrame[TASK_ASRC_VX_UL_SLT][TASK_ASRC_VX_UL_IDX] = + ABE_TASK_ID(C_ABE_FW_TASK_ASRC_VX_UL_16_SIB); + /* Init VX_UL ASRC & VX_DL ASRC and enable its adaptation */ + abe_init_asrc_vx_ul(-250); + abe_init_asrc_vx_dl(250); + } else { + /* Do nothing, Scheduling Table has already been patched */ + } + } + break; + case OMAP_ABE_VX_UL_PORT: + abe->MultiFrame[16][3] = ABE_TASK_ID(C_ABE_FW_TASK_IO_VX_UL); + /* check for 8kHz/16kHz */ + if (abe_port[id].format.f == 8000) { + abe->MultiFrame[TASK_VX_UL_SLT][TASK_VX_UL_IDX] = + ABE_TASK_ID(C_ABE_FW_TASK_VX_UL_48_8); + /* MultiFrame[TASK_ECHO_SLT][TASK_ECHO_IDX] = + ABE_TASK_ID(C_ABE_FW_TASK_ECHO_REF_48_8); */ + smem1 = Voice_8k_UL_labelID; + + if ((abe_port[OMAP_ABE_VX_DL_PORT].status == + OMAP_ABE_PORT_ACTIVITY_IDLE) && + (abe_port[OMAP_ABE_VX_UL_PORT].status == + OMAP_ABE_PORT_ACTIVITY_IDLE)) { + /* the 1st opened port is VX_UL_PORT + * both VX_UL ASRC and VX_DL ASRC will add/remove sample + * referring to VX_UL flow_counter */ + abe->MultiFrame[TASK_ASRC_VX_DL_SLT][TASK_ASRC_VX_DL_IDX] = + ABE_TASK_ID(C_ABE_FW_TASK_ASRC_VX_DL_8_SIB); + abe->MultiFrame[TASK_ASRC_VX_UL_SLT][TASK_ASRC_VX_UL_IDX] = + ABE_TASK_ID(C_ABE_FW_TASK_ASRC_VX_UL_8); + /* Init VX_UL ASRC & VX_DL ASRC and enable its adaptation */ + abe_init_asrc_vx_ul(-250); + abe_init_asrc_vx_dl(250); + } else { + /* Do nothing, Scheduling Table has already been patched */ + } + } else { + abe->MultiFrame[TASK_VX_UL_SLT][TASK_VX_UL_IDX] = + ABE_TASK_ID(C_ABE_FW_TASK_VX_UL_48_16); + /* MultiFrame[TASK_ECHO_SLT][TASK_ECHO_IDX] = + ABE_TASK_ID(C_ABE_FW_TASK_ECHO_REF_48_16); */ + smem1 = Voice_16k_UL_labelID; + + if ((abe_port[OMAP_ABE_VX_DL_PORT].status == + OMAP_ABE_PORT_ACTIVITY_IDLE) && + (abe_port[OMAP_ABE_VX_UL_PORT].status == + OMAP_ABE_PORT_ACTIVITY_IDLE)) { + /* the 1st opened port is VX_UL_PORT + * both VX_UL ASRC and VX_DL ASRC will add/remove sample + * referring to VX_UL flow_counter */ + abe->MultiFrame[TASK_ASRC_VX_DL_SLT][TASK_ASRC_VX_DL_IDX] = + ABE_TASK_ID(C_ABE_FW_TASK_ASRC_VX_DL_16_SIB); + abe->MultiFrame[TASK_ASRC_VX_UL_SLT][TASK_ASRC_VX_UL_IDX] = + ABE_TASK_ID(C_ABE_FW_TASK_ASRC_VX_UL_16); + /* Init VX_UL ASRC & VX_DL ASRC and enable its adaptation */ + abe_init_asrc_vx_ul(-250); + abe_init_asrc_vx_dl(250); + } else { + /* Do nothing, Scheduling Table has already been patched */ + } + } + break; + case OMAP_ABE_BT_VX_DL_PORT: + /* check for 8kHz/16kHz */ + omap_abe_mem_read(abe, OMAP_ABE_DMEM, + OMAP_ABE_D_MAXTASKBYTESINSLOT_ADDR, &dOppMode32, + sizeof(u32)); + + /* Disable BT ASRC */ + dOppMode32 = DOPPMODE32_OPP50; + + if (abe_port[id].format.f == 8000) { + if (dOppMode32 == DOPPMODE32_OPP100) { + abe->MultiFrame[TASK_BT_DL_48_8_SLT][TASK_BT_DL_48_8_IDX] = + ABE_TASK_ID(C_ABE_FW_TASK_BT_DL_48_8_FIR_OPP100); + smem1 = BT_DL_8k_opp100_labelID; + } else { + abe->MultiFrame[TASK_BT_DL_48_8_SLT][TASK_BT_DL_48_8_IDX] = + ABE_TASK_ID(C_ABE_FW_TASK_BT_DL_48_8_FIR); + smem1 = BT_DL_8k_labelID; + } +#if 0 + if ((abe_port[OMAP_ABE_BT_VX_DL_PORT].status == + OMAP_ABE_PORT_ACTIVITY_IDLE) && + (abe_port[OMAP_ABE_BT_VX_UL_PORT].status == + OMAP_ABE_PORT_ACTIVITY_IDLE)) { + /* the 1st opened port is BT_VX_DL_PORT + * both BT_VX_DL ASRC and BT_VX_UL ASRC will add/remove sample + * referring to BT_VX_DL flow_counter */ + abe->MultiFrame[TASK_ASRC_BT_DL_SLT][TASK_ASRC_BT_DL_IDX] = + ABE_TASK_ID(C_ABE_FW_TASK_ASRC_BT_DL_8); + abe->MultiFrame[TASK_ASRC_BT_UL_SLT][TASK_ASRC_BT_UL_IDX] = + ABE_TASK_ID(C_ABE_FW_TASK_ASRC_BT_UL_8_SIB); + } else { + /* Do nothing, Scheduling Table has already been patched */ + } +#endif + } else { + if (dOppMode32 == DOPPMODE32_OPP100) { + abe->MultiFrame[TASK_BT_DL_48_8_SLT][TASK_BT_DL_48_8_IDX] = + ABE_TASK_ID(C_ABE_FW_TASK_BT_DL_48_16_OPP100); + smem1 = BT_DL_16k_opp100_labelID; + } else { + abe->MultiFrame[TASK_BT_DL_48_8_SLT][TASK_BT_DL_48_8_IDX] = + ABE_TASK_ID(C_ABE_FW_TASK_BT_DL_48_16); + smem1 = BT_DL_16k_labelID; + } +#if 0 + if ((abe_port[OMAP_ABE_BT_VX_DL_PORT].status == + OMAP_ABE_PORT_ACTIVITY_IDLE) && + (abe_port[OMAP_ABE_BT_VX_UL_PORT].status == + OMAP_ABE_PORT_ACTIVITY_IDLE)) { + /* the 1st opened port is BT_VX_DL_PORT + * both BT_VX_DL ASRC and BT_VX_UL ASRC will add/remove sample + * referring to BT_VX_DL flow_counter */ + abe->MultiFrame[TASK_ASRC_BT_DL_SLT][TASK_ASRC_BT_DL_IDX] = + ABE_TASK_ID(C_ABE_FW_TASK_ASRC_BT_DL_16); + abe->MultiFrame[TASK_ASRC_BT_UL_SLT][TASK_ASRC_BT_UL_IDX] = + ABE_TASK_ID(C_ABE_FW_TASK_ASRC_BT_UL_16_SIB); + } else { + /* Do nothing, Scheduling Table has already been patched */ + } +#endif + } + break; + case OMAP_ABE_BT_VX_UL_PORT: + /* check for 8kHz/16kHz */ + /* set the SMEM buffer -- programming sequence */ + omap_abe_mem_read(abe, OMAP_ABE_DMEM, + OMAP_ABE_D_MAXTASKBYTESINSLOT_ADDR, &dOppMode32, + sizeof(u32)); + + /* Disable BT ASRC */ + dOppMode32 = DOPPMODE32_OPP50; + + if (abe_port[id].format.f == 8000) { + abe->MultiFrame[TASK_BT_UL_8_48_SLT][TASK_BT_UL_8_48_IDX] = + ABE_TASK_ID(C_ABE_FW_TASK_BT_UL_8_48); + if (dOppMode32 == DOPPMODE32_OPP100) + /* ASRC input buffer, size 40 */ + smem1 = smem_bt_vx_ul_opp100; + else + /* at OPP 50 without ASRC */ + smem1 = BT_UL_8k_labelID; +#if 0 + if ((abe_port[OMAP_ABE_BT_VX_UL_PORT].status == + OMAP_ABE_PORT_ACTIVITY_IDLE) && + (abe_port[OMAP_ABE_BT_VX_DL_PORT].status == + OMAP_ABE_PORT_ACTIVITY_IDLE)) { + /* the 1st opened port is BT_VX_UL_PORT */ + /* both BT_VX_UL ASRC and BT_VX_DL ASRC will add/remove sample + referring to BT_VX_UL flow_counter */ + abe->MultiFrame[TASK_ASRC_BT_UL_SLT][TASK_ASRC_BT_UL_IDX] = + ABE_TASK_ID(C_ABE_FW_TASK_ASRC_BT_UL_8); + abe->MultiFrame[TASK_ASRC_BT_DL_SLT][TASK_ASRC_BT_DL_IDX] = + ABE_TASK_ID(C_ABE_FW_TASK_ASRC_BT_DL_8_SIB); + } else { + /* Do nothing, Scheduling Table has already been patched */ + } +#endif + } else { + abe->MultiFrame[TASK_BT_UL_8_48_SLT][TASK_BT_UL_8_48_IDX] = + ABE_TASK_ID(C_ABE_FW_TASK_BT_UL_16_48); + if (dOppMode32 == DOPPMODE32_OPP100) + /* ASRC input buffer, size 40 */ + smem1 = smem_bt_vx_ul_opp100; + else + /* at OPP 50 without ASRC */ + smem1 = BT_UL_16k_labelID; +#if 0 + if ((abe_port[OMAP_ABE_BT_VX_UL_PORT].status == + OMAP_ABE_PORT_ACTIVITY_IDLE) && + (abe_port[OMAP_ABE_BT_VX_DL_PORT].status == + OMAP_ABE_PORT_ACTIVITY_IDLE)) { + /* the 1st opened port is BT_VX_UL_PORT */ + /* both BT_VX_UL ASRC and BT_VX_DL ASRC will add/remove sample + referring to BT_VX_UL flow_counter */ + abe->MultiFrame[TASK_ASRC_BT_UL_SLT][TASK_ASRC_BT_UL_IDX] = + ABE_TASK_ID(C_ABE_FW_TASK_ASRC_BT_UL_16); + abe->MultiFrame[TASK_ASRC_BT_DL_SLT][TASK_ASRC_BT_DL_IDX] = + ABE_TASK_ID(C_ABE_FW_TASK_ASRC_BT_DL_16_SIB); + } else { + /* Do nothing, Scheduling Table has already been patched */ + } +#endif + } + break; + case OMAP_ABE_MM_DL_PORT: + /* check for CBPr / serial_port / Ping-pong access */ + smem1 = smem_mm_dl; + break; + case OMAP_ABE_MM_EXT_IN_PORT: + /* set the SMEM buffer -- programming sequence */ + omap_abe_mem_read(abe, OMAP_ABE_DMEM, + OMAP_ABE_D_MAXTASKBYTESINSLOT_ADDR, &dOppMode32, + sizeof(u32)); + + /* Disable MM EXT ASRC */ + dOppMode32 = DOPPMODE32_OPP50; + + if (dOppMode32 == DOPPMODE32_OPP100) + /* ASRC input buffer, size 40 */ + smem1 = smem_mm_ext_in_opp100; + else + /* at OPP 50 without ASRC */ + smem1 = smem_mm_ext_in_opp50; + + break; + case OMAP_ABE_MM_EXT_OUT_PORT: + break; + default: + break; + } + + if (abe_port[id].protocol.direction == ABE_ATC_DIRECTION_IN) + direction = 0; + else + /* offset of the write pointer in the ATC descriptor */ + direction = 3; + + sio_desc.drift_ASRC = 0; + sio_desc.drift_io = 0; + sio_desc.io_type_idx = (u8) io_sub_id; + sio_desc.samp_size = (u8) datasize; + sio_desc.hw_ctrl_addr = (u16) (dmareq_addr << 2); + sio_desc.atc_irq_data = (u8) dmareq_field; + sio_desc.flow_counter = (u16) 0; + sio_desc.direction_rw = (u8) direction; + sio_desc.repeat_last_samp = (u8) io_flag; + sio_desc.nsamp = (u8) nsamp; + sio_desc.x_io = (u8) x_io; + /* set ATC ON */ + sio_desc.on_off = 0x80; + sio_desc.split_addr1 = (u16) smem1; + sio_desc.split_addr2 = (u16) smem2; + sio_desc.split_addr3 = (u16) smem3; + sio_desc.before_f_index = (u8) before_func_index; + sio_desc.after_f_index = (u8) after_func_index; + sio_desc.smem_addr1 = (u16) smem1; + sio_desc.atc_address1 = (u16) atc_desc_address1; + sio_desc.atc_pointer_saved1 = (u16) atc_ptr_saved; + sio_desc.data_size1 = (u8) datasize; + sio_desc.copy_f_index1 = (u8) copy_func_index1; + sio_desc.smem_addr2 = (u16) smem2; + sio_desc.atc_address2 = (u16) atc_desc_address2; + sio_desc.atc_pointer_saved2 = (u16) atc_ptr_saved2; + sio_desc.data_size2 = (u8) datasize2; + sio_desc.copy_f_index2 = (u8) copy_func_index2; + sio_desc_address = OMAP_ABE_D_IODESCR_ADDR + (id * + sizeof(struct ABE_SIODescriptor)); + + omap_abe_mem_write(abe, OMAP_ABE_DMEM, + sio_desc_address, (u32 *) &sio_desc, + sizeof(sio_desc)); + + omap_abe_mem_write(abe, OMAP_ABE_DMEM, + OMAP_ABE_D_MULTIFRAME_ADDR, (u32 *) abe->MultiFrame, + sizeof(abe->MultiFrame)); + } + +} + +/** + * omap_abe_select_main_port - Select stynchronization port for Event generator. + * @id: audio port name + * + * tells the FW which is the reference stream for adjusting + * the processing on 23/24/25 slots + */ +int omap_abe_select_main_port(u32 id) +{ + u32 selection; + + _log(ABE_ID_SELECT_MAIN_PORT, id, 0, 0); + + /* flow control */ + selection = OMAP_ABE_D_IODESCR_ADDR + id * sizeof(struct ABE_SIODescriptor) + + flow_counter_; + /* when the main port is a sink port from AESS point of view + the sign the firmware task analysis must be changed */ + selection &= 0xFFFFL; + if (abe_port[id].protocol.direction == ABE_ATC_DIRECTION_IN) + selection |= 0x80000; + omap_abe_mem_write(abe, OMAP_ABE_DMEM, OMAP_ABE_D_SLOT23_CTRL_ADDR, + &selection, 4); + return 0; +} +/** + * abe_decide_main_port - Select stynchronization port for Event generator. + * @id: audio port name + * + * tells the FW which is the reference stream for adjusting + * the processing on 23/24/25 slots + * + * takes the first port in a list which is slave on the data interface + */ +u32 abe_valid_port_for_synchro(u32 id) +{ + if ((abe_port[id].protocol.protocol_switch == + DMAREQ_PORT_PROT) || + (abe_port[id].protocol.protocol_switch == + PINGPONG_PORT_PROT) || + (abe_port[id].status != OMAP_ABE_PORT_ACTIVITY_RUNNING)) + return 0; + else + return 1; +} +void abe_decide_main_port(void) +{ + u32 id, id_not_found; + id_not_found = 1; + for (id = 0; id < LAST_PORT_ID - 1; id++) { + if (abe_valid_port_for_synchro(abe_port_priority[id])) { + id_not_found = 0; + break; + } + } + /* if no port is currently activated, the default one is PDM_DL */ + if (id_not_found) + omap_abe_select_main_port(OMAP_ABE_PDM_DL_PORT); + else + omap_abe_select_main_port(abe_port_priority[id]); +} +/** + * abe_format_switch + * @f: port format + * @iter: port iteration + * @mulfac: multiplication factor + * + * translates the sampling and data length to ITER number for the DMA + * and the multiplier factor to apply during data move with DMEM + * + */ +void abe_format_switch(abe_data_format_t *f, u32 *iter, u32 *mulfac) +{ + u32 n_freq; +#if FW_SCHED_LOOP_FREQ == 4000 + switch (f->f) { + /* nb of samples processed by scheduling loop */ + case 8000: + n_freq = 2; + break; + case 16000: + n_freq = 4; + break; + case 24000: + n_freq = 6; + break; + case 44100: + n_freq = 12; + break; + case 96000: + n_freq = 24; + break; + default/*case 48000 */ : + n_freq = 12; + break; + } +#else + /* erroneous cases */ + n_freq = 0; +#endif + switch (f->samp_format) { + case MONO_MSB: + case MONO_RSHIFTED_16: + case STEREO_16_16: + *mulfac = 1; + break; + case STEREO_MSB: + case STEREO_RSHIFTED_16: + *mulfac = 2; + break; + case THREE_MSB: + *mulfac = 3; + break; + case FOUR_MSB: + *mulfac = 4; + break; + case FIVE_MSB: + *mulfac = 5; + break; + case SIX_MSB: + *mulfac = 6; + break; + case SEVEN_MSB: + *mulfac = 7; + break; + case EIGHT_MSB: + *mulfac = 8; + break; + case NINE_MSB: + *mulfac = 9; + break; + default: + *mulfac = 1; + break; + } + *iter = (n_freq * (*mulfac)); +} +/** + * abe_dma_port_iteration + * @f: port format + * + * translates the sampling and data length to ITER number for the DMA + */ +u32 abe_dma_port_iteration(abe_data_format_t *f) +{ + u32 iter, mulfac; + abe_format_switch(f, &iter, &mulfac); + return iter; +} +/** + * abe_dma_port_iter_factor + * @f: port format + * + * returns the multiplier factor to apply during data move with DMEM + */ +u32 abe_dma_port_iter_factor(abe_data_format_t *f) +{ + u32 iter, mulfac; + abe_format_switch(f, &iter, &mulfac); + return mulfac; +} +/** + * omap_abe_dma_port_iter_factor + * @f: port format + * + * returns the multiplier factor to apply during data move with DMEM + */ +u32 omap_abe_dma_port_iter_factor(struct omap_abe_data_format *f) +{ + u32 iter, mulfac; + abe_format_switch((abe_data_format_t *)f, &iter, &mulfac); + return mulfac; +} +/** + * abe_dma_port_copy_subroutine_id + * + * @port_id: ABE port ID + * + * returns the index of the function doing the copy in I/O tasks + */ +u32 abe_dma_port_copy_subroutine_id(u32 port_id) +{ + u32 sub_id; + if (abe_port[port_id].protocol.direction == ABE_ATC_DIRECTION_IN) { + switch (abe_port[port_id].format.samp_format) { + case MONO_MSB: + sub_id = D2S_MONO_MSB_CFPID; + break; + case MONO_RSHIFTED_16: + sub_id = D2S_MONO_RSHIFTED_16_CFPID; + break; + case STEREO_RSHIFTED_16: + sub_id = D2S_STEREO_RSHIFTED_16_CFPID; + break; + case STEREO_16_16: + sub_id = D2S_STEREO_16_16_CFPID; + break; + case STEREO_MSB: + sub_id = D2S_STEREO_MSB_CFPID; + break; + case SIX_MSB: + if (port_id == OMAP_ABE_DMIC_PORT) { + sub_id = COPY_DMIC_CFPID; + break; + } + default: + sub_id = NULL_COPY_CFPID; + break; + } + } else { + switch (abe_port[port_id].format.samp_format) { + case MONO_MSB: + sub_id = S2D_MONO_MSB_CFPID; + break; + case MONO_RSHIFTED_16: + sub_id = S2D_MONO_RSHIFTED_16_CFPID; + break; + case STEREO_RSHIFTED_16: + sub_id = S2D_STEREO_RSHIFTED_16_CFPID; + break; + case STEREO_16_16: + sub_id = S2D_STEREO_16_16_CFPID; + break; + case STEREO_MSB: + sub_id = S2D_STEREO_MSB_CFPID; + break; + case SIX_MSB: + if (port_id == OMAP_ABE_PDM_DL_PORT) { + sub_id = COPY_MCPDM_DL_CFPID; + break; + } + if (port_id == OMAP_ABE_MM_UL_PORT) { + sub_id = COPY_MM_UL_CFPID; + break; + } + case THREE_MSB: + case FOUR_MSB: + case FIVE_MSB: + case SEVEN_MSB: + case EIGHT_MSB: + case NINE_MSB: + sub_id = COPY_MM_UL_CFPID; + break; + default: + sub_id = NULL_COPY_CFPID; + break; + } + } + return sub_id; +} + +/** + * abe_read_remaining_data + * @id: ABE port_ID + * @n: size pointer to the remaining number of 32bits words + * + * computes the remaining amount of data in the buffer. + */ +abehal_status abe_read_remaining_data(u32 port, u32 *n) +{ + u32 sio_pp_desc_address; + struct ABE_SPingPongDescriptor desc_pp; + + _log(ABE_ID_READ_REMAINING_DATA, port, 0, 0); + + /* + * read the port SIO descriptor and extract the + * current pointer address after reading the counter + */ + sio_pp_desc_address = OMAP_ABE_D_PINGPONGDESC_ADDR; + omap_abe_mem_read(abe, OMAP_ABE_DMEM, sio_pp_desc_address, + (u32 *) &desc_pp, sizeof(struct ABE_SPingPongDescriptor)); + *n = desc_pp.workbuff_Samples; + + return 0; +} +EXPORT_SYMBOL(abe_read_remaining_data); + +/** + * omap_abe_mono_mixer + * @id: name of the mixer (MIXDL1, MIXDL2 or MIXAUDUL) + * on_off: enable\disable flag + * + * This API Programs DL1Mixer or DL2Mixer to output mono data + * on both left and right data paths. + */ +int omap_abe_mono_mixer(struct omap_abe *abe, u32 id, u32 on_off) +{ + switch (id) { + case MIXDL1: + if (on_off) + abe->MultiFrame[TASK_DL1Mixer_SLT][TASK_DL1Mixer_IDX] = + ABE_TASK_ID(C_ABE_FW_TASK_DL1Mixer_dual_mono); + else + abe->MultiFrame[TASK_DL1Mixer_SLT][TASK_DL1Mixer_IDX] = + ABE_TASK_ID(C_ABE_FW_TASK_DL1Mixer); + break; + case MIXDL2: + if (on_off) + abe->MultiFrame[TASK_DL2Mixer_SLT][TASK_DL2Mixer_IDX] = + ABE_TASK_ID(C_ABE_FW_TASK_DL2Mixer_dual_mono); + else + abe->MultiFrame[TASK_DL2Mixer_SLT][TASK_DL2Mixer_IDX] = + ABE_TASK_ID(C_ABE_FW_TASK_DL2Mixer); + break; + case MIXAUDUL: + if (on_off) + abe->MultiFrame[12][4] = + ABE_TASK_ID(C_ABE_FW_TASK_ULMixer_dual_mono); + else + abe->MultiFrame[12][4] = + ABE_TASK_ID(C_ABE_FW_TASK_ULMixer); + break; + default: + break; + } + + omap_abe_mem_write(abe, OMAP_ABE_DMEM, OMAP_ABE_D_MULTIFRAME_ADDR, + (u32 *) abe->MultiFrame, sizeof(abe->MultiFrame)); + + return 0; +} +EXPORT_SYMBOL(omap_abe_mono_mixer); +/** + * abe_write_pdmdl_offset - write the desired offset on the DL1/DL2 paths + * + * Parameters: + * path: 1 for the DL1 ABE path, 2 for the DL2 ABE path + * offset_left: integer value that will be added on all PDM left samples + * offset_right: integer value that will be added on all PDM right samples + * + */ +void abe_write_pdmdl_offset(u32 path, u32 offset_left, u32 offset_right) +{ + switch (path) { + case 1: + omap_abe_mem_write(abe, OMAP_ABE_SMEM, OMAP_ABE_S_DC_HS_ADDR + 4, + &offset_left, sizeof(u32)); + omap_abe_mem_write(abe, OMAP_ABE_SMEM, OMAP_ABE_S_DC_HS_ADDR, + &offset_right, sizeof(u32)); + break; + case 2: + omap_abe_mem_write(abe, OMAP_ABE_SMEM, OMAP_ABE_S_DC_HF_ADDR + 4, + &offset_left, sizeof(u32)); + omap_abe_mem_write(abe, OMAP_ABE_SMEM, OMAP_ABE_S_DC_HF_ADDR, + &offset_right, sizeof(u32)); + break; + default: + break; + } +} +EXPORT_SYMBOL(abe_write_pdmdl_offset); + diff --git a/sound/soc/omap/abe/abe_port.h b/sound/soc/omap/abe/abe_port.h new file mode 100644 index 0000000..290f8b5 --- /dev/null +++ b/sound/soc/omap/abe/abe_port.h @@ -0,0 +1,161 @@ +/* + + This file is provided under a dual BSD/GPLv2 license. When using or + redistributing this file, you may do so under either license. + + GPL LICENSE SUMMARY + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License 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. + The full GNU General Public License is included in this distribution + in the file called LICENSE.GPL. + + BSD LICENSE + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name of Texas Instruments Incorporated nor the names of + its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef _ABE_PORT_H_ +#define _ABE_PORT_H_ + +struct omap_abe_data_format { + /* Sampling frequency of the stream */ + u32 f; + /* Sample format type */ + u32 samp_format; +}; + +struct omap_abe_port_protocol { + /* Direction=0 means input from AESS point of view */ + u32 direction; + /* Protocol type (switch) during the data transfers */ + u32 protocol_switch; + union { + /* McBSP/McASP peripheral connected to ATC */ + struct { + u32 desc_addr; + /* Address of ATC McBSP/McASP descriptor's in bytes */ + u32 buf_addr; + /* DMEM address in bytes */ + u32 buf_size; + /* ITERation on each DMAreq signals */ + u32 iter; + } serial; + /* DMIC peripheral connected to ATC */ + struct { + /* DMEM address in bytes */ + u32 buf_addr; + /* DMEM buffer size in bytes */ + u32 buf_size; + /* Number of activated DMIC */ + u32 nbchan; + } dmic; + /* McPDMDL peripheral connected to ATC */ + struct { + /* DMEM address in bytes */ + u32 buf_addr; + /* DMEM size in bytes */ + u32 buf_size; + /* Control allowed on McPDM DL */ + u32 control; + } mcpdmdl; + /* McPDMUL peripheral connected to ATC */ + struct { + /* DMEM address size in bytes */ + u32 buf_addr; + /* DMEM buffer size size in bytes */ + u32 buf_size; + } mcpdmul; + /* Ping-Pong interface to the Host using cache-flush */ + struct { + /* Address of ATC descriptor's */ + u32 desc_addr; + /* DMEM buffer base address in bytes */ + u32 buf_addr; + /* DMEM size in bytes for each ping and pong buffers */ + u32 buf_size; + /* IRQ address (either DMA (0) MCU (1) or DSP(2)) */ + u32 irq_addr; + /* IRQ data content loaded in the AESS IRQ register */ + u32 irq_data; + /* Call-back function upon IRQ reception */ + u32 callback; + } pingpong; + /* DMAreq line to CBPr */ + struct { + /* Address of ATC descriptor's */ + u32 desc_addr; + /* DMEM buffer address in bytes */ + u32 buf_addr; + /* DMEM buffer size size in bytes */ + u32 buf_size; + /* ITERation on each DMAreq signals */ + u32 iter; + /* DMAreq address */ + u32 dma_addr; + /* DMA/AESS = 1 << #DMA */ + u32 dma_data; + } dmareq; + /* Circular buffer - direct addressing to DMEM */ + struct { + /* DMEM buffer base address in bytes */ + u32 buf_addr; + /* DMEM buffer size in bytes */ + u32 buf_size; + /* DMAreq address */ + u32 dma_addr; + /* DMA/AESS = 1 << #DMA */ + u32 dma_data; + } circular_buffer; + } port; +}; + +extern const abe_port_t abe_port_init[]; +extern abe_port_t abe_port[]; +extern const u32 abe_port_priority[]; + +int omap_abe_select_main_port(u32 id); +u32 omap_abe_dma_port_iter_factor(struct omap_abe_data_format *f); + +#endif/* _ABE_PORT_H_ */ diff --git a/sound/soc/omap/abe/abe_ref.h b/sound/soc/omap/abe/abe_ref.h new file mode 100644 index 0000000..4c8a9bb --- /dev/null +++ b/sound/soc/omap/abe/abe_ref.h @@ -0,0 +1,152 @@ +/* + + This file is provided under a dual BSD/GPLv2 license. When using or + redistributing this file, you may do so under either license. + + GPL LICENSE SUMMARY + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License 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. + The full GNU General Public License is included in this distribution + in the file called LICENSE.GPL. + + BSD LICENSE + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name of Texas Instruments Incorporated nor the names of + its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef _ABE_REF_H_ +#define _ABE_REF_H_ + +#include "abe_api.h" + +/* + * 'ABE_PRO.H' all non-API prototypes for INI, IRQ, SEQ ... + */ +/* + * HAL EXTERNAL AP + */ +/* + * HAL INTERNAL AP + */ +void abe_decide_main_port(void); +void abe_reset_all_ports(void); +void abe_reset_all_fifo(void); +void abe_reset_all_sequence(void); +u32 abe_dma_port_iteration(abe_data_format_t *format); +void abe_read_sys_clock(u32 *time); +void abe_enable_atc(u32 id); +void abe_disable_atc(u32 id); +void abe_init_io_tasks(u32 id, abe_data_format_t *format, + abe_port_protocol_t *prot); +void abe_init_dma_t(u32 id, abe_port_protocol_t *prot); +u32 abe_dma_port_iter_factor(abe_data_format_t *f); +u32 abe_dma_port_copy_subroutine_id(u32 i); +void abe_call_subroutine(u32 idx, u32 p1, u32 p2, u32 p3, u32 p4); +void abe_monitoring(void); +void abe_add_subroutine(u32 *id, abe_subroutine2 f, u32 nparam, u32 *params); +abehal_status abe_read_next_ping_pong_buffer(u32 port, u32 *p, u32 *n); +void abe_irq_ping_pong(void); +void abe_irq_check_for_sequences(u32 seq_info); +void abe_default_irq_pingpong_player(void); +void abe_default_irq_pingpong_player_32bits(void); +void abe_rshifted16_irq_pingpong_player_32bits(void); +void abe_1616_irq_pingpong_player_1616bits(void); +void abe_default_irq_aps_adaptation(void); +void abe_irq_aps(u32 aps_info); +void abe_dbg_error_log(u32 x); +void abe_init_asrc_vx_dl(s32 dppm); +void abe_init_asrc_vx_ul(s32 dppm); +void abe_init_asrc_mm_ext_in(s32 dppm); +void abe_init_asrc_bt_ul(s32 dppm); +void abe_init_asrc_bt_dl(s32 dppm); + +void omap_abe_hw_configuration(struct omap_abe *abe); +void omap_abe_gain_offset(struct omap_abe *abe, u32 id, u32 *mixer_offset); +int omap_abe_use_compensated_gain(struct omap_abe *abe, int on_off); + +/* + * HAL INTERNAL DATA + */ +extern const u32 abe_port_priority[LAST_PORT_ID - 1]; +extern const u32 abe_firmware_array[ABE_FIRMWARE_MAX_SIZE]; +extern const u32 abe_atc_srcid[]; +extern const u32 abe_atc_dstid[]; +extern const abe_port_t abe_port_init[]; +extern const abe_seq_t all_sequence_init[]; +extern const abe_router_t abe_router_ul_table_preset + [NBROUTE_CONFIG][NBROUTE_UL]; +extern const abe_sequence_t seq_null; + +extern abe_port_t abe_port[]; +extern abe_seq_t all_sequence[]; +extern abe_router_t abe_router_ul_table[NBROUTE_CONFIG_MAX][NBROUTE_UL]; +/* table of new subroutines called in the sequence */ +extern abe_subroutine2 abe_all_subsubroutine[MAXNBSUBROUTINE]; +/* number of parameters per calls */ +extern u32 abe_all_subsubroutine_nparam[MAXNBSUBROUTINE]; +extern u32 abe_subroutine_id[MAXNBSUBROUTINE]; +extern u32 *abe_all_subroutine_params[MAXNBSUBROUTINE]; +extern u32 abe_subroutine_write_pointer; +extern abe_sequence_t abe_all_sequence[MAXNBSEQUENCE]; +extern u32 abe_sequence_write_pointer; +/* current number of pending sequences (avoids to look in the table) */ +extern u32 abe_nb_pending_sequences; +/* pending sequences due to ressource collision */ +extern u32 abe_pending_sequences[MAXNBSEQUENCE]; +/* mask of unsharable ressources among other sequences */ +extern u32 abe_global_sequence_mask; +/* table of active sequences */ +extern abe_seq_t abe_active_sequence[MAXACTIVESEQUENCE][MAXSEQUENCESTEPS]; +/* index of the plugged subroutine doing ping-pong cache-flush + DMEM accesses */ +extern u32 abe_irq_aps_adaptation_id; +/* base addresses of the ping pong buffers */ +extern u32 abe_base_address_pingpong[MAX_PINGPONG_BUFFERS]; +/* size of each ping/pong buffers */ +extern u32 abe_size_pingpong; +/* number of ping/pong buffer being used */ +extern u32 abe_nb_pingpong; + +#endif/* _ABE_REF_H_ */ diff --git a/sound/soc/omap/abe/abe_seq.c b/sound/soc/omap/abe/abe_seq.c new file mode 100644 index 0000000..6ae2aa5 --- /dev/null +++ b/sound/soc/omap/abe/abe_seq.c @@ -0,0 +1,308 @@ +/* + + This file is provided under a dual BSD/GPLv2 license. When using or + redistributing this file, you may do so under either license. + + GPL LICENSE SUMMARY + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License 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. + The full GNU General Public License is included in this distribution + in the file called LICENSE.GPL. + + BSD LICENSE + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name of Texas Instruments Incorporated nor the names of + its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include "abe_legacy.h" + +#include "abe_mem.h" + +extern struct omap_abe *abe; +extern u32 abe_irq_pingpong_player_id; + +/** + * abe_null_subroutine + * + */ +void abe_null_subroutine_0(void) +{ +} +void abe_null_subroutine_2(u32 a, u32 b) +{ +} +void abe_null_subroutine_4(u32 a, u32 b, u32 c, u32 d) +{ +} +/** + * abe_init_subroutine_table - initializes the default table of pointers + * to subroutines + * + * initializes the default table of pointers to subroutines + * + */ +void abe_init_subroutine_table(void) +{ + u32 id; + /* reset the table's pointers */ + abe_subroutine_write_pointer = 0; + /* the first index is the NULL task */ + abe_add_subroutine(&id, (abe_subroutine2) abe_null_subroutine_2, + SUB_0_PARAM, (u32 *) 0); + /* write mixer has 4 parameters */ + abe_add_subroutine(&(abe_subroutine_id[SUB_WRITE_MIXER]), + (abe_subroutine2) abe_write_mixer, SUB_4_PARAM, + (u32 *) 0); + /* ping-pong player IRQ */ + abe_add_subroutine(&abe_irq_pingpong_player_id, + (abe_subroutine2) abe_null_subroutine_0, SUB_0_PARAM, + (u32 *) 0); +} +/** + * abe_add_subroutine + * @id: ABE port id + * @f: pointer to the subroutines + * @nparam: number of parameters + * @params: pointer to the psrameters + * + * add one function pointer more and returns the index to it + */ +void abe_add_subroutine(u32 *id, abe_subroutine2 f, u32 nparam, u32 *params) +{ + u32 i, i_found; + if ((abe_subroutine_write_pointer >= MAXNBSUBROUTINE) || + ((u32) f == 0)) { + omap_abe_dbg_error(abe, OMAP_ABE_ERR_SEQ, + ABE_PARAMETER_OVERFLOW); + } else { + /* search if this subroutine address was not already + * declared, then return the previous index + */ + for (i_found = abe_subroutine_write_pointer, i = 0; + i < abe_subroutine_write_pointer; i++) { + if (f == abe_all_subsubroutine[i]) + i_found = i; + } + if (i_found == abe_subroutine_write_pointer) { + *id = abe_subroutine_write_pointer; + abe_all_subsubroutine + [abe_subroutine_write_pointer] = (f); + abe_all_subroutine_params + [abe_subroutine_write_pointer] = params; + abe_all_subsubroutine_nparam + [abe_subroutine_write_pointer] = nparam; + abe_subroutine_write_pointer++; + } else { + abe_all_subroutine_params[i_found] = params; + *id = i_found; + } + } +} +/** + * abe_add_sequence + * @id: returned sequence index after pluging a new sequence + * (index in the tables) + * @s: sequence to be inserted + * + * Load a time-sequenced operations. + */ +void abe_add_sequence(u32 *id, abe_sequence_t *s) +{ + abe_seq_t *seq_src, *seq_dst; + u32 i, no_end_of_sequence_found; + seq_src = &(s->seq1); + seq_dst = &((abe_all_sequence[abe_sequence_write_pointer]).seq1); + if ((abe_sequence_write_pointer >= MAXNBSEQUENCE) || ((u32) s == 0)) { + omap_abe_dbg_error(abe, OMAP_ABE_ERR_SEQ, + ABE_PARAMETER_OVERFLOW); + } else { + *id = abe_subroutine_write_pointer; + /* copy the mask */ + (abe_all_sequence[abe_sequence_write_pointer]).mask = s->mask; + for (no_end_of_sequence_found = 1, i = 0; i < MAXSEQUENCESTEPS; + i++, seq_src++, seq_dst++) { + /* sequence copied line by line */ + (*seq_dst) = (*seq_src); + /* stop when the line start with time=(-1) */ + if ((*(s32 *) seq_src) == (-1)) { + /* stop when the line start with time=(-1) */ + no_end_of_sequence_found = 0; + break; + } + } + abe_subroutine_write_pointer++; + if (no_end_of_sequence_found) + omap_abe_dbg_error(abe, OMAP_ABE_ERR_API, + ABE_SEQTOOLONG); + } +} +/** + * abe_reset_one_sequence + * @id: sequence ID + * + * load default configuration for that sequence + * kill running activities + */ +void abe_reset_one_sequence(u32 id) +{ +} +/** + * abe_reset_all_sequence + * + * load default configuration for all sequences + * kill any running activities + */ +void omap_abe_reset_all_sequence(struct omap_abe *abe) +{ + u32 i; + abe_init_subroutine_table(); + /* arrange to have the first sequence index=0 to the NULL operation + sequence */ + abe_add_sequence(&i, (abe_sequence_t *) &seq_null); + /* reset the the collision protection mask */ + abe_global_sequence_mask = 0; + /* reset the pending sequences list */ + for (abe_nb_pending_sequences = i = 0; i < MAXNBSEQUENCE; i++) + abe_pending_sequences[i] = 0; +} +/** + * abe_call_subroutine + * @idx: index to the table of all registered Call-backs and subroutines + * + * run and log a subroutine + */ +void abe_call_subroutine(u32 idx, u32 p1, u32 p2, u32 p3, u32 p4) +{ + abe_subroutine0 f0; + abe_subroutine1 f1; + abe_subroutine2 f2; + abe_subroutine3 f3; + abe_subroutine4 f4; + u32 *params; + if (idx > MAXNBSUBROUTINE) + return; + switch (idx) { + /* call the subroutines defined at compilation time + (const .. sequences) */ +#if 0 + case SUB_WRITE_MIXER_DL1: + abe_write_mixer_dl1(p1, p2, p3) + abe_fprintf("write_mixer"); + break; +#endif + /* call the subroutines defined at execution time + (dynamic sequences) */ + default: + switch (abe_all_subsubroutine_nparam[idx]) { + case SUB_0_PARAM: + f0 = (abe_subroutine0) abe_all_subsubroutine[idx]; + (*f0) (); + break; + case SUB_1_PARAM: + f1 = (abe_subroutine1) abe_all_subsubroutine[idx]; + params = abe_all_subroutine_params + [abe_irq_pingpong_player_id]; + if (params != (u32 *) 0) + p1 = params[0]; + (*f1) (p1); + break; + case SUB_2_PARAM: + f2 = abe_all_subsubroutine[idx]; + params = abe_all_subroutine_params + [abe_irq_pingpong_player_id]; + if (params != (u32 *) 0) { + p1 = params[0]; + p2 = params[1]; + } + (*f2) (p1, p2); + break; + case SUB_3_PARAM: + f3 = (abe_subroutine3) abe_all_subsubroutine[idx]; + params = abe_all_subroutine_params + [abe_irq_pingpong_player_id]; + if (params != (u32 *) 0) { + p1 = params[0]; + p2 = params[1]; + p3 = params[2]; + } + (*f3) (p1, p2, p3); + break; + case SUB_4_PARAM: + f4 = (abe_subroutine4) abe_all_subsubroutine[idx]; + params = abe_all_subroutine_params + [abe_irq_pingpong_player_id]; + if (params != (u32 *) 0) { + p1 = params[0]; + p2 = params[1]; + p3 = params[2]; + p4 = params[3]; + } + (*f4) (p1, p2, p3, p4); + break; + default: + break; + } + } +} + +/** + * abe_set_sequence_time_accuracy + * @fast: fast counter + * @slow: slow counter + * + */ +abehal_status abe_set_sequence_time_accuracy(u32 fast, u32 slow) +{ + u32 data; + _log(ABE_ID_SET_SEQUENCE_TIME_ACCURACY, fast, slow, 0); + data = minimum(MAX_UINT16, fast / FW_SCHED_LOOP_FREQ_DIV1000); + omap_abe_mem_write(abe, OMAP_ABE_DMEM, OMAP_ABE_D_FASTCOUNTER_ADDR, + &data, sizeof(data)); + data = minimum(MAX_UINT16, slow / FW_SCHED_LOOP_FREQ_DIV1000); + omap_abe_mem_write(abe, OMAP_ABE_DMEM, OMAP_ABE_D_SLOWCOUNTER_ADDR, + &data, sizeof(data)); + return 0; +} +EXPORT_SYMBOL(abe_set_sequence_time_accuracy); diff --git a/sound/soc/omap/abe/abe_seq.h b/sound/soc/omap/abe/abe_seq.h new file mode 100644 index 0000000..e5047ad --- /dev/null +++ b/sound/soc/omap/abe/abe_seq.h @@ -0,0 +1,64 @@ +/* + + This file is provided under a dual BSD/GPLv2 license. When using or + redistributing this file, you may do so under either license. + + GPL LICENSE SUMMARY + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License 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. + The full GNU General Public License is included in this distribution + in the file called LICENSE.GPL. + + BSD LICENSE + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name of Texas Instruments Incorporated nor the names of + its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef _ABE_SEQ_H_ +#define _ABE_SEQ_H_ + +void omap_abe_reset_all_sequence(struct omap_abe *abe); + +#endif /* _ABE_SEQ_H_ */ diff --git a/sound/soc/omap/abe/abe_sm_addr.h b/sound/soc/omap/abe/abe_sm_addr.h new file mode 100644 index 0000000..514ed0c --- /dev/null +++ b/sound/soc/omap/abe/abe_sm_addr.h @@ -0,0 +1,363 @@ +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2010-2011 Texas Instruments Incorporated, + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License 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. + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * BSD LICENSE + * + * Copyright(c) 2010-2011 Texas Instruments Incorporated, + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#define OMAP_ABE_INIT_SM_ADDR 0x0 +#define OMAP_ABE_INIT_SM_SIZE 0xC80 +#define OMAP_ABE_S_DATA0_ADDR 0xC80 +#define OMAP_ABE_S_DATA0_SIZE 0x8 +#define OMAP_ABE_S_TEMP_ADDR 0xC88 +#define OMAP_ABE_S_TEMP_SIZE 0x8 +#define OMAP_ABE_S_PHOENIXOFFSET_ADDR 0xC90 +#define OMAP_ABE_S_PHOENIXOFFSET_SIZE 0x8 +#define OMAP_ABE_S_GTARGET1_ADDR 0xC98 +#define OMAP_ABE_S_GTARGET1_SIZE 0x38 +#define OMAP_ABE_S_GTARGET_DL1_ADDR 0xCD0 +#define OMAP_ABE_S_GTARGET_DL1_SIZE 0x10 +#define OMAP_ABE_S_GTARGET_DL2_ADDR 0xCE0 +#define OMAP_ABE_S_GTARGET_DL2_SIZE 0x10 +#define OMAP_ABE_S_GTARGET_ECHO_ADDR 0xCF0 +#define OMAP_ABE_S_GTARGET_ECHO_SIZE 0x8 +#define OMAP_ABE_S_GTARGET_SDT_ADDR 0xCF8 +#define OMAP_ABE_S_GTARGET_SDT_SIZE 0x8 +#define OMAP_ABE_S_GTARGET_VXREC_ADDR 0xD00 +#define OMAP_ABE_S_GTARGET_VXREC_SIZE 0x10 +#define OMAP_ABE_S_GTARGET_UL_ADDR 0xD10 +#define OMAP_ABE_S_GTARGET_UL_SIZE 0x10 +#define OMAP_ABE_S_GTARGET_BTUL_ADDR 0xD20 +#define OMAP_ABE_S_GTARGET_BTUL_SIZE 0x8 +#define OMAP_ABE_S_GCURRENT_ADDR 0xD28 +#define OMAP_ABE_S_GCURRENT_SIZE 0x90 +#define OMAP_ABE_S_GAIN_ONE_ADDR 0xDB8 +#define OMAP_ABE_S_GAIN_ONE_SIZE 0x8 +#define OMAP_ABE_S_TONES_ADDR 0xDC0 +#define OMAP_ABE_S_TONES_SIZE 0x60 +#define OMAP_ABE_S_VX_DL_ADDR 0xE20 +#define OMAP_ABE_S_VX_DL_SIZE 0x60 +#define OMAP_ABE_S_MM_UL2_ADDR 0xE80 +#define OMAP_ABE_S_MM_UL2_SIZE 0x60 +#define OMAP_ABE_S_MM_DL_ADDR 0xEE0 +#define OMAP_ABE_S_MM_DL_SIZE 0x60 +#define OMAP_ABE_S_DL1_M_OUT_ADDR 0xF40 +#define OMAP_ABE_S_DL1_M_OUT_SIZE 0x60 +#define OMAP_ABE_S_DL2_M_OUT_ADDR 0xFA0 +#define OMAP_ABE_S_DL2_M_OUT_SIZE 0x60 +#define OMAP_ABE_S_ECHO_M_OUT_ADDR 0x1000 +#define OMAP_ABE_S_ECHO_M_OUT_SIZE 0x60 +#define OMAP_ABE_S_SDT_M_OUT_ADDR 0x1060 +#define OMAP_ABE_S_SDT_M_OUT_SIZE 0x60 +#define OMAP_ABE_S_VX_UL_ADDR 0x10C0 +#define OMAP_ABE_S_VX_UL_SIZE 0x60 +#define OMAP_ABE_S_VX_UL_M_ADDR 0x1120 +#define OMAP_ABE_S_VX_UL_M_SIZE 0x60 +#define OMAP_ABE_S_BT_DL_ADDR 0x1180 +#define OMAP_ABE_S_BT_DL_SIZE 0x60 +#define OMAP_ABE_S_BT_UL_ADDR 0x11E0 +#define OMAP_ABE_S_BT_UL_SIZE 0x60 +#define OMAP_ABE_S_BT_DL_8K_ADDR 0x1240 +#define OMAP_ABE_S_BT_DL_8K_SIZE 0x18 +#define OMAP_ABE_S_BT_DL_16K_ADDR 0x1258 +#define OMAP_ABE_S_BT_DL_16K_SIZE 0x28 +#define OMAP_ABE_S_BT_UL_8K_ADDR 0x1280 +#define OMAP_ABE_S_BT_UL_8K_SIZE 0x10 +#define OMAP_ABE_S_BT_UL_16K_ADDR 0x1290 +#define OMAP_ABE_S_BT_UL_16K_SIZE 0x20 +#define OMAP_ABE_S_SDT_F_ADDR 0x12B0 +#define OMAP_ABE_S_SDT_F_SIZE 0x60 +#define OMAP_ABE_S_SDT_F_DATA_ADDR 0x1310 +#define OMAP_ABE_S_SDT_F_DATA_SIZE 0x48 +#define OMAP_ABE_S_MM_DL_OSR_ADDR 0x1358 +#define OMAP_ABE_S_MM_DL_OSR_SIZE 0xC0 +#define OMAP_ABE_S_24_ZEROS_ADDR 0x1418 +#define OMAP_ABE_S_24_ZEROS_SIZE 0xC0 +#define OMAP_ABE_S_DMIC1_ADDR 0x14D8 +#define OMAP_ABE_S_DMIC1_SIZE 0x60 +#define OMAP_ABE_S_DMIC2_ADDR 0x1538 +#define OMAP_ABE_S_DMIC2_SIZE 0x60 +#define OMAP_ABE_S_DMIC3_ADDR 0x1598 +#define OMAP_ABE_S_DMIC3_SIZE 0x60 +#define OMAP_ABE_S_AMIC_ADDR 0x15F8 +#define OMAP_ABE_S_AMIC_SIZE 0x60 +#define OMAP_ABE_S_DMIC1_L_ADDR 0x1658 +#define OMAP_ABE_S_DMIC1_L_SIZE 0x60 +#define OMAP_ABE_S_DMIC1_R_ADDR 0x16B8 +#define OMAP_ABE_S_DMIC1_R_SIZE 0x60 +#define OMAP_ABE_S_DMIC2_L_ADDR 0x1718 +#define OMAP_ABE_S_DMIC2_L_SIZE 0x60 +#define OMAP_ABE_S_DMIC2_R_ADDR 0x1778 +#define OMAP_ABE_S_DMIC2_R_SIZE 0x60 +#define OMAP_ABE_S_DMIC3_L_ADDR 0x17D8 +#define OMAP_ABE_S_DMIC3_L_SIZE 0x60 +#define OMAP_ABE_S_DMIC3_R_ADDR 0x1838 +#define OMAP_ABE_S_DMIC3_R_SIZE 0x60 +#define OMAP_ABE_S_BT_UL_L_ADDR 0x1898 +#define OMAP_ABE_S_BT_UL_L_SIZE 0x60 +#define OMAP_ABE_S_BT_UL_R_ADDR 0x18F8 +#define OMAP_ABE_S_BT_UL_R_SIZE 0x60 +#define OMAP_ABE_S_AMIC_L_ADDR 0x1958 +#define OMAP_ABE_S_AMIC_L_SIZE 0x60 +#define OMAP_ABE_S_AMIC_R_ADDR 0x19B8 +#define OMAP_ABE_S_AMIC_R_SIZE 0x60 +#define OMAP_ABE_S_ECHOREF_L_ADDR 0x1A18 +#define OMAP_ABE_S_ECHOREF_L_SIZE 0x60 +#define OMAP_ABE_S_ECHOREF_R_ADDR 0x1A78 +#define OMAP_ABE_S_ECHOREF_R_SIZE 0x60 +#define OMAP_ABE_S_MM_DL_L_ADDR 0x1AD8 +#define OMAP_ABE_S_MM_DL_L_SIZE 0x60 +#define OMAP_ABE_S_MM_DL_R_ADDR 0x1B38 +#define OMAP_ABE_S_MM_DL_R_SIZE 0x60 +#define OMAP_ABE_S_MM_UL_ADDR 0x1B98 +#define OMAP_ABE_S_MM_UL_SIZE 0x3C0 +#define OMAP_ABE_S_AMIC_96K_ADDR 0x1F58 +#define OMAP_ABE_S_AMIC_96K_SIZE 0xC0 +#define OMAP_ABE_S_DMIC0_96K_ADDR 0x2018 +#define OMAP_ABE_S_DMIC0_96K_SIZE 0xC0 +#define OMAP_ABE_S_DMIC1_96K_ADDR 0x20D8 +#define OMAP_ABE_S_DMIC1_96K_SIZE 0xC0 +#define OMAP_ABE_S_DMIC2_96K_ADDR 0x2198 +#define OMAP_ABE_S_DMIC2_96K_SIZE 0xC0 +#define OMAP_ABE_S_UL_VX_UL_48_8K_ADDR 0x2258 +#define OMAP_ABE_S_UL_VX_UL_48_8K_SIZE 0x60 +#define OMAP_ABE_S_UL_VX_UL_48_16K_ADDR 0x22B8 +#define OMAP_ABE_S_UL_VX_UL_48_16K_SIZE 0x60 +#define OMAP_ABE_S_UL_MIC_48K_ADDR 0x2318 +#define OMAP_ABE_S_UL_MIC_48K_SIZE 0x60 +#define OMAP_ABE_S_VOICE_8K_UL_ADDR 0x2378 +#define OMAP_ABE_S_VOICE_8K_UL_SIZE 0x18 +#define OMAP_ABE_S_VOICE_8K_DL_ADDR 0x2390 +#define OMAP_ABE_S_VOICE_8K_DL_SIZE 0x10 +#define OMAP_ABE_S_MCPDM_OUT1_ADDR 0x23A0 +#define OMAP_ABE_S_MCPDM_OUT1_SIZE 0xC0 +#define OMAP_ABE_S_MCPDM_OUT2_ADDR 0x2460 +#define OMAP_ABE_S_MCPDM_OUT2_SIZE 0xC0 +#define OMAP_ABE_S_MCPDM_OUT3_ADDR 0x2520 +#define OMAP_ABE_S_MCPDM_OUT3_SIZE 0xC0 +#define OMAP_ABE_S_VOICE_16K_UL_ADDR 0x25E0 +#define OMAP_ABE_S_VOICE_16K_UL_SIZE 0x28 +#define OMAP_ABE_S_VOICE_16K_DL_ADDR 0x2608 +#define OMAP_ABE_S_VOICE_16K_DL_SIZE 0x20 +#define OMAP_ABE_S_XINASRC_DL_VX_ADDR 0x2628 +#define OMAP_ABE_S_XINASRC_DL_VX_SIZE 0x140 +#define OMAP_ABE_S_XINASRC_UL_VX_ADDR 0x2768 +#define OMAP_ABE_S_XINASRC_UL_VX_SIZE 0x140 +#define OMAP_ABE_S_XINASRC_MM_EXT_IN_ADDR 0x28A8 +#define OMAP_ABE_S_XINASRC_MM_EXT_IN_SIZE 0x140 +#define OMAP_ABE_S_VX_REC_ADDR 0x29E8 +#define OMAP_ABE_S_VX_REC_SIZE 0x60 +#define OMAP_ABE_S_VX_REC_L_ADDR 0x2A48 +#define OMAP_ABE_S_VX_REC_L_SIZE 0x60 +#define OMAP_ABE_S_VX_REC_R_ADDR 0x2AA8 +#define OMAP_ABE_S_VX_REC_R_SIZE 0x60 +#define OMAP_ABE_S_DL2_M_L_ADDR 0x2B08 +#define OMAP_ABE_S_DL2_M_L_SIZE 0x60 +#define OMAP_ABE_S_DL2_M_R_ADDR 0x2B68 +#define OMAP_ABE_S_DL2_M_R_SIZE 0x60 +#define OMAP_ABE_S_DL2_M_LR_EQ_DATA_ADDR 0x2BC8 +#define OMAP_ABE_S_DL2_M_LR_EQ_DATA_SIZE 0xC8 +#define OMAP_ABE_S_DL1_M_EQ_DATA_ADDR 0x2C90 +#define OMAP_ABE_S_DL1_M_EQ_DATA_SIZE 0xC8 +#define OMAP_ABE_S_EARP_48_96_LP_DATA_ADDR 0x2D58 +#define OMAP_ABE_S_EARP_48_96_LP_DATA_SIZE 0x78 +#define OMAP_ABE_S_IHF_48_96_LP_DATA_ADDR 0x2DD0 +#define OMAP_ABE_S_IHF_48_96_LP_DATA_SIZE 0x78 +#define OMAP_ABE_S_VX_UL_8_TEMP_ADDR 0x2E48 +#define OMAP_ABE_S_VX_UL_8_TEMP_SIZE 0x10 +#define OMAP_ABE_S_VX_UL_16_TEMP_ADDR 0x2E58 +#define OMAP_ABE_S_VX_UL_16_TEMP_SIZE 0x20 +#define OMAP_ABE_S_VX_DL_8_48_LP_DATA_ADDR 0x2E78 +#define OMAP_ABE_S_VX_DL_8_48_LP_DATA_SIZE 0x68 +#define OMAP_ABE_S_VX_DL_8_48_HP_DATA_ADDR 0x2EE0 +#define OMAP_ABE_S_VX_DL_8_48_HP_DATA_SIZE 0x38 +#define OMAP_ABE_S_VX_DL_16_48_LP_DATA_ADDR 0x2F18 +#define OMAP_ABE_S_VX_DL_16_48_LP_DATA_SIZE 0x68 +#define OMAP_ABE_S_VX_DL_16_48_HP_DATA_ADDR 0x2F80 +#define OMAP_ABE_S_VX_DL_16_48_HP_DATA_SIZE 0x28 +#define OMAP_ABE_S_VX_UL_48_8_LP_DATA_ADDR 0x2FA8 +#define OMAP_ABE_S_VX_UL_48_8_LP_DATA_SIZE 0x68 +#define OMAP_ABE_S_VX_UL_48_8_HP_DATA_ADDR 0x3010 +#define OMAP_ABE_S_VX_UL_48_8_HP_DATA_SIZE 0x38 +#define OMAP_ABE_S_VX_UL_48_16_LP_DATA_ADDR 0x3048 +#define OMAP_ABE_S_VX_UL_48_16_LP_DATA_SIZE 0x68 +#define OMAP_ABE_S_VX_UL_48_16_HP_DATA_ADDR 0x30B0 +#define OMAP_ABE_S_VX_UL_48_16_HP_DATA_SIZE 0x28 +#define OMAP_ABE_S_BT_UL_8_48_LP_DATA_ADDR 0x30D8 +#define OMAP_ABE_S_BT_UL_8_48_LP_DATA_SIZE 0x68 +#define OMAP_ABE_S_BT_UL_8_48_HP_DATA_ADDR 0x3140 +#define OMAP_ABE_S_BT_UL_8_48_HP_DATA_SIZE 0x38 +#define OMAP_ABE_S_BT_UL_16_48_LP_DATA_ADDR 0x3178 +#define OMAP_ABE_S_BT_UL_16_48_LP_DATA_SIZE 0x68 +#define OMAP_ABE_S_BT_UL_16_48_HP_DATA_ADDR 0x31E0 +#define OMAP_ABE_S_BT_UL_16_48_HP_DATA_SIZE 0x28 +#define OMAP_ABE_S_BT_DL_48_8_LP_DATA_ADDR 0x3208 +#define OMAP_ABE_S_BT_DL_48_8_LP_DATA_SIZE 0x68 +#define OMAP_ABE_S_BT_DL_48_8_HP_DATA_ADDR 0x3270 +#define OMAP_ABE_S_BT_DL_48_8_HP_DATA_SIZE 0x38 +#define OMAP_ABE_S_BT_DL_48_16_LP_DATA_ADDR 0x32A8 +#define OMAP_ABE_S_BT_DL_48_16_LP_DATA_SIZE 0x68 +#define OMAP_ABE_S_BT_DL_48_16_HP_DATA_ADDR 0x3310 +#define OMAP_ABE_S_BT_DL_48_16_HP_DATA_SIZE 0x28 +#define OMAP_ABE_S_ECHO_REF_48_8_LP_DATA_ADDR 0x3338 +#define OMAP_ABE_S_ECHO_REF_48_8_LP_DATA_SIZE 0x68 +#define OMAP_ABE_S_ECHO_REF_48_8_HP_DATA_ADDR 0x33A0 +#define OMAP_ABE_S_ECHO_REF_48_8_HP_DATA_SIZE 0x38 +#define OMAP_ABE_S_ECHO_REF_48_16_LP_DATA_ADDR 0x33D8 +#define OMAP_ABE_S_ECHO_REF_48_16_LP_DATA_SIZE 0x68 +#define OMAP_ABE_S_ECHO_REF_48_16_HP_DATA_ADDR 0x3440 +#define OMAP_ABE_S_ECHO_REF_48_16_HP_DATA_SIZE 0x28 +#define OMAP_ABE_S_XINASRC_ECHO_REF_ADDR 0x3468 +#define OMAP_ABE_S_XINASRC_ECHO_REF_SIZE 0x140 +#define OMAP_ABE_S_ECHO_REF_16K_ADDR 0x35A8 +#define OMAP_ABE_S_ECHO_REF_16K_SIZE 0x28 +#define OMAP_ABE_S_ECHO_REF_8K_ADDR 0x35D0 +#define OMAP_ABE_S_ECHO_REF_8K_SIZE 0x18 +#define OMAP_ABE_S_DL1_EQ_ADDR 0x35E8 +#define OMAP_ABE_S_DL1_EQ_SIZE 0x60 +#define OMAP_ABE_S_DL2_EQ_ADDR 0x3648 +#define OMAP_ABE_S_DL2_EQ_SIZE 0x60 +#define OMAP_ABE_S_DL1_GAIN_OUT_ADDR 0x36A8 +#define OMAP_ABE_S_DL1_GAIN_OUT_SIZE 0x60 +#define OMAP_ABE_S_DL2_GAIN_OUT_ADDR 0x3708 +#define OMAP_ABE_S_DL2_GAIN_OUT_SIZE 0x60 +#define OMAP_ABE_S_DC_HS_ADDR 0x3768 +#define OMAP_ABE_S_DC_HS_SIZE 0x8 +#define OMAP_ABE_S_DC_HF_ADDR 0x3770 +#define OMAP_ABE_S_DC_HF_SIZE 0x8 +#define OMAP_ABE_S_VIBRA_ADDR 0x3778 +#define OMAP_ABE_S_VIBRA_SIZE 0x30 +#define OMAP_ABE_S_VIBRA2_IN_ADDR 0x37A8 +#define OMAP_ABE_S_VIBRA2_IN_SIZE 0x30 +#define OMAP_ABE_S_VIBRA2_ADDR_ADDR 0x37D8 +#define OMAP_ABE_S_VIBRA2_ADDR_SIZE 0x8 +#define OMAP_ABE_S_VIBRACTRL_FORRIGHTSM_ADDR 0x37E0 +#define OMAP_ABE_S_VIBRACTRL_FORRIGHTSM_SIZE 0xC0 +#define OMAP_ABE_S_RNOISE_MEM_ADDR 0x38A0 +#define OMAP_ABE_S_RNOISE_MEM_SIZE 0x8 +#define OMAP_ABE_S_CTRL_ADDR 0x38A8 +#define OMAP_ABE_S_CTRL_SIZE 0x90 +#define OMAP_ABE_S_VIBRA1_IN_ADDR 0x3938 +#define OMAP_ABE_S_VIBRA1_IN_SIZE 0x30 +#define OMAP_ABE_S_VIBRA1_TEMP_ADDR 0x3968 +#define OMAP_ABE_S_VIBRA1_TEMP_SIZE 0xC0 +#define OMAP_ABE_S_VIBRACTRL_FORLEFTSM_ADDR 0x3A28 +#define OMAP_ABE_S_VIBRACTRL_FORLEFTSM_SIZE 0xC0 +#define OMAP_ABE_S_VIBRA1_MEM_ADDR 0x3AE8 +#define OMAP_ABE_S_VIBRA1_MEM_SIZE 0x58 +#define OMAP_ABE_S_VIBRACTRL_STEREO_ADDR 0x3B40 +#define OMAP_ABE_S_VIBRACTRL_STEREO_SIZE 0xC0 +#define OMAP_ABE_S_AMIC_96_48_DATA_ADDR 0x3C00 +#define OMAP_ABE_S_AMIC_96_48_DATA_SIZE 0x98 +#define OMAP_ABE_S_DMIC0_96_48_DATA_ADDR 0x3C98 +#define OMAP_ABE_S_DMIC0_96_48_DATA_SIZE 0x98 +#define OMAP_ABE_S_DMIC1_96_48_DATA_ADDR 0x3D30 +#define OMAP_ABE_S_DMIC1_96_48_DATA_SIZE 0x98 +#define OMAP_ABE_S_DMIC2_96_48_DATA_ADDR 0x3DC8 +#define OMAP_ABE_S_DMIC2_96_48_DATA_SIZE 0x98 +#define OMAP_ABE_S_DBG_8K_PATTERN_ADDR 0x3E60 +#define OMAP_ABE_S_DBG_8K_PATTERN_SIZE 0x10 +#define OMAP_ABE_S_DBG_16K_PATTERN_ADDR 0x3E70 +#define OMAP_ABE_S_DBG_16K_PATTERN_SIZE 0x20 +#define OMAP_ABE_S_DBG_24K_PATTERN_ADDR 0x3E90 +#define OMAP_ABE_S_DBG_24K_PATTERN_SIZE 0x30 +#define OMAP_ABE_S_DBG_48K_PATTERN_ADDR 0x3EC0 +#define OMAP_ABE_S_DBG_48K_PATTERN_SIZE 0x60 +#define OMAP_ABE_S_DBG_96K_PATTERN_ADDR 0x3F20 +#define OMAP_ABE_S_DBG_96K_PATTERN_SIZE 0xC0 +#define OMAP_ABE_S_MM_EXT_IN_ADDR 0x3FE0 +#define OMAP_ABE_S_MM_EXT_IN_SIZE 0x60 +#define OMAP_ABE_S_MM_EXT_IN_L_ADDR 0x4040 +#define OMAP_ABE_S_MM_EXT_IN_L_SIZE 0x60 +#define OMAP_ABE_S_MM_EXT_IN_R_ADDR 0x40A0 +#define OMAP_ABE_S_MM_EXT_IN_R_SIZE 0x60 +#define OMAP_ABE_S_MIC4_ADDR 0x4100 +#define OMAP_ABE_S_MIC4_SIZE 0x60 +#define OMAP_ABE_S_MIC4_L_ADDR 0x4160 +#define OMAP_ABE_S_MIC4_L_SIZE 0x60 +#define OMAP_ABE_S_SATURATION_7FFF_ADDR 0x41C0 +#define OMAP_ABE_S_SATURATION_7FFF_SIZE 0x8 +#define OMAP_ABE_S_SATURATION_ADDR 0x41C8 +#define OMAP_ABE_S_SATURATION_SIZE 0x8 +#define OMAP_ABE_S_XINASRC_BT_UL_ADDR 0x41D0 +#define OMAP_ABE_S_XINASRC_BT_UL_SIZE 0x140 +#define OMAP_ABE_S_XINASRC_BT_DL_ADDR 0x4310 +#define OMAP_ABE_S_XINASRC_BT_DL_SIZE 0x140 +#define OMAP_ABE_S_BT_DL_8K_TEMP_ADDR 0x4450 +#define OMAP_ABE_S_BT_DL_8K_TEMP_SIZE 0x10 +#define OMAP_ABE_S_BT_DL_16K_TEMP_ADDR 0x4460 +#define OMAP_ABE_S_BT_DL_16K_TEMP_SIZE 0x20 +#define OMAP_ABE_S_VX_DL_8_48_OSR_LP_DATA_ADDR 0x4480 +#define OMAP_ABE_S_VX_DL_8_48_OSR_LP_DATA_SIZE 0xE0 +#define OMAP_ABE_S_BT_UL_8_48_OSR_LP_DATA_ADDR 0x4560 +#define OMAP_ABE_S_BT_UL_8_48_OSR_LP_DATA_SIZE 0xE0 +#define OMAP_ABE_S_MM_DL_44P1_ADDR 0x4640 +#define OMAP_ABE_S_MM_DL_44P1_SIZE 0x300 +#define OMAP_ABE_S_TONES_44P1_ADDR 0x4940 +#define OMAP_ABE_S_TONES_44P1_SIZE 0x300 +#define OMAP_ABE_S_MM_DL_44P1_XK_ADDR 0x4C40 +#define OMAP_ABE_S_MM_DL_44P1_XK_SIZE 0x10 +#define OMAP_ABE_S_TONES_44P1_XK_ADDR 0x4C50 +#define OMAP_ABE_S_TONES_44P1_XK_SIZE 0x10 +#define OMAP_ABE_S_SRC_44P1_MULFAC1_ADDR 0x4C60 +#define OMAP_ABE_S_SRC_44P1_MULFAC1_SIZE 0x8 +#define OMAP_ABE_S_SATURATION_EQ_ADDR 0x4C68 +#define OMAP_ABE_S_SATURATION_EQ_SIZE 0x8 +#define OMAP_ABE_S_BT_DL_48_8_LP_NEW_DATA_ADDR 0x4C70 +#define OMAP_ABE_S_BT_DL_48_8_LP_NEW_DATA_SIZE 0x88 +#define OMAP_ABE_S_BT_DL_8_48_OSR_LP_DATA_ADDR 0x4CF8 +#define OMAP_ABE_S_BT_DL_8_48_OSR_LP_DATA_SIZE 0x3C8 +#define OMAP_ABE_S_VX_UL_48_8_LP_NEW_DATA_ADDR 0x50C0 +#define OMAP_ABE_S_VX_UL_48_8_LP_NEW_DATA_SIZE 0x88 +#define OMAP_ABE_S_VX_UL_8_48_OSR_LP_DATA_ADDR 0x5148 +#define OMAP_ABE_S_VX_UL_8_48_OSR_LP_DATA_SIZE 0x3C8 diff --git a/sound/soc/omap/abe/abe_taskid.h b/sound/soc/omap/abe/abe_taskid.h new file mode 100644 index 0000000..abf31f3 --- /dev/null +++ b/sound/soc/omap/abe/abe_taskid.h @@ -0,0 +1,196 @@ +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2010-2011 Texas Instruments Incorporated, + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License 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. + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * BSD LICENSE + * + * Copyright(c) 2010-2011 Texas Instruments Incorporated, + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef _ABE_TASKID_H_ +#define _ABE_TASKID_H_ +#define C_ABE_FW_TASK_ASRC_VX_DL_8 0 +#define C_ABE_FW_TASK_ASRC_VX_DL_16 1 +#define C_ABE_FW_TASK_ASRC_VX_DL_8_SIB 2 +#define C_ABE_FW_TASK_ASRC_VX_DL_16_SIB 3 +#define C_ABE_FW_TASK_ASRC_MM_EXT_IN 4 +#define C_ABE_FW_TASK_ASRC_VX_UL_8 5 +#define C_ABE_FW_TASK_ASRC_VX_UL_16 6 +#define C_ABE_FW_TASK_ASRC_VX_UL_8_SIB 7 +#define C_ABE_FW_TASK_ASRC_VX_UL_16_SIB 8 +#define C_ABE_FW_TASK_VX_UL_48_8_DEC 9 +#define C_ABE_FW_TASK_VX_UL_48_16_DEC 10 +#define C_ABE_FW_TASK_BT_DL_48_8_DEC 11 +#define C_ABE_FW_TASK_BT_DL_48_16_DEC 12 +#define C_ABE_FW_TASK_ECHO_REF_48_8_DEC 13 +#define C_ABE_FW_TASK_ECHO_REF_48_16_DEC 14 +#define C_ABE_FW_TASK_DL2_EQ 15 +#define C_ABE_FW_TASK_ECHO_REF_48_16 16 +#define C_ABE_FW_TASK_ECHO_REF_48_8 17 +#define C_ABE_FW_TASK_GAIN_UPDATE 18 +#define C_ABE_FW_TASK_SideTone 19 +#define C_ABE_FW_TASK_VX_DL_8_48_LP 20 +#define C_ABE_FW_TASK_VX_DL_8_48_HP 21 +#define C_ABE_FW_TASK_VX_DL_16_48_LP 22 +#define C_ABE_FW_TASK_VX_DL_16_48_HP 23 +#define C_ABE_FW_TASK_VX_UL_48_8_LP 24 +#define C_ABE_FW_TASK_VX_UL_48_8_HP 25 +#define C_ABE_FW_TASK_VX_UL_48_16_LP 26 +#define C_ABE_FW_TASK_VX_UL_48_16_HP 27 +#define C_ABE_FW_TASK_BT_UL_8_48_LP 28 +#define C_ABE_FW_TASK_BT_UL_8_48_HP 29 +#define C_ABE_FW_TASK_BT_UL_16_48_LP 30 +#define C_ABE_FW_TASK_BT_UL_16_48_HP 31 +#define C_ABE_FW_TASK_BT_DL_48_8_LP 32 +#define C_ABE_FW_TASK_BT_DL_48_8_HP 33 +#define C_ABE_FW_TASK_BT_DL_48_16_LP 34 +#define C_ABE_FW_TASK_BT_DL_48_16_HP 35 +#define C_ABE_FW_TASK_ECHO_REF_48_8_LP 36 +#define C_ABE_FW_TASK_ECHO_REF_48_8_HP 37 +#define C_ABE_FW_TASK_ECHO_REF_48_16_LP 38 +#define C_ABE_FW_TASK_ECHO_REF_48_16_HP 39 +#define C_ABE_FW_TASK_DL1_EQ 40 +#define C_ABE_FW_TASK_IHF_48_96_LP 41 +#define C_ABE_FW_TASK_EARP_48_96_LP 42 +#define C_ABE_FW_TASK_DL1_GAIN 43 +#define C_ABE_FW_TASK_DL2_GAIN 44 +#define C_ABE_FW_TASK_IO_PING_PONG 45 +#define C_ABE_FW_TASK_IO_DMIC 46 +#define C_ABE_FW_TASK_IO_PDM_UL 47 +#define C_ABE_FW_TASK_IO_BT_VX_UL 48 +#define C_ABE_FW_TASK_IO_MM_UL 49 +#define C_ABE_FW_TASK_IO_MM_UL2 50 +#define C_ABE_FW_TASK_IO_VX_UL 51 +#define C_ABE_FW_TASK_IO_MM_DL 52 +#define C_ABE_FW_TASK_IO_VX_DL 53 +#define C_ABE_FW_TASK_IO_TONES_DL 54 +#define C_ABE_FW_TASK_IO_VIB_DL 55 +#define C_ABE_FW_TASK_IO_BT_VX_DL 56 +#define C_ABE_FW_TASK_IO_PDM_DL 57 +#define C_ABE_FW_TASK_IO_MM_EXT_OUT 58 +#define C_ABE_FW_TASK_IO_MM_EXT_IN 59 +#define C_ABE_FW_TASK_DEBUG_IRQFIFO 60 +#define C_ABE_FW_TASK_EchoMixer 61 +#define C_ABE_FW_TASK_SDTMixer 62 +#define C_ABE_FW_TASK_DL1Mixer 63 +#define C_ABE_FW_TASK_DL2Mixer 64 +#define C_ABE_FW_TASK_DL1Mixer_dual_mono 65 +#define C_ABE_FW_TASK_DL2Mixer_dual_mono 66 +#define C_ABE_FW_TASK_VXRECMixer 67 +#define C_ABE_FW_TASK_ULMixer 68 +#define C_ABE_FW_TASK_ULMixer_dual_mono 69 +#define C_ABE_FW_TASK_VIBRA_PACK 70 +#define C_ABE_FW_TASK_VX_DL_8_48_0SR 71 +#define C_ABE_FW_TASK_VX_DL_16_48_0SR 72 +#define C_ABE_FW_TASK_BT_UL_8_48_0SR 73 +#define C_ABE_FW_TASK_BT_UL_16_48_0SR 74 +#define C_ABE_FW_TASK_IHF_48_96_0SR 75 +#define C_ABE_FW_TASK_EARP_48_96_0SR 76 +#define C_ABE_FW_TASK_AMIC_SPLIT 77 +#define C_ABE_FW_TASK_DMIC1_SPLIT 78 +#define C_ABE_FW_TASK_DMIC2_SPLIT 79 +#define C_ABE_FW_TASK_DMIC3_SPLIT 80 +#define C_ABE_FW_TASK_VXREC_SPLIT 81 +#define C_ABE_FW_TASK_BT_UL_SPLIT 82 +#define C_ABE_FW_TASK_MM_SPLIT 83 +#define C_ABE_FW_TASK_VIBRA_SPLIT 84 +#define C_ABE_FW_TASK_MM_EXT_IN_SPLIT 85 +#define C_ABE_FW_TASK_ECHO_REF_SPLIT 86 +#define C_ABE_FW_TASK_UNUSED_1 87 +#define C_ABE_FW_TASK_VX_UL_ROUTING 88 +#define C_ABE_FW_TASK_MM_UL2_ROUTING 89 +#define C_ABE_FW_TASK_VIBRA1 90 +#define C_ABE_FW_TASK_VIBRA2 91 +#define C_ABE_FW_TASK_BT_UL_16_48 92 +#define C_ABE_FW_TASK_BT_UL_8_48 93 +#define C_ABE_FW_TASK_BT_DL_48_16 94 +#define C_ABE_FW_TASK_BT_DL_48_8 95 +#define C_ABE_FW_TASK_VX_DL_16_48 96 +#define C_ABE_FW_TASK_VX_DL_8_48 97 +#define C_ABE_FW_TASK_VX_UL_48_16 98 +#define C_ABE_FW_TASK_VX_UL_48_8 99 +#define C_ABE_FW_TASK_DBG_SYNC 100 +#define C_ABE_FW_TASK_AMIC_96_48_LP 101 +#define C_ABE_FW_TASK_DMIC1_96_48_LP 102 +#define C_ABE_FW_TASK_DMIC2_96_48_LP 103 +#define C_ABE_FW_TASK_DMIC3_96_48_LP 104 +#define C_ABE_FW_TASK_INIT_FW_MEMORY 105 +#define C_ABE_FW_TASK_DEBUGTRACE_VX_ASRCs 106 +#define C_ABE_FW_TASK_ASRC_BT_UL_8 107 +#define C_ABE_FW_TASK_ASRC_BT_UL_16 108 +#define C_ABE_FW_TASK_ASRC_BT_UL_8_SIB 109 +#define C_ABE_FW_TASK_ASRC_BT_UL_16_SIB 110 +#define C_ABE_FW_TASK_ASRC_BT_DL_8 111 +#define C_ABE_FW_TASK_ASRC_BT_DL_16 112 +#define C_ABE_FW_TASK_ASRC_BT_DL_8_SIB 113 +#define C_ABE_FW_TASK_ASRC_BT_DL_16_SIB 114 +#define C_ABE_FW_TASK_BT_DL_48_8_HP_OPP100 115 +#define C_ABE_FW_TASK_BT_DL_48_16_HP_OPP100 116 +#define C_ABE_FW_TASK_BT_DL_48_8_OPP100 117 +#define C_ABE_FW_TASK_BT_DL_48_16_OPP100 118 +#define C_ABE_FW_TASK_VX_DL_8_48_OSR_LP 119 +#define C_ABE_FW_TASK_VX_DL_8_48_FIR 120 +#define C_ABE_FW_TASK_BT_UL_8_48_OSR_LP 121 +#define C_ABE_FW_TASK_BT_UL_8_48_FIR 122 +#define C_ABE_FW_TASK_SRC44P1_MMDL 123 +#define C_ABE_FW_TASK_SRC44P1_TONES 124 +#define C_ABE_FW_TASK_SRC44P1_MMDL_1211 125 +#define C_ABE_FW_TASK_SRC44P1_TONES_1211 126 +#define C_ABE_FW_TASK_SRC44P1_MMDL_PP 127 +#define C_ABE_FW_TASK_SRC44P1_MMDL_1211_PP 128 +#define C_ABE_FW_TASK_CHECK_IIR_LEFT 129 +#define C_ABE_FW_TASK_CHECK_IIR_RIGHT 130 +#define C_ABE_FW_TASK_BT_DL_48_8_LP_FIR 131 +#define C_ABE_FW_TASK_BT_DL_48_8_FIR 132 +#define C_ABE_FW_TASK_BT_DL_48_8_FIR_OPP100 133 +#define C_ABE_FW_TASK_VX_UL_48_8_FIR 134 +#define C_ABE_FW_TASK_VX_UL_48_8_LP_FIR 135 +#endif /* _ABE_TASKID_H_ */ diff --git a/sound/soc/omap/abe/abe_typ.h b/sound/soc/omap/abe/abe_typ.h new file mode 100644 index 0000000..650d043 --- /dev/null +++ b/sound/soc/omap/abe/abe_typ.h @@ -0,0 +1,654 @@ +/* + + This file is provided under a dual BSD/GPLv2 license. When using or + redistributing this file, you may do so under either license. + + GPL LICENSE SUMMARY + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License 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. + The full GNU General Public License is included in this distribution + in the file called LICENSE.GPL. + + BSD LICENSE + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name of Texas Instruments Incorporated nor the names of + its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include "abe_def.h" +#include "abe_initxxx_labels.h" + +#ifndef _ABE_TYP_H_ +#define _ABE_TYP_H_ +/* + * BASIC TYPES + */ +#define MAX_UINT8 ((((1L << 7) - 1) << 1) + 1) +#define MAX_UINT16 ((((1L << 15) - 1) << 1) + 1) +#define MAX_UINT32 ((((1L << 31) - 1) << 1) + 1) +#define s8 char +#define u8 unsigned char +#define s16 short +#define u16 unsigned short +#define s32 int +#define u32 unsigned int +/* returned status from HAL APIs */ +#define abehal_status u32 +/* 4 bytes Bit field indicating the type of informations to be traced */ +typedef u32 abe_dbg_mask_t; +/* scheduling task loops (250us / 272us with respectively 48kHz / + 44.1kHz on Phoenix). */ +typedef u32 abe_dbg_t; +/* Index to the table of sequences */ +typedef u32 abe_seq_code_t; +/* Index to the table of subroutines called in the sequence */ +typedef u32 abe_sub_code_t; +/* subroutine with no parameter */ +typedef void (*abe_subroutine0) (void); +/* subroutine with one parameter */ +typedef void (*abe_subroutine1) (u32); +typedef void (*abe_subroutine2) (u32, u32); +typedef void (*abe_subroutine3) (u32, u32, u32); +typedef void (*abe_subroutine4) (u32, u32, u32, u32); +/* + * CODE PORTABILITY - FUTURE PATCHES + * + * 32bits field for having the code compatible with future revisions of + * the hardware (audio integration) or evolution of the software + * partitionning. Used for the highest level APIs (launch_sequences) + */ +typedef u32 abe_patch_rev; +/* + * ENUMS + */ +/* + * MEMORY CONFIG TYPE + * + * 0: Ultra Lowest power consumption audio player + * 1: OPP 25% (simple multimedia features) + * 2: OPP 50% (multimedia and voice calls) + * 3: OPP100% (multimedia complex use-cases) + */ +#define ABE_AUDIO_PLAYER_ON_HEADSET_OR_EARPHONE 1 +#define ABE_DRIFT_MANAGEMENT_FOR_AUDIO_PLAYER 2 +#define ABE_DRIFT_MANAGEMENT_FOR_VOICE_CALL 3 +#define ABE_VOICE_CALL_ON_HEADSET_OR_EARPHONE_OR_BT 4 +#define ABE_MULTIMEDIA_AUDIO_RECORDER 5 +#define ABE_VIBRATOR_OR_HAPTICS 6 +#define ABE_VOICE_CALL_ON_HANDS_FREE_SPEAKER 7 +#define ABE_RINGER_TONES 8 +#define ABE_VOICE_CALL_WITH_EARPHONE_ACTIVE_NOISE_CANCELLER 9 +#define ABE_LAST_USE_CASE 10 +/* + * OPP TYPE + * + * 0: Ultra Lowest power consumption audio player + * 1: OPP 25% (simple multimedia features) + * 2: OPP 50% (multimedia and voice calls) + * 3: OPP100% (multimedia complex use-cases) + */ +#define ABE_OPP0 0 +#define ABE_OPP25 1 +#define ABE_OPP50 2 +#define ABE_OPP100 3 +/* + * DMIC DECIMATION RATIO + * + */ +#define ABE_DEC16 16 +#define ABE_DEC25 25 +#define ABE_DEC32 32 +#define ABE_DEC40 40 +/* + * SAMPLES TYPE + * + * mono 16 bit sample LSB aligned, 16 MSB bits are unused; + * mono right shifted to 16bits LSBs on a 32bits DMEM FIFO for McBSP + * TX purpose; + * mono sample MSB aligned (16/24/32bits); + * two successive mono samples in one 32bits container; + * Two L/R 16bits samples in a 32bits container; + * Two channels defined with two MSB aligned samples; + * Three channels defined with three MSB aligned samples (MIC); + * Four channels defined with four MSB aligned samples (MIC); + * . . . + * Eight channels defined with eight MSB aligned samples (MIC); + */ +#define MONO_MSB 1 +#define MONO_RSHIFTED_16 2 +#define STEREO_RSHIFTED_16 3 +#define STEREO_16_16 4 +#define STEREO_MSB 5 +#define THREE_MSB 6 +#define FOUR_MSB 7 +#define FIVE_MSB 8 +#define SIX_MSB 9 +#define SEVEN_MSB 10 +#define EIGHT_MSB 11 +#define NINE_MSB 12 +#define TEN_MSB 13 +/* + * PORT PROTOCOL TYPE - abe_port_protocol_switch_id + */ +#define SLIMBUS_PORT_PROT 1 +#define SERIAL_PORT_PROT 2 +#define TDM_SERIAL_PORT_PROT 3 +#define DMIC_PORT_PROT 4 +#define MCPDMDL_PORT_PROT 5 +#define MCPDMUL_PORT_PROT 6 +#define PINGPONG_PORT_PROT 7 +#define DMAREQ_PORT_PROT 8 +/* + * PORT IDs, this list is aligned with the FW data mapping + */ +#define OMAP_ABE_DMIC_PORT 0 +#define OMAP_ABE_PDM_UL_PORT 1 +#define OMAP_ABE_BT_VX_UL_PORT 2 +#define OMAP_ABE_MM_UL_PORT 3 +#define OMAP_ABE_MM_UL2_PORT 4 +#define OMAP_ABE_VX_UL_PORT 5 +#define OMAP_ABE_MM_DL_PORT 6 +#define OMAP_ABE_VX_DL_PORT 7 +#define OMAP_ABE_TONES_DL_PORT 8 +#define OMAP_ABE_VIB_DL_PORT 9 +#define OMAP_ABE_BT_VX_DL_PORT 10 +#define OMAP_ABE_PDM_DL_PORT 11 +#define OMAP_ABE_MM_EXT_OUT_PORT 12 +#define OMAP_ABE_MM_EXT_IN_PORT 13 +#define TDM_DL_PORT 14 +#define TDM_UL_PORT 15 +#define DEBUG_PORT 16 +#define LAST_PORT_ID 17 +/* definitions for the compatibility with HAL05xx */ +#define PDM_DL1_PORT 18 +#define PDM_DL2_PORT 19 +#define PDM_VIB_PORT 20 +/* There is only one DMIC port, always used with 6 samples + per 96kHz periods */ +#define DMIC_PORT1 DMIC_PORT +#define DMIC_PORT2 DMIC_PORT +#define DMIC_PORT3 DMIC_PORT +/* + * ABE_DL_SRC_ID source of samples + */ +#define SRC_DL1_MIXER_OUTPUT DL1_M_labelID +#define SRC_SDT_MIXER_OUTPUT SDT_M_labelID +#define SRC_DL1_GAIN_OUTPUT DL1_GAIN_out_labelID +#define SRC_DL1_EQ_OUTPUT DL1_EQ_labelID +#define SRC_DL2_GAIN_OUTPUT DL2_GAIN_out_labelID +#define SRC_DL2_EQ_OUTPUT DL2_EQ_labelID +#define SRC_MM_DL MM_DL_labelID +#define SRC_TONES_DL Tones_labelID +#define SRC_VX_DL VX_DL_labelID +#define SRC_VX_UL VX_UL_labelID +#define SRC_MM_UL2 MM_UL2_labelID +#define SRC_MM_UL MM_UL_labelID +/* + * abe_patched_pattern_id + * selection of the audio engine signal to + * replace by a precomputed pattern + */ +#define DBG_PATCH_AMIC 1 +#define DBG_PATCH_DMIC1 2 +#define DBG_PATCH_DMIC2 3 +#define DBG_PATCH_DMIC3 4 +#define DBG_PATCH_VX_REC 5 +#define DBG_PATCH_BT_UL 6 +#define DBG_PATCH_MM_DL 7 +#define DBG_PATCH_DL2_EQ 8 +#define DBG_PATCH_VIBRA 9 +#define DBG_PATCH_MM_EXT_IN 10 +#define DBG_PATCH_EANC_FBK_Out 11 +#define DBG_PATCH_MIC4 12 +#define DBG_PATCH_MM_DL_MIXDL1 13 +#define DBG_PATCH_MM_DL_MIXDL2 14 +/* + * Signal processing module names - EQ APS MIX ROUT + */ +/* equalizer downlink path headset + earphone */ +#define FEAT_EQ1 1 +/* equalizer downlink path integrated handsfree LEFT */ +#define FEAT_EQ2L (FEAT_EQ1+1) +/* equalizer downlink path integrated handsfree RIGHT */ +#define FEAT_EQ2R (FEAT_EQ2L+1) +/* equalizer downlink path side-tone */ +#define FEAT_EQSDT (FEAT_EQ2R+1) +/* equalizer uplink path AMIC */ +#define FEAT_EQAMIC (FEAT_EQSDT+1) +/* equalizer uplink path DMIC */ +#define FEAT_EQDMIC (FEAT_EQAMIC+1) +/* Acoustic protection for headset */ +#define FEAT_APS1 (FEAT_EQDMIC+1) +/* acoustic protection high-pass filter for handsfree "Left" */ +#define FEAT_APS2 (FEAT_APS1+1) +/* acoustic protection high-pass filter for handsfree "Right" */ +#define FEAT_APS3 (FEAT_APS2+1) +/* asynchronous sample-rate-converter for the downlink voice path */ +#define FEAT_ASRC1 (FEAT_APS3+1) +/* asynchronous sample-rate-converter for the uplink voice path */ +#define FEAT_ASRC2 (FEAT_ASRC1+1) +/* asynchronous sample-rate-converter for the multimedia player */ +#define FEAT_ASRC3 (FEAT_ASRC2+1) +/* asynchronous sample-rate-converter for the echo reference */ +#define FEAT_ASRC4 (FEAT_ASRC3+1) +/* mixer of the headset and earphone path */ +#define FEAT_MIXDL1 (FEAT_ASRC4+1) +/* mixer of the hands-free path */ +#define FEAT_MIXDL2 (FEAT_MIXDL1+1) +/* mixer for audio being sent on the voice_ul path */ +#define FEAT_MIXAUDUL (FEAT_MIXDL2+1) +/* mixer for voice communication recording */ +#define FEAT_MIXVXREC (FEAT_MIXAUDUL+1) +/* mixer for side-tone */ +#define FEAT_MIXSDT (FEAT_MIXVXREC+1) +/* mixer for echo reference */ +#define FEAT_MIXECHO (FEAT_MIXSDT+1) +/* router of the uplink path */ +#define FEAT_UPROUTE (FEAT_MIXECHO+1) +/* all gains */ +#define FEAT_GAINS (FEAT_UPROUTE+1) +#define FEAT_GAINS_DMIC1 (FEAT_GAINS+1) +#define FEAT_GAINS_DMIC2 (FEAT_GAINS_DMIC1+1) +#define FEAT_GAINS_DMIC3 (FEAT_GAINS_DMIC2+1) +#define FEAT_GAINS_AMIC (FEAT_GAINS_DMIC3+1) +#define FEAT_GAINS_SPLIT (FEAT_GAINS_AMIC+1) +#define FEAT_GAINS_DL1 (FEAT_GAINS_SPLIT+1) +#define FEAT_GAINS_DL2 (FEAT_GAINS_DL1+1) +#define FEAT_GAIN_BTUL (FEAT_GAINS_DL2+1) +/* sequencing queue of micro tasks */ +#define FEAT_SEQ (FEAT_GAIN_BTUL+1) +/* Phoenix control queue through McPDM */ +#define FEAT_CTL (FEAT_SEQ+1) +/* list of features of the firmware -------------------------------*/ +#define MAXNBFEATURE FEAT_CTL +/* abe_equ_id */ +/* equalizer downlink path headset + earphone */ +#define EQ1 FEAT_EQ1 +/* equalizer downlink path integrated handsfree LEFT */ +#define EQ2L FEAT_EQ2L +#define EQ2R FEAT_EQ2R +/* equalizer downlink path side-tone */ +#define EQSDT FEAT_EQSDT +#define EQAMIC FEAT_EQAMIC +#define EQDMIC FEAT_EQDMIC +/* abe_aps_id */ +/* Acoustic protection for headset */ +#define APS1 FEAT_APS1 +#define APS2L FEAT_APS2 +#define APS2R FEAT_APS3 +/* abe_asrc_id */ +/* asynchronous sample-rate-converter for the downlink voice path */ +#define ASRC1 FEAT_ASRC1 +/* asynchronous sample-rate-converter for the uplink voice path */ +#define ASRC2 FEAT_ASRC2 +/* asynchronous sample-rate-converter for the multimedia player */ +#define ASRC3 FEAT_ASRC3 +/* asynchronous sample-rate-converter for the voice uplink echo_reference */ +#define ASRC4 FEAT_ASRC4 +/* abe_mixer_id */ +#define MIXDL1 FEAT_MIXDL1 +#define MIXDL2 FEAT_MIXDL2 +#define MIXSDT FEAT_MIXSDT +#define MIXECHO FEAT_MIXECHO +#define MIXAUDUL FEAT_MIXAUDUL +#define MIXVXREC FEAT_MIXVXREC +/* abe_router_id */ +/* there is only one router up to now */ +#define UPROUTE FEAT_UPROUTE +/* + * GAIN IDs + */ +#define GAINS_DMIC1 FEAT_GAINS_DMIC1 +#define GAINS_DMIC2 FEAT_GAINS_DMIC2 +#define GAINS_DMIC3 FEAT_GAINS_DMIC3 +#define GAINS_AMIC FEAT_GAINS_AMIC +#define GAINS_SPLIT FEAT_GAINS_SPLIT +#define GAINS_DL1 FEAT_GAINS_DL1 +#define GAINS_DL2 FEAT_GAINS_DL2 +#define GAINS_BTUL FEAT_GAIN_BTUL +/* + * EVENT GENERATORS - abe_event_id + */ +#define EVENT_TIMER 0 +#define EVENT_44100 1 +/* + * SERIAL PORTS IDs - abe_mcbsp_id + */ +#define MCBSP1_TX MCBSP1_DMA_TX +#define MCBSP1_RX MCBSP1_DMA_RX +#define MCBSP2_TX MCBSP2_DMA_TX +#define MCBSP2_RX MCBSP2_DMA_RX +#define MCBSP3_TX MCBSP3_DMA_TX +#define MCBSP3_RX MCBSP3_DMA_RX +/* + * SERIAL PORTS IDs - abe_slimbus_id; + */ +#define SLIMBUS1_TX0 SLIMBUS1_DMA_TX0 +#define SLIMBUS1_TX1 SLIMBUS1_DMA_TX1 +#define SLIMBUS1_TX2 SLIMBUS1_DMA_TX2 +#define SLIMBUS1_TX3 SLIMBUS1_DMA_TX3 +#define SLIMBUS1_TX4 SLIMBUS1_DMA_TX4 +#define SLIMBUS1_TX5 SLIMBUS1_DMA_TX5 +#define SLIMBUS1_TX6 SLIMBUS1_DMA_TX6 +#define SLIMBUS1_TX7 SLIMBUS1_DMA_TX7 +#define SLIMBUS1_RX0 SLIMBUS1_DMA_RX0 +#define SLIMBUS1_RX1 SLIMBUS1_DMA_RX1 +#define SLIMBUS1_RX2 SLIMBUS1_DMA_RX2 +#define SLIMBUS1_RX3 SLIMBUS1_DMA_RX3 +#define SLIMBUS1_RX4 SLIMBUS1_DMA_RX4 +#define SLIMBUS1_RX5 SLIMBUS1_DMA_RX5 +#define SLIMBUS1_RX6 SLIMBUS1_DMA_RX6 +#define SLIMBUS1_RX7 SLIMBUS1_DMA_RX7 +#define SLIMBUS_UNUSED _DUMMY_FIFO_ +/* + * ----------------- TYPES USED FOR APIS --------------- + */ + +/* + * EQU_T + * + * coefficients of the equalizer + */ +typedef struct { + /* type of filter */ + u32 equ_type; + /* filter length */ + u32 equ_length; + union { + /* parameters are the direct and recursive coefficients in */ + /* Q6.26 integer fixed-point format. */ + s32 type1[NBEQ1]; + struct { + /* center frequency of the band [Hz] */ + s32 freq[NBEQ2]; + /* gain of each band. [dB] */ + s32 gain[NBEQ2]; + /* Q factor of this band [dB] */ + s32 q[NBEQ2]; + } type2; + } coef; + s32 equ_param3; +} abe_equ_t; + +/* + * APS_T + * + * coefficients of the Acoustics Protection and Safety + */ +struct abe_aps_t { + s32 coef1[NBAPS1]; + s32 coef2[NBAPS2]; +}; + +struct abe_aps_energy_t { + /* structure of two energy_t estimation for coil and membrane */ + u32 e1; + u32 e2; +}; +/* + * ROUTER_T + * + * table of indexes in unsigned bytes + */ +typedef u16 abe_router_t; +/* + * DATA_FORMAT_T + * + * used in port declaration + */ +typedef struct { + /* Sampling frequency of the stream */ + u32 f; + /* Sample format type */ + u32 samp_format; +} abe_data_format_t; +/* + * PORT_PROTOCOL_T + * + * port declaration + */ +typedef struct { + /* Direction=0 means input from AESS point of view */ + u32 direction; + /* Protocol type (switch) during the data transfers */ + u32 protocol_switch; + union { + /* Slimbus peripheral connected to ATC */ + struct { + /* Address of ATC Slimbus descriptor's index */ + u32 desc_addr1; + /* DMEM address 1 in bytes */ + u32 buf_addr1; + /* DMEM buffer size size in bytes */ + u32 buf_size; + /* ITERation on each DMAreq signals */ + u32 iter; + /* Second ATC index for SlimBus reception (or NULL) */ + u32 desc_addr2; + /* DMEM address 2 in bytes */ + u32 buf_addr2; + } prot_slimbus; + /* McBSP/McASP peripheral connected to ATC */ + struct { + u32 desc_addr; + /* Address of ATC McBSP/McASP descriptor's in bytes */ + u32 buf_addr; + /* DMEM address in bytes */ + u32 buf_size; + /* ITERation on each DMAreq signals */ + u32 iter; + } prot_serial; + /* DMIC peripheral connected to ATC */ + struct { + /* DMEM address in bytes */ + u32 buf_addr; + /* DMEM buffer size in bytes */ + u32 buf_size; + /* Number of activated DMIC */ + u32 nbchan; + } prot_dmic; + /* McPDMDL peripheral connected to ATC */ + struct { + /* DMEM address in bytes */ + u32 buf_addr; + /* DMEM size in bytes */ + u32 buf_size; + /* Control allowed on McPDM DL */ + u32 control; + } prot_mcpdmdl; + /* McPDMUL peripheral connected to ATC */ + struct { + /* DMEM address size in bytes */ + u32 buf_addr; + /* DMEM buffer size size in bytes */ + u32 buf_size; + } prot_mcpdmul; + /* Ping-Pong interface to the Host using cache-flush */ + struct { + /* Address of ATC descriptor's */ + u32 desc_addr; + /* DMEM buffer base address in bytes */ + u32 buf_addr; + /* DMEM size in bytes for each ping and pong buffers */ + u32 buf_size; + /* IRQ address (either DMA (0) MCU (1) or DSP(2)) */ + u32 irq_addr; + /* IRQ data content loaded in the AESS IRQ register */ + u32 irq_data; + /* Call-back function upon IRQ reception */ + u32 callback; + } prot_pingpong; + /* DMAreq line to CBPr */ + struct { + /* Address of ATC descriptor's */ + u32 desc_addr; + /* DMEM buffer address in bytes */ + u32 buf_addr; + /* DMEM buffer size size in bytes */ + u32 buf_size; + /* ITERation on each DMAreq signals */ + u32 iter; + /* DMAreq address */ + u32 dma_addr; + /* DMA/AESS = 1 << #DMA */ + u32 dma_data; + } prot_dmareq; + /* Circular buffer - direct addressing to DMEM */ + struct { + /* DMEM buffer base address in bytes */ + u32 buf_addr; + /* DMEM buffer size in bytes */ + u32 buf_size; + /* DMAreq address */ + u32 dma_addr; + /* DMA/AESS = 1 << #DMA */ + u32 dma_data; + } prot_circular_buffer; + } p; +} abe_port_protocol_t; +/* + * DMA_T + * + * dma structure for easing programming + */ +typedef struct { + /* OCP L3 pointer to the first address of the */ + void *data; + /* destination buffer (either DMA or Ping-Pong read/write pointers). */ + /* address L3 when addressing the DMEM buffer instead of CBPr */ + void *l3_dmem; + /* address L3 translated to L4 the ARM memory space */ + void *l4_dmem; + /* number of iterations for the DMA data moves. */ + u32 iter; +} abe_dma_t; + +typedef struct { + /* Offset to the first address of the */ + u32 data; + /* number of iterations for the DMA data moves. */ + u32 iter; +} abe_dma_t_offset; +/* + * SEQ_T + * + * struct { + * micros_t time; Waiting time before executing next line + * seq_code_t code Subroutine index interpreted in the HAL + * and translated to FW subroutine codes + * in case of ABE tasks + * int32 param[2] Two parameters + * } seq_t + * + */ +typedef struct { + u32 delta_time; + u32 code; + u32 param[4]; + u8 tag; +} abe_seq_t; + +typedef struct { + u32 mask; + abe_seq_t seq1; + abe_seq_t seq2; +} abe_sequence_t; +/* + * DRIFT_T abe_drift_t = s32 + * + * ASRC drift parameter in [ppm] value + */ +/* + * -------------------- INTERNAL DATA TYPES --------------------- + */ +/* + * ABE_IRQ_DATA_T + * + * IRQ FIFO content declaration + * APS interrupts : IRQ_FIFO[31:28] = IRQtag_APS, + * IRQ_FIFO[27:16] = APS_IRQs, IRQ_FIFO[15:0] = loopCounter + * SEQ interrupts : IRQ_FIFO[31:28] IRQtag_COUNT, + * IRQ_FIFO[27:16] = Count_IRQs, IRQ_FIFO[15:0] = loopCounter + * Ping-Pong Interrupts : IRQ_FIFO[31:28] = IRQtag_PP, + * IRQ_FIFO[27:16] = PP_MCU_IRQ, IRQ_FIFO[15:0] = loopCounter + */ +typedef struct { + unsigned int counter:16; + unsigned int data:12; + unsigned int tag:4; +} abe_irq_data_t; +/* + * ABE_PORT_T status / format / sampling / protocol(call_back) / + * features / gain / name .. + * + */ +typedef struct { + /* running / idled */ + u16 status; + /* Sample format type */ + abe_data_format_t format; + /* API : for ASRC */ + s32 drift; + /* optionnal call-back index for errors and ack */ + u16 callback; + /* IO tasks buffers */ + u16 smem_buffer1; + u16 smem_buffer2; + abe_port_protocol_t protocol; + /* pointer and iteration counter of the xDMA */ + abe_dma_t_offset dma; + /* list of features associated to a port (EQ, APS, ... , ends with 0) */ + u16 feature_index[MAXFEATUREPORT]; + char name[NBCHARPORTNAME]; +} abe_port_t; +/* + * ABE_SUBROUTINE_T + * + */ +typedef struct { + u32 sub_id; + s32 param[4]; +} abe_subroutine_t; + +#endif/* ifndef _ABE_TYP_H_ */ diff --git a/sound/soc/omap/abe/abe_typedef.h b/sound/soc/omap/abe/abe_typedef.h new file mode 100644 index 0000000..943968e --- /dev/null +++ b/sound/soc/omap/abe/abe_typedef.h @@ -0,0 +1,240 @@ +/* + + This file is provided under a dual BSD/GPLv2 license. When using or + redistributing this file, you may do so under either license. + + GPL LICENSE SUMMARY + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License 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. + The full GNU General Public License is included in this distribution + in the file called LICENSE.GPL. + + BSD LICENSE + + Copyright(c) 2010-2011 Texas Instruments Incorporated, + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name of Texas Instruments Incorporated nor the names of + its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef _ABE_TYPEDEF_H_ +#define _ABE_TYPEDEF_H_ + +#include "abe_define.h" +#include "abe_typ.h" + +/* + * Basic types definition + */ +/* + * Commonly used structures + */ +typedef struct abetaskTag { + /* 0 ... Index of called function */ + u16 iF; + /* 2 ... for INITPTR of A0 */ + u16 A0; + /* 4 ... for INITPTR of A1 */ + u16 A1; + /* 6 ... for INITPTR of A2 & A3 */ + u16 A2_3; + /* 8 ... for INITPTR of A4 & A5 */ + u16 A4_5; + /* 10 ... for INITREG of R0, R1, R2, R3 */ + u16 R; + /* 12 */ + u16 misc0; + /* 14 */ + u16 misc1; +} ABE_STask; +typedef ABE_STask *pABE_STask; +typedef ABE_STask **ppABE_STask; + +struct ABE_SIODescriptor { + /* 0 */ + u16 drift_ASRC; + /* 2 */ + u16 drift_io; + /* 4 "Function index" of XLS sheet "Functions" */ + u8 io_type_idx; + /* 5 1 = MONO or Stereo1616, 2= STEREO, ... */ + u8 samp_size; + /* 6 drift "issues" for ASRC */ + s16 flow_counter; + /* 8 address for IRQ or DMArequests */ + u16 hw_ctrl_addr; + /* 10 DMA request bit-field or IRQ (DSP/MCU) */ + u8 atc_irq_data; + /* 11 0 = Read, 3 = Write */ + u8 direction_rw; + /* 12 */ + u8 repeat_last_samp; + /* 13 12 at 48kHz, ... */ + u8 nsamp; + /* 14 nsamp x samp_size */ + u8 x_io; + /* 15 ON = 0x80, OFF = 0x00 */ + u8 on_off; + /* 16 For Slimbus and TDM purpose */ + u16 split_addr1; + /* 18 */ + u16 split_addr2; + /* 20 */ + u16 split_addr3; + /* 22 */ + u8 before_f_index; + /* 23 */ + u8 after_f_index; + /* 24 SM/CM INITPTR field */ + u16 smem_addr1; + /* 26 in bytes */ + u16 atc_address1; + /* 28 DMIC_ATC_PTR, MCPDM_UL_ATC_PTR, ... */ + u16 atc_pointer_saved1; + /* 30 samp_size (except in TDM or Slimbus) */ + u8 data_size1; + /* 31 "Function index" of XLS sheet "Functions" */ + u8 copy_f_index1; + /* 32 For Slimbus and TDM purpose */ + u16 smem_addr2; + /* 34 */ + u16 atc_address2; + /* 36 */ + u16 atc_pointer_saved2; + /* 38 */ + u8 data_size2; + /* 39 */ + u8 copy_f_index2; +}; + +/* [w] asrc output used for the next asrc call (+/- 1 / 0) */ +#define drift_asrc_ 0 +/* [w] asrc output used for controlling the number of samples to be + exchanged (+/- 1 / 0) */ +#define drift_io_ 2 +/* address of the IO subroutine */ +#define io_type_idx_ 4 +#define samp_size_ 5 +/* flow error counter */ +#define flow_counter_ 6 +/* dmareq address or host irq buffer address (atc address) */ +#define hw_ctrl_addr_ 8 +/* data content to be loaded to "hw_ctrl_addr" */ +#define atc_irq_data_ 10 +/* read dmem =0, write dmem =3 (atc offset of the access pointer) */ +#define direction_rw_ 11 +/* flag set to allow repeating the last sample on downlink paths */ +#define repeat_last_samp_ 12 +/* number of samples (either mono stereo...) */ +#define nsamp_ 13 +/* x number of raw DMEM data moved */ +#define x_io_ 14 +#define on_off_ 15 +/* internal smem buffer initptr pointer index */ +#define split_addr1_ 16 +/* internal smem buffer initptr pointer index */ +#define split_addr2_ 18 +/* internal smem buffer initptr pointer index */ +#define split_addr3_ 20 +/* index of the copy subroutine */ +#define before_f_index_ 22 +/* index of the copy subroutine */ +#define after_f_index_ 23 +#define minidesc1_ 24 +/* internal smem buffer initptr pointer index */ +#define rel_smem_ 0 +/* atc descriptor address (byte address x4) */ +#define rel_atc_ 2 +/* location of the saved ATC pointer (+debug info) */ +#define rel_atc_saved 4 +/* size of each sample (1:mono/1616 2:stereo ... ) */ +#define rel_size_ 6 +/* index of the copy subroutine */ +#define rel_f_ 7 +#define s_mem_mm_ul 24 +#define s_mm_ul_size 30 +#define minidesc2_ 32 +#define Struct_Size 40 + +struct ABE_SPingPongDescriptor { + /* 0: [W] asrc output used for the next ASRC call (+/- 1 / 0) */ + u16 drift_ASRC; + /* 2: [W] asrc output used for controlling the number of + samples to be exchanged (+/- 1 / 0) */ + u16 drift_io; + /* 4: DMAReq address or HOST IRQ buffer address (ATC ADDRESS) */ + u16 hw_ctrl_addr; + /* 6: index of the copy subroutine */ + u8 copy_func_index; + /* 7: X number of SMEM samples to move */ + u8 x_io; + /* 8: 0 for mono data, 1 for stereo data */ + u8 data_size; + /* 9: internal SMEM buffer INITPTR pointer index */ + u8 smem_addr; + /* 10: data content to be loaded to "hw_ctrl_addr" */ + u8 atc_irq_data; + /* 11: ping/pong buffer flag */ + u8 counter; + /* 12: reseved */ + u16 dummy1; + /* 14: reseved */ + u16 dummy2; + /* 16 For 12/11 in case of 44.1 mode (same address as SIO desc)*/ + u16 split_addr1; + /* 18: reseved */ + u16 dummy3; + /* 20: current Base address of the working buffer */ + u16 workbuff_BaseAddr; + /* 14: samples left in the working buffer */ + u16 workbuff_Samples; + /* 16: Base address of the ping/pong buffer 0 */ + u16 nextbuff0_BaseAddr; + /* 18: samples available in the ping/pong buffer 0 */ + u16 nextbuff0_Samples; + /* 20: Base address of the ping/pong buffer 1 */ + u16 nextbuff1_BaseAddr; + /* 22: samples available in the ping/pong buffer 1 */ + u16 nextbuff1_Samples; +}; + +#endif/* _ABE_TYPEDEF_H_ */ diff --git a/sound/soc/omap/abe/port_mgr.c b/sound/soc/omap/abe/port_mgr.c new file mode 100644 index 0000000..ef9d7a6 --- /dev/null +++ b/sound/soc/omap/abe/port_mgr.c @@ -0,0 +1,345 @@ +/* + * ALSA SoC OMAP ABE port manager + * + * Author: Liam Girdwood <lrg@slimlogic.co.uk> + * + * 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 + */ + +//#define DEBUG + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/errno.h> +#include <linux/spinlock.h> +#include <linux/list.h> +#include <linux/debugfs.h> +#include <linux/device.h> +#include "port_mgr.h" +#include "abe_main.h" + +#ifdef CONFIG_DEBUG_FS +/* this must match logical ID numbers in port_mgr.h */ +static const char *lport_name[] = { + "dmic0", "dmic1", "dmic2", "pdmdl1", "pdmdl2", "pdmvib", + "pdmul1", "bt_vx_dl", "bt_vx_ul", "mm_ext_ul", "mm_ext_dl", + "mm_dl1", "mm_ul1", "mm_ul2", "vx_dl", "vx_ul", "vib", "tones" +}; +#endif + +static DEFINE_MUTEX(port_mgr_mutex); +static struct abe *the_abe = NULL; +static int users = 0; + +/* + * Get the Physical port ID based on the logical port ID + * + * FE and BE ports have unique ID's within the driver but share + * ID's within the ABE. This maps a driver port ID to an ABE port ID. + */ +static int get_physical_id(int logical_id) +{ + switch (logical_id) { + /* backend ports */ + case OMAP_ABE_BE_PORT_DMIC0: + case OMAP_ABE_BE_PORT_DMIC1: + case OMAP_ABE_BE_PORT_DMIC2: + return DMIC_PORT; + case OMAP_ABE_BE_PORT_PDM_DL1: + case OMAP_ABE_BE_PORT_PDM_DL2: + return PDM_DL_PORT; + case OMAP_ABE_BE_PORT_PDM_VIB: + return VIB_DL_PORT; + case OMAP_ABE_BE_PORT_PDM_UL1: + return PDM_UL_PORT; + case OMAP_ABE_BE_PORT_BT_VX_DL: + return BT_VX_DL_PORT; + case OMAP_ABE_BE_PORT_BT_VX_UL: + return BT_VX_UL_PORT; + case OMAP_ABE_BE_PORT_MM_EXT_UL: + return MM_EXT_OUT_PORT; + case OMAP_ABE_BE_PORT_MM_EXT_DL: + return MM_EXT_IN_PORT; + /* front end ports */ + case OMAP_ABE_FE_PORT_MM_DL1: + return MM_DL_PORT; + case OMAP_ABE_FE_PORT_MM_UL1: + return MM_UL_PORT; + case OMAP_ABE_FE_PORT_MM_UL2: + return MM_UL2_PORT; + case OMAP_ABE_FE_PORT_VX_DL: + return VX_DL_PORT; + case OMAP_ABE_FE_PORT_VX_UL: + return VX_UL_PORT; + case OMAP_ABE_FE_PORT_VIB: + return VIB_DL_PORT; + case OMAP_ABE_FE_PORT_TONES: + return TONES_DL_PORT; + } + return -EINVAL; +} + +/* + * Get the number of enabled users of the physical port shared by this client. + * Locks held by callers. + */ +static int port_get_num_users(struct abe *abe, struct omap_abe_port *port) +{ + struct omap_abe_port *p; + int users = 0; + + list_for_each_entry(p, &abe->ports, list) { + if (p->physical_id == port->physical_id && p->state == PORT_ENABLED) + users++; + } + return users; +} + +static int port_is_open(struct abe *abe, int phy_port) +{ + struct omap_abe_port *p; + + list_for_each_entry(p, &abe->ports, list) { + if (p->physical_id == phy_port && p->state == PORT_ENABLED) + return 1; + } + return 0; +} + +/* + * Check whether the physical port is enabled for this PHY port ID. + * Locks held by callers. + */ +int omap_abe_port_is_enabled(struct abe *abe, struct omap_abe_port *port) +{ + struct omap_abe_port *p; + unsigned long flags; + + spin_lock_irqsave(&abe->lock, flags); + + list_for_each_entry(p, &abe->ports, list) { + if (p->physical_id == port->physical_id && p->state == PORT_ENABLED) { + spin_unlock_irqrestore(&abe->lock, flags); + return 1; + } + } + + spin_unlock_irqrestore(&abe->lock, flags); + return 0; +} +EXPORT_SYMBOL(omap_abe_port_is_enabled); + +/* + * omap_abe_port_enable - enable ABE logical port + * + * @abe - ABE. + * @port - logical ABE port ID to be enabled. + */ +int omap_abe_port_enable(struct abe *abe, struct omap_abe_port *port) +{ + int ret = 0; + unsigned long flags; + + /* only enable the physical port iff it is disabled */ + pr_debug("port %s increment count %d\n", + lport_name[port->logical_id], port->users); + + spin_lock_irqsave(&abe->lock, flags); + if (port->users == 0 && port_get_num_users(abe, port) == 0) { + + /* enable the physical port */ + pr_debug("port %s phy port %d enabled\n", + lport_name[port->logical_id], port->physical_id); + abe_enable_data_transfer(port->physical_id); + } + + port->state = PORT_ENABLED; + port->users++; + spin_unlock_irqrestore(&abe->lock, flags); + return ret; +} +EXPORT_SYMBOL(omap_abe_port_enable); + +/* + * omap_abe_port_disable - disable ABE logical port + * + * @abe - ABE. + * @port - logical ABE port ID to be disabled. + */ +int omap_abe_port_disable(struct abe *abe, struct omap_abe_port *port) +{ + int ret = 0; + unsigned long flags; + + /* only disable the port iff no other users are using it */ + pr_debug("port %s decrement count %d\n", + lport_name[port->logical_id], port->users); + + spin_lock_irqsave(&abe->lock, flags); + + WARN(!port->users, "port %s phy port %d is already disabled\n", + lport_name[port->logical_id], port->physical_id); + + if (port->users == 1 && port_get_num_users(abe, port) == 1) { + /* disable the physical port */ + pr_debug("port %s phy port %d disabled\n", + lport_name[port->logical_id], port->physical_id); + + abe_disable_data_transfer(port->physical_id); + } + + port->state = PORT_DISABLED; + port->users--; + spin_unlock_irqrestore(&abe->lock, flags); + return ret; +} +EXPORT_SYMBOL(omap_abe_port_disable); + +/* + * omap_abe_port_open - open ABE logical port + * + * @abe - ABE. + * @logical_id - logical ABE port ID to be opened. + */ +struct omap_abe_port *omap_abe_port_open(struct abe *abe, int logical_id) +{ + struct omap_abe_port *port; + unsigned long flags; + +#ifdef CONFIG_DEBUG_FS + char debug_fs_name[32]; +#endif + + if (logical_id < 0 || logical_id > OMAP_ABE_MAX_PORT_ID) + return NULL; + + if (port_is_open(abe, logical_id)) + return NULL; + + port = kzalloc(sizeof(struct omap_abe_port), GFP_KERNEL); + if (port == NULL) + return NULL; + + port->logical_id = logical_id; + port->physical_id = get_physical_id(logical_id); + port->state = PORT_DISABLED; + port->abe = abe; + + spin_lock_irqsave(&abe->lock, flags); + list_add(&port->list, &abe->ports); + spin_unlock_irqrestore(&abe->lock, flags); + port->physical_users = port_get_num_users(abe, port); + +#ifdef CONFIG_DEBUG_FS + sprintf(debug_fs_name, "%s_state", lport_name[logical_id]); + port->debugfs_lstate = debugfs_create_u32(debug_fs_name, 0644, + abe->debugfs_root, &port->state); + sprintf(debug_fs_name, "%s_phy", lport_name[logical_id]); + port->debugfs_lphy = debugfs_create_u32(debug_fs_name, 0644, + abe->debugfs_root, &port->physical_id); + sprintf(debug_fs_name, "%s_users", lport_name[logical_id]); + port->debugfs_lusers = debugfs_create_u32(debug_fs_name, 0644, + abe->debugfs_root, &port->users); +#endif + + pr_debug("opened port %s\n", lport_name[logical_id]); + return port; +} +EXPORT_SYMBOL(omap_abe_port_open); + +/* + * omap_abe_port_close - close ABE logical port + * + * @port - logical ABE port to be closed (and disabled). + */ +void omap_abe_port_close(struct abe *abe, struct omap_abe_port *port) +{ + unsigned long flags; + + /* disable the port */ + omap_abe_port_disable(abe, port); + + spin_lock_irqsave(&abe->lock, flags); + list_del(&port->list); + spin_unlock_irqrestore(&abe->lock, flags); + + pr_debug("closed port %s\n", lport_name[port->logical_id]); + kfree(port); +} +EXPORT_SYMBOL(omap_abe_port_close); + +static struct abe *omap_abe_port_mgr_init(void) +{ + struct abe *abe; + + abe = kzalloc(sizeof(struct abe), GFP_KERNEL); + if (abe == NULL) + return NULL; + + spin_lock_init(&abe->lock); + + INIT_LIST_HEAD(&abe->ports); + the_abe = abe; + +#ifdef CONFIG_DEBUG_FS + abe->debugfs_root = debugfs_create_dir("abe_port", NULL); + if (!abe->debugfs_root) { + pr_debug( "Failed to create port manager debugfs directory\n"); + } +#endif + return abe; +} + +static void omap_abe_port_mgr_free(struct abe *abe) +{ + debugfs_remove_recursive(abe->debugfs_root); + kfree(abe); + the_abe = NULL; +} + +struct abe *omap_abe_port_mgr_get(void) +{ + struct abe * abe; + + mutex_lock(&port_mgr_mutex); + + if (the_abe) + abe = the_abe; + else + abe = omap_abe_port_mgr_init(); + + users++; + mutex_unlock(&port_mgr_mutex); + return abe; +} +EXPORT_SYMBOL(omap_abe_port_mgr_get); + +void omap_abe_port_mgr_put(struct abe *abe) +{ + mutex_lock(&port_mgr_mutex); + + if (users == 0) + goto out; + + if (--users == 0) + omap_abe_port_mgr_free(abe); + +out: + mutex_unlock(&port_mgr_mutex); +} +EXPORT_SYMBOL(omap_abe_port_mgr_put); + +MODULE_LICENSE("GPL"); diff --git a/sound/soc/omap/abe/port_mgr.h b/sound/soc/omap/abe/port_mgr.h new file mode 100644 index 0000000..a65b0d3 --- /dev/null +++ b/sound/soc/omap/abe/port_mgr.h @@ -0,0 +1,98 @@ +/* + * ABE Port manager + * + * Author: Liam Girdwood <lrg@slimlogic.co.uk> + * + * 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. + */ + +#ifndef __LINUX_SND_SOC_OMAP_PORT_MGR_H +#define __LINUX_SND_SOC_OMAP_PORT_MGR_H + +#include <linux/debugfs.h> + +/* + * TODO: These structures, enums and port ID macros should be moved to the + * new public ABE API header. + */ + +/* Logical PORT IDs - Backend */ +#define OMAP_ABE_BE_PORT_DMIC0 0 +#define OMAP_ABE_BE_PORT_DMIC1 1 +#define OMAP_ABE_BE_PORT_DMIC2 2 +#define OMAP_ABE_BE_PORT_PDM_DL1 3 +#define OMAP_ABE_BE_PORT_PDM_DL2 4 +#define OMAP_ABE_BE_PORT_PDM_VIB 5 +#define OMAP_ABE_BE_PORT_PDM_UL1 6 +#define OMAP_ABE_BE_PORT_BT_VX_DL 7 +#define OMAP_ABE_BE_PORT_BT_VX_UL 8 +#define OMAP_ABE_BE_PORT_MM_EXT_UL 9 +#define OMAP_ABE_BE_PORT_MM_EXT_DL 10 + +/* Logical PORT IDs - Frontend */ +#define OMAP_ABE_FE_PORT_MM_DL1 11 +#define OMAP_ABE_FE_PORT_MM_UL1 12 +#define OMAP_ABE_FE_PORT_MM_UL2 13 +#define OMAP_ABE_FE_PORT_VX_DL 14 +#define OMAP_ABE_FE_PORT_VX_UL 15 +#define OMAP_ABE_FE_PORT_VIB 16 +#define OMAP_ABE_FE_PORT_TONES 17 + +#define OMAP_ABE_MAX_PORT_ID OMAP_ABE_FE_PORT_TONES + +/* ports can either be enabled or disabled */ +enum port_state { + PORT_DISABLED = 0, + PORT_ENABLED, +}; + +/* structure used for client port info */ +struct omap_abe_port { + + /* logical and physical port IDs that correspond this port */ + int logical_id; + int physical_id; + int physical_users; + + /* enabled or disabled */ + enum port_state state; + + /* logical port ref count */ + int users; + + struct list_head list; + struct abe *abe; + +#ifdef CONFIG_DEBUG_FS + struct dentry *debugfs_lstate; + struct dentry *debugfs_lphy; + struct dentry *debugfs_lusers; +#endif +}; + +/* main ABE structure */ +struct abe { + + /* List of open ABE logical ports */ + struct list_head ports; + + /* spinlock */ + spinlock_t lock; + + +#ifdef CONFIG_DEBUG_FS + struct dentry *debugfs_root; +#endif +}; + +struct omap_abe_port *omap_abe_port_open(struct abe *abe, int logical_id); +void omap_abe_port_close(struct abe *abe, struct omap_abe_port *port); +int omap_abe_port_enable(struct abe *abe, struct omap_abe_port *port); +int omap_abe_port_disable(struct abe *abe, struct omap_abe_port *port); +int omap_abe_port_is_enabled(struct abe *abe, struct omap_abe_port *port); +struct abe *omap_abe_port_mgr_get(void); +void omap_abe_port_mgr_put(struct abe *abe); + +#endif /* __LINUX_SND_SOC_OMAP_PORT_MGR_H */ diff --git a/sound/soc/omap/mcpdm.c b/sound/soc/omap/mcpdm.c deleted file mode 100644 index 928f037..0000000 --- a/sound/soc/omap/mcpdm.c +++ /dev/null @@ -1,470 +0,0 @@ -/* - * mcpdm.c -- McPDM interface driver - * - * Author: Jorge Eduardo Candelaria <x0107209@ti.com> - * Copyright (C) 2009 - Texas Instruments, 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/module.h> -#include <linux/init.h> -#include <linux/device.h> -#include <linux/platform_device.h> -#include <linux/wait.h> -#include <linux/slab.h> -#include <linux/interrupt.h> -#include <linux/err.h> -#include <linux/clk.h> -#include <linux/delay.h> -#include <linux/io.h> -#include <linux/irq.h> - -#include "mcpdm.h" - -static struct omap_mcpdm *mcpdm; - -static inline void omap_mcpdm_write(u16 reg, u32 val) -{ - __raw_writel(val, mcpdm->io_base + reg); -} - -static inline int omap_mcpdm_read(u16 reg) -{ - return __raw_readl(mcpdm->io_base + reg); -} - -static void omap_mcpdm_reg_dump(void) -{ - dev_dbg(mcpdm->dev, "***********************\n"); - dev_dbg(mcpdm->dev, "IRQSTATUS_RAW: 0x%04x\n", - omap_mcpdm_read(MCPDM_IRQSTATUS_RAW)); - dev_dbg(mcpdm->dev, "IRQSTATUS: 0x%04x\n", - omap_mcpdm_read(MCPDM_IRQSTATUS)); - dev_dbg(mcpdm->dev, "IRQENABLE_SET: 0x%04x\n", - omap_mcpdm_read(MCPDM_IRQENABLE_SET)); - dev_dbg(mcpdm->dev, "IRQENABLE_CLR: 0x%04x\n", - omap_mcpdm_read(MCPDM_IRQENABLE_CLR)); - dev_dbg(mcpdm->dev, "IRQWAKE_EN: 0x%04x\n", - omap_mcpdm_read(MCPDM_IRQWAKE_EN)); - dev_dbg(mcpdm->dev, "DMAENABLE_SET: 0x%04x\n", - omap_mcpdm_read(MCPDM_DMAENABLE_SET)); - dev_dbg(mcpdm->dev, "DMAENABLE_CLR: 0x%04x\n", - omap_mcpdm_read(MCPDM_DMAENABLE_CLR)); - dev_dbg(mcpdm->dev, "DMAWAKEEN: 0x%04x\n", - omap_mcpdm_read(MCPDM_DMAWAKEEN)); - dev_dbg(mcpdm->dev, "CTRL: 0x%04x\n", - omap_mcpdm_read(MCPDM_CTRL)); - dev_dbg(mcpdm->dev, "DN_DATA: 0x%04x\n", - omap_mcpdm_read(MCPDM_DN_DATA)); - dev_dbg(mcpdm->dev, "UP_DATA: 0x%04x\n", - omap_mcpdm_read(MCPDM_UP_DATA)); - dev_dbg(mcpdm->dev, "FIFO_CTRL_DN: 0x%04x\n", - omap_mcpdm_read(MCPDM_FIFO_CTRL_DN)); - dev_dbg(mcpdm->dev, "FIFO_CTRL_UP: 0x%04x\n", - omap_mcpdm_read(MCPDM_FIFO_CTRL_UP)); - dev_dbg(mcpdm->dev, "DN_OFFSET: 0x%04x\n", - omap_mcpdm_read(MCPDM_DN_OFFSET)); - dev_dbg(mcpdm->dev, "***********************\n"); -} - -/* - * Takes the McPDM module in and out of reset state. - * Uplink and downlink can be reset individually. - */ -static void omap_mcpdm_reset_capture(int reset) -{ - int ctrl = omap_mcpdm_read(MCPDM_CTRL); - - if (reset) - ctrl |= SW_UP_RST; - else - ctrl &= ~SW_UP_RST; - - omap_mcpdm_write(MCPDM_CTRL, ctrl); -} - -static void omap_mcpdm_reset_playback(int reset) -{ - int ctrl = omap_mcpdm_read(MCPDM_CTRL); - - if (reset) - ctrl |= SW_DN_RST; - else - ctrl &= ~SW_DN_RST; - - omap_mcpdm_write(MCPDM_CTRL, ctrl); -} - -/* - * Enables the transfer through the PDM interface to/from the Phoenix - * codec by enabling the corresponding UP or DN channels. - */ -void omap_mcpdm_start(int stream) -{ - int ctrl = omap_mcpdm_read(MCPDM_CTRL); - - if (stream) - ctrl |= mcpdm->up_channels; - else - ctrl |= mcpdm->dn_channels; - - omap_mcpdm_write(MCPDM_CTRL, ctrl); -} - -/* - * Disables the transfer through the PDM interface to/from the Phoenix - * codec by disabling the corresponding UP or DN channels. - */ -void omap_mcpdm_stop(int stream) -{ - int ctrl = omap_mcpdm_read(MCPDM_CTRL); - - if (stream) - ctrl &= ~mcpdm->up_channels; - else - ctrl &= ~mcpdm->dn_channels; - - omap_mcpdm_write(MCPDM_CTRL, ctrl); -} - -/* - * Configures McPDM uplink for audio recording. - * This function should be called before omap_mcpdm_start. - */ -int omap_mcpdm_capture_open(struct omap_mcpdm_link *uplink) -{ - int irq_mask = 0; - int ctrl; - - if (!uplink) - return -EINVAL; - - mcpdm->uplink = uplink; - - /* Enable irq request generation */ - irq_mask |= uplink->irq_mask & MCPDM_UPLINK_IRQ_MASK; - omap_mcpdm_write(MCPDM_IRQENABLE_SET, irq_mask); - - /* Configure uplink threshold */ - if (uplink->threshold > UP_THRES_MAX) - uplink->threshold = UP_THRES_MAX; - - omap_mcpdm_write(MCPDM_FIFO_CTRL_UP, uplink->threshold); - - /* Configure DMA controller */ - omap_mcpdm_write(MCPDM_DMAENABLE_SET, DMA_UP_ENABLE); - - /* Set pdm out format */ - ctrl = omap_mcpdm_read(MCPDM_CTRL); - ctrl &= ~PDMOUTFORMAT; - ctrl |= uplink->format & PDMOUTFORMAT; - - /* Uplink channels */ - mcpdm->up_channels = uplink->channels & (PDM_UP_MASK | PDM_STATUS_MASK); - - omap_mcpdm_write(MCPDM_CTRL, ctrl); - - return 0; -} - -/* - * Configures McPDM downlink for audio playback. - * This function should be called before omap_mcpdm_start. - */ -int omap_mcpdm_playback_open(struct omap_mcpdm_link *downlink) -{ - int irq_mask = 0; - int ctrl; - - if (!downlink) - return -EINVAL; - - mcpdm->downlink = downlink; - - /* Enable irq request generation */ - irq_mask |= downlink->irq_mask & MCPDM_DOWNLINK_IRQ_MASK; - omap_mcpdm_write(MCPDM_IRQENABLE_SET, irq_mask); - - /* Configure uplink threshold */ - if (downlink->threshold > DN_THRES_MAX) - downlink->threshold = DN_THRES_MAX; - - omap_mcpdm_write(MCPDM_FIFO_CTRL_DN, downlink->threshold); - - /* Enable DMA request generation */ - omap_mcpdm_write(MCPDM_DMAENABLE_SET, DMA_DN_ENABLE); - - /* Set pdm out format */ - ctrl = omap_mcpdm_read(MCPDM_CTRL); - ctrl &= ~PDMOUTFORMAT; - ctrl |= downlink->format & PDMOUTFORMAT; - - /* Downlink channels */ - mcpdm->dn_channels = downlink->channels & (PDM_DN_MASK | PDM_CMD_MASK); - - omap_mcpdm_write(MCPDM_CTRL, ctrl); - - return 0; -} - -/* - * Cleans McPDM uplink configuration. - * This function should be called when the stream is closed. - */ -int omap_mcpdm_capture_close(struct omap_mcpdm_link *uplink) -{ - int irq_mask = 0; - - if (!uplink) - return -EINVAL; - - /* Disable irq request generation */ - irq_mask |= uplink->irq_mask & MCPDM_UPLINK_IRQ_MASK; - omap_mcpdm_write(MCPDM_IRQENABLE_CLR, irq_mask); - - /* Disable DMA request generation */ - omap_mcpdm_write(MCPDM_DMAENABLE_CLR, DMA_UP_ENABLE); - - /* Clear Downlink channels */ - mcpdm->up_channels = 0; - - mcpdm->uplink = NULL; - - return 0; -} - -/* - * Cleans McPDM downlink configuration. - * This function should be called when the stream is closed. - */ -int omap_mcpdm_playback_close(struct omap_mcpdm_link *downlink) -{ - int irq_mask = 0; - - if (!downlink) - return -EINVAL; - - /* Disable irq request generation */ - irq_mask |= downlink->irq_mask & MCPDM_DOWNLINK_IRQ_MASK; - omap_mcpdm_write(MCPDM_IRQENABLE_CLR, irq_mask); - - /* Disable DMA request generation */ - omap_mcpdm_write(MCPDM_DMAENABLE_CLR, DMA_DN_ENABLE); - - /* clear Downlink channels */ - mcpdm->dn_channels = 0; - - mcpdm->downlink = NULL; - - return 0; -} - -static irqreturn_t omap_mcpdm_irq_handler(int irq, void *dev_id) -{ - struct omap_mcpdm *mcpdm_irq = dev_id; - int irq_status; - - irq_status = omap_mcpdm_read(MCPDM_IRQSTATUS); - - /* Acknowledge irq event */ - omap_mcpdm_write(MCPDM_IRQSTATUS, irq_status); - - if (irq & MCPDM_DN_IRQ_FULL) { - dev_err(mcpdm_irq->dev, "DN FIFO error %x\n", irq_status); - omap_mcpdm_reset_playback(1); - omap_mcpdm_playback_open(mcpdm_irq->downlink); - omap_mcpdm_reset_playback(0); - } - - if (irq & MCPDM_DN_IRQ_EMPTY) { - dev_err(mcpdm_irq->dev, "DN FIFO error %x\n", irq_status); - omap_mcpdm_reset_playback(1); - omap_mcpdm_playback_open(mcpdm_irq->downlink); - omap_mcpdm_reset_playback(0); - } - - if (irq & MCPDM_DN_IRQ) { - dev_dbg(mcpdm_irq->dev, "DN write request\n"); - } - - if (irq & MCPDM_UP_IRQ_FULL) { - dev_err(mcpdm_irq->dev, "UP FIFO error %x\n", irq_status); - omap_mcpdm_reset_capture(1); - omap_mcpdm_capture_open(mcpdm_irq->uplink); - omap_mcpdm_reset_capture(0); - } - - if (irq & MCPDM_UP_IRQ_EMPTY) { - dev_err(mcpdm_irq->dev, "UP FIFO error %x\n", irq_status); - omap_mcpdm_reset_capture(1); - omap_mcpdm_capture_open(mcpdm_irq->uplink); - omap_mcpdm_reset_capture(0); - } - - if (irq & MCPDM_UP_IRQ) { - dev_dbg(mcpdm_irq->dev, "UP write request\n"); - } - - return IRQ_HANDLED; -} - -int omap_mcpdm_request(void) -{ - int ret; - - clk_enable(mcpdm->clk); - - spin_lock(&mcpdm->lock); - - if (!mcpdm->free) { - dev_err(mcpdm->dev, "McPDM interface is in use\n"); - spin_unlock(&mcpdm->lock); - ret = -EBUSY; - goto err; - } - mcpdm->free = 0; - - spin_unlock(&mcpdm->lock); - - /* Disable lines while request is ongoing */ - omap_mcpdm_write(MCPDM_CTRL, 0x00); - - ret = request_irq(mcpdm->irq, omap_mcpdm_irq_handler, - 0, "McPDM", (void *)mcpdm); - if (ret) { - dev_err(mcpdm->dev, "Request for McPDM IRQ failed\n"); - goto err; - } - - return 0; - -err: - clk_disable(mcpdm->clk); - return ret; -} - -void omap_mcpdm_free(void) -{ - spin_lock(&mcpdm->lock); - if (mcpdm->free) { - dev_err(mcpdm->dev, "McPDM interface is already free\n"); - spin_unlock(&mcpdm->lock); - return; - } - mcpdm->free = 1; - spin_unlock(&mcpdm->lock); - - clk_disable(mcpdm->clk); - - free_irq(mcpdm->irq, (void *)mcpdm); -} - -/* Enable/disable DC offset cancelation for the analog - * headset path (PDM channels 1 and 2). - */ -int omap_mcpdm_set_offset(int offset1, int offset2) -{ - int offset; - - if ((offset1 > DN_OFST_MAX) || (offset2 > DN_OFST_MAX)) - return -EINVAL; - - offset = (offset1 << DN_OFST_RX1) | (offset2 << DN_OFST_RX2); - - /* offset cancellation for channel 1 */ - if (offset1) - offset |= DN_OFST_RX1_EN; - else - offset &= ~DN_OFST_RX1_EN; - - /* offset cancellation for channel 2 */ - if (offset2) - offset |= DN_OFST_RX2_EN; - else - offset &= ~DN_OFST_RX2_EN; - - omap_mcpdm_write(MCPDM_DN_OFFSET, offset); - - return 0; -} - -int __devinit omap_mcpdm_probe(struct platform_device *pdev) -{ - struct resource *res; - int ret = 0; - - mcpdm = kzalloc(sizeof(struct omap_mcpdm), GFP_KERNEL); - if (!mcpdm) { - ret = -ENOMEM; - goto exit; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res == NULL) { - dev_err(&pdev->dev, "no resource\n"); - goto err_resource; - } - - spin_lock_init(&mcpdm->lock); - mcpdm->free = 1; - mcpdm->io_base = ioremap(res->start, resource_size(res)); - if (!mcpdm->io_base) { - ret = -ENOMEM; - goto err_resource; - } - - mcpdm->irq = platform_get_irq(pdev, 0); - - mcpdm->clk = clk_get(&pdev->dev, "pdm_ck"); - if (IS_ERR(mcpdm->clk)) { - ret = PTR_ERR(mcpdm->clk); - dev_err(&pdev->dev, "unable to get pdm_ck: %d\n", ret); - goto err_clk; - } - - mcpdm->dev = &pdev->dev; - platform_set_drvdata(pdev, mcpdm); - - return 0; - -err_clk: - iounmap(mcpdm->io_base); -err_resource: - kfree(mcpdm); -exit: - return ret; -} - -int __devexit omap_mcpdm_remove(struct platform_device *pdev) -{ - struct omap_mcpdm *mcpdm_ptr = platform_get_drvdata(pdev); - - platform_set_drvdata(pdev, NULL); - - clk_put(mcpdm_ptr->clk); - - iounmap(mcpdm_ptr->io_base); - - mcpdm_ptr->clk = NULL; - mcpdm_ptr->free = 0; - mcpdm_ptr->dev = NULL; - - kfree(mcpdm_ptr); - - return 0; -} - diff --git a/sound/soc/omap/mcpdm.h b/sound/soc/omap/mcpdm.h deleted file mode 100644 index df3e16f..0000000 --- a/sound/soc/omap/mcpdm.h +++ /dev/null @@ -1,153 +0,0 @@ -/* - * mcpdm.h -- Defines for McPDM driver - * - * Author: Jorge Eduardo Candelaria <x0107209@ti.com> - * - * 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 - * - */ - -/* McPDM registers */ - -#define MCPDM_REVISION 0x00 -#define MCPDM_SYSCONFIG 0x10 -#define MCPDM_IRQSTATUS_RAW 0x24 -#define MCPDM_IRQSTATUS 0x28 -#define MCPDM_IRQENABLE_SET 0x2C -#define MCPDM_IRQENABLE_CLR 0x30 -#define MCPDM_IRQWAKE_EN 0x34 -#define MCPDM_DMAENABLE_SET 0x38 -#define MCPDM_DMAENABLE_CLR 0x3C -#define MCPDM_DMAWAKEEN 0x40 -#define MCPDM_CTRL 0x44 -#define MCPDM_DN_DATA 0x48 -#define MCPDM_UP_DATA 0x4C -#define MCPDM_FIFO_CTRL_DN 0x50 -#define MCPDM_FIFO_CTRL_UP 0x54 -#define MCPDM_DN_OFFSET 0x58 - -/* - * MCPDM_IRQ bit fields - * IRQSTATUS_RAW, IRQSTATUS, IRQENABLE_SET, IRQENABLE_CLR - */ - -#define MCPDM_DN_IRQ (1 << 0) -#define MCPDM_DN_IRQ_EMPTY (1 << 1) -#define MCPDM_DN_IRQ_ALMST_EMPTY (1 << 2) -#define MCPDM_DN_IRQ_FULL (1 << 3) - -#define MCPDM_UP_IRQ (1 << 8) -#define MCPDM_UP_IRQ_EMPTY (1 << 9) -#define MCPDM_UP_IRQ_ALMST_FULL (1 << 10) -#define MCPDM_UP_IRQ_FULL (1 << 11) - -#define MCPDM_DOWNLINK_IRQ_MASK 0x00F -#define MCPDM_UPLINK_IRQ_MASK 0xF00 - -/* - * MCPDM_DMAENABLE bit fields - */ - -#define DMA_DN_ENABLE 0x1 -#define DMA_UP_ENABLE 0x2 - -/* - * MCPDM_CTRL bit fields - */ - -#define PDM_UP1_EN 0x0001 -#define PDM_UP2_EN 0x0002 -#define PDM_UP3_EN 0x0004 -#define PDM_DN1_EN 0x0008 -#define PDM_DN2_EN 0x0010 -#define PDM_DN3_EN 0x0020 -#define PDM_DN4_EN 0x0040 -#define PDM_DN5_EN 0x0080 -#define PDMOUTFORMAT 0x0100 -#define CMD_INT 0x0200 -#define STATUS_INT 0x0400 -#define SW_UP_RST 0x0800 -#define SW_DN_RST 0x1000 -#define PDM_UP_MASK 0x007 -#define PDM_DN_MASK 0x0F8 -#define PDM_CMD_MASK 0x200 -#define PDM_STATUS_MASK 0x400 - - -#define PDMOUTFORMAT_LJUST (0 << 8) -#define PDMOUTFORMAT_RJUST (1 << 8) - -/* - * MCPDM_FIFO_CTRL bit fields - */ - -#define UP_THRES_MAX 0xF -#define DN_THRES_MAX 0xF - -/* - * MCPDM_DN_OFFSET bit fields - */ - -#define DN_OFST_RX1_EN 0x0001 -#define DN_OFST_RX2_EN 0x0100 - -#define DN_OFST_RX1 1 -#define DN_OFST_RX2 9 -#define DN_OFST_MAX 0x1F - -#define MCPDM_UPLINK 1 -#define MCPDM_DOWNLINK 2 - -struct omap_mcpdm_link { - int irq_mask; - int threshold; - int format; - int channels; -}; - -struct omap_mcpdm_platform_data { - unsigned long phys_base; - u16 irq; -}; - -struct omap_mcpdm { - struct device *dev; - unsigned long phys_base; - void __iomem *io_base; - u8 free; - int irq; - - spinlock_t lock; - struct omap_mcpdm_platform_data *pdata; - struct clk *clk; - struct omap_mcpdm_link *downlink; - struct omap_mcpdm_link *uplink; - struct completion irq_completion; - - int dn_channels; - int up_channels; -}; - -extern void omap_mcpdm_start(int stream); -extern void omap_mcpdm_stop(int stream); -extern int omap_mcpdm_capture_open(struct omap_mcpdm_link *uplink); -extern int omap_mcpdm_playback_open(struct omap_mcpdm_link *downlink); -extern int omap_mcpdm_capture_close(struct omap_mcpdm_link *uplink); -extern int omap_mcpdm_playback_close(struct omap_mcpdm_link *downlink); -extern int omap_mcpdm_request(void); -extern void omap_mcpdm_free(void); -extern int omap_mcpdm_set_offset(int offset1, int offset2); -int __devinit omap_mcpdm_probe(struct platform_device *pdev); -int __devexit omap_mcpdm_remove(struct platform_device *pdev); diff --git a/sound/soc/omap/omap-abe-dsp.c b/sound/soc/omap/omap-abe-dsp.c new file mode 100644 index 0000000..b66db25 --- /dev/null +++ b/sound/soc/omap/omap-abe-dsp.c @@ -0,0 +1,2876 @@ +/* + * omap-abe-dsp.c + * + * 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 + * + * Copyright (C) 2010 Texas Instruments Inc. + * + * Authors: Liam Girdwood <lrg@ti.com> + * Misael Lopez Cruz <misael.lopez@ti.com> + * Sebastien Guiriec <s-guiriec@ti.com> + * + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/i2c.h> +#include <linux/gpio.h> +#include <linux/platform_device.h> +#include <linux/workqueue.h> +#include <linux/i2c/twl.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/slab.h> +#include <linux/pm_runtime.h> +#include <linux/dma-mapping.h> +#include <linux/wait.h> +#include <linux/firmware.h> +#include <linux/debugfs.h> +#include <linux/opp.h> + +#include <plat/omap_hwmod.h> +#include <plat/omap_device.h> +#include <plat/dma.h> + +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <sound/initval.h> +#include <sound/tlv.h> +#include <sound/omap-abe-dsp.h> + +#include "omap-abe-dsp.h" +#include "omap-abe.h" +#include "abe/abe_main.h" +#include "abe/port_mgr.h" + +#define OMAP_ABE_HS_DC_OFFSET_STEP (1800 / 8) +#define OMAP_ABE_HF_DC_OFFSET_STEP (4600 / 8) + +static const char *abe_memory_bank[5] = { + "dmem", + "cmem", + "smem", + "pmem", + "mpu" +}; + + +/* + * ABE loadable coefficients. + * The coefficient and their mixer configurations are loaded with the firmware + * blob duing probe(). + */ + +struct coeff_config { + char name[ABE_COEFF_NAME_SIZE]; + u32 count; + u32 coeff; + char texts[ABE_COEFF_NUM_TEXTS][ABE_COEFF_TEXT_SIZE]; +}; + +/* + * ABE Firmware Header. + * The ABE firmware blob has a header that describes each data section. This + * way we can store coefficients etc in the firmware. + */ +struct fw_header { + u32 magic; /* magic number */ + u32 crc; /* optional crc */ + u32 firmware_size; /* payload size */ + u32 coeff_size; /* payload size */ + u32 coeff_version; /* coefficent version */ + u32 firmware_version; /* min version of ABE firmware required */ + u32 num_equ; /* number of equalizers */ +}; + +struct abe_opp_req { + struct device *dev; + struct list_head node; + int opp; +}; + +/* + * ABE private data. + */ +struct abe_data { + struct omap4_abe_dsp_pdata *abe_pdata; + struct device *dev; + struct snd_soc_platform *platform; + struct delayed_work delayed_work; + struct mutex mutex; + struct mutex opp_mutex; + struct mutex opp_req_mutex; + struct clk *clk; + void __iomem *io_base[5]; + int irq; + int opp; + unsigned long opp_freqs[OMAP_ABE_OPP_COUNT]; + + /* DC offset cancellation */ + int power_mode; + u32 dc_hsl; + u32 dc_hsr; + u32 dc_hfl; + u32 dc_hfr; + + int active; + + /* coefficients */ + struct fw_header hdr; + u32 *firmware; + s32 *equ[ABE_MAX_EQU]; + int equ_profile[ABE_MAX_EQU]; + struct soc_enum equalizer_enum[ABE_MAX_EQU]; + struct snd_kcontrol_new equalizer_control[ABE_MAX_EQU]; + struct coeff_config *equ_texts; + + int mono_mix[ABE_NUM_MONO_MIXERS]; + + /* DAPM mixer config - TODO: some of this can be replaced with HAL update */ + u32 widget_opp[ABE_NUM_DAPM_REG + 1]; + + struct list_head opp_req; + int opp_req_count; + + u16 router[16]; + + struct snd_pcm_substream *ping_pong_substream; + int first_irq; + + struct snd_pcm_substream *psubs; + +#ifdef CONFIG_DEBUG_FS + /* ABE runtime debug config */ + + /* its intended we can switch on/off individual debug items */ + u32 dbg_format1; /* TODO: match flag names here to debug format flags */ + u32 dbg_format2; + u32 dbg_format3; + + u32 dbg_buffer_bytes; + u32 dbg_circular; + u32 dbg_buffer_msecs; /* size of buffer in secs */ + u32 dbg_elem_bytes; + dma_addr_t dbg_buffer_addr; + wait_queue_head_t wait; + int dbg_reader_offset; + int dbg_dma_offset; + int dbg_complete; + struct dentry *debugfs_root; + struct dentry *debugfs_fmt1; + struct dentry *debugfs_fmt2; + struct dentry *debugfs_fmt3; + struct dentry *debugfs_size; + struct dentry *debugfs_data; + struct dentry *debugfs_circ; + struct dentry *debugfs_elem_bytes; + struct dentry *debugfs_opp_level; + char *dbg_buffer; + struct omap_pcm_dma_data *dma_data; + int dma_ch; + int dma_req; +#endif +}; + +static struct abe_data *the_abe; + +static int aess_set_runtime_opp_level(struct abe_data *abe); + +// TODO: map to the new version of HAL +static unsigned int abe_dsp_read(struct snd_soc_platform *platform, + unsigned int reg) +{ + struct abe_data *abe = snd_soc_platform_get_drvdata(platform); + + BUG_ON(reg > ABE_NUM_DAPM_REG); + return abe->widget_opp[reg]; +} + +static int abe_dsp_write(struct snd_soc_platform *platform, unsigned int reg, + unsigned int val) +{ + struct abe_data *abe = snd_soc_platform_get_drvdata(platform); + + BUG_ON(reg > ABE_NUM_DAPM_REG); + abe->widget_opp[reg] = val; + return 0; +} + +static void abe_irq_pingpong_subroutine(u32 *data) +{ + u32 dst, n_bytes; + + abe_read_next_ping_pong_buffer(MM_DL_PORT, &dst, &n_bytes); + abe_set_ping_pong_buffer(MM_DL_PORT, n_bytes); + + /* Do not call ALSA function for first IRQ */ + if (the_abe->first_irq) { + the_abe->first_irq = 0; + } else { + if (the_abe->ping_pong_substream) + snd_pcm_period_elapsed(the_abe->ping_pong_substream); + } +} + +static irqreturn_t abe_irq_handler(int irq, void *dev_id) +{ + struct abe_data *abe = dev_id; + + /* TODO: handle underruns/overruns/errors */ + pm_runtime_get_sync(abe->dev); + abe_clear_irq(); // TODO: why is IRQ not cleared after processing ? + abe_irq_processing(); + pm_runtime_put_sync_suspend(abe->dev); + return IRQ_HANDLED; +} + +// TODO: these should really be called internally since we will know the McPDM state +void abe_dsp_pm_get(void) +{ + pm_runtime_get_sync(the_abe->dev); +} +EXPORT_SYMBOL_GPL(abe_dsp_pm_get); + +void abe_dsp_pm_put(void) +{ + pm_runtime_put_sync(the_abe->dev); +} +EXPORT_SYMBOL_GPL(abe_dsp_pm_put); + +void abe_dsp_shutdown(void) +{ + struct omap4_abe_dsp_pdata *pdata = the_abe->abe_pdata; + int ret; + + if (!the_abe->active && !abe_check_activity()) { + abe_set_opp_processing(ABE_OPP25); + the_abe->opp = 25; + abe_stop_event_generator(); + udelay(250); + if (pdata && pdata->device_scale) { + ret = pdata->device_scale(the_abe->dev, the_abe->dev, + the_abe->opp_freqs[0]); + if (ret) + dev_err(the_abe->dev, + "failed to scale to lowest OPP\n"); + } + } +} +EXPORT_SYMBOL_GPL(abe_dsp_shutdown); + +void abe_dsp_set_hs_offset(int left, int right, int mult) +{ + /* TODO: do not use abe global structure */ + if (the_abe == NULL) + return; + + if (left >= 8) + left -= 16; + the_abe->dc_hsl = OMAP_ABE_HS_DC_OFFSET_STEP * left * mult; + + if (right >= 8) + right -= 16; + the_abe->dc_hsr = OMAP_ABE_HS_DC_OFFSET_STEP * right * mult; +} +EXPORT_SYMBOL(abe_dsp_set_hs_offset); + +void abe_dsp_set_hf_offset(int left, int right) +{ + /* TODO: do not use abe global structure */ + if (the_abe == NULL) + return; + + if (left >= 8) + left -= 16; + the_abe->dc_hfl = OMAP_ABE_HF_DC_OFFSET_STEP * left; + + if (right >= 8) + right -= 16; + the_abe->dc_hfr = OMAP_ABE_HF_DC_OFFSET_STEP * right; +} +EXPORT_SYMBOL(abe_dsp_set_hf_offset); + +void abe_dsp_set_power_mode(int mode) +{ + if (the_abe == NULL) + return; + + /* TODO: do not use abe global structure */ + the_abe->power_mode = mode; +} +EXPORT_SYMBOL(abe_dsp_set_power_mode); + +/* + * These TLV settings will need fine tuned for each individual control + */ + +/* Media DL1 volume control from -120 to 30 dB in 1 dB steps */ +static DECLARE_TLV_DB_SCALE(mm_dl1_tlv, -12000, 100, 3000); + +/* Media DL1 volume control from -120 to 30 dB in 1 dB steps */ +static DECLARE_TLV_DB_SCALE(tones_dl1_tlv, -12000, 100, 3000); + +/* Media DL1 volume control from -120 to 30 dB in 1 dB steps */ +static DECLARE_TLV_DB_SCALE(voice_dl1_tlv, -12000, 100, 3000); + +/* Media DL1 volume control from -120 to 30 dB in 1 dB steps */ +static DECLARE_TLV_DB_SCALE(capture_dl1_tlv, -12000, 100, 3000); + +/* Media DL2 volume control from -120 to 30 dB in 1 dB steps */ +static DECLARE_TLV_DB_SCALE(mm_dl2_tlv, -12000, 100, 3000); + +/* Media DL2 volume control from -120 to 30 dB in 1 dB steps */ +static DECLARE_TLV_DB_SCALE(tones_dl2_tlv, -12000, 100, 3000); + +/* Media DL2 volume control from -120 to 30 dB in 1 dB steps */ +static DECLARE_TLV_DB_SCALE(voice_dl2_tlv, -12000, 100, 3000); + +/* Media DL2 volume control from -120 to 30 dB in 1 dB steps */ +static DECLARE_TLV_DB_SCALE(capture_dl2_tlv, -12000, 100, 3000); + +/* SDT volume control from -120 to 30 dB in 1 dB steps */ +static DECLARE_TLV_DB_SCALE(sdt_ul_tlv, -12000, 100, 3000); + +/* SDT volume control from -120 to 30 dB in 1 dB steps */ +static DECLARE_TLV_DB_SCALE(sdt_dl_tlv, -12000, 100, 3000); + +/* AUDUL volume control from -120 to 30 dB in 1 dB steps */ +static DECLARE_TLV_DB_SCALE(audul_mm_tlv, -12000, 100, 3000); + +/* AUDUL volume control from -120 to 30 dB in 1 dB steps */ +static DECLARE_TLV_DB_SCALE(audul_tones_tlv, -12000, 100, 3000); + +/* AUDUL volume control from -120 to 30 dB in 1 dB steps */ +static DECLARE_TLV_DB_SCALE(audul_vx_ul_tlv, -12000, 100, 3000); + +/* AUDUL volume control from -120 to 30 dB in 1 dB steps */ +static DECLARE_TLV_DB_SCALE(audul_vx_dl_tlv, -12000, 100, 3000); + +/* VXREC volume control from -120 to 30 dB in 1 dB steps */ +static DECLARE_TLV_DB_SCALE(vxrec_mm_dl_tlv, -12000, 100, 3000); + +/* VXREC volume control from -120 to 30 dB in 1 dB steps */ +static DECLARE_TLV_DB_SCALE(vxrec_tones_tlv, -12000, 100, 3000); + +/* VXREC volume control from -120 to 30 dB in 1 dB steps */ +static DECLARE_TLV_DB_SCALE(vxrec_vx_dl_tlv, -12000, 100, 3000); + +/* VXREC volume control from -120 to 30 dB in 1 dB steps */ +static DECLARE_TLV_DB_SCALE(vxrec_vx_ul_tlv, -12000, 100, 3000); + +/* DMIC volume control from -120 to 30 dB in 1 dB steps */ +static DECLARE_TLV_DB_SCALE(dmic_tlv, -12000, 100, 3000); + +/* BT UL volume control from -120 to 30 dB in 1 dB steps */ +static DECLARE_TLV_DB_SCALE(btul_tlv, -12000, 100, 3000); + +/* AMIC volume control from -120 to 30 dB in 1 dB steps */ +static DECLARE_TLV_DB_SCALE(amic_tlv, -12000, 100, 3000); + +//TODO: we have to use the shift value atm to represent register id due to current HAL +static int dl1_put_mixer(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); + struct snd_soc_dapm_widget *widget = wlist->widgets[0]; + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + + pm_runtime_get_sync(the_abe->dev); + + // TODO: optimise all of these to call HAL abe_enable_gain(mixer, enable) + if (ucontrol->value.integer.value[0]) { + the_abe->widget_opp[mc->shift] = ucontrol->value.integer.value[0]; + snd_soc_dapm_mixer_update_power(widget, kcontrol, 1); + abe_enable_gain(MIXDL1, mc->reg); + } else { + the_abe->widget_opp[mc->shift] = ucontrol->value.integer.value[0]; + snd_soc_dapm_mixer_update_power(widget, kcontrol, 0); + abe_disable_gain(MIXDL1, mc->reg); + } + pm_runtime_put_sync(the_abe->dev); + + return 1; +} + +static int dl2_put_mixer(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); + struct snd_soc_dapm_widget *widget = wlist->widgets[0]; + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + + pm_runtime_get_sync(the_abe->dev); + + if (ucontrol->value.integer.value[0]) { + the_abe->widget_opp[mc->shift] = ucontrol->value.integer.value[0]; + snd_soc_dapm_mixer_update_power(widget, kcontrol, 1); + abe_enable_gain(MIXDL2, mc->reg); + } else { + the_abe->widget_opp[mc->shift] = ucontrol->value.integer.value[0]; + snd_soc_dapm_mixer_update_power(widget, kcontrol, 0); + abe_disable_gain(MIXDL2, mc->reg); + } + + pm_runtime_put_sync(the_abe->dev); + return 1; +} + +static int audio_ul_put_mixer(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); + struct snd_soc_dapm_widget *widget = wlist->widgets[0]; + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + + pm_runtime_get_sync(the_abe->dev); + + if (ucontrol->value.integer.value[0]) { + the_abe->widget_opp[mc->shift] = ucontrol->value.integer.value[0]; + snd_soc_dapm_mixer_update_power(widget, kcontrol, 1); + abe_enable_gain(MIXAUDUL, mc->reg); + } else { + the_abe->widget_opp[mc->shift] = ucontrol->value.integer.value[0]; + snd_soc_dapm_mixer_update_power(widget, kcontrol, 0); + abe_disable_gain(MIXAUDUL, mc->reg); + } + pm_runtime_put_sync(the_abe->dev); + + return 1; +} + +static int vxrec_put_mixer(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); + struct snd_soc_dapm_widget *widget = wlist->widgets[0]; + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + + pm_runtime_get_sync(the_abe->dev); + + if (ucontrol->value.integer.value[0]) { + the_abe->widget_opp[mc->shift] = ucontrol->value.integer.value[0]; + snd_soc_dapm_mixer_update_power(widget, kcontrol, 1); + abe_enable_gain(MIXVXREC, mc->reg); + } else { + the_abe->widget_opp[mc->shift] = ucontrol->value.integer.value[0]; + snd_soc_dapm_mixer_update_power(widget, kcontrol, 0); + abe_disable_gain(MIXVXREC, mc->reg); + } + pm_runtime_put_sync(the_abe->dev); + + return 1; +} + +static int sdt_put_mixer(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); + struct snd_soc_dapm_widget *widget = wlist->widgets[0]; + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + + pm_runtime_get_sync(the_abe->dev); + + if (ucontrol->value.integer.value[0]) { + the_abe->widget_opp[mc->shift] = ucontrol->value.integer.value[0]; + snd_soc_dapm_mixer_update_power(widget, kcontrol, 1); + abe_enable_gain(MIXSDT, mc->reg); + } else { + the_abe->widget_opp[mc->shift] = ucontrol->value.integer.value[0]; + snd_soc_dapm_mixer_update_power(widget, kcontrol, 0); + abe_disable_gain(MIXSDT, mc->reg); + } + pm_runtime_put_sync(the_abe->dev); + + return 1; +} + +static int abe_get_mixer(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + + ucontrol->value.integer.value[0] = the_abe->widget_opp[mc->shift]; + return 0; +} + +static int abe_dsp_set_mono_mixer(int id, int enable) +{ + int mixer; + + switch (id) { + case MIX_DL1_MONO: + mixer = MIXDL1; + break; + case MIX_DL2_MONO: + mixer = MIXDL2; + break; + case MIX_AUDUL_MONO: + mixer = MIXAUDUL; + break; + default: + return -EINVAL; + } + + pm_runtime_get_sync(the_abe->dev); + abe_mono_mixer(mixer, enable); + pm_runtime_put_sync(the_abe->dev); + + return 0; +} + +static int abe_put_mono_mixer(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + int id = mc->shift - MIX_DL1_MONO; + + the_abe->mono_mix[id] = ucontrol->value.integer.value[0]; + abe_dsp_set_mono_mixer(mc->shift, the_abe->mono_mix[id]); + + return 1; +} + +static int abe_get_mono_mixer(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + int id = mc->shift - MIX_DL1_MONO; + + ucontrol->value.integer.value[0] = the_abe->mono_mix[id]; + return 0; +} + +/* router IDs that match our mixer strings */ +static const abe_router_t router[] = { + ZERO_labelID, /* strangely this is not 0 */ + DMIC1_L_labelID, DMIC1_R_labelID, + DMIC2_L_labelID, DMIC2_R_labelID, + DMIC3_L_labelID, DMIC3_R_labelID, + BT_UL_L_labelID, BT_UL_R_labelID, + MM_EXT_IN_L_labelID, MM_EXT_IN_R_labelID, + AMIC_L_labelID, AMIC_R_labelID, + VX_REC_L_labelID, VX_REC_R_labelID, +}; + +static int ul_mux_put_route(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); + struct snd_soc_dapm_widget *widget = wlist->widgets[0]; + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + int mux = ucontrol->value.enumerated.item[0]; + int reg = e->reg - ABE_MUX(0); + + pm_runtime_get_sync(the_abe->dev); + + if (mux > ABE_ROUTES_UL) + return 0; + + // TODO: get all this via firmware + if (reg < 8) { + /* 0 .. 9 = MM_UL */ + the_abe->router[reg] = router[mux]; + } else if (reg < 12) { + /* 10 .. 11 = MM_UL2 */ + /* 12 .. 13 = VX_UL */ + the_abe->router[reg + 2] = router[mux]; + } + + /* 2nd arg here is unused */ + abe_set_router_configuration(UPROUTE, 0, (u32 *)the_abe->router); + + if (router[mux] != ZERO_labelID) + the_abe->widget_opp[e->reg] = e->shift_l; + else + the_abe->widget_opp[e->reg] = 0; + + snd_soc_dapm_mux_update_power(widget, kcontrol, 1, mux, e); + pm_runtime_put_sync(the_abe->dev); + + return 1; +} + +static int ul_mux_get_route(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_enum *e = + (struct soc_enum *)kcontrol->private_value; + int reg = e->reg - ABE_MUX(0), i, rval = 0; + + // TODO: get all this via firmware + if (reg < 8) { + /* 0 .. 9 = MM_UL */ + rval = the_abe->router[reg]; + } else if (reg < 12) { + /* 10 .. 11 = MM_UL2 */ + /* 12 .. 13 = VX_UL */ + rval = the_abe->router[reg + 2]; + } + + for (i = 0; i < ARRAY_SIZE(router); i++) { + if (router[i] == rval) { + ucontrol->value.integer.value[0] = i; + return 0; + } + } + + return 1; +} + + +static int abe_put_switch(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); + struct snd_soc_dapm_widget *widget = wlist->widgets[0]; + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + + pm_runtime_get_sync(the_abe->dev); + + if (ucontrol->value.integer.value[0]) { + the_abe->widget_opp[mc->shift] = ucontrol->value.integer.value[0]; + snd_soc_dapm_mixer_update_power(widget, kcontrol, 1); + } else { + the_abe->widget_opp[mc->shift] = ucontrol->value.integer.value[0]; + snd_soc_dapm_mixer_update_power(widget, kcontrol, 0); + } + pm_runtime_put_sync(the_abe->dev); + + return 1; +} + + +static int volume_put_sdt_mixer(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + + pm_runtime_get_sync(the_abe->dev); + + abe_write_mixer(MIXSDT, abe_val_to_gain(ucontrol->value.integer.value[0]), + RAMP_2MS, mc->reg); + pm_runtime_put_sync(the_abe->dev); + + return 1; +} + +static int volume_put_audul_mixer(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + + pm_runtime_get_sync(the_abe->dev); + abe_write_mixer(MIXAUDUL, abe_val_to_gain(ucontrol->value.integer.value[0]), + RAMP_2MS, mc->reg); + pm_runtime_put_sync(the_abe->dev); + + return 1; +} + +static int volume_put_vxrec_mixer(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + + pm_runtime_get_sync(the_abe->dev); + abe_write_mixer(MIXVXREC, abe_val_to_gain(ucontrol->value.integer.value[0]), + RAMP_2MS, mc->reg); + pm_runtime_put_sync(the_abe->dev); + + return 1; +} + +static int volume_put_dl1_mixer(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + + pm_runtime_get_sync(the_abe->dev); + abe_write_mixer(MIXDL1, abe_val_to_gain(ucontrol->value.integer.value[0]), + RAMP_2MS, mc->reg); + pm_runtime_put_sync(the_abe->dev); + + return 1; +} + +static int volume_put_dl2_mixer(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + + pm_runtime_get_sync(the_abe->dev); + abe_write_mixer(MIXDL2, abe_val_to_gain(ucontrol->value.integer.value[0]), + RAMP_2MS, mc->reg); + pm_runtime_put_sync(the_abe->dev); + + return 1; +} + +static int volume_put_gain(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + + pm_runtime_get_sync(the_abe->dev); + abe_write_gain(mc->reg, + abe_val_to_gain(ucontrol->value.integer.value[0]), + RAMP_2MS, mc->shift); + abe_write_gain(mc->reg, + -12000 + (ucontrol->value.integer.value[1] * 100), + RAMP_2MS, mc->rshift); + pm_runtime_put_sync(the_abe->dev); + + return 1; +} + +static int volume_get_dl1_mixer(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + u32 val; + + pm_runtime_get_sync(the_abe->dev); + abe_read_mixer(MIXDL1, &val, mc->reg); + ucontrol->value.integer.value[0] = abe_gain_to_val(val); + pm_runtime_put_sync(the_abe->dev); + + return 0; +} + +static int volume_get_dl2_mixer(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + u32 val; + + pm_runtime_get_sync(the_abe->dev); + abe_read_mixer(MIXDL2, &val, mc->reg); + ucontrol->value.integer.value[0] = abe_gain_to_val(val); + pm_runtime_put_sync(the_abe->dev); + + return 0; +} + +static int volume_get_audul_mixer(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + u32 val; + + pm_runtime_get_sync(the_abe->dev); + abe_read_mixer(MIXAUDUL, &val, mc->reg); + ucontrol->value.integer.value[0] = abe_gain_to_val(val); + pm_runtime_put_sync(the_abe->dev); + + return 0; +} + +static int volume_get_vxrec_mixer(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + u32 val; + + pm_runtime_get_sync(the_abe->dev); + abe_read_mixer(MIXVXREC, &val, mc->reg); + ucontrol->value.integer.value[0] = abe_gain_to_val(val); + pm_runtime_put_sync(the_abe->dev); + + return 0; +} + +static int volume_get_sdt_mixer(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + u32 val; + + pm_runtime_get_sync(the_abe->dev); + abe_read_mixer(MIXSDT, &val, mc->reg); + ucontrol->value.integer.value[0] = abe_gain_to_val(val); + pm_runtime_put_sync(the_abe->dev); + + return 0; +} + +static int volume_get_gain(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + u32 val; + + pm_runtime_get_sync(the_abe->dev); + abe_read_gain(mc->reg, &val, mc->shift); + ucontrol->value.integer.value[0] = abe_gain_to_val(val); + abe_read_gain(mc->reg, &val, mc->rshift); + ucontrol->value.integer.value[1] = abe_gain_to_val(val); + pm_runtime_put_sync(the_abe->dev); + + return 0; +} + +static int abe_dsp_set_equalizer(unsigned int id, unsigned int profile) +{ + abe_equ_t equ_params; + int len; + + if (id >= the_abe->hdr.num_equ) + return -EINVAL; + + if (profile >= the_abe->equ_texts[id].count) + return -EINVAL; + + len = the_abe->equ_texts[id].coeff; + equ_params.equ_length = len; + memcpy(equ_params.coef.type1, the_abe->equ[id] + profile * len, + len * sizeof(u32)); + the_abe->equ_profile[id] = profile; + + pm_runtime_get_sync(the_abe->dev); + abe_write_equalizer(id + 1, &equ_params); + pm_runtime_put_sync(the_abe->dev); + + return 0; +} + +static int abe_get_equalizer(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_enum *eqc = (struct soc_enum *)kcontrol->private_value; + + ucontrol->value.integer.value[0] = the_abe->equ_profile[eqc->reg]; + return 0; +} + +static int abe_put_equalizer(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_enum *eqc = (struct soc_enum *)kcontrol->private_value; + u16 val = ucontrol->value.enumerated.item[0]; + int ret; + + ret = abe_dsp_set_equalizer(eqc->reg, val); + if (ret < 0) + return ret; + + return 1; +} + +int snd_soc_info_enum_ext1(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = e->max; + + if (uinfo->value.enumerated.item > e->max - 1) + uinfo->value.enumerated.item = e->max - 1; + strcpy(uinfo->value.enumerated.name, + snd_soc_get_enum_text(e, uinfo->value.enumerated.item)); + + return 0; +} + +static const char *route_ul_texts[] = { + "None", "DMic0L", "DMic0R", "DMic1L", "DMic1R", "DMic2L", "DMic2R", + "BT Left", "BT Right", "MMExt Left", "MMExt Right", "AMic0", "AMic1", + "VX Left", "VX Right" +}; + +/* ROUTE_UL Mux table */ +static const struct soc_enum abe_enum[] = { + SOC_ENUM_SINGLE(MUX_MM_UL10, 0, 15, route_ul_texts), + SOC_ENUM_SINGLE(MUX_MM_UL11, 0, 15, route_ul_texts), + SOC_ENUM_SINGLE(MUX_MM_UL12, 0, 15, route_ul_texts), + SOC_ENUM_SINGLE(MUX_MM_UL13, 0, 15, route_ul_texts), + SOC_ENUM_SINGLE(MUX_MM_UL14, 0, 15, route_ul_texts), + SOC_ENUM_SINGLE(MUX_MM_UL15, 0, 15, route_ul_texts), + SOC_ENUM_SINGLE(MUX_MM_UL16, 0, 15, route_ul_texts), + SOC_ENUM_SINGLE(MUX_MM_UL17, 0, 15, route_ul_texts), + SOC_ENUM_SINGLE(MUX_MM_UL20, 0, 15, route_ul_texts), + SOC_ENUM_SINGLE(MUX_MM_UL21, 0, 15, route_ul_texts), + SOC_ENUM_SINGLE(MUX_VX_UL0, 0, 15, route_ul_texts), + SOC_ENUM_SINGLE(MUX_VX_UL1, 0, 15, route_ul_texts), +}; + +static const struct snd_kcontrol_new mm_ul00_control = + SOC_DAPM_ENUM_EXT("Route", abe_enum[0], + ul_mux_get_route, ul_mux_put_route); + +static const struct snd_kcontrol_new mm_ul01_control = + SOC_DAPM_ENUM_EXT("Route", abe_enum[1], + ul_mux_get_route, ul_mux_put_route); + +static const struct snd_kcontrol_new mm_ul02_control = + SOC_DAPM_ENUM_EXT("Route", abe_enum[2], + ul_mux_get_route, ul_mux_put_route); + +static const struct snd_kcontrol_new mm_ul03_control = + SOC_DAPM_ENUM_EXT("Route", abe_enum[3], + ul_mux_get_route, ul_mux_put_route); + +static const struct snd_kcontrol_new mm_ul04_control = + SOC_DAPM_ENUM_EXT("Route", abe_enum[4], + ul_mux_get_route, ul_mux_put_route); + +static const struct snd_kcontrol_new mm_ul05_control = + SOC_DAPM_ENUM_EXT("Route", abe_enum[5], + ul_mux_get_route, ul_mux_put_route); + +static const struct snd_kcontrol_new mm_ul06_control = + SOC_DAPM_ENUM_EXT("Route", abe_enum[6], + ul_mux_get_route, ul_mux_put_route); + +static const struct snd_kcontrol_new mm_ul07_control = + SOC_DAPM_ENUM_EXT("Route", abe_enum[7], + ul_mux_get_route, ul_mux_put_route); + +static const struct snd_kcontrol_new mm_ul10_control = + SOC_DAPM_ENUM_EXT("Route", abe_enum[8], + ul_mux_get_route, ul_mux_put_route); + +static const struct snd_kcontrol_new mm_ul11_control = + SOC_DAPM_ENUM_EXT("Route", abe_enum[9], + ul_mux_get_route, ul_mux_put_route); + +static const struct snd_kcontrol_new mm_vx0_control = + SOC_DAPM_ENUM_EXT("Route", abe_enum[10], + ul_mux_get_route, ul_mux_put_route); + +static const struct snd_kcontrol_new mm_vx1_control = + SOC_DAPM_ENUM_EXT("Route", abe_enum[11], + ul_mux_get_route, ul_mux_put_route); + +/* DL1 mixer paths */ +static const struct snd_kcontrol_new dl1_mixer_controls[] = { + SOC_SINGLE_EXT("Tones", MIX_DL1_INPUT_TONES, MIX_DL1_TONES, 1, 0, + abe_get_mixer, dl1_put_mixer), + SOC_SINGLE_EXT("Voice", MIX_DL1_INPUT_VX_DL, MIX_DL1_VOICE, 1, 0, + abe_get_mixer, dl1_put_mixer), + SOC_SINGLE_EXT("Capture", MIX_DL1_INPUT_MM_UL2, MIX_DL1_CAPTURE, 1, 0, + abe_get_mixer, dl1_put_mixer), + SOC_SINGLE_EXT("Multimedia", MIX_DL1_INPUT_MM_DL, MIX_DL1_MEDIA, 1, 0, + abe_get_mixer, dl1_put_mixer), +}; + +/* DL2 mixer paths */ +static const struct snd_kcontrol_new dl2_mixer_controls[] = { + SOC_SINGLE_EXT("Tones", MIX_DL2_INPUT_TONES, MIX_DL2_TONES, 1, 0, + abe_get_mixer, dl2_put_mixer), + SOC_SINGLE_EXT("Voice", MIX_DL2_INPUT_VX_DL, MIX_DL2_VOICE, 1, 0, + abe_get_mixer, dl2_put_mixer), + SOC_SINGLE_EXT("Capture", MIX_DL2_INPUT_MM_UL2, MIX_DL2_CAPTURE, 1, 0, + abe_get_mixer, dl2_put_mixer), + SOC_SINGLE_EXT("Multimedia", MIX_DL2_INPUT_MM_DL, MIX_DL2_MEDIA, 1, 0, + abe_get_mixer, dl2_put_mixer), +}; + +/* AUDUL ("Voice Capture Mixer") mixer paths */ +static const struct snd_kcontrol_new audio_ul_mixer_controls[] = { + SOC_SINGLE_EXT("Tones Playback", MIX_AUDUL_INPUT_TONES, MIX_AUDUL_TONES, 1, 0, + abe_get_mixer, audio_ul_put_mixer), + SOC_SINGLE_EXT("Media Playback", MIX_AUDUL_INPUT_MM_DL, MIX_AUDUL_MEDIA, 1, 0, + abe_get_mixer, audio_ul_put_mixer), + SOC_SINGLE_EXT("Capture", MIX_AUDUL_INPUT_UPLINK, MIX_AUDUL_CAPTURE, 1, 0, + abe_get_mixer, audio_ul_put_mixer), +}; + +/* VXREC ("Capture Mixer") mixer paths */ +static const struct snd_kcontrol_new vx_rec_mixer_controls[] = { + SOC_SINGLE_EXT("Tones", MIX_VXREC_INPUT_TONES, MIX_VXREC_TONES, 1, 0, + abe_get_mixer, vxrec_put_mixer), + SOC_SINGLE_EXT("Voice Playback", MIX_VXREC_INPUT_VX_DL, + MIX_VXREC_VOICE_PLAYBACK, 1, 0, abe_get_mixer, vxrec_put_mixer), + SOC_SINGLE_EXT("Voice Capture", MIX_VXREC_INPUT_VX_UL, + MIX_VXREC_VOICE_CAPTURE, 1, 0, abe_get_mixer, vxrec_put_mixer), + SOC_SINGLE_EXT("Media Playback", MIX_VXREC_INPUT_MM_DL, + MIX_VXREC_MEDIA, 1, 0, abe_get_mixer, vxrec_put_mixer), +}; + +/* SDT ("Sidetone Mixer") mixer paths */ +static const struct snd_kcontrol_new sdt_mixer_controls[] = { + SOC_SINGLE_EXT("Capture", MIX_SDT_INPUT_UP_MIXER, MIX_SDT_CAPTURE, 1, 0, + abe_get_mixer, sdt_put_mixer), + SOC_SINGLE_EXT("Playback", MIX_SDT_INPUT_DL1_MIXER, MIX_SDT_PLAYBACK, 1, 0, + abe_get_mixer, sdt_put_mixer), +}; + +/* Virtual PDM_DL Switch */ +static const struct snd_kcontrol_new pdm_dl1_switch_controls = + SOC_SINGLE_EXT("Switch", ABE_VIRTUAL_SWITCH, MIX_SWITCH_PDM_DL, 1, 0, + abe_get_mixer, abe_put_switch); + +/* Virtual BT_VX_DL Switch */ +static const struct snd_kcontrol_new bt_vx_dl_switch_controls = + SOC_SINGLE_EXT("Switch", ABE_VIRTUAL_SWITCH, MIX_SWITCH_BT_VX_DL, 1, 0, + abe_get_mixer, abe_put_switch); + +/* Virtual MM_EXT_DL Switch */ +static const struct snd_kcontrol_new mm_ext_dl_switch_controls = + SOC_SINGLE_EXT("Switch", ABE_VIRTUAL_SWITCH, MIX_SWITCH_MM_EXT_DL, 1, 0, + abe_get_mixer, abe_put_switch); + +static const struct snd_kcontrol_new abe_controls[] = { + /* DL1 mixer gains */ + SOC_SINGLE_EXT_TLV("DL1 Media Playback Volume", + MIX_DL1_INPUT_MM_DL, 0, 149, 0, + volume_get_dl1_mixer, volume_put_dl1_mixer, mm_dl1_tlv), + SOC_SINGLE_EXT_TLV("DL1 Tones Playback Volume", + MIX_DL1_INPUT_TONES, 0, 149, 0, + volume_get_dl1_mixer, volume_put_dl1_mixer, tones_dl1_tlv), + SOC_SINGLE_EXT_TLV("DL1 Voice Playback Volume", + MIX_DL1_INPUT_VX_DL, 0, 149, 0, + volume_get_dl1_mixer, volume_put_dl1_mixer, voice_dl1_tlv), + SOC_SINGLE_EXT_TLV("DL1 Capture Playback Volume", + MIX_DL1_INPUT_MM_UL2, 0, 149, 0, + volume_get_dl1_mixer, volume_put_dl1_mixer, capture_dl1_tlv), + + /* DL2 mixer gains */ + SOC_SINGLE_EXT_TLV("DL2 Media Playback Volume", + MIX_DL2_INPUT_MM_DL, 0, 149, 0, + volume_get_dl2_mixer, volume_put_dl2_mixer, mm_dl2_tlv), + SOC_SINGLE_EXT_TLV("DL2 Tones Playback Volume", + MIX_DL2_INPUT_TONES, 0, 149, 0, + volume_get_dl2_mixer, volume_put_dl2_mixer, tones_dl2_tlv), + SOC_SINGLE_EXT_TLV("DL2 Voice Playback Volume", + MIX_DL2_INPUT_VX_DL, 0, 149, 0, + volume_get_dl2_mixer, volume_put_dl2_mixer, voice_dl2_tlv), + SOC_SINGLE_EXT_TLV("DL2 Capture Playback Volume", + MIX_DL2_INPUT_MM_UL2, 0, 149, 0, + volume_get_dl2_mixer, volume_put_dl2_mixer, capture_dl2_tlv), + + /* VXREC mixer gains */ + SOC_SINGLE_EXT_TLV("VXREC Media Volume", + MIX_VXREC_INPUT_MM_DL, 0, 149, 0, + volume_get_vxrec_mixer, volume_put_vxrec_mixer, vxrec_mm_dl_tlv), + SOC_SINGLE_EXT_TLV("VXREC Tones Volume", + MIX_VXREC_INPUT_TONES, 0, 149, 0, + volume_get_vxrec_mixer, volume_put_vxrec_mixer, vxrec_tones_tlv), + SOC_SINGLE_EXT_TLV("VXREC Voice DL Volume", + MIX_VXREC_INPUT_VX_UL, 0, 149, 0, + volume_get_vxrec_mixer, volume_put_vxrec_mixer, vxrec_vx_dl_tlv), + SOC_SINGLE_EXT_TLV("VXREC Voice UL Volume", + MIX_VXREC_INPUT_VX_DL, 0, 149, 0, + volume_get_vxrec_mixer, volume_put_vxrec_mixer, vxrec_vx_ul_tlv), + + /* AUDUL mixer gains */ + SOC_SINGLE_EXT_TLV("AUDUL Media Volume", + MIX_AUDUL_INPUT_MM_DL, 0, 149, 0, + volume_get_audul_mixer, volume_put_audul_mixer, audul_mm_tlv), + SOC_SINGLE_EXT_TLV("AUDUL Tones Volume", + MIX_AUDUL_INPUT_TONES, 0, 149, 0, + volume_get_audul_mixer, volume_put_audul_mixer, audul_tones_tlv), + SOC_SINGLE_EXT_TLV("AUDUL Voice UL Volume", + MIX_AUDUL_INPUT_UPLINK, 0, 149, 0, + volume_get_audul_mixer, volume_put_audul_mixer, audul_vx_ul_tlv), + SOC_SINGLE_EXT_TLV("AUDUL Voice DL Volume", + MIX_AUDUL_INPUT_VX_DL, 0, 149, 0, + volume_get_audul_mixer, volume_put_audul_mixer, audul_vx_dl_tlv), + + /* SDT mixer gains */ + SOC_SINGLE_EXT_TLV("SDT UL Volume", + MIX_SDT_INPUT_UP_MIXER, 0, 149, 0, + volume_get_sdt_mixer, volume_put_sdt_mixer, sdt_ul_tlv), + SOC_SINGLE_EXT_TLV("SDT DL Volume", + MIX_SDT_INPUT_DL1_MIXER, 0, 149, 0, + volume_get_sdt_mixer, volume_put_sdt_mixer, sdt_dl_tlv), + + /* DMIC gains */ + SOC_DOUBLE_EXT_TLV("DMIC1 UL Volume", + GAINS_DMIC1, GAIN_LEFT_OFFSET, GAIN_RIGHT_OFFSET, 149, 0, + volume_get_gain, volume_put_gain, dmic_tlv), + + SOC_DOUBLE_EXT_TLV("DMIC2 UL Volume", + GAINS_DMIC2, GAIN_LEFT_OFFSET, GAIN_RIGHT_OFFSET, 149, 0, + volume_get_gain, volume_put_gain, dmic_tlv), + + SOC_DOUBLE_EXT_TLV("DMIC3 UL Volume", + GAINS_DMIC3, GAIN_LEFT_OFFSET, GAIN_RIGHT_OFFSET, 149, 0, + volume_get_gain, volume_put_gain, dmic_tlv), + + SOC_DOUBLE_EXT_TLV("AMIC UL Volume", + GAINS_AMIC, GAIN_LEFT_OFFSET, GAIN_RIGHT_OFFSET, 149, 0, + volume_get_gain, volume_put_gain, amic_tlv), + + SOC_DOUBLE_EXT_TLV("BT UL Volume", + GAINS_BTUL, GAIN_LEFT_OFFSET, GAIN_RIGHT_OFFSET, 149, 0, + volume_get_gain, volume_put_gain, btul_tlv), + + SOC_SINGLE_EXT("DL1 Mono Mixer", MIXDL1, MIX_DL1_MONO, 1, 0, + abe_get_mono_mixer, abe_put_mono_mixer), + SOC_SINGLE_EXT("DL2 Mono Mixer", MIXDL2, MIX_DL2_MONO, 1, 0, + abe_get_mono_mixer, abe_put_mono_mixer), + SOC_SINGLE_EXT("AUDUL Mono Mixer", MIXAUDUL, MIX_AUDUL_MONO, 1, 0, + abe_get_mono_mixer, abe_put_mono_mixer), +}; + +static const struct snd_soc_dapm_widget abe_dapm_widgets[] = { + + /* Frontend AIFs */ + SND_SOC_DAPM_AIF_IN("TONES_DL", "Tones Playback", 0, + W_AIF_TONES_DL, ABE_OPP_25, 0), + SND_SOC_DAPM_AIF_IN("VX_DL", "Voice Playback", 0, + W_AIF_VX_DL, ABE_OPP_50, 0), + SND_SOC_DAPM_AIF_OUT("VX_UL", "Voice Capture", 0, + W_AIF_VX_UL, ABE_OPP_50, 0), + /* the MM_UL mapping is intentional */ + SND_SOC_DAPM_AIF_OUT("MM_UL1", "MultiMedia1 Capture", 0, + W_AIF_MM_UL1, ABE_OPP_100, 0), + SND_SOC_DAPM_AIF_OUT("MM_UL2", "MultiMedia2 Capture", 0, + W_AIF_MM_UL2, ABE_OPP_50, 0), + SND_SOC_DAPM_AIF_IN("MM_DL", " MultiMedia1 Playback", 0, + W_AIF_MM_DL, ABE_OPP_25, 0), + SND_SOC_DAPM_AIF_IN("MM_DL_LP", " MultiMedia1 LP Playback", 0, + W_AIF_MM_DL_LP, ABE_OPP_25, 0), + SND_SOC_DAPM_AIF_IN("VIB_DL", "Vibra Playback", 0, + W_AIF_VIB_DL, ABE_OPP_100, 0), + SND_SOC_DAPM_AIF_IN("MODEM_DL", "MODEM Playback", 0, + W_AIF_MODEM_DL, ABE_OPP_50, 0), + SND_SOC_DAPM_AIF_OUT("MODEM_UL", "MODEM Capture", 0, + W_AIF_MODEM_UL, ABE_OPP_50, 0), + + /* Backend DAIs */ + SND_SOC_DAPM_AIF_IN("PDM_UL1", "Analog Capture", 0, + W_AIF_PDM_UL1, ABE_OPP_50, 0), + SND_SOC_DAPM_AIF_OUT("PDM_DL1", "HS Playback", 0, + W_AIF_PDM_DL1, ABE_OPP_25, 0), + SND_SOC_DAPM_AIF_OUT("PDM_DL2", "HF Playback", 0, + W_AIF_PDM_DL2, ABE_OPP_100, 0), + SND_SOC_DAPM_AIF_OUT("PDM_VIB", "Vibra Playback", 0, + W_AIF_PDM_VIB, ABE_OPP_100, 0), + SND_SOC_DAPM_AIF_IN("BT_VX_UL", "BT Capture", 0, + W_AIF_BT_VX_UL, ABE_OPP_50, 0), + SND_SOC_DAPM_AIF_OUT("BT_VX_DL", "BT Playback", 0, + W_AIF_BT_VX_DL, ABE_OPP_50, 0), + SND_SOC_DAPM_AIF_IN("MM_EXT_UL", "FM Capture", 0, + W_AIF_MM_EXT_UL, ABE_OPP_50, 0), + SND_SOC_DAPM_AIF_OUT("MM_EXT_DL", "FM Playback", 0, + W_AIF_MM_EXT_DL, ABE_OPP_25, 0), + SND_SOC_DAPM_AIF_IN("DMIC0", "DMIC0 Capture", 0, + W_AIF_DMIC0, ABE_OPP_50, 0), + SND_SOC_DAPM_AIF_IN("DMIC1", "DMIC1 Capture", 0, + W_AIF_DMIC1, ABE_OPP_50, 0), + SND_SOC_DAPM_AIF_IN("DMIC2", "DMIC2 Capture", 0, + W_AIF_DMIC2, ABE_OPP_50, 0), + + /* ROUTE_UL Capture Muxes */ + SND_SOC_DAPM_MUX("MUX_UL00", + W_MUX_UL00, ABE_OPP_50, 0, &mm_ul00_control), + SND_SOC_DAPM_MUX("MUX_UL01", + W_MUX_UL01, ABE_OPP_50, 0, &mm_ul01_control), + SND_SOC_DAPM_MUX("MUX_UL02", + W_MUX_UL02, ABE_OPP_50, 0, &mm_ul02_control), + SND_SOC_DAPM_MUX("MUX_UL03", + W_MUX_UL03, ABE_OPP_50, 0, &mm_ul03_control), + SND_SOC_DAPM_MUX("MUX_UL04", + W_MUX_UL04, ABE_OPP_50, 0, &mm_ul04_control), + SND_SOC_DAPM_MUX("MUX_UL05", + W_MUX_UL05, ABE_OPP_50, 0, &mm_ul05_control), + SND_SOC_DAPM_MUX("MUX_UL06", + W_MUX_UL06, ABE_OPP_50, 0, &mm_ul06_control), + SND_SOC_DAPM_MUX("MUX_UL07", + W_MUX_UL07, ABE_OPP_50, 0, &mm_ul07_control), + SND_SOC_DAPM_MUX("MUX_UL10", + W_MUX_UL10, ABE_OPP_50, 0, &mm_ul10_control), + SND_SOC_DAPM_MUX("MUX_UL11", + W_MUX_UL11, ABE_OPP_50, 0, &mm_ul11_control), + SND_SOC_DAPM_MUX("MUX_VX0", + W_MUX_VX00, ABE_OPP_50, 0, &mm_vx0_control), + SND_SOC_DAPM_MUX("MUX_VX1", + W_MUX_VX01, ABE_OPP_50, 0, &mm_vx1_control), + + /* DL1 & DL2 Playback Mixers */ + SND_SOC_DAPM_MIXER("DL1 Mixer", + W_MIXER_DL1, ABE_OPP_25, 0, dl1_mixer_controls, + ARRAY_SIZE(dl1_mixer_controls)), + SND_SOC_DAPM_MIXER("DL2 Mixer", + W_MIXER_DL2, ABE_OPP_100, 0, dl2_mixer_controls, + ARRAY_SIZE(dl2_mixer_controls)), + + /* DL1 Mixer Input volumes ?????*/ + SND_SOC_DAPM_PGA("DL1 Media Volume", + W_VOLUME_DL1, 0, 0, NULL, 0), + + /* AUDIO_UL_MIXER */ + SND_SOC_DAPM_MIXER("Voice Capture Mixer", + W_MIXER_AUDIO_UL, ABE_OPP_50, 0, audio_ul_mixer_controls, + ARRAY_SIZE(audio_ul_mixer_controls)), + + /* VX_REC_MIXER */ + SND_SOC_DAPM_MIXER("Capture Mixer", + W_MIXER_VX_REC, ABE_OPP_50, 0, vx_rec_mixer_controls, + ARRAY_SIZE(vx_rec_mixer_controls)), + + /* SDT_MIXER - TODO: shoult this not be OPP25 ??? */ + SND_SOC_DAPM_MIXER("Sidetone Mixer", + W_MIXER_SDT, ABE_OPP_25, 0, sdt_mixer_controls, + ARRAY_SIZE(sdt_mixer_controls)), + + /* + * The Following three are virtual switches to select the output port + * after DL1 Gain. + */ + + /* Virtual PDM_DL1 Switch */ + SND_SOC_DAPM_MIXER("DL1 PDM", + W_VSWITCH_DL1_PDM, ABE_OPP_25, 0, &pdm_dl1_switch_controls, 1), + + /* Virtual BT_VX_DL Switch */ + SND_SOC_DAPM_MIXER("DL1 BT_VX", + W_VSWITCH_DL1_BT_VX, ABE_OPP_50, 0, &bt_vx_dl_switch_controls, 1), + + /* Virtual MM_EXT_DL Switch TODO: confrm OPP level here */ + SND_SOC_DAPM_MIXER("DL1 MM_EXT", + W_VSWITCH_DL1_MM_EXT, ABE_OPP_50, 0, &mm_ext_dl_switch_controls, 1), + + /* Virtuals to join our capture sources */ + SND_SOC_DAPM_MIXER("Sidetone Capture VMixer", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("Voice Capture VMixer", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("DL1 Capture VMixer", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("DL2 Capture VMixer", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* Join our MM_DL and MM_DL_LP playback */ + SND_SOC_DAPM_MIXER("MM_DL VMixer", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* Virtual MODEM and VX_UL mixer */ + SND_SOC_DAPM_MIXER("VX UL VMixer", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("VX DL VMixer", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* Virtual Pins to force backends ON atm */ + SND_SOC_DAPM_OUTPUT("BE_OUT"), + SND_SOC_DAPM_INPUT("BE_IN"), +}; + +static const struct snd_soc_dapm_route intercon[] = { + + /* MUX_UL00 - ROUTE_UL - Chan 0 */ + {"MUX_UL00", "DMic0L", "DMIC0"}, + {"MUX_UL00", "DMic0R", "DMIC0"}, + {"MUX_UL00", "DMic1L", "DMIC1"}, + {"MUX_UL00", "DMic1R", "DMIC1"}, + {"MUX_UL00", "DMic2L", "DMIC2"}, + {"MUX_UL00", "DMic2R", "DMIC2"}, + {"MUX_UL00", "BT Left", "BT_VX_UL"}, + {"MUX_UL00", "BT Right", "BT_VX_UL"}, + {"MUX_UL00", "MMExt Left", "MM_EXT_UL"}, + {"MUX_UL00", "MMExt Right", "MM_EXT_UL"}, + {"MUX_UL00", "AMic0", "PDM_UL1"}, + {"MUX_UL00", "AMic1", "PDM_UL1"}, + {"MUX_UL00", "VX Left", "Capture Mixer"}, + {"MUX_UL00", "VX Right", "Capture Mixer"}, + {"MM_UL1", NULL, "MUX_UL00"}, + + /* MUX_UL01 - ROUTE_UL - Chan 1 */ + {"MUX_UL01", "DMic0L", "DMIC0"}, + {"MUX_UL01", "DMic0R", "DMIC0"}, + {"MUX_UL01", "DMic1L", "DMIC1"}, + {"MUX_UL01", "DMic1R", "DMIC1"}, + {"MUX_UL01", "DMic2L", "DMIC2"}, + {"MUX_UL01", "DMic2R", "DMIC2"}, + {"MUX_UL01", "BT Left", "BT_VX_UL"}, + {"MUX_UL01", "BT Right", "BT_VX_UL"}, + {"MUX_UL01", "MMExt Left", "MM_EXT_UL"}, + {"MUX_UL01", "MMExt Right", "MM_EXT_UL"}, + {"MUX_UL01", "AMic0", "PDM_UL1"}, + {"MUX_UL01", "AMic1", "PDM_UL1"}, + {"MUX_UL01", "VX Left", "Capture Mixer"}, + {"MUX_UL01", "VX Right", "Capture Mixer"}, + {"MM_UL1", NULL, "MUX_UL01"}, + + /* MUX_UL02 - ROUTE_UL - Chan 2 */ + {"MUX_UL02", "DMic0L", "DMIC0"}, + {"MUX_UL02", "DMic0R", "DMIC0"}, + {"MUX_UL02", "DMic1L", "DMIC1"}, + {"MUX_UL02", "DMic1R", "DMIC1"}, + {"MUX_UL02", "DMic2L", "DMIC2"}, + {"MUX_UL02", "DMic2R", "DMIC2"}, + {"MUX_UL02", "BT Left", "BT_VX_UL"}, + {"MUX_UL02", "BT Right", "BT_VX_UL"}, + {"MUX_UL02", "MMExt Left", "MM_EXT_UL"}, + {"MUX_UL02", "MMExt Right", "MM_EXT_UL"}, + {"MUX_UL02", "AMic0", "PDM_UL1"}, + {"MUX_UL02", "AMic1", "PDM_UL1"}, + {"MUX_UL02", "VX Left", "Capture Mixer"}, + {"MUX_UL02", "VX Right", "Capture Mixer"}, + {"MM_UL1", NULL, "MUX_UL02"}, + + /* MUX_UL03 - ROUTE_UL - Chan 3 */ + {"MUX_UL03", "DMic0L", "DMIC0"}, + {"MUX_UL03", "DMic0R", "DMIC0"}, + {"MUX_UL03", "DMic1L", "DMIC1"}, + {"MUX_UL03", "DMic1R", "DMIC1"}, + {"MUX_UL03", "DMic2L", "DMIC2"}, + {"MUX_UL03", "DMic2R", "DMIC2"}, + {"MUX_UL03", "BT Left", "BT_VX_UL"}, + {"MUX_UL03", "BT Right", "BT_VX_UL"}, + {"MUX_UL03", "MMExt Left", "MM_EXT_UL"}, + {"MUX_UL03", "MMExt Right", "MM_EXT_UL"}, + {"MUX_UL03", "AMic0", "PDM_UL1"}, + {"MUX_UL03", "AMic1", "PDM_UL1"}, + {"MUX_UL03", "VX Left", "Capture Mixer"}, + {"MUX_UL03", "VX Right", "Capture Mixer"}, + {"MM_UL1", NULL, "MUX_UL03"}, + + /* MUX_UL04 - ROUTE_UL - Chan 4 */ + {"MUX_UL04", "DMic0L", "DMIC0"}, + {"MUX_UL04", "DMic0R", "DMIC0"}, + {"MUX_UL04", "DMic1L", "DMIC1"}, + {"MUX_UL04", "DMic1R", "DMIC1"}, + {"MUX_UL04", "DMic2L", "DMIC2"}, + {"MUX_UL04", "DMic2R", "DMIC2"}, + {"MUX_UL04", "BT Left", "BT_VX_UL"}, + {"MUX_UL04", "BT Right", "BT_VX_UL"}, + {"MUX_UL04", "MMExt Left", "MM_EXT_UL"}, + {"MUX_UL04", "MMExt Right", "MM_EXT_UL"}, + {"MUX_UL04", "AMic0", "PDM_UL1"}, + {"MUX_UL04", "AMic1", "PDM_UL1"}, + {"MUX_UL04", "VX Left", "Capture Mixer"}, + {"MUX_UL04", "VX Right", "Capture Mixer"}, + {"MM_UL1", NULL, "MUX_UL04"}, + + /* MUX_UL05 - ROUTE_UL - Chan 5 */ + {"MUX_UL05", "DMic0L", "DMIC0"}, + {"MUX_UL05", "DMic0R", "DMIC0"}, + {"MUX_UL05", "DMic1L", "DMIC1"}, + {"MUX_UL05", "DMic1R", "DMIC1"}, + {"MUX_UL05", "DMic2L", "DMIC2"}, + {"MUX_UL05", "DMic2R", "DMIC2"}, + {"MUX_UL05", "BT Left", "BT_VX_UL"}, + {"MUX_UL05", "BT Right", "BT_VX_UL"}, + {"MUX_UL05", "MMExt Left", "MM_EXT_UL"}, + {"MUX_UL05", "MMExt Right", "MM_EXT_UL"}, + {"MUX_UL05", "AMic0", "PDM_UL1"}, + {"MUX_UL05", "AMic1", "PDM_UL1"}, + {"MUX_UL05", "VX Left", "Capture Mixer"}, + {"MUX_UL05", "VX Right", "Capture Mixer"}, + {"MM_UL1", NULL, "MUX_UL05"}, + + /* MUX_UL06 - ROUTE_UL - Chan 6 */ + {"MUX_UL06", "DMic0L", "DMIC0"}, + {"MUX_UL06", "DMic0R", "DMIC0"}, + {"MUX_UL06", "DMic1L", "DMIC1"}, + {"MUX_UL06", "DMic1R", "DMIC1"}, + {"MUX_UL06", "DMic2L", "DMIC2"}, + {"MUX_UL06", "DMic2R", "DMIC2"}, + {"MUX_UL06", "BT Left", "BT_VX_UL"}, + {"MUX_UL06", "BT Right", "BT_VX_UL"}, + {"MUX_UL06", "MMExt Left", "MM_EXT_UL"}, + {"MUX_UL06", "MMExt Right", "MM_EXT_UL"}, + {"MUX_UL06", "AMic0", "PDM_UL1"}, + {"MUX_UL06", "AMic1", "PDM_UL1"}, + {"MUX_UL06", "VX Left", "Capture Mixer"}, + {"MUX_UL06", "VX Right", "Capture Mixer"}, + {"MM_UL1", NULL, "MUX_UL06"}, + + /* MUX_UL07 - ROUTE_UL - Chan 7 */ + {"MUX_UL07", "DMic0L", "DMIC0"}, + {"MUX_UL07", "DMic0R", "DMIC0"}, + {"MUX_UL07", "DMic1L", "DMIC1"}, + {"MUX_UL07", "DMic1R", "DMIC1"}, + {"MUX_UL07", "DMic2L", "DMIC2"}, + {"MUX_UL07", "DMic2R", "DMIC2"}, + {"MUX_UL07", "BT Left", "BT_VX_UL"}, + {"MUX_UL07", "BT Right", "BT_VX_UL"}, + {"MUX_UL07", "MMExt Left", "MM_EXT_UL"}, + {"MUX_UL07", "MMExt Right", "MM_EXT_UL"}, + {"MUX_UL07", "AMic0", "PDM_UL1"}, + {"MUX_UL07", "AMic1", "PDM_UL1"}, + {"MUX_UL07", "VX Left", "Capture Mixer"}, + {"MUX_UL07", "VX Right", "Capture Mixer"}, + {"MM_UL1", NULL, "MUX_UL07"}, + + /* MUX_UL10 - ROUTE_UL - Chan 10 */ + {"MUX_UL10", "DMic0L", "DMIC0"}, + {"MUX_UL10", "DMic0R", "DMIC0"}, + {"MUX_UL10", "DMic1L", "DMIC1"}, + {"MUX_UL10", "DMic1R", "DMIC1"}, + {"MUX_UL10", "DMic2L", "DMIC2"}, + {"MUX_UL10", "DMic2R", "DMIC2"}, + {"MUX_UL10", "BT Left", "BT_VX_UL"}, + {"MUX_UL10", "BT Right", "BT_VX_UL"}, + {"MUX_UL10", "MMExt Left", "MM_EXT_UL"}, + {"MUX_UL10", "MMExt Right", "MM_EXT_UL"}, + {"MUX_UL10", "AMic0", "PDM_UL1"}, + {"MUX_UL10", "AMic1", "PDM_UL1"}, + {"MUX_UL10", "VX Left", "Capture Mixer"}, + {"MUX_UL10", "VX Right", "Capture Mixer"}, + {"MM_UL2", NULL, "MUX_UL10"}, + + /* MUX_UL11 - ROUTE_UL - Chan 11 */ + {"MUX_UL11", "DMic0L", "DMIC0"}, + {"MUX_UL11", "DMic0R", "DMIC0"}, + {"MUX_UL11", "DMic1L", "DMIC1"}, + {"MUX_UL11", "DMic1R", "DMIC1"}, + {"MUX_UL11", "DMic2L", "DMIC2"}, + {"MUX_UL11", "DMic2R", "DMIC2"}, + {"MUX_UL11", "BT Left", "BT_VX_UL"}, + {"MUX_UL11", "BT Right", "BT_VX_UL"}, + {"MUX_UL11", "MMExt Left", "MM_EXT_UL"}, + {"MUX_UL11", "MMExt Right", "MM_EXT_UL"}, + {"MUX_UL11", "AMic0", "PDM_UL1"}, + {"MUX_UL11", "AMic1", "PDM_UL1"}, + {"MUX_UL11", "VX Left", "Capture Mixer"}, + {"MUX_UL11", "VX Right", "Capture Mixer"}, + {"MM_UL2", NULL, "MUX_UL11"}, + + /* MUX_VX0 - ROUTE_UL - Chan 20 */ + {"MUX_VX0", "DMic0L", "DMIC0"}, + {"MUX_VX0", "DMic0R", "DMIC0"}, + {"MUX_VX0", "DMic1L", "DMIC1"}, + {"MUX_VX0", "DMic1R", "DMIC1"}, + {"MUX_VX0", "DMic2L", "DMIC2"}, + {"MUX_VX0", "DMic2R", "DMIC2"}, + {"MUX_VX0", "BT Left", "BT_VX_UL"}, + {"MUX_VX0", "BT Right", "BT_VX_UL"}, + {"MUX_VX0", "MMExt Left", "MM_EXT_UL"}, + {"MUX_VX0", "MMExt Right", "MM_EXT_UL"}, + {"MUX_VX0", "AMic0", "PDM_UL1"}, + {"MUX_VX0", "AMic1", "PDM_UL1"}, + {"MUX_VX0", "VX Left", "Capture Mixer"}, + {"MUX_VX0", "VX Right", "Capture Mixer"}, + + /* MUX_VX1 - ROUTE_UL - Chan 20 */ + {"MUX_VX1", "DMic0L", "DMIC0"}, + {"MUX_VX1", "DMic0R", "DMIC0"}, + {"MUX_VX1", "DMic1L", "DMIC1"}, + {"MUX_VX1", "DMic1R", "DMIC1"}, + {"MUX_VX1", "DMic2L", "DMIC2"}, + {"MUX_VX1", "DMic2R", "DMIC2"}, + {"MUX_VX1", "BT Left", "BT_VX_UL"}, + {"MUX_VX1", "BT Right", "BT_VX_UL"}, + {"MUX_VX1", "MMExt Left", "MM_EXT_UL"}, + {"MUX_VX1", "MMExt Right", "MM_EXT_UL"}, + {"MUX_VX1", "AMic0", "PDM_UL1"}, + {"MUX_VX1", "AMic1", "PDM_UL1"}, + {"MUX_VX1", "VX Left", "Capture Mixer"}, + {"MUX_VX1", "VX Right", "Capture Mixer"}, + + /* Headset (DL1) playback path */ + {"DL1 Mixer", "Tones", "TONES_DL"}, + {"DL1 Mixer", "Voice", "VX DL VMixer"}, + {"DL1 Mixer", "Capture", "DL1 Capture VMixer"}, + {"DL1 Capture VMixer", NULL, "MUX_UL10"}, + {"DL1 Capture VMixer", NULL, "MUX_UL11"}, + {"DL1 Mixer", "Multimedia", "MM_DL VMixer"}, + {"MM_DL VMixer", NULL, "MM_DL"}, + {"MM_DL VMixer", NULL, "MM_DL_LP"}, + + /* Sidetone Mixer */ + {"Sidetone Mixer", "Playback", "DL1 Mixer"}, + {"Sidetone Mixer", "Capture", "Sidetone Capture VMixer"}, + {"Sidetone Capture VMixer", NULL, "MUX_VX0"}, + {"Sidetone Capture VMixer", NULL, "MUX_VX1"}, + + /* Playback Output selection after DL1 Gain */ + {"DL1 BT_VX", "Switch", "Sidetone Mixer"}, + {"DL1 MM_EXT", "Switch", "Sidetone Mixer"}, + {"DL1 PDM", "Switch", "Sidetone Mixer"}, + {"PDM_DL1", NULL, "DL1 PDM"}, + {"BT_VX_DL", NULL, "DL1 BT_VX"}, + {"MM_EXT_DL", NULL, "DL1 MM_EXT"}, + + /* Handsfree (DL2) playback path */ + {"DL2 Mixer", "Tones", "TONES_DL"}, + {"DL2 Mixer", "Voice", "VX DL VMixer"}, + {"DL2 Mixer", "Capture", "DL2 Capture VMixer"}, + {"DL2 Capture VMixer", NULL, "MUX_UL10"}, + {"DL2 Capture VMixer", NULL, "MUX_UL11"}, + {"DL2 Mixer", "Multimedia", "MM_DL VMixer"}, + {"MM_DL VMixer", NULL, "MM_DL"}, + {"MM_DL VMixer", NULL, "MM_DL_LP"}, + {"PDM_DL2", NULL, "DL2 Mixer"}, + + /* VxREC Mixer */ + {"Capture Mixer", "Tones", "TONES_DL"}, + {"Capture Mixer", "Voice Playback", "VX DL VMixer"}, + {"Capture Mixer", "Voice Capture", "VX UL VMixer"}, + {"Capture Mixer", "Media Playback", "MM_DL VMixer"}, + {"MM_DL VMixer", NULL, "MM_DL"}, + {"MM_DL VMixer", NULL, "MM_DL_LP"}, + + /* Audio UL mixer */ + {"Voice Capture Mixer", "Tones Playback", "TONES_DL"}, + {"Voice Capture Mixer", "Media Playback", "MM_DL VMixer"}, + {"MM_DL VMixer", NULL, "MM_DL"}, + {"MM_DL VMixer", NULL, "MM_DL_LP"}, + {"Voice Capture Mixer", "Capture", "Voice Capture VMixer"}, + {"Voice Capture VMixer", NULL, "MUX_VX0"}, + {"Voice Capture VMixer", NULL, "MUX_VX1"}, + + /* BT */ + {"VX UL VMixer", NULL, "Voice Capture Mixer"}, + + /* Vibra */ + {"PDM_VIB", NULL, "VIB_DL"}, + + /* VX and MODEM */ + {"VX_UL", NULL, "VX UL VMixer"}, + {"MODEM_UL", NULL, "VX UL VMixer"}, + {"VX DL VMixer", NULL, "VX_DL"}, + {"VX DL VMixer", NULL, "MODEM_DL"}, + + /* Backend Enablement - TODO: maybe re-work*/ + {"BE_OUT", NULL, "PDM_DL1"}, + {"BE_OUT", NULL, "PDM_DL2"}, + {"BE_OUT", NULL, "PDM_VIB"}, + {"BE_OUT", NULL, "MM_EXT_DL"}, + {"BE_OUT", NULL, "BT_VX_DL"}, + {"PDM_UL1", NULL, "BE_IN"}, + {"BT_VX_UL", NULL, "BE_IN"}, + {"MM_EXT_UL", NULL, "BE_IN"}, + {"DMIC0", NULL, "BE_IN"}, + {"DMIC1", NULL, "BE_IN"}, + {"DMIC2", NULL, "BE_IN"}, +}; + +#ifdef CONFIG_DEBUG_FS + +static int abe_dbg_get_dma_pos(struct abe_data *abe) +{ + return omap_get_dma_dst_pos(abe->dma_ch) - abe->dbg_buffer_addr; +} + +static void abe_dbg_dma_irq(int ch, u16 stat, void *data) +{ +} + +static int abe_dbg_start_dma(struct abe_data *abe, int circular) +{ + struct omap_dma_channel_params dma_params; + int err; + + /* TODO: start the DMA in either :- + * + * 1) circular buffer mode where the DMA will restart when it get to + * the end of the buffer. + * 2) default mode, where DMA stops at the end of the buffer. + */ + + abe->dma_req = OMAP44XX_DMA_ABE_REQ_7; + err = omap_request_dma(abe->dma_req, "ABE debug", + abe_dbg_dma_irq, abe, &abe->dma_ch); + if (abe->dbg_circular) { + /* + * Link channel with itself so DMA doesn't need any + * reprogramming while looping the buffer + */ + omap_dma_link_lch(abe->dma_ch, abe->dma_ch); + } + + memset(&dma_params, 0, sizeof(dma_params)); + dma_params.data_type = OMAP_DMA_DATA_TYPE_S32; + dma_params.trigger = abe->dma_req; + dma_params.sync_mode = OMAP_DMA_SYNC_FRAME; + dma_params.src_amode = OMAP_DMA_AMODE_DOUBLE_IDX; + dma_params.dst_amode = OMAP_DMA_AMODE_POST_INC; + dma_params.src_or_dst_synch = OMAP_DMA_SRC_SYNC; + dma_params.src_start = D_DEBUG_FIFO_ADDR + ABE_DMEM_BASE_ADDRESS_L3; + dma_params.dst_start = abe->dbg_buffer_addr; + dma_params.src_port = OMAP_DMA_PORT_MPUI; + dma_params.src_ei = 1; + dma_params.src_fi = 1 - abe->dbg_elem_bytes; + + dma_params.elem_count = abe->dbg_elem_bytes >> 2; /* 128 bytes shifted into words */ + dma_params.frame_count = abe->dbg_buffer_bytes / abe->dbg_elem_bytes; + omap_set_dma_params(abe->dma_ch, &dma_params); + + omap_enable_dma_irq(abe->dma_ch, OMAP_DMA_FRAME_IRQ); + omap_set_dma_src_burst_mode(abe->dma_ch, OMAP_DMA_DATA_BURST_16); + omap_set_dma_dest_burst_mode(abe->dma_ch, OMAP_DMA_DATA_BURST_16); + + abe->dbg_reader_offset = 0; + + pm_runtime_get_sync(abe->dev); + omap_start_dma(abe->dma_ch); + return 0; +} + +static void abe_dbg_stop_dma(struct abe_data *abe) +{ + while (omap_get_dma_active_status(abe->dma_ch)) + omap_stop_dma(abe->dma_ch); + + if (abe->dbg_circular) + omap_dma_unlink_lch(abe->dma_ch, abe->dma_ch); + omap_free_dma(abe->dma_ch); + pm_runtime_put_sync(abe->dev); +} + +static int abe_open_data(struct inode *inode, struct file *file) +{ + struct abe_data *abe = inode->i_private; + + abe->dbg_elem_bytes = 128; /* size of debug data per tick */ + + if (abe->dbg_format1) + abe->dbg_elem_bytes += ABE_DBG_FLAG1_SIZE; + if (abe->dbg_format2) + abe->dbg_elem_bytes += ABE_DBG_FLAG2_SIZE; + if (abe->dbg_format3) + abe->dbg_elem_bytes += ABE_DBG_FLAG3_SIZE; + + abe->dbg_buffer_bytes = abe->dbg_elem_bytes * 4 * + abe->dbg_buffer_msecs; + + abe->dbg_buffer = dma_alloc_writecombine(abe->dev, + abe->dbg_buffer_bytes, &abe->dbg_buffer_addr, GFP_KERNEL); + if (abe->dbg_buffer == NULL) + return -ENOMEM; + + file->private_data = inode->i_private; + abe->dbg_complete = 0; + abe_dbg_start_dma(abe, abe->dbg_circular); + + return 0; +} + +static int abe_release_data(struct inode *inode, struct file *file) +{ + struct abe_data *abe = inode->i_private; + + abe_dbg_stop_dma(abe); + + dma_free_writecombine(abe->dev, abe->dbg_buffer_bytes, + abe->dbg_buffer, abe->dbg_buffer_addr); + return 0; +} + +static ssize_t abe_copy_to_user(struct abe_data *abe, char __user *user_buf, + size_t count) +{ + /* check for reader buffer wrap */ + if (abe->dbg_reader_offset + count > abe->dbg_buffer_bytes) { + int size = abe->dbg_buffer_bytes - abe->dbg_reader_offset; + + /* wrap */ + if (copy_to_user(user_buf, + abe->dbg_buffer + abe->dbg_reader_offset, size)) + return -EFAULT; + + /* need to just return if non circular */ + if (!abe->dbg_circular) { + abe->dbg_complete = 1; + return count; + } + + if (copy_to_user(user_buf, + abe->dbg_buffer, count - size)) + return -EFAULT; + abe->dbg_reader_offset = count - size; + return count; + } else { + /* no wrap */ + if (copy_to_user(user_buf, + abe->dbg_buffer + abe->dbg_reader_offset, count)) + return -EFAULT; + abe->dbg_reader_offset += count; + + if (!abe->dbg_circular && + abe->dbg_reader_offset == abe->dbg_buffer_bytes) + abe->dbg_complete = 1; + + return count; + } +} + +static ssize_t abe_read_data(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + ssize_t ret = 0; + struct abe_data *abe = file->private_data; + DECLARE_WAITQUEUE(wait, current); + int dma_offset, bytes; + + add_wait_queue(&abe->wait, &wait); + do { + set_current_state(TASK_INTERRUPTIBLE); + /* TODO: Check if really needed. Or adjust sleep delay + * If not delay trace is not working */ + msleep_interruptible(1); + dma_offset = abe_dbg_get_dma_pos(abe); + + /* is DMA finished ? */ + if (abe->dbg_complete) + break; + + /* get maximum amount of debug bytes we can read */ + if (dma_offset >= abe->dbg_reader_offset) { + /* dma ptr is ahead of reader */ + bytes = dma_offset - abe->dbg_reader_offset; + } else { + /* dma ptr is behind reader */ + bytes = dma_offset + abe->dbg_buffer_bytes - + abe->dbg_reader_offset; + } + + if (count > bytes) + count = bytes; + + if (count > 0) { + ret = abe_copy_to_user(abe, user_buf, count); + break; + } + + if (file->f_flags & O_NONBLOCK) { + ret = -EAGAIN; + break; + } + + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + + schedule(); + + } while (1); + + __set_current_state(TASK_RUNNING); + remove_wait_queue(&abe->wait, &wait); + + return ret; +} + +static const struct file_operations abe_data_fops = { + .open = abe_open_data, + .read = abe_read_data, + .release = abe_release_data, +}; + +static void abe_init_debugfs(struct abe_data *abe) +{ + abe->debugfs_root = debugfs_create_dir("omap4-abe", NULL); + if (!abe->debugfs_root) { + printk(KERN_WARNING "ABE: Failed to create debugfs directory\n"); + return; + } + + abe->debugfs_fmt1 = debugfs_create_bool("format1", 0644, + abe->debugfs_root, + &abe->dbg_format1); + if (!abe->debugfs_fmt1) + printk(KERN_WARNING "ABE: Failed to create format1 debugfs file\n"); + + abe->debugfs_fmt2 = debugfs_create_bool("format2", 0644, + abe->debugfs_root, + &abe->dbg_format2); + if (!abe->debugfs_fmt2) + printk(KERN_WARNING "ABE: Failed to create format2 debugfs file\n"); + + abe->debugfs_fmt3 = debugfs_create_bool("format3", 0644, + abe->debugfs_root, + &abe->dbg_format3); + if (!abe->debugfs_fmt3) + printk(KERN_WARNING "ABE: Failed to create format3 debugfs file\n"); + + abe->debugfs_elem_bytes = debugfs_create_u32("element_bytes", 0604, + abe->debugfs_root, + &abe->dbg_elem_bytes); + if (!abe->debugfs_elem_bytes) + printk(KERN_WARNING "ABE: Failed to create element size debugfs file\n"); + + abe->debugfs_size = debugfs_create_u32("msecs", 0644, + abe->debugfs_root, + &abe->dbg_buffer_msecs); + if (!abe->debugfs_size) + printk(KERN_WARNING "ABE: Failed to create buffer size debugfs file\n"); + + abe->debugfs_circ = debugfs_create_bool("circular", 0644, + abe->debugfs_root, + &abe->dbg_circular); + if (!abe->debugfs_size) + printk(KERN_WARNING "ABE: Failed to create circular mode debugfs file\n"); + + abe->debugfs_data = debugfs_create_file("debug", 0644, + abe->debugfs_root, + abe, &abe_data_fops); + if (!abe->debugfs_data) + printk(KERN_WARNING "ABE: Failed to create data debugfs file\n"); + + abe->debugfs_opp_level = debugfs_create_u32("opp_level", 0604, + abe->debugfs_root, + &abe->opp); + if (!abe->debugfs_opp_level) + printk(KERN_WARNING "ABE: Failed to create OPP level debugfs file\n"); + + abe->dbg_buffer_msecs = 500; + init_waitqueue_head(&abe->wait); +} + +static void abe_cleanup_debugfs(struct abe_data *abe) +{ + debugfs_remove_recursive(abe->debugfs_root); +} + +#else + +static inline void abe_init_debugfs(struct abe_data *abe) +{ +} + +static inline void abe_cleanup_debugfs(struct abe_data *abe) +{ +} +#endif + +static const struct snd_pcm_hardware omap_abe_hardware = { + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_RESUME, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE, + .period_bytes_min = 4 * 1024, + .period_bytes_max = 24 * 1024, + .periods_min = 4, + .periods_max = 4, + .buffer_bytes_max = 24 * 1024 * 2, +}; + +static struct abe_opp_req *abe_opp_req_lookup(struct abe_data *abe, + struct device *dev) +{ + struct abe_opp_req *req, *tmp_req; + + req = NULL; + list_for_each_entry(tmp_req, &abe->opp_req, node) { + if (tmp_req->dev == dev) { + req = tmp_req; + break; + } + } + + return req; +} + +static int abe_get_opp_req(struct abe_data *abe) +{ + struct abe_opp_req *req; + int opp = 0; + + list_for_each_entry(req, &abe->opp_req, node) + opp |= req->opp; + + opp = (1 << (fls(opp) - 1)) * 25; + + return opp; +} + +int abe_add_opp_req(struct device *dev, int opp) +{ + struct abe_opp_req *req; + int ret = 0; + + mutex_lock(&the_abe->opp_req_mutex); + + req = abe_opp_req_lookup(the_abe, dev); + if (!req) { + req = kzalloc(sizeof(struct abe_opp_req), GFP_KERNEL); + if (!req) { + ret = -ENOMEM; + goto out; + } + req->dev = dev; + /* use the same convention as ABE DSP DAPM */ + req->opp = 1 << opp; + list_add(&req->node, &the_abe->opp_req); + the_abe->opp_req_count++; + } else { + req->opp = opp; + } + + aess_set_runtime_opp_level(the_abe); + +out: + mutex_unlock(&the_abe->opp_req_mutex); + return ret; +} +EXPORT_SYMBOL(abe_add_opp_req); + +int abe_remove_opp_req(struct device *dev) +{ + struct abe_opp_req *req; + int ret = 0; + + mutex_lock(&the_abe->opp_req_mutex); + + req = abe_opp_req_lookup(the_abe, dev); + if (!req) { + dev_err(dev, "trying to remove an invalid opp req\n"); + ret = -EINVAL; + goto out; + } + + list_del(&req->node); + the_abe->opp_req_count--; + kfree(req); + + aess_set_runtime_opp_level(the_abe); + +out: + mutex_unlock(&the_abe->opp_req_mutex); + return ret; +} +EXPORT_SYMBOL(abe_remove_opp_req); + +static int abe_set_opp_mode(struct abe_data *abe, int opp) +{ + struct omap4_abe_dsp_pdata *pdata = abe->abe_pdata; + int ret = 0; + + if (abe->opp > opp) { + /* Decrease OPP mode - no need of OPP100% */ + switch (opp) { + case 25: + abe_set_opp_processing(ABE_OPP25); + udelay(250); + if (pdata && pdata->device_scale) { + ret = pdata->device_scale(abe->dev, abe->dev, + abe->opp_freqs[OMAP_ABE_OPP25]); + if (ret) + goto err_scale; + } + break; + case 50: + default: + abe_set_opp_processing(ABE_OPP50); + udelay(250); + if (pdata && pdata->device_scale) { + ret = pdata->device_scale(abe->dev, abe->dev, + abe->opp_freqs[OMAP_ABE_OPP50]); + if (ret) + goto err_scale; + } + break; + } + } else if (abe->opp < opp) { + /* Increase OPP mode */ + switch (opp) { + case 25: + if (pdata && pdata->device_scale) { + pdata->device_scale(abe->dev, abe->dev, + abe->opp_freqs[OMAP_ABE_OPP25]); + if (ret) + goto err_scale; + } + abe_set_opp_processing(ABE_OPP25); + break; + case 50: + if (pdata && pdata->device_scale) { + ret = pdata->device_scale(abe->dev, abe->dev, + abe->opp_freqs[OMAP_ABE_OPP50]); + if (ret) + goto err_scale; + } + abe_set_opp_processing(ABE_OPP50); + break; + case 100: + default: + if (pdata && pdata->device_scale) { + ret = pdata->device_scale(abe->dev, abe->dev, + abe->opp_freqs[OMAP_ABE_OPP100]); + if (ret) + goto err_scale; + } + abe_set_opp_processing(ABE_OPP100); + break; + } + } + abe->opp = opp; + dev_dbg(abe->dev, "new OPP level is %d\n", opp); + + return 0; + +err_scale: + dev_err(abe->dev, "failed to scale to OPP%d\n", opp); + return ret; +} + +static int aess_set_runtime_opp_level(struct abe_data *abe) +{ + int i, req_opp, opp = 0; + + mutex_lock(&abe->opp_mutex); + + /* now calculate OPP level based upon DAPM widget status */ + for (i = 0; i < ABE_NUM_WIDGETS; i++) { + if (abe->widget_opp[ABE_WIDGET(i)]) { + dev_dbg(abe->dev, "OPP: id %d = %d%%\n", i, + abe->widget_opp[ABE_WIDGET(i)] * 25); + opp |= abe->widget_opp[ABE_WIDGET(i)]; + } + } + opp = (1 << (fls(opp) - 1)) * 25; + + /* opps requested outside ABE DSP driver (e.g. McPDM) */ + req_opp = abe_get_opp_req(abe); + + pm_runtime_get_sync(abe->dev); + abe_set_opp_mode(abe, max(opp, req_opp)); + pm_runtime_put_sync(abe->dev); + + mutex_unlock(&abe->opp_mutex); + + return 0; +} + +static void abe_dsp_init_gains(struct abe_data *abe) +{ + /* Uplink gains */ + abe_mute_gain(MIXAUDUL, MIX_AUDUL_INPUT_MM_DL); + abe_mute_gain(MIXAUDUL, MIX_AUDUL_INPUT_TONES); + abe_mute_gain(MIXAUDUL, MIX_AUDUL_INPUT_UPLINK); + abe_mute_gain(MIXAUDUL, MIX_AUDUL_INPUT_VX_DL); + + abe_mute_gain(MIXVXREC, MIX_VXREC_INPUT_TONES); + abe_mute_gain(MIXVXREC, MIX_VXREC_INPUT_VX_DL); + abe_mute_gain(MIXVXREC, MIX_VXREC_INPUT_MM_DL); + abe_mute_gain(MIXVXREC, MIX_VXREC_INPUT_VX_UL); + + abe_mute_gain(GAINS_DMIC1, GAIN_LEFT_OFFSET); + abe_mute_gain(GAINS_DMIC1, GAIN_RIGHT_OFFSET); + abe_mute_gain(GAINS_DMIC2, GAIN_LEFT_OFFSET); + abe_mute_gain(GAINS_DMIC2, GAIN_RIGHT_OFFSET); + abe_mute_gain(GAINS_DMIC3, GAIN_LEFT_OFFSET); + abe_mute_gain(GAINS_DMIC3, GAIN_RIGHT_OFFSET); + + abe_mute_gain(GAINS_AMIC, GAIN_LEFT_OFFSET); + abe_mute_gain(GAINS_AMIC, GAIN_RIGHT_OFFSET); + + abe_mute_gain(GAINS_BTUL, GAIN_LEFT_OFFSET); + abe_mute_gain(GAINS_BTUL, GAIN_RIGHT_OFFSET); + + /* Downlink gains */ + abe_write_gain(GAINS_DL1, GAIN_0dB, RAMP_2MS, GAIN_LEFT_OFFSET); + abe_write_gain(GAINS_DL1, GAIN_0dB, RAMP_2MS, GAIN_RIGHT_OFFSET); + abe_mute_gain(GAINS_DL1, GAIN_LEFT_OFFSET); + abe_mute_gain(GAINS_DL1, GAIN_RIGHT_OFFSET); + + abe_write_gain(GAINS_DL2, GAIN_M7dB, RAMP_2MS, GAIN_LEFT_OFFSET); + abe_write_gain(GAINS_DL2, GAIN_M7dB, RAMP_2MS, GAIN_RIGHT_OFFSET); + abe_mute_gain(GAINS_DL2, GAIN_LEFT_OFFSET); + abe_mute_gain(GAINS_DL2, GAIN_RIGHT_OFFSET); + + abe_mute_gain(MIXDL1, MIX_DL1_INPUT_MM_DL); + abe_mute_gain(MIXDL1, MIX_DL1_INPUT_MM_UL2); + abe_mute_gain(MIXDL1, MIX_DL1_INPUT_VX_DL); + abe_mute_gain(MIXDL1, MIX_DL1_INPUT_TONES); + + abe_mute_gain(MIXDL2, MIX_DL2_INPUT_TONES); + abe_mute_gain(MIXDL2, MIX_DL2_INPUT_VX_DL); + abe_mute_gain(MIXDL2, MIX_DL2_INPUT_MM_DL); + abe_mute_gain(MIXDL2, MIX_DL2_INPUT_MM_UL2); + + abe_mute_gain(MIXECHO, MIX_ECHO_DL1); + abe_mute_gain(MIXECHO, MIX_ECHO_DL2); + + /* Sidetone gains */ + abe_mute_gain(MIXSDT, MIX_SDT_INPUT_UP_MIXER); + abe_mute_gain(MIXSDT, MIX_SDT_INPUT_DL1_MIXER); +} + +static int aess_save_context(struct abe_data *abe) +{ + /* mute gains not associated with FEs/BEs */ + abe_mute_gain(MIXAUDUL, MIX_AUDUL_INPUT_MM_DL); + abe_mute_gain(MIXAUDUL, MIX_AUDUL_INPUT_TONES); + abe_mute_gain(MIXAUDUL, MIX_AUDUL_INPUT_VX_DL); + abe_mute_gain(MIXVXREC, MIX_VXREC_INPUT_TONES); + abe_mute_gain(MIXVXREC, MIX_VXREC_INPUT_VX_DL); + abe_mute_gain(MIXVXREC, MIX_VXREC_INPUT_MM_DL); + abe_mute_gain(MIXVXREC, MIX_VXREC_INPUT_VX_UL); + abe_mute_gain(MIXECHO, MIX_ECHO_DL1); + abe_mute_gain(MIXECHO, MIX_ECHO_DL2); + + return 0; +} + +static int aess_restore_context(struct abe_data *abe) +{ + struct omap4_abe_dsp_pdata *pdata = abe->abe_pdata; + int i, ret; + + if (pdata && pdata->device_scale) { + ret = pdata->device_scale(the_abe->dev, the_abe->dev, + abe->opp_freqs[OMAP_ABE_OPP50]); + if (ret) { + dev_err(abe->dev, "failed to scale to OPP50\n"); + return ret; + } + } + + if (pdata->was_context_lost && pdata->was_context_lost(abe->dev)) + abe_reload_fw(abe->firmware); + + /* unmute gains not associated with FEs/BEs */ + abe_unmute_gain(MIXAUDUL, MIX_AUDUL_INPUT_MM_DL); + abe_unmute_gain(MIXAUDUL, MIX_AUDUL_INPUT_TONES); + abe_unmute_gain(MIXAUDUL, MIX_AUDUL_INPUT_VX_DL); + abe_unmute_gain(MIXVXREC, MIX_VXREC_INPUT_TONES); + abe_unmute_gain(MIXVXREC, MIX_VXREC_INPUT_VX_DL); + abe_unmute_gain(MIXVXREC, MIX_VXREC_INPUT_MM_DL); + abe_unmute_gain(MIXVXREC, MIX_VXREC_INPUT_VX_UL); + abe_unmute_gain(MIXECHO, MIX_ECHO_DL1); + abe_unmute_gain(MIXECHO, MIX_ECHO_DL2); + + abe_set_router_configuration(UPROUTE, 0, (u32 *)abe->router); + + /* DC offset cancellation setting */ + if (abe->power_mode) + abe_write_pdmdl_offset(1, abe->dc_hsl * 2, abe->dc_hsr * 2); + else + abe_write_pdmdl_offset(1, abe->dc_hsl, abe->dc_hsr); + + abe_write_pdmdl_offset(2, abe->dc_hfl, abe->dc_hfr); + + for (i = 0; i < abe->hdr.num_equ; i++) + abe_dsp_set_equalizer(i, abe->equ_profile[i]); + + for (i = 0; i < ABE_NUM_MONO_MIXERS; i++) + abe_dsp_set_mono_mixer(MIX_DL1_MONO + i, abe->mono_mix[i]); + + return 0; +} + +static int aess_open(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_platform *platform = rtd->platform; + struct abe_data *abe = snd_soc_platform_get_drvdata(platform); + struct snd_soc_dai *dai = rtd->cpu_dai; + int ret = 0; + + mutex_lock(&abe->mutex); + + dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); + + pm_runtime_get_sync(abe->dev); + + if (!abe->active++) { + abe->opp = 0; + aess_restore_context(abe); + abe_set_opp_mode(abe, 100); + abe_wakeup(); + } + + switch (dai->id) { + case ABE_FRONTEND_DAI_MODEM: + break; + case ABE_FRONTEND_DAI_LP_MEDIA: + snd_soc_set_runtime_hwparams(substream, &omap_abe_hardware); + ret = snd_pcm_hw_constraint_step(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 1024); + break; + default: + break; + } + + mutex_unlock(&abe->mutex); + return ret; +} + +static int aess_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_platform *platform = rtd->platform; + struct abe_data *abe = snd_soc_platform_get_drvdata(platform); + struct snd_soc_dai *dai = rtd->cpu_dai; + abe_data_format_t format; + size_t period_size; + u32 dst; + + dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); + + if (dai->id != ABE_FRONTEND_DAI_LP_MEDIA) + return 0; + + /*Storing substream pointer for irq*/ + abe->ping_pong_substream = substream; + + format.f = params_rate(params); + if (params_format(params) == SNDRV_PCM_FORMAT_S32_LE) + format.samp_format = STEREO_MSB; + else + format.samp_format = STEREO_16_16; + + if (format.f == 44100) + abe_write_event_generator(EVENT_44100); + + period_size = params_period_bytes(params); + + /*Adding ping pong buffer subroutine*/ + abe_plug_subroutine(&abe_irq_pingpong_player_id, + (abe_subroutine2) abe_irq_pingpong_subroutine, + SUB_1_PARAM, (u32 *)abe); + + /* Connect a Ping-Pong cache-flush protocol to MM_DL port */ + abe_connect_irq_ping_pong_port(MM_DL_PORT, &format, + abe_irq_pingpong_player_id, + period_size, &dst, + PING_PONG_WITH_MCU_IRQ); + + /* Memory mapping for hw params */ + runtime->dma_area = abe->io_base[0] + dst; + runtime->dma_addr = 0; + runtime->dma_bytes = period_size * 4; + + /* Need to set the first buffer in order to get interrupt */ + abe_set_ping_pong_buffer(MM_DL_PORT, period_size); + abe->first_irq = 1; + + return 0; +} + +static int aess_prepare(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_platform *platform = rtd->platform; + struct abe_data *abe = snd_soc_platform_get_drvdata(platform); + struct snd_soc_dai *dai = rtd->cpu_dai; + + mutex_lock(&abe->mutex); + dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); + aess_set_runtime_opp_level(abe); + mutex_unlock(&abe->mutex); + return 0; +} + +static int aess_close(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_platform *platform = rtd->platform; + struct abe_data *abe = snd_soc_platform_get_drvdata(platform); + struct snd_soc_dai *dai = rtd->cpu_dai; + + mutex_lock(&abe->mutex); + + dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); + + if (!--abe->active) { + abe_disable_irq(); + aess_save_context(abe); + abe_dsp_shutdown(); + } else { + /* Only scale OPP level + * if ABE is still active */ + aess_set_runtime_opp_level(abe); + } + + pm_runtime_put_sync(abe->dev); + + mutex_unlock(&abe->mutex); + return 0; +} + +static int aess_mmap(struct snd_pcm_substream *substream, + struct vm_area_struct *vma) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *dai = rtd->cpu_dai; + int offset, size, err; + + if (dai->id != ABE_FRONTEND_DAI_LP_MEDIA) + return -EINVAL; + + vma->vm_flags |= VM_IO | VM_RESERVED; + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + size = vma->vm_end - vma->vm_start; + offset = vma->vm_pgoff << PAGE_SHIFT; + + err = io_remap_pfn_range(vma, vma->vm_start, + (ABE_DMEM_BASE_ADDRESS_MPU + + ABE_DMEM_BASE_OFFSET_PING_PONG + offset) >> PAGE_SHIFT, + size, vma->vm_page_prot); + + if (err) + return -EAGAIN; + + return 0; +} + +static snd_pcm_uframes_t aess_pointer(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_platform *platform = rtd->platform; + struct abe_data *abe = snd_soc_platform_get_drvdata(platform); + snd_pcm_uframes_t offset = 0; + u32 pingpong; + + if (!abe->first_irq) { + abe_read_offset_from_ping_buffer(MM_DL_PORT, &pingpong); + offset = (snd_pcm_uframes_t)pingpong; + } + + return offset; +} + +static struct snd_pcm_ops omap_aess_pcm_ops = { + .open = aess_open, + .hw_params = aess_hw_params, + .prepare = aess_prepare, + .close = aess_close, + .pointer = aess_pointer, + .mmap = aess_mmap, +}; + +static int aess_stream_event(struct snd_soc_dapm_context *dapm) +{ + struct snd_soc_platform *platform = dapm->platform; + struct abe_data *abe = snd_soc_platform_get_drvdata(platform); + + if (abe->active) + aess_set_runtime_opp_level(abe); + + return 0; +} + +static int abe_add_widgets(struct snd_soc_platform *platform) +{ + struct abe_data *abe = snd_soc_platform_get_drvdata(platform); + struct fw_header *hdr = &abe->hdr; + int i, j; + + /* create equalizer controls */ + for (i = 0; i < hdr->num_equ; i++) { + struct soc_enum *equalizer_enum = &abe->equalizer_enum[i]; + struct snd_kcontrol_new *equalizer_control = + &abe->equalizer_control[i]; + + equalizer_enum->reg = i; + equalizer_enum->max = abe->equ_texts[i].count; + for (j = 0; j < abe->equ_texts[i].count; j++) + equalizer_enum->dtexts[j] = abe->equ_texts[i].texts[j]; + + equalizer_control->name = abe->equ_texts[i].name; + equalizer_control->private_value = (unsigned long)equalizer_enum; + equalizer_control->get = abe_get_equalizer; + equalizer_control->put = abe_put_equalizer; + equalizer_control->info = snd_soc_info_enum_ext1; + equalizer_control->iface = SNDRV_CTL_ELEM_IFACE_MIXER; + + dev_dbg(platform->dev, "added EQU mixer: %s profiles %d\n", + abe->equ_texts[i].name, abe->equ_texts[i].count); + + for (j = 0; j < abe->equ_texts[i].count; j++) + dev_dbg(platform->dev, " %s\n", equalizer_enum->dtexts[j]); + } + + snd_soc_add_platform_controls(platform, abe->equalizer_control, + hdr->num_equ); + + snd_soc_add_platform_controls(platform, abe_controls, + ARRAY_SIZE(abe_controls)); + + snd_soc_dapm_new_controls(&platform->dapm, abe_dapm_widgets, + ARRAY_SIZE(abe_dapm_widgets)); + + snd_soc_dapm_add_routes(&platform->dapm, intercon, ARRAY_SIZE(intercon)); + + snd_soc_dapm_new_widgets(&platform->dapm); + + return 0; +} + +#ifdef CONFIG_PM +static int abe_suspend(struct snd_soc_dai *dai) +{ + struct abe_data *abe = the_abe; + int ret = 0; + + dev_dbg(dai->dev, "%s: %s active %d\n", + __func__, dai->name, dai->active); + + if (!dai->active) + return 0; + + pm_runtime_get_sync(abe->dev); + + switch (dai->id) { + case OMAP_ABE_DAI_PDM_UL: + abe_mute_gain(GAINS_AMIC, GAIN_LEFT_OFFSET); + abe_mute_gain(GAINS_AMIC, GAIN_RIGHT_OFFSET); + break; + case OMAP_ABE_DAI_PDM_DL1: + case OMAP_ABE_DAI_PDM_DL2: + case OMAP_ABE_DAI_PDM_VIB: + break; + case OMAP_ABE_DAI_BT_VX: + abe_mute_gain(GAINS_BTUL, GAIN_LEFT_OFFSET); + abe_mute_gain(GAINS_BTUL, GAIN_RIGHT_OFFSET); + break; + case OMAP_ABE_DAI_MM_FM: + case OMAP_ABE_DAI_MODEM: + break; + case OMAP_ABE_DAI_DMIC0: + abe_mute_gain(GAINS_DMIC1, GAIN_LEFT_OFFSET); + abe_mute_gain(GAINS_DMIC1, GAIN_RIGHT_OFFSET); + break; + case OMAP_ABE_DAI_DMIC1: + abe_mute_gain(GAINS_DMIC2, GAIN_LEFT_OFFSET); + abe_mute_gain(GAINS_DMIC2, GAIN_RIGHT_OFFSET); + break; + case OMAP_ABE_DAI_DMIC2: + abe_mute_gain(GAINS_DMIC3, GAIN_LEFT_OFFSET); + abe_mute_gain(GAINS_DMIC3, GAIN_RIGHT_OFFSET); + break; + default: + dev_err(dai->dev, "%s: invalid DAI id %d\n", + __func__, dai->id); + ret = -EINVAL; + goto out; + } + +out: + pm_runtime_put_sync(abe->dev); + return ret; +} + +static int abe_resume(struct snd_soc_dai *dai) +{ + struct abe_data *abe = the_abe; + struct omap4_abe_dsp_pdata *pdata = abe->abe_pdata; + int i, ret = 0; + + dev_dbg(dai->dev, "%s: %s active %d\n", + __func__, dai->name, dai->active); + + if (!dai->active) + return 0; + + /* context retained, no need to restore */ + if (pdata->was_context_lost && !pdata->was_context_lost(abe->dev)) + return 0; + + pm_runtime_get_sync(abe->dev); + + if (pdata && pdata->device_scale) { + ret = pdata->device_scale(abe->dev, abe->dev, + abe->opp_freqs[OMAP_ABE_OPP50]); + if (ret) { + dev_err(abe->dev, "failed to scale to OPP50\n"); + goto out; + } + } + + abe_reload_fw(abe->firmware); + + switch (dai->id) { + case OMAP_ABE_DAI_PDM_UL: + abe_unmute_gain(GAINS_AMIC, GAIN_LEFT_OFFSET); + abe_unmute_gain(GAINS_AMIC, GAIN_RIGHT_OFFSET); + break; + case OMAP_ABE_DAI_PDM_DL1: + case OMAP_ABE_DAI_PDM_DL2: + case OMAP_ABE_DAI_PDM_VIB: + break; + case OMAP_ABE_DAI_BT_VX: + abe_unmute_gain(GAINS_BTUL, GAIN_LEFT_OFFSET); + abe_unmute_gain(GAINS_BTUL, GAIN_RIGHT_OFFSET); + break; + case OMAP_ABE_DAI_MM_FM: + case OMAP_ABE_DAI_MODEM: + break; + case OMAP_ABE_DAI_DMIC0: + abe_unmute_gain(GAINS_DMIC1, GAIN_LEFT_OFFSET); + abe_unmute_gain(GAINS_DMIC1, GAIN_RIGHT_OFFSET); + break; + case OMAP_ABE_DAI_DMIC1: + abe_unmute_gain(GAINS_DMIC2, GAIN_LEFT_OFFSET); + abe_unmute_gain(GAINS_DMIC2, GAIN_RIGHT_OFFSET); + break; + case OMAP_ABE_DAI_DMIC2: + abe_unmute_gain(GAINS_DMIC3, GAIN_LEFT_OFFSET); + abe_unmute_gain(GAINS_DMIC3, GAIN_RIGHT_OFFSET); + break; + default: + dev_err(dai->dev, "%s: invalid DAI id %d\n", + __func__, dai->id); + ret = -EINVAL; + goto out; + } + + abe_set_router_configuration(UPROUTE, 0, (u32 *)abe->router); + + if (abe->power_mode) + abe_write_pdmdl_offset(1, abe->dc_hsl * 2, abe->dc_hsr * 2); + else + abe_write_pdmdl_offset(1, abe->dc_hsl, abe->dc_hsr); + + abe_write_pdmdl_offset(2, abe->dc_hfl, abe->dc_hfr); + + for (i = 0; i < abe->hdr.num_equ; i++) + abe_dsp_set_equalizer(i, abe->equ_profile[i]); + + for (i = 0; i < ABE_NUM_MONO_MIXERS; i++) + abe_dsp_set_mono_mixer(MIX_DL1_MONO + i, abe->mono_mix[i]); +out: + pm_runtime_put_sync(abe->dev); + return ret; +} +#else +#define abe_suspend NULL +#define abe_resume NULL +#endif + +static int abe_probe(struct snd_soc_platform *platform) +{ + struct abe_data *abe = snd_soc_platform_get_drvdata(platform); + struct opp *opp; + const u8 *fw_data; + unsigned long freq = ULONG_MAX; + int ret = 0, i, opp_count, offset = 0; +#if defined(CONFIG_SND_OMAP_SOC_ABE_DSP_MODULE) + const struct firmware *fw; +#endif + + abe->platform = platform; + + pm_runtime_enable(abe->dev); + pm_runtime_irq_safe(abe->dev); + +#if defined(CONFIG_SND_OMAP_SOC_ABE_DSP_MODULE) + /* request firmware & coefficients */ + ret = request_firmware(&fw, "omap4_abe", platform->dev); + if (ret != 0) { + dev_err(abe->dev, "Failed to load firmware: %d\n", ret); + return ret; + } + fw_data = fw->data; +#else + fw_data = (u8 *)abe_get_default_fw(); +#endif + + /* get firmware and coefficients header info */ + memcpy(&abe->hdr, fw_data, sizeof(struct fw_header)); + if (abe->hdr.firmware_size > ABE_MAX_FW_SIZE) { + dev_err(abe->dev, "Firmware too large at %d bytes: %d\n", + abe->hdr.firmware_size, ret); + ret = -EINVAL; + goto err_fw; + } + dev_dbg(abe->dev, "ABE firmware size %d bytes\n", abe->hdr.firmware_size); + + if (abe->hdr.coeff_size > ABE_MAX_COEFF_SIZE) { + dev_err(abe->dev, "Coefficients too large at %d bytes: %d\n", + abe->hdr.coeff_size, ret); + ret = -EINVAL; + goto err_fw; + } + dev_dbg(abe->dev, "ABE coefficients size %d bytes\n", abe->hdr.coeff_size); + + /* get coefficient EQU mixer strings */ + if (abe->hdr.num_equ >= ABE_MAX_EQU) { + dev_err(abe->dev, "Too many equalizers got %d\n", abe->hdr.num_equ); + ret = -EINVAL; + goto err_fw; + } + abe->equ_texts = kzalloc(abe->hdr.num_equ * sizeof(struct coeff_config), + GFP_KERNEL); + if (abe->equ_texts == NULL) { + ret = -ENOMEM; + goto err_fw; + } + offset = sizeof(struct fw_header); + memcpy(abe->equ_texts, fw_data + offset, + abe->hdr.num_equ * sizeof(struct coeff_config)); + + /* get coefficients from firmware */ + abe->equ[0] = kmalloc(abe->hdr.coeff_size, GFP_KERNEL); + if (abe->equ[0] == NULL) { + ret = -ENOMEM; + goto err_equ; + } + offset += abe->hdr.num_equ * sizeof(struct coeff_config); + memcpy(abe->equ[0], fw_data + offset, abe->hdr.coeff_size); + + /* allocate coefficient mixer texts */ + dev_dbg(abe->dev, "loaded %d equalizers\n", abe->hdr.num_equ); + for (i = 0; i < abe->hdr.num_equ; i++) { + dev_dbg(abe->dev, "equ %d: %s profiles %d\n", i, + abe->equ_texts[i].name, abe->equ_texts[i].count); + if (abe->equ_texts[i].count >= ABE_MAX_PROFILES) { + dev_err(abe->dev, "Too many profiles got %d for equ %d\n", + abe->equ_texts[i].count, i); + ret = -EINVAL; + goto err_texts; + } + abe->equalizer_enum[i].dtexts = + kzalloc(abe->equ_texts[i].count * sizeof(char *), GFP_KERNEL); + if (abe->equalizer_enum[i].dtexts == NULL) { + ret = -ENOMEM; + goto err_texts; + } + } + + /* initialise coefficient equalizers */ + for (i = 1; i < abe->hdr.num_equ; i++) { + abe->equ[i] = abe->equ[i - 1] + + abe->equ_texts[i - 1].count * abe->equ_texts[i - 1].coeff; + } + + /* store ABE firmware for later context restore */ + abe->firmware = kzalloc(abe->hdr.firmware_size, GFP_KERNEL); + if (abe->firmware == NULL) { + ret = -ENOMEM; + goto err_texts; + } + + memcpy(abe->firmware, + fw_data + sizeof(struct fw_header) + abe->hdr.coeff_size, + abe->hdr.firmware_size); + + ret = request_threaded_irq(abe->irq, NULL, abe_irq_handler, + IRQF_ONESHOT, "ABE", (void *)abe); + if (ret) { + dev_err(platform->dev, "request for ABE IRQ %d failed %d\n", + abe->irq, ret); + goto err_irq; + } + + /* query supported opps */ + rcu_read_lock(); + opp_count = opp_get_opp_count(abe->dev); + if (opp_count <= 0) { + dev_err(abe->dev, "invalid OPP data\n"); + ret = opp_count; + goto err_opp; + } else if (opp_count > OMAP_ABE_OPP_COUNT) { + dev_err(abe->dev, "unsupported OPP count %d (max:%d)\n", + opp_count, OMAP_ABE_OPP_COUNT); + ret = -EINVAL; + goto err_opp; + } + + /* assume provided opps are always higher */ + for (i = OMAP_ABE_OPP_COUNT - 1; i >= 0; i--) { + opp = opp_find_freq_floor(abe->dev, &freq); + if (IS_ERR_OR_NULL(opp)) + break; + abe->opp_freqs[i] = freq; + /* prepare to obtain next available opp */ + freq--; + } + /* use lowest available opp for non-populated items */ + for (freq++; i >= 0; i--) + abe->opp_freqs[i] = freq; + rcu_read_unlock(); + + /* aess_clk has to be enabled to access hal register. + * Disable the clk after it has been used. + */ + pm_runtime_get_sync(abe->dev); + + abe_init_mem(abe->io_base); + + abe_reset_hal(); + + abe_load_fw(abe->firmware); + + /* "tick" of the audio engine */ + abe_write_event_generator(EVENT_TIMER); + + abe_dsp_init_gains(abe); + + /* Stop the engine */ + abe_stop_event_generator(); + abe_disable_irq(); + + pm_runtime_put_sync(abe->dev); + abe_add_widgets(platform); + +#if defined(CONFIG_SND_OMAP_SOC_ABE_DSP_MODULE) + release_firmware(fw); +#endif + return ret; + +err_opp: + rcu_read_unlock(); + free_irq(abe->irq, (void *)abe); +err_irq: + kfree(abe->firmware); +err_texts: + for (i = 0; i < abe->hdr.num_equ; i++) + kfree(abe->equalizer_enum[i].texts); + kfree(abe->equ[0]); +err_equ: + kfree(abe->equ_texts); +err_fw: +#if defined(CONFIG_SND_OMAP_SOC_ABE_DSP_MODULE) + release_firmware(fw); +#endif + return ret; +} + +static int abe_remove(struct snd_soc_platform *platform) +{ + struct abe_data *abe = snd_soc_platform_get_drvdata(platform); + int i; + + free_irq(abe->irq, (void *)abe); + + for (i = 0; i < abe->hdr.num_equ; i++) + kfree(abe->equalizer_enum[i].texts); + + kfree(abe->equ[0]); + kfree(abe->equ_texts); + kfree(abe->firmware); + + pm_runtime_disable(abe->dev); + + return 0; +} + +static struct snd_soc_platform_driver omap_aess_platform = { + .ops = &omap_aess_pcm_ops, + .probe = abe_probe, + .remove = abe_remove, + .suspend = abe_suspend, + .resume = abe_resume, + .read = abe_dsp_read, + .write = abe_dsp_write, + .stream_event = aess_stream_event, +}; + +static int __devinit abe_engine_probe(struct platform_device *pdev) +{ + struct resource *res; + struct omap4_abe_dsp_pdata *pdata = pdev->dev.platform_data; + struct abe_data *abe; + int ret = -EINVAL, i; + + abe = kzalloc(sizeof(struct abe_data), GFP_KERNEL); + if (abe == NULL) + return -ENOMEM; + dev_set_drvdata(&pdev->dev, abe); + the_abe = abe; + + /* ZERO_labelID should really be 0 */ + for (i = 0; i < ABE_ROUTES_UL + 2; i++) + abe->router[i] = ZERO_labelID; + + for (i = 0; i < 5; i++) { + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + abe_memory_bank[i]); + if (res == NULL) { + dev_err(&pdev->dev, "no resource %s\n", + abe_memory_bank[i]); + goto err; + } + abe->io_base[i] = ioremap(res->start, resource_size(res)); + if (!abe->io_base[i]) { + ret = -ENOMEM; + goto err; + } + } + + abe->irq = platform_get_irq(pdev, 0); + if (abe->irq < 0) { + ret = abe->irq; + goto err; + } + + abe->abe_pdata = pdata; + abe->dev = &pdev->dev; + mutex_init(&abe->mutex); + mutex_init(&abe->opp_mutex); + mutex_init(&abe->opp_req_mutex); + INIT_LIST_HEAD(&abe->opp_req); + abe->opp_req_count = 0; + + ret = snd_soc_register_platform(abe->dev, + &omap_aess_platform); + if (ret < 0) + return ret; + + abe_init_debugfs(abe); + return ret; + +err: + for (--i; i >= 0; i--) + iounmap(abe->io_base[i]); + kfree(abe); + return ret; +} + +static int __devexit abe_engine_remove(struct platform_device *pdev) +{ + struct abe_data *abe = dev_get_drvdata(&pdev->dev); + int i; + + abe_cleanup_debugfs(abe); + snd_soc_unregister_platform(&pdev->dev); + for (i = 0; i < 5; i++) + iounmap(abe->io_base[i]); + kfree(abe); + return 0; +} + +static struct platform_driver omap_aess_driver = { + .driver = { + .name = "aess", + .owner = THIS_MODULE, + }, + .probe = abe_engine_probe, + .remove = __devexit_p(abe_engine_remove), +}; + +static int __init abe_engine_init(void) +{ + return platform_driver_register(&omap_aess_driver); +} +module_init(abe_engine_init); + +static void __exit abe_engine_exit(void) +{ + platform_driver_unregister(&omap_aess_driver); +} +module_exit(abe_engine_exit); + +MODULE_DESCRIPTION("ASoC OMAP4 ABE"); +MODULE_AUTHOR("Liam Girdwood <lrg@ti.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/omap/omap-abe-dsp.h b/sound/soc/omap/omap-abe-dsp.h new file mode 100644 index 0000000..8462290 --- /dev/null +++ b/sound/soc/omap/omap-abe-dsp.h @@ -0,0 +1,177 @@ +/* + * omap-abe-dsp.h + * + * Copyright (C) 2010 Texas Instruments + * + * Contact: Liam Girdwood <lrg@ti.com> + * + * 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 __OMAP_ABE_DSP_H__ +#define __OMAP_ABE_DSP_H__ + +#define ABE_MIXER(x) (x) + +#define MIX_DL1_TONES ABE_MIXER(0) +#define MIX_DL1_VOICE ABE_MIXER(1) +#define MIX_DL1_CAPTURE ABE_MIXER(2) +#define MIX_DL1_MEDIA ABE_MIXER(3) +#define MIX_DL2_TONES ABE_MIXER(4) +#define MIX_DL2_VOICE ABE_MIXER(5) +#define MIX_DL2_CAPTURE ABE_MIXER(6) +#define MIX_DL2_MEDIA ABE_MIXER(7) +#define MIX_AUDUL_TONES ABE_MIXER(8) +#define MIX_AUDUL_MEDIA ABE_MIXER(9) +#define MIX_AUDUL_CAPTURE ABE_MIXER(10) +#define MIX_VXREC_TONES ABE_MIXER(11) +#define MIX_VXREC_VOICE_PLAYBACK ABE_MIXER(12) +#define MIX_VXREC_VOICE_CAPTURE ABE_MIXER(13) +#define MIX_VXREC_MEDIA ABE_MIXER(14) +#define MIX_SDT_CAPTURE ABE_MIXER(15) +#define MIX_SDT_PLAYBACK ABE_MIXER(16) +#define MIX_SWITCH_PDM_DL ABE_MIXER(17) +#define MIX_SWITCH_BT_VX_DL ABE_MIXER(18) +#define MIX_SWITCH_MM_EXT_DL ABE_MIXER(19) +#define MIX_DL1_MONO ABE_MIXER(20) +#define MIX_DL2_MONO ABE_MIXER(21) +#define MIX_AUDUL_MONO ABE_MIXER(22) + +#define ABE_NUM_MONO_MIXERS (MIX_AUDUL_MONO - MIX_DL1_MONO + 1) +#define ABE_NUM_MIXERS (MIX_AUDUL_MONO + 1) + +#define ABE_MUX(x) (x + ABE_NUM_MIXERS) + +#define MUX_MM_UL10 ABE_MUX(0) +#define MUX_MM_UL11 ABE_MUX(1) +#define MUX_MM_UL12 ABE_MUX(2) +#define MUX_MM_UL13 ABE_MUX(3) +#define MUX_MM_UL14 ABE_MUX(4) +#define MUX_MM_UL15 ABE_MUX(5) +#define MUX_MM_UL16 ABE_MUX(6) +#define MUX_MM_UL17 ABE_MUX(7) +#define MUX_MM_UL20 ABE_MUX(8) +#define MUX_MM_UL21 ABE_MUX(9) +#define MUX_VX_UL0 ABE_MUX(10) +#define MUX_VX_UL1 ABE_MUX(11) + +#define ABE_NUM_MUXES (MUX_VX_UL1 - MUX_MM_UL10) + +#define ABE_WIDGET(x) (x + ABE_NUM_MIXERS + ABE_NUM_MUXES) + +/* ABE AIF Frontend Widgets */ +#define W_AIF_TONES_DL ABE_WIDGET(0) +#define W_AIF_VX_DL ABE_WIDGET(1) +#define W_AIF_VX_UL ABE_WIDGET(2) +#define W_AIF_MM_UL1 ABE_WIDGET(3) +#define W_AIF_MM_UL2 ABE_WIDGET(4) +#define W_AIF_MM_DL ABE_WIDGET(5) +#define W_AIF_MM_DL_LP W_AIF_MM_DL +#define W_AIF_VIB_DL ABE_WIDGET(6) +#define W_AIF_MODEM_DL ABE_WIDGET(7) +#define W_AIF_MODEM_UL ABE_WIDGET(8) + +/* ABE AIF Backend Widgets */ +#define W_AIF_PDM_UL1 ABE_WIDGET(9) +#define W_AIF_PDM_DL1 ABE_WIDGET(10) +#define W_AIF_PDM_DL2 ABE_WIDGET(11) +#define W_AIF_PDM_VIB ABE_WIDGET(12) +#define W_AIF_BT_VX_UL ABE_WIDGET(13) +#define W_AIF_BT_VX_DL ABE_WIDGET(14) +#define W_AIF_MM_EXT_UL ABE_WIDGET(15) +#define W_AIF_MM_EXT_DL ABE_WIDGET(16) +#define W_AIF_DMIC0 ABE_WIDGET(17) +#define W_AIF_DMIC1 ABE_WIDGET(18) +#define W_AIF_DMIC2 ABE_WIDGET(19) + +/* ABE ROUTE_UL MUX Widgets */ +#define W_MUX_UL00 ABE_WIDGET(20) +#define W_MUX_UL01 ABE_WIDGET(21) +#define W_MUX_UL02 ABE_WIDGET(22) +#define W_MUX_UL03 ABE_WIDGET(23) +#define W_MUX_UL04 ABE_WIDGET(24) +#define W_MUX_UL05 ABE_WIDGET(25) +#define W_MUX_UL06 ABE_WIDGET(26) +#define W_MUX_UL07 ABE_WIDGET(27) +#define W_MUX_UL10 ABE_WIDGET(28) +#define W_MUX_UL11 ABE_WIDGET(29) +#define W_MUX_VX00 ABE_WIDGET(30) +#define W_MUX_VX01 ABE_WIDGET(31) + +/* ABE Volume and Mixer Widgets */ +#define W_MIXER_DL1 ABE_WIDGET(32) +#define W_MIXER_DL2 ABE_WIDGET(33) +#define W_VOLUME_DL1 ABE_WIDGET(34) +#define W_MIXER_AUDIO_UL ABE_WIDGET(35) +#define W_MIXER_VX_REC ABE_WIDGET(36) +#define W_MIXER_SDT ABE_WIDGET(37) +#define W_VSWITCH_DL1_PDM ABE_WIDGET(38) +#define W_VSWITCH_DL1_BT_VX ABE_WIDGET(39) +#define W_VSWITCH_DL1_MM_EXT ABE_WIDGET(40) + +#define ABE_NUM_WIDGETS (W_VSWITCH_DL1_MM_EXT - W_AIF_TONES_DL) +#define ABE_WIDGET_LAST W_VSWITCH_DL1_MM_EXT + +#define ABE_NUM_DAPM_REG \ + (ABE_NUM_MIXERS + ABE_NUM_MUXES + ABE_NUM_WIDGETS) + +#define ABE_VIRTUAL_SWITCH 0 +#define ABE_ROUTES_UL 14 + +// TODO: OPP bitmask - Use HAL version after update +#define ABE_OPP_25 0 +#define ABE_OPP_50 1 +#define ABE_OPP_100 2 + +/* TODO: size in bytes of debug options */ +#define ABE_DBG_FLAG1_SIZE 0 +#define ABE_DBG_FLAG2_SIZE 0 +#define ABE_DBG_FLAG3_SIZE 0 + +/* TODO: Pong start offset of DMEM */ +/* Ping pong buffer DMEM offset */ +#define ABE_DMEM_BASE_OFFSET_PING_PONG 0x4000 + +/* Gain value conversion */ +#define ABE_MAX_GAIN 12000 +#define ABE_GAIN_SCALE 100 +#define abe_gain_to_val(gain) ((val + ABE_MAX_GAIN) / ABE_GAIN_SCALE) +#define abe_val_to_gain(val) (-ABE_MAX_GAIN + (val * ABE_GAIN_SCALE)) + +/* Firmware coefficients and equalizers */ +#define ABE_MAX_FW_SIZE (1024 * 128) +#define ABE_MAX_COEFF_SIZE (1024 * 4) +#define ABE_COEFF_NAME_SIZE 20 +#define ABE_COEFF_TEXT_SIZE 20 +#define ABE_COEFF_NUM_TEXTS 10 +#define ABE_MAX_EQU 10 +#define ABE_MAX_PROFILES 30 + +#define OMAP_ABE_OPP25 0 +#define OMAP_ABE_OPP50 1 +#define OMAP_ABE_OPP100 2 +#define OMAP_ABE_OPP_COUNT 3 + +void abe_dsp_shutdown(void); +void abe_dsp_pm_get(void); +void abe_dsp_pm_put(void); +int abe_add_opp_req(struct device *dev, int opp); +int abe_remove_opp_req(struct device *dev); +void abe_dsp_set_power_mode(int mode); +void abe_dsp_set_hs_offset(int left, int right, int mult); +void abe_dsp_set_hf_offset(int left, int right); + +#endif /* End of __OMAP_ABE_DSP_H__ */ diff --git a/sound/soc/omap/omap-abe.c b/sound/soc/omap/omap-abe.c new file mode 100644 index 0000000..da5ba44 --- /dev/null +++ b/sound/soc/omap/omap-abe.c @@ -0,0 +1,1563 @@ +/* + * omap-abe.c -- OMAP ALSA SoC DAI driver using Audio Backend + * + * Copyright (C) 2010 Texas Instruments + * + * Contact: Liam Girdwood <lrg@ti.com> + * Misael Lopez Cruz <misael.lopez@ti.com> + * Sebastien Guiriec <s-guiriec@ti.com> + * + * 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/init.h> +#include <linux/module.h> +#include <linux/device.h> +#include <linux/slab.h> +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/initval.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <sound/soc-dsp.h> + +#include <plat/dma-44xx.h> +#include <plat/dma.h> +#include "omap-pcm.h" +#include "omap-abe.h" +#include "omap-abe-dsp.h" +#include "abe/abe_main.h" +#include "abe/port_mgr.h" + +#define OMAP_ABE_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE) + +struct omap_abe_data { + /* MODEM FE*/ + struct snd_pcm_substream *modem_substream[2]; + struct snd_soc_dai *modem_dai; + + struct abe *abe; + + /* BE & FE Ports */ + struct omap_abe_port *port[OMAP_ABE_MAX_PORT_ID + 1]; + + int active_dais; + int suspended_dais; +}; + +/* + * Stream DMA parameters + */ +static struct omap_pcm_dma_data omap_abe_dai_dma_params[7][2] = { +{ + { + .name = "Media Playback", + .dma_req = OMAP44XX_DMA_ABE_REQ_0, + .sync_mode = OMAP_DMA_SYNC_PACKET, + }, + { + .name = "Media Capture1", + .dma_req = OMAP44XX_DMA_ABE_REQ_3, + .sync_mode = OMAP_DMA_SYNC_PACKET, + }, +}, +{ + {}, + { + .name = "Media Capture2", + .dma_req = OMAP44XX_DMA_ABE_REQ_4, + .sync_mode = OMAP_DMA_SYNC_PACKET, + }, +}, +{ + { + .name = "Voice Playback", + .dma_req = OMAP44XX_DMA_ABE_REQ_1, + .sync_mode = OMAP_DMA_SYNC_PACKET, + }, + { + .name = "Voice Capture", + .dma_req = OMAP44XX_DMA_ABE_REQ_2, + .sync_mode = OMAP_DMA_SYNC_PACKET, + }, +}, +{ + { + .name = "Tones Playback", + .dma_req = OMAP44XX_DMA_ABE_REQ_5, + .sync_mode = OMAP_DMA_SYNC_PACKET, + },{}, +}, +{ + { + .name = "Vibra Playback", + .dma_req = OMAP44XX_DMA_ABE_REQ_6, + .sync_mode = OMAP_DMA_SYNC_PACKET, + },{}, +}, +{ + { + .name = "MODEM Playback", + .dma_req = OMAP44XX_DMA_ABE_REQ_1, + .sync_mode = OMAP_DMA_SYNC_PACKET, + }, + { + .name = "MODEM Capture", + .dma_req = OMAP44XX_DMA_ABE_REQ_2, + .sync_mode = OMAP_DMA_SYNC_PACKET, + }, +}, +{ + { + .name = "Low Power Playback", + .dma_req = OMAP44XX_DMA_ABE_REQ_0, + .sync_mode = OMAP_DMA_SYNC_PACKET, + },{}, +},}; + +static int modem_get_dai(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct omap_abe_data *abe_priv = snd_soc_dai_get_drvdata(dai); + struct snd_soc_pcm_runtime *modem_rtd; + + abe_priv->modem_substream[substream->stream] = + snd_soc_get_dai_substream(rtd->card, + OMAP_ABE_BE_MM_EXT1, !substream->stream); + + if (abe_priv->modem_substream[substream->stream] == NULL) + return -ENODEV; + + modem_rtd = abe_priv->modem_substream[substream->stream]->private_data; + abe_priv->modem_substream[substream->stream]->runtime = substream->runtime; + abe_priv->modem_dai = modem_rtd->cpu_dai; + + return 0; +} + +int omap_abe_set_dl1_output(int output) +{ + int gain; + + /* + * the output itself is not important, but the DL1 gain + * to use when each output is active + */ + switch (output) { + case OMAP_ABE_DL1_HEADSET_LP: + gain = GAIN_M8dB; + break; + case OMAP_ABE_DL1_HEADSET_HP: + case OMAP_ABE_DL1_EARPIECE: + gain = GAIN_M1dB; + break; + case OMAP_ABE_DL1_NO_PDM: + gain = GAIN_0dB; + break; + default: + return -EINVAL; + } + + abe_write_gain(GAINS_DL1, gain, RAMP_2MS, GAIN_LEFT_OFFSET); + abe_write_gain(GAINS_DL1, gain, RAMP_2MS, GAIN_RIGHT_OFFSET); + + return 0; +} +EXPORT_SYMBOL(omap_abe_set_dl1_output); + +static int omap_abe_dl1_enabled(struct omap_abe_data *abe_priv) +{ + /* DL1 path is common for PDM_DL1, BT_VX_DL and MM_EXT_DL */ + return omap_abe_port_is_enabled(abe_priv->abe, + abe_priv->port[OMAP_ABE_BE_PORT_PDM_DL1]) + + omap_abe_port_is_enabled(abe_priv->abe, + abe_priv->port[OMAP_ABE_BE_PORT_BT_VX_DL]) + + omap_abe_port_is_enabled(abe_priv->abe, + abe_priv->port[OMAP_ABE_BE_PORT_MM_EXT_DL]); +} + +static int omap_abe_dl2_enabled(struct omap_abe_data *abe_priv) +{ + return omap_abe_port_is_enabled(abe_priv->abe, + abe_priv->port[OMAP_ABE_BE_PORT_PDM_DL2]); +} + +static void mute_be(struct snd_soc_pcm_runtime *be, + struct snd_soc_dai *dai, int stream) +{ + struct omap_abe_data *abe_priv = snd_soc_dai_get_drvdata(dai); + + dev_dbg(&be->dev, "%s: %s %d\n", __func__, be->cpu_dai->name, stream); + + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + switch (be->dai_link->be_id) { + case OMAP_ABE_DAI_PDM_DL1: + case OMAP_ABE_DAI_BT_VX: + case OMAP_ABE_DAI_MM_FM: + /* + * DL1 Mixer->SDT Mixer and DL1 gain are common for + * PDM_DL1, BT_VX_DL and MM_EXT_DL, mute those gains + * only if the last active BE + */ + if (omap_abe_dl1_enabled(abe_priv) == 1) { + abe_mute_gain(GAINS_DL1, GAIN_LEFT_OFFSET); + abe_mute_gain(GAINS_DL1, GAIN_RIGHT_OFFSET); + abe_mute_gain(MIXSDT, MIX_SDT_INPUT_DL1_MIXER); + } + break; + case OMAP_ABE_DAI_PDM_DL2: + abe_mute_gain(GAINS_DL2, GAIN_LEFT_OFFSET); + abe_mute_gain(GAINS_DL2, GAIN_RIGHT_OFFSET); + break; + case OMAP_ABE_DAI_PDM_VIB: + case OMAP_ABE_DAI_MODEM: + break; + } + } else { + switch (be->dai_link->be_id) { + case OMAP_ABE_DAI_PDM_UL: + abe_mute_gain(GAINS_AMIC, GAIN_LEFT_OFFSET); + abe_mute_gain(GAINS_AMIC, GAIN_RIGHT_OFFSET); + break; + case OMAP_ABE_DAI_BT_VX: + abe_mute_gain(GAINS_BTUL, GAIN_LEFT_OFFSET); + abe_mute_gain(GAINS_BTUL, GAIN_RIGHT_OFFSET); + break; + case OMAP_ABE_DAI_MM_FM: + case OMAP_ABE_DAI_MODEM: + break; + case OMAP_ABE_DAI_DMIC0: + abe_mute_gain(GAINS_DMIC1, GAIN_LEFT_OFFSET); + abe_mute_gain(GAINS_DMIC1, GAIN_RIGHT_OFFSET); + break; + case OMAP_ABE_DAI_DMIC1: + abe_mute_gain(GAINS_DMIC2, GAIN_LEFT_OFFSET); + abe_mute_gain(GAINS_DMIC2, GAIN_RIGHT_OFFSET); + break; + case OMAP_ABE_DAI_DMIC2: + abe_mute_gain(GAINS_DMIC3, GAIN_LEFT_OFFSET); + abe_mute_gain(GAINS_DMIC3, GAIN_RIGHT_OFFSET); + break; + } + } +} + +static void unmute_be(struct snd_soc_pcm_runtime *be, + struct snd_soc_dai *dai, int stream) +{ + dev_dbg(&be->dev, "%s: %s %d\n", __func__, be->cpu_dai->name, stream); + + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + switch (be->dai_link->be_id) { + case OMAP_ABE_DAI_PDM_DL1: + case OMAP_ABE_DAI_BT_VX: + case OMAP_ABE_DAI_MM_FM: + /* + * DL1 Mixer->SDT Mixer and DL1 gain are common for + * PDM_DL1, BT_VX_DL and MM_EXT_DL, unmute when any + * of them becomes active + */ + abe_unmute_gain(GAINS_DL1, GAIN_LEFT_OFFSET); + abe_unmute_gain(GAINS_DL1, GAIN_RIGHT_OFFSET); + abe_unmute_gain(MIXSDT, MIX_SDT_INPUT_DL1_MIXER); + break; + case OMAP_ABE_DAI_PDM_DL2: + abe_unmute_gain(GAINS_DL2, GAIN_LEFT_OFFSET); + abe_unmute_gain(GAINS_DL2, GAIN_RIGHT_OFFSET); + break; + case OMAP_ABE_DAI_PDM_VIB: + break; + case OMAP_ABE_DAI_MODEM: + break; + } + } else { + + switch (be->dai_link->be_id) { + case OMAP_ABE_DAI_PDM_UL: + abe_unmute_gain(GAINS_AMIC, GAIN_LEFT_OFFSET); + abe_unmute_gain(GAINS_AMIC, GAIN_RIGHT_OFFSET); + break; + case OMAP_ABE_DAI_BT_VX: + abe_unmute_gain(GAINS_BTUL, GAIN_LEFT_OFFSET); + abe_unmute_gain(GAINS_BTUL, GAIN_RIGHT_OFFSET); + break; + case OMAP_ABE_DAI_MM_FM: + case OMAP_ABE_DAI_MODEM: + break; + case OMAP_ABE_DAI_DMIC0: + abe_unmute_gain(GAINS_DMIC1, GAIN_LEFT_OFFSET); + abe_unmute_gain(GAINS_DMIC1, GAIN_RIGHT_OFFSET); + break; + case OMAP_ABE_DAI_DMIC1: + abe_unmute_gain(GAINS_DMIC2, GAIN_LEFT_OFFSET); + abe_unmute_gain(GAINS_DMIC2, GAIN_RIGHT_OFFSET); + break; + case OMAP_ABE_DAI_DMIC2: + abe_unmute_gain(GAINS_DMIC3, GAIN_LEFT_OFFSET); + abe_unmute_gain(GAINS_DMIC3, GAIN_RIGHT_OFFSET); + break; + } + } +} + +static void enable_be_port(struct snd_soc_pcm_runtime *be, + struct snd_soc_dai *dai, int stream) +{ + struct omap_abe_data *abe_priv = snd_soc_dai_get_drvdata(dai); + abe_data_format_t format; + + dev_dbg(&be->dev, "%s: %s %d\n", __func__, be->cpu_dai->name, stream); + + switch (be->dai_link->be_id) { + /* McPDM is a special case, handled by McPDM driver */ + case OMAP_ABE_DAI_PDM_DL1: + case OMAP_ABE_DAI_PDM_DL2: + case OMAP_ABE_DAI_PDM_VIB: + case OMAP_ABE_DAI_PDM_UL: + break; + case OMAP_ABE_DAI_BT_VX: + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + + /* port can only be configured if it's not running */ + if (omap_abe_port_is_enabled(abe_priv->abe, + abe_priv->port[OMAP_ABE_BE_PORT_BT_VX_DL])) + return; + + /* BT_DL connection to McBSP 1 ports */ + format.f = 8000; + format.samp_format = MONO_RSHIFTED_16; + abe_connect_serial_port(BT_VX_DL_PORT, &format, MCBSP1_TX); + omap_abe_port_enable(abe_priv->abe, + abe_priv->port[OMAP_ABE_BE_PORT_BT_VX_DL]); + } else { + + /* port can only be configured if it's not running */ + if (omap_abe_port_is_enabled(abe_priv->abe, + abe_priv->port[OMAP_ABE_BE_PORT_BT_VX_UL])) + return; + + /* BT_UL connection to McBSP 1 ports */ + format.f = 8000; + format.samp_format = MONO_RSHIFTED_16; + abe_connect_serial_port(BT_VX_UL_PORT, &format, MCBSP1_RX); + omap_abe_port_enable(abe_priv->abe, + abe_priv->port[OMAP_ABE_BE_PORT_BT_VX_UL]); + } + break; + case OMAP_ABE_DAI_MM_FM: + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + + /* port can only be configured if it's not running */ + if (omap_abe_port_is_enabled(abe_priv->abe, + abe_priv->port[OMAP_ABE_BE_PORT_MM_EXT_DL])) + return; + + /* MM_EXT connection to McBSP 2 ports */ + format.f = 48000; + format.samp_format = STEREO_RSHIFTED_16; + abe_connect_serial_port(MM_EXT_OUT_PORT, &format, MCBSP2_TX); + omap_abe_port_enable(abe_priv->abe, + abe_priv->port[OMAP_ABE_BE_PORT_MM_EXT_DL]); + } else { + + /* port can only be configured if it's not running */ + if (omap_abe_port_is_enabled(abe_priv->abe, + abe_priv->port[OMAP_ABE_BE_PORT_MM_EXT_UL])) + return; + + /* MM_EXT connection to McBSP 2 ports */ + format.f = 48000; + format.samp_format = STEREO_RSHIFTED_16; + abe_connect_serial_port(MM_EXT_IN_PORT, &format, MCBSP2_RX); + omap_abe_port_enable(abe_priv->abe, + abe_priv->port[OMAP_ABE_BE_PORT_MM_EXT_UL]); + } + break; + case OMAP_ABE_DAI_DMIC0: + omap_abe_port_enable(abe_priv->abe, + abe_priv->port[OMAP_ABE_BE_PORT_DMIC0]); + break; + case OMAP_ABE_DAI_DMIC1: + omap_abe_port_enable(abe_priv->abe, + abe_priv->port[OMAP_ABE_BE_PORT_DMIC1]); + break; + case OMAP_ABE_DAI_DMIC2: + omap_abe_port_enable(abe_priv->abe, + abe_priv->port[OMAP_ABE_BE_PORT_DMIC2]); + break; + } +} + +static void enable_fe_port(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai, int stream) +{ + struct snd_soc_pcm_runtime *fe = substream->private_data; + struct omap_abe_data *abe_priv = snd_soc_dai_get_drvdata(dai); + + dev_dbg(&fe->dev, "%s: %s %d\n", __func__, dai->name, stream); + + switch(dai->id) { + case ABE_FRONTEND_DAI_MEDIA: + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + omap_abe_port_enable(abe_priv->abe, + abe_priv->port[OMAP_ABE_FE_PORT_MM_DL1]); + else + omap_abe_port_enable(abe_priv->abe, + abe_priv->port[OMAP_ABE_FE_PORT_MM_UL1]); + break; + case ABE_FRONTEND_DAI_LP_MEDIA: + abe_enable_data_transfer(MM_DL_PORT); + break; + case ABE_FRONTEND_DAI_MEDIA_CAPTURE: + if (stream == SNDRV_PCM_STREAM_CAPTURE) + omap_abe_port_enable(abe_priv->abe, + abe_priv->port[OMAP_ABE_FE_PORT_MM_UL2]); + break; + case ABE_FRONTEND_DAI_MODEM: + case ABE_FRONTEND_DAI_VOICE: + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + omap_abe_port_enable(abe_priv->abe, + abe_priv->port[OMAP_ABE_FE_PORT_VX_DL]); + else + omap_abe_port_enable(abe_priv->abe, + abe_priv->port[OMAP_ABE_FE_PORT_VX_UL]); + break; + case ABE_FRONTEND_DAI_TONES: + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + omap_abe_port_enable(abe_priv->abe, + abe_priv->port[OMAP_ABE_FE_PORT_TONES]); + break; + case ABE_FRONTEND_DAI_VIBRA: + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + omap_abe_port_enable(abe_priv->abe, + abe_priv->port[OMAP_ABE_FE_PORT_VIB]); + break; + } +} + +static void disable_be_port(struct snd_soc_pcm_runtime *be, + struct snd_soc_dai *dai, int stream) +{ + struct omap_abe_data *abe_priv = snd_soc_dai_get_drvdata(dai); + + dev_dbg(&be->dev, "%s: %s %d\n", __func__, be->cpu_dai->name, stream); + + switch (be->dai_link->be_id) { + /* McPDM is a special case, handled by McPDM driver */ + case OMAP_ABE_DAI_PDM_DL1: + case OMAP_ABE_DAI_PDM_DL2: + case OMAP_ABE_DAI_PDM_VIB: + case OMAP_ABE_DAI_PDM_UL: + break; + case OMAP_ABE_DAI_BT_VX: + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + omap_abe_port_disable(abe_priv->abe, + abe_priv->port[OMAP_ABE_BE_PORT_BT_VX_DL]); + else + omap_abe_port_disable(abe_priv->abe, + abe_priv->port[OMAP_ABE_BE_PORT_BT_VX_UL]); + break; + case OMAP_ABE_DAI_MM_FM: + case OMAP_ABE_DAI_MODEM: + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + omap_abe_port_disable(abe_priv->abe, + abe_priv->port[OMAP_ABE_BE_PORT_MM_EXT_DL]); + else + omap_abe_port_disable(abe_priv->abe, + abe_priv->port[OMAP_ABE_BE_PORT_MM_EXT_UL]); + break; + case OMAP_ABE_DAI_DMIC0: + omap_abe_port_disable(abe_priv->abe, + abe_priv->port[OMAP_ABE_BE_PORT_DMIC0]); + break; + case OMAP_ABE_DAI_DMIC1: + omap_abe_port_disable(abe_priv->abe, + abe_priv->port[OMAP_ABE_BE_PORT_DMIC1]); + break; + case OMAP_ABE_DAI_DMIC2: + omap_abe_port_disable(abe_priv->abe, + abe_priv->port[OMAP_ABE_BE_PORT_DMIC2]); + break; + } +} + +static void disable_fe_port(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai, int stream) +{ + struct snd_soc_pcm_runtime *fe = substream->private_data; + struct omap_abe_data *abe_priv = snd_soc_dai_get_drvdata(dai); + + dev_dbg(&fe->dev, "%s: %s %d\n", __func__, dai->name, stream); + + switch(dai->id) { + case ABE_FRONTEND_DAI_MEDIA: + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + omap_abe_port_disable(abe_priv->abe, + abe_priv->port[OMAP_ABE_FE_PORT_MM_DL1]); + else + omap_abe_port_disable(abe_priv->abe, + abe_priv->port[OMAP_ABE_FE_PORT_MM_UL1]); + break; + case ABE_FRONTEND_DAI_LP_MEDIA: + abe_disable_data_transfer(MM_DL_PORT); + break; + case ABE_FRONTEND_DAI_MEDIA_CAPTURE: + if (stream == SNDRV_PCM_STREAM_CAPTURE) + omap_abe_port_disable(abe_priv->abe, + abe_priv->port[OMAP_ABE_FE_PORT_MM_UL2]); + break; + case ABE_FRONTEND_DAI_MODEM: + case ABE_FRONTEND_DAI_VOICE: + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + omap_abe_port_disable(abe_priv->abe, + abe_priv->port[OMAP_ABE_FE_PORT_VX_DL]); + else + omap_abe_port_disable(abe_priv->abe, + abe_priv->port[OMAP_ABE_FE_PORT_VX_UL]); + break; + case ABE_FRONTEND_DAI_TONES: + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + omap_abe_port_disable(abe_priv->abe, + abe_priv->port[OMAP_ABE_FE_PORT_TONES]); + break; + case ABE_FRONTEND_DAI_VIBRA: + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + omap_abe_port_disable(abe_priv->abe, + abe_priv->port[OMAP_ABE_FE_PORT_VIB]); + break; + } +} + +static void mute_fe_port_capture(struct snd_soc_pcm_runtime *fe, + struct snd_soc_pcm_runtime *be, int mute) +{ + struct omap_abe_data *abe_priv = snd_soc_dai_get_drvdata(fe->cpu_dai); + + dev_dbg(&fe->dev, "%s: %s FE %s BE %s\n", + __func__, mute ? "mute" : "unmute", + fe->dai_link->name, be->dai_link->name); + + switch (fe->cpu_dai->id) { + case ABE_FRONTEND_DAI_MEDIA_CAPTURE: + if (omap_abe_dl1_enabled(abe_priv)) { + if (mute) + abe_mute_gain(MIXDL1, MIX_DL1_INPUT_MM_UL2); + else + abe_unmute_gain(MIXDL1, MIX_DL1_INPUT_MM_UL2); + } + if (omap_abe_dl2_enabled(abe_priv)) { + if (mute) + abe_mute_gain(MIXDL2, MIX_DL2_INPUT_MM_UL2); + else + abe_unmute_gain(MIXDL2, MIX_DL2_INPUT_MM_UL2); + } + break; + case ABE_FRONTEND_DAI_MODEM: + case ABE_FRONTEND_DAI_VOICE: + if (mute) { + abe_mute_gain(MIXSDT, MIX_SDT_INPUT_UP_MIXER); + abe_mute_gain(MIXAUDUL, MIX_AUDUL_INPUT_UPLINK); + } else { + abe_unmute_gain(MIXSDT, MIX_SDT_INPUT_UP_MIXER); + abe_unmute_gain(MIXAUDUL, MIX_AUDUL_INPUT_UPLINK); + } + break; + case ABE_FRONTEND_DAI_MEDIA: + default: + break; + } +} + +static void mute_fe_port_playback(struct snd_soc_pcm_runtime *fe, + struct snd_soc_pcm_runtime *be, int mute) +{ + struct omap_abe_data *abe_priv = snd_soc_dai_get_drvdata(fe->cpu_dai); + + dev_dbg(&fe->dev, "%s: %s FE %s BE %s\n", + __func__, mute ? "mute" : "unmute", + fe->dai_link->name, be->dai_link->name); + + switch (fe->cpu_dai->id) { + case ABE_FRONTEND_DAI_MEDIA: + case ABE_FRONTEND_DAI_LP_MEDIA: + switch (be->dai_link->be_id) { + case OMAP_ABE_DAI_PDM_DL1: + case OMAP_ABE_DAI_BT_VX: + case OMAP_ABE_DAI_MM_FM: + if (mute) { + /* mute if last running DL1-related BE */ + if (omap_abe_dl1_enabled(abe_priv) == 1) + abe_mute_gain(MIXDL1, + MIX_DL1_INPUT_MM_DL); + } else { + abe_unmute_gain(MIXDL1, MIX_DL1_INPUT_MM_DL); + } + break; + case OMAP_ABE_DAI_PDM_DL2: + if (mute) + abe_mute_gain(MIXDL2, MIX_DL2_INPUT_MM_DL); + else + abe_unmute_gain(MIXDL2, MIX_DL2_INPUT_MM_DL); + break; + case OMAP_ABE_DAI_MODEM: + case OMAP_ABE_DAI_PDM_VIB: + default: + break; + } + break; + case ABE_FRONTEND_DAI_VOICE: + case ABE_FRONTEND_DAI_MODEM: + switch (be->dai_link->be_id) { + case OMAP_ABE_DAI_PDM_DL1: + case OMAP_ABE_DAI_BT_VX: + case OMAP_ABE_DAI_MM_FM: + if (mute) { + /* mute if last running DL1-related BE */ + if (omap_abe_dl1_enabled(abe_priv) == 1) + abe_mute_gain(MIXDL1, + MIX_DL1_INPUT_VX_DL); + } else { + abe_unmute_gain(MIXDL1, MIX_DL1_INPUT_VX_DL); + } + break; + case OMAP_ABE_DAI_PDM_DL2: + if (mute) + abe_mute_gain(MIXDL2, MIX_DL2_INPUT_VX_DL); + else + abe_unmute_gain(MIXDL2, MIX_DL2_INPUT_VX_DL); + break; + case OMAP_ABE_DAI_MODEM: + case OMAP_ABE_DAI_PDM_VIB: + default: + break; + } + break; + case ABE_FRONTEND_DAI_TONES: + switch (be->dai_link->be_id) { + case OMAP_ABE_DAI_PDM_DL1: + case OMAP_ABE_DAI_BT_VX: + case OMAP_ABE_DAI_MM_FM: + if (mute) { + /* mute if last running DL1-related BE */ + if (omap_abe_dl1_enabled(abe_priv) == 1) + abe_mute_gain(MIXDL1, + MIX_DL1_INPUT_TONES); + } else{ + abe_unmute_gain(MIXDL1, MIX_DL1_INPUT_TONES); + } + break; + case OMAP_ABE_DAI_PDM_DL2: + if (mute) + abe_mute_gain(MIXDL2, MIX_DL2_INPUT_TONES); + else + abe_unmute_gain(MIXDL2, MIX_DL2_INPUT_TONES); + break; + case OMAP_ABE_DAI_MODEM: + case OMAP_ABE_DAI_PDM_VIB: + default: + break; + } + break; + case ABE_FRONTEND_DAI_VIBRA: + default: + break; + } +} + +static void mute_fe_port(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai, int stream) +{ + struct snd_soc_pcm_runtime *fe = substream->private_data; + struct snd_soc_dsp_params *dsp_params; + + dev_dbg(&fe->dev, "%s: %s %d\n", __func__, dai->name, stream); + + list_for_each_entry(dsp_params, &fe->dsp[stream].be_clients, list_be) { + struct snd_soc_pcm_runtime *be = dsp_params->be; + + if (!snd_soc_dsp_is_op_for_be(fe, be, stream)) + continue; + + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + mute_fe_port_playback(fe, be, 1); + else + mute_fe_port_capture(fe, be, 1); + } +} + +static void unmute_fe_port(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai, int stream) +{ + struct snd_soc_pcm_runtime *fe = substream->private_data; + struct snd_soc_dsp_params *dsp_params; + + dev_dbg(&fe->dev, "%s: %s %d\n", __func__, dai->name, stream); + + list_for_each_entry(dsp_params, &fe->dsp[stream].be_clients, list_be) { + struct snd_soc_pcm_runtime *be = dsp_params->be; + + if (!snd_soc_dsp_is_op_for_be(fe, be, stream)) + continue; + + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + mute_fe_port_playback(fe, be, 0); + else + mute_fe_port_capture(fe, be, 0); + } +} + +static void capture_trigger(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai, int cmd) +{ + struct snd_soc_pcm_runtime *fe = substream->private_data; + struct snd_soc_dsp_params *dsp_params; + struct snd_pcm_substream *be_substream; + int stream = substream->stream; + + dev_dbg(&fe->dev, "%s: %s %d\n", __func__, fe->cpu_dai->name, stream); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + + /* mute and enable BE ports */ + list_for_each_entry(dsp_params, &fe->dsp[stream].be_clients, list_be) { + struct snd_soc_pcm_runtime *be = dsp_params->be; + + /* does this trigger() apply to this BE and stream ? */ + if (!snd_soc_dsp_is_op_for_be(fe, be, stream)) + continue; + + if ((be->dsp[stream].state != SND_SOC_DSP_STATE_PREPARE) && + (be->dsp[stream].state != SND_SOC_DSP_STATE_STOP)) + continue; + + be_substream = snd_soc_dsp_get_substream(be, stream); + + /* mute the BE port */ + mute_be(be, dai, stream); + + /* enable the BE port */ + enable_be_port(be, dai, stream); + + /* DAI work must be started/stopped at least 250us after ABE */ + udelay(250); + + /* trigger the BE port */ + snd_soc_dai_trigger(be_substream, cmd, be->cpu_dai); + + be->dsp[stream].state = SND_SOC_DSP_STATE_START; + } + + /* does this trigger() apply to the FE ? */ + if (snd_soc_dsp_is_trigger_for_fe(fe, stream)) { + /* Enable Frontend sDMA */ + snd_soc_dsp_platform_trigger(substream, cmd, fe->platform); + enable_fe_port(substream, dai, stream); + + /* unmute FE port */ + unmute_fe_port(substream, dai, stream); + } + + /* Restore ABE GAINS AMIC */ + list_for_each_entry(dsp_params, &fe->dsp[stream].be_clients, list_be) { + struct snd_soc_pcm_runtime *be = dsp_params->be; + + /* does this trigger() apply to this BE and stream ? */ + if (!snd_soc_dsp_is_op_for_be(fe, be, stream)) + continue; + + /* unmute this BE port */ + unmute_be(be, dai, stream); + } + break; + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + /* Enable sDMA */ + snd_soc_dsp_platform_trigger(substream, cmd, fe->platform); + enable_fe_port(substream, dai, stream); + break; + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + /* Disable sDMA */ + disable_fe_port(substream, dai, stream); + snd_soc_dsp_platform_trigger(substream, cmd, fe->platform); + break; + case SNDRV_PCM_TRIGGER_STOP: + /* does this trigger() apply to the FE ? */ + if (snd_soc_dsp_is_trigger_for_fe(fe, stream)) { + /* mute FE port */ + mute_fe_port(substream, dai, stream); + + /* Disable sDMA */ + disable_fe_port(substream, dai, stream); + snd_soc_dsp_platform_trigger(substream, cmd, fe->platform); + } + + /* disable BE ports */ + list_for_each_entry(dsp_params, &fe->dsp[stream].be_clients, list_be) { + struct snd_soc_pcm_runtime *be = dsp_params->be; + + /* does this trigger() apply to this BE and stream ? */ + if (!snd_soc_dsp_is_op_for_be(fe, be, stream)) + continue; + + if (be->dsp[stream].state != SND_SOC_DSP_STATE_START) + continue; + + /* only stop if last running user */ + if (soc_dsp_fe_state_count(be, stream, + SND_SOC_DSP_STATE_START) > 1) + continue; + + be_substream = snd_soc_dsp_get_substream(be, stream); + + /* mute the BE port */ + mute_be(be, dai, stream); + + /* disable the BE port */ + disable_be_port(be, dai, stream); + + /* DAI work must be started/stopped at least 250us after ABE */ + udelay(250); + + /* trigger BE port */ + snd_soc_dai_trigger(be_substream, cmd, be->cpu_dai); + + be->dsp[stream].state = SND_SOC_DSP_STATE_STOP; + } + break; + default: + break; + } +} + +static void playback_trigger(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai, int cmd) +{ + struct snd_soc_pcm_runtime *fe = substream->private_data; + struct snd_soc_dsp_params *dsp_params; + struct snd_pcm_substream *be_substream; + int stream = substream->stream; + + dev_dbg(&fe->dev, "%s: %s %d\n", __func__, fe->cpu_dai->name, stream); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + + /* mute and enable ports */ + list_for_each_entry(dsp_params, &fe->dsp[stream].be_clients, list_be) { + struct snd_soc_pcm_runtime *be = dsp_params->be; + + /* does this trigger() apply to the FE ? */ + if (!snd_soc_dsp_is_op_for_be(fe, be, stream)) + continue; + + if ((be->dsp[stream].state != SND_SOC_DSP_STATE_PREPARE) && + (be->dsp[stream].state != SND_SOC_DSP_STATE_STOP)) + continue; + + be_substream = snd_soc_dsp_get_substream(be, stream); + + /* mute BE port */ + mute_be(be, dai, stream); + + /* enabled BE port */ + enable_be_port(be, dai, stream); + + /* DAI work must be started/stopped at least 250us after ABE */ + udelay(250); + + /* trigger BE port */ + snd_soc_dai_trigger(be_substream, cmd, be->cpu_dai); + + /* unmute the BE port */ + unmute_be(be, dai, stream); + + be->dsp[stream].state = SND_SOC_DSP_STATE_START; + } + + /* does this trigger() apply to the FE ? */ + if (snd_soc_dsp_is_trigger_for_fe(fe, stream)) { + /* Enable Frontend sDMA */ + snd_soc_dsp_platform_trigger(substream, cmd, fe->platform); + enable_fe_port(substream, dai, stream); + } + + /* unmute FE port (sensitive to runtime udpates) */ + unmute_fe_port(substream, dai, stream); + + break; + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + /* Enable Frontend sDMA */ + snd_soc_dsp_platform_trigger(substream, cmd, fe->platform); + enable_fe_port(substream, dai, stream); + + /* unmute FE port */ + unmute_fe_port(substream, dai, stream); + break; + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + /* mute FE port */ + mute_fe_port(substream, dai, stream); + + /* disable Frontend sDMA */ + disable_fe_port(substream, dai, stream); + snd_soc_dsp_platform_trigger(substream, cmd, fe->platform); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + + /* mute FE port (sensitive to runtime udpates) */ + mute_fe_port(substream, dai, stream); + + /* does this trigger() apply to the FE ? */ + if (snd_soc_dsp_is_trigger_for_fe(fe, stream)) { + /* disable the transfer */ + disable_fe_port(substream, dai, stream); + snd_soc_dsp_platform_trigger(substream, cmd, fe->platform); + } + + /* disable BE ports */ + list_for_each_entry(dsp_params, &fe->dsp[stream].be_clients, list_be) { + struct snd_soc_pcm_runtime *be = dsp_params->be; + + /* does this trigger() apply to this BE and stream ? */ + if (!snd_soc_dsp_is_op_for_be(fe, be, stream)) + continue; + + if (be->dsp[stream].state != SND_SOC_DSP_STATE_START) + continue; + + /* only stop if last running user */ + if (soc_dsp_fe_state_count(be, stream, + SND_SOC_DSP_STATE_START) > 1) + continue; + + be_substream = snd_soc_dsp_get_substream(be, stream); + + /* mute the BE port */ + mute_be(be, dai, stream); + + /* disable the BE */ + disable_be_port(be, dai, stream); + + /* DAI work must be started/stopped at least 250us after ABE */ + udelay(250); + + /* trigger the BE port */ + snd_soc_dai_trigger(be_substream, cmd, be->cpu_dai); + + be->dsp[stream].state = SND_SOC_DSP_STATE_STOP; + } + break; + default: + break; + } +} + +static int omap_abe_dai_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct omap_abe_data *abe_priv = snd_soc_dai_get_drvdata(dai); + int ret = 0; + + dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); + + abe_priv->active_dais++; + + abe_dsp_pm_get(); + + if (dai->id == ABE_FRONTEND_DAI_MODEM) { + + ret = modem_get_dai(substream, dai); + if (ret < 0) { + dev_err(dai->dev, "failed to get MODEM DAI\n"); + return ret; + } + dev_dbg(abe_priv->modem_dai->dev, "%s: MODEM stream %d\n", + __func__, substream->stream); + + ret = snd_soc_dai_startup(abe_priv->modem_substream[substream->stream], + abe_priv->modem_dai); + if (ret < 0) { + dev_err(abe_priv->modem_dai->dev, "failed to open DAI %d\n", ret); + return ret; + } + } + + return ret; +} + +static int omap_abe_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct omap_abe_data *abe_priv = snd_soc_dai_get_drvdata(dai); + struct omap_pcm_dma_data *dma_data; + abe_data_format_t format; + abe_dma_t dma_sink; + abe_dma_t dma_params; + int data_type = OMAP_DMA_DATA_TYPE_S32; + int ret; + + dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); + + dma_data = &omap_abe_dai_dma_params[dai->id][substream->stream]; + + switch (params_channels(params)) { + case 1: + if (params_format(params) == SNDRV_PCM_FORMAT_S16_LE) { + format.samp_format = MONO_RSHIFTED_16; + data_type = OMAP_DMA_DATA_TYPE_S16; + } else { + format.samp_format = MONO_MSB; + } + break; + case 2: + if (params_format(params) == SNDRV_PCM_FORMAT_S16_LE) + format.samp_format = STEREO_16_16; + else + format.samp_format = STEREO_MSB; + break; + case 3: + format.samp_format = THREE_MSB; + break; + case 4: + format.samp_format = FOUR_MSB; + break; + case 5: + format.samp_format = FIVE_MSB; + break; + case 6 : + format.samp_format = SIX_MSB; + break; + case 7 : + format.samp_format = SEVEN_MSB; + break; + case 8: + format.samp_format = EIGHT_MSB; + break; + default: + dev_err(dai->dev, "%d channels not supported", + params_channels(params)); + return -EINVAL; + } + + format.f = params_rate(params); + + switch (dai->id) { + case ABE_FRONTEND_DAI_MEDIA: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + abe_connect_cbpr_dmareq_port(MM_DL_PORT, &format, ABE_CBPR0_IDX, + &dma_sink); + abe_read_port_address(MM_DL_PORT, &dma_params); + } else { + abe_connect_cbpr_dmareq_port(MM_UL_PORT, &format, ABE_CBPR3_IDX, + &dma_sink); + abe_read_port_address(MM_UL_PORT, &dma_params); + } + break; + case ABE_FRONTEND_DAI_LP_MEDIA: + return 0; + break; + case ABE_FRONTEND_DAI_MEDIA_CAPTURE: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + return -EINVAL; + else { + abe_connect_cbpr_dmareq_port(MM_UL2_PORT, &format, ABE_CBPR4_IDX, + &dma_sink); + abe_read_port_address(MM_UL2_PORT, &dma_params); + } + break; + case ABE_FRONTEND_DAI_VOICE: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + abe_connect_cbpr_dmareq_port(VX_DL_PORT, &format, ABE_CBPR1_IDX, + &dma_sink); + abe_read_port_address(VX_DL_PORT, &dma_params); + } else { + abe_connect_cbpr_dmareq_port(VX_UL_PORT, &format, ABE_CBPR2_IDX, + &dma_sink); + abe_read_port_address(VX_UL_PORT, &dma_params); + } + break; + case ABE_FRONTEND_DAI_TONES: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + abe_connect_cbpr_dmareq_port(TONES_DL_PORT, &format, ABE_CBPR5_IDX, + &dma_sink); + abe_read_port_address(TONES_DL_PORT, &dma_params); + } else + return -EINVAL; + break; + case ABE_FRONTEND_DAI_VIBRA: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + abe_connect_cbpr_dmareq_port(VIB_DL_PORT, &format, ABE_CBPR6_IDX, + &dma_sink); + abe_read_port_address(VIB_DL_PORT, &dma_params); + } else + return -EINVAL; + break; + case ABE_FRONTEND_DAI_MODEM: + /* MODEM is special case where data IO is performed by McBSP2 + * directly onto VX_DL and VX_UL (instead of SDMA). + */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + /* Vx_DL connection to McBSP 2 ports */ + format.samp_format = STEREO_RSHIFTED_16; + abe_connect_serial_port(VX_DL_PORT, &format, MCBSP2_RX); + abe_read_port_address(VX_DL_PORT, &dma_params); + } else { + /* Vx_UL connection to McBSP 2 ports */ + format.samp_format = STEREO_RSHIFTED_16; + abe_connect_serial_port(VX_UL_PORT, &format, MCBSP2_TX); + abe_read_port_address(VX_UL_PORT, &dma_params); + } + break; + } + + /* configure frontend SDMA data */ + dma_data->port_addr = (unsigned long)dma_params.data; + dma_data->packet_size = dma_params.iter; + dma_data->data_type = data_type; + + if (dai->id == ABE_FRONTEND_DAI_MODEM) { + /* call hw_params on McBSP with correct DMA data */ + snd_soc_dai_set_dma_data(abe_priv->modem_dai, substream, + dma_data); + + dev_dbg(abe_priv->modem_dai->dev, "%s: MODEM stream %d\n", + __func__, substream->stream); + + ret = snd_soc_dai_hw_params(abe_priv->modem_substream[substream->stream], + params, abe_priv->modem_dai); + if (ret < 0) + dev_err(abe_priv->modem_dai->dev, "MODEM hw_params failed\n"); + return ret; + } + + snd_soc_dai_set_dma_data(dai, substream, dma_data); + + return 0; +} + +static int omap_abe_dai_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct omap_abe_data *abe_priv = snd_soc_dai_get_drvdata(dai); + int ret = 0; + + dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); + + if (dai->id == ABE_FRONTEND_DAI_MODEM) { + ret = snd_soc_dai_prepare(abe_priv->modem_substream[substream->stream], + abe_priv->modem_dai); + + dev_dbg(abe_priv->modem_dai->dev, "%s: MODEM stream %d\n", + __func__, substream->stream); + + if (ret < 0) { + dev_err(abe_priv->modem_dai->dev, "MODEM prepare failed\n"); + return ret; + } + } + return ret; +} + +static int omap_abe_dai_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) +{ + struct omap_abe_data *abe_priv = snd_soc_dai_get_drvdata(dai); + int ret = 0; + + dev_dbg(dai->dev, "%s: %s cmd %d\n", __func__, dai->name, cmd); + + if (dai->id == ABE_FRONTEND_DAI_MODEM) { + + dev_dbg(abe_priv->modem_dai->dev, "%s: MODEM stream %d cmd %d\n", + __func__, substream->stream, cmd); + + ret = snd_soc_dai_trigger(abe_priv->modem_substream[substream->stream], + cmd, abe_priv->modem_dai); + if (ret < 0) { + dev_err(abe_priv->modem_dai->dev, "MODEM trigger failed\n"); + return ret; + } + } + + return ret; +} + +static int omap_abe_dai_bespoke_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *fe = substream->private_data; + struct omap_abe_data *abe_priv = snd_soc_dai_get_drvdata(dai); + int ret = 0; + + dev_dbg(dai->dev, "%s: %s cmd %d\n", __func__, dai->name, cmd); + + if ((dai->id == ABE_FRONTEND_DAI_MODEM) && + snd_soc_dsp_is_trigger_for_fe(fe, substream->stream)) { + + dev_dbg(abe_priv->modem_dai->dev, "%s: MODEM stream %d cmd %d\n", + __func__, substream->stream, cmd); + + ret = snd_soc_dai_trigger(abe_priv->modem_substream[substream->stream], + cmd, abe_priv->modem_dai); + if (ret < 0) { + dev_err(abe_priv->modem_dai->dev, "MODEM trigger failed\n"); + return ret; + } + } + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + playback_trigger(substream, dai, cmd); + else + capture_trigger(substream, dai, cmd); + + return ret; +} + +static int omap_abe_dai_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct omap_abe_data *abe_priv = snd_soc_dai_get_drvdata(dai); + int ret = 0; + + dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); + + if (dai->id == ABE_FRONTEND_DAI_MODEM) { + + dev_dbg(abe_priv->modem_dai->dev, "%s: MODEM stream %d\n", + __func__, substream->stream); + + ret = snd_soc_dai_hw_free(abe_priv->modem_substream[substream->stream], + abe_priv->modem_dai); + if (ret < 0) { + dev_err(abe_priv->modem_dai->dev, "MODEM hw_free failed\n"); + return ret; + } + } + return ret; +} + +static void omap_abe_dai_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct omap_abe_data *abe_priv = snd_soc_dai_get_drvdata(dai); + + dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); + + if (dai->id == ABE_FRONTEND_DAI_MODEM) { + dev_dbg(abe_priv->modem_dai->dev, "%s: MODEM stream %d\n", + __func__, substream->stream); + + snd_soc_dai_shutdown(abe_priv->modem_substream[substream->stream], + abe_priv->modem_dai); + } + + abe_dsp_shutdown(); + abe_dsp_pm_put(); + + abe_priv->active_dais--; +} + +#ifdef CONFIG_PM +static int omap_abe_dai_suspend(struct snd_soc_dai *dai) +{ + struct omap_abe_data *abe_priv = snd_soc_dai_get_drvdata(dai); + + dev_dbg(dai->dev, "%s: %s active %d\n", + __func__, dai->name, dai->active); + + if (!dai->active) + return 0; + + if (++abe_priv->suspended_dais < abe_priv->active_dais) + return 0; + + abe_mute_gain(MIXSDT, MIX_SDT_INPUT_UP_MIXER); + abe_mute_gain(MIXSDT, MIX_SDT_INPUT_DL1_MIXER); + abe_mute_gain(MIXAUDUL, MIX_AUDUL_INPUT_MM_DL); + abe_mute_gain(MIXAUDUL, MIX_AUDUL_INPUT_TONES); + abe_mute_gain(MIXAUDUL, MIX_AUDUL_INPUT_UPLINK); + abe_mute_gain(MIXAUDUL, MIX_AUDUL_INPUT_VX_DL); + abe_mute_gain(MIXVXREC, MIX_VXREC_INPUT_TONES); + abe_mute_gain(MIXVXREC, MIX_VXREC_INPUT_VX_DL); + abe_mute_gain(MIXVXREC, MIX_VXREC_INPUT_MM_DL); + abe_mute_gain(MIXVXREC, MIX_VXREC_INPUT_VX_UL); + abe_mute_gain(MIXDL1, MIX_DL1_INPUT_MM_DL); + abe_mute_gain(MIXDL1, MIX_DL1_INPUT_MM_UL2); + abe_mute_gain(MIXDL1, MIX_DL1_INPUT_VX_DL); + abe_mute_gain(MIXDL1, MIX_DL1_INPUT_TONES); + abe_mute_gain(MIXDL2, MIX_DL2_INPUT_TONES); + abe_mute_gain(MIXDL2, MIX_DL2_INPUT_VX_DL); + abe_mute_gain(MIXDL2, MIX_DL2_INPUT_MM_DL); + abe_mute_gain(MIXDL2, MIX_DL2_INPUT_MM_UL2); + abe_mute_gain(MIXECHO, MIX_ECHO_DL1); + abe_mute_gain(MIXECHO, MIX_ECHO_DL2); + + return 0; +} + +static int omap_abe_dai_resume(struct snd_soc_dai *dai) +{ + struct omap_abe_data *abe_priv = snd_soc_dai_get_drvdata(dai); + + dev_dbg(dai->dev, "%s: %s active %d\n", + __func__, dai->name, dai->active); + + if (!dai->active) + return 0; + + if (abe_priv->suspended_dais-- < abe_priv->active_dais) + return 0; + + abe_unmute_gain(MIXSDT, MIX_SDT_INPUT_UP_MIXER); + abe_unmute_gain(MIXSDT, MIX_SDT_INPUT_DL1_MIXER); + abe_unmute_gain(MIXAUDUL, MIX_AUDUL_INPUT_MM_DL); + abe_unmute_gain(MIXAUDUL, MIX_AUDUL_INPUT_TONES); + abe_unmute_gain(MIXAUDUL, MIX_AUDUL_INPUT_UPLINK); + abe_unmute_gain(MIXAUDUL, MIX_AUDUL_INPUT_VX_DL); + abe_unmute_gain(MIXVXREC, MIX_VXREC_INPUT_TONES); + abe_unmute_gain(MIXVXREC, MIX_VXREC_INPUT_VX_DL); + abe_unmute_gain(MIXVXREC, MIX_VXREC_INPUT_MM_DL); + abe_unmute_gain(MIXVXREC, MIX_VXREC_INPUT_VX_UL); + abe_unmute_gain(MIXDL1, MIX_DL1_INPUT_MM_DL); + abe_unmute_gain(MIXDL1, MIX_DL1_INPUT_MM_UL2); + abe_unmute_gain(MIXDL1, MIX_DL1_INPUT_VX_DL); + abe_unmute_gain(MIXDL1, MIX_DL1_INPUT_TONES); + abe_unmute_gain(MIXDL2, MIX_DL2_INPUT_TONES); + abe_unmute_gain(MIXDL2, MIX_DL2_INPUT_VX_DL); + abe_unmute_gain(MIXDL2, MIX_DL2_INPUT_MM_DL); + abe_unmute_gain(MIXDL2, MIX_DL2_INPUT_MM_UL2); + abe_unmute_gain(MIXECHO, MIX_ECHO_DL1); + abe_unmute_gain(MIXECHO, MIX_ECHO_DL2); + + return 0; +} +#else +#define omap_abe_dai_suspend NULL +#define omap_abe_dai_resume NULL +#endif + +static int omap_abe_dai_probe(struct snd_soc_dai *dai) +{ + struct omap_abe_data *abe_priv; + int i; + + abe_priv = kzalloc(sizeof(struct omap_abe_data), GFP_KERNEL); + if (abe_priv == NULL) + return -ENOMEM; + + abe_priv->abe = omap_abe_port_mgr_get(); + if (!abe_priv->abe) + goto err; + + for (i = 0; i <= OMAP_ABE_MAX_PORT_ID; i++) { + + abe_priv->port[i] = omap_abe_port_open(abe_priv->abe, i); + if (abe_priv->port[i] == NULL) { + for (--i; i >= 0; i--) + omap_abe_port_close(abe_priv->abe, abe_priv->port[i]); + + goto err_port; + } + } + + snd_soc_dai_set_drvdata(dai, abe_priv); + return 0; + +err_port: + omap_abe_port_mgr_put(abe_priv->abe); +err: + kfree(abe_priv); + return -ENOMEM; +} + +static int omap_abe_dai_remove(struct snd_soc_dai *dai) +{ + struct omap_abe_data *abe_priv = snd_soc_dai_get_drvdata(dai); + + omap_abe_port_mgr_put(abe_priv->abe); + kfree(abe_priv); + return 0; +} + +static struct snd_soc_dai_ops omap_abe_dai_ops = { + .startup = omap_abe_dai_startup, + .shutdown = omap_abe_dai_shutdown, + .hw_params = omap_abe_dai_hw_params, + .hw_free = omap_abe_dai_hw_free, + .prepare = omap_abe_dai_prepare, + .trigger = omap_abe_dai_trigger, + .bespoke_trigger = omap_abe_dai_bespoke_trigger, +}; + +static struct snd_soc_dai_driver omap_abe_dai[] = { + { /* Multimedia Playback and Capture */ + .name = "MultiMedia1", + .probe = omap_abe_dai_probe, + .remove = omap_abe_dai_remove, + .suspend = omap_abe_dai_suspend, + .resume = omap_abe_dai_resume, + .playback = { + .stream_name = "MultiMedia1 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_48000, + .formats = OMAP_ABE_FORMATS, + }, + .capture = { + .stream_name = "MultiMedia1 Capture", + .channels_min = 2, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_48000, + .formats = OMAP_ABE_FORMATS, + }, + .ops = &omap_abe_dai_ops, + }, + { /* Multimedia Capture */ + .name = "MultiMedia2", + .suspend = omap_abe_dai_suspend, + .resume = omap_abe_dai_resume, + .capture = { + .stream_name = "MultiMedia2 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_48000, + .formats = OMAP_ABE_FORMATS, + }, + .ops = &omap_abe_dai_ops, + }, + { /* Voice Playback and Capture */ + .name = "Voice", + .suspend = omap_abe_dai_suspend, + .resume = omap_abe_dai_resume, + .playback = { + .stream_name = "Voice Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000, + .formats = OMAP_ABE_FORMATS, + }, + .capture = { + .stream_name = "Voice Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000, + .formats = OMAP_ABE_FORMATS, + }, + .ops = &omap_abe_dai_ops, + }, + { /* Tones Playback */ + .name = "Tones", + .suspend = omap_abe_dai_suspend, + .resume = omap_abe_dai_resume, + .playback = { + .stream_name = "Tones Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_48000, + .formats = OMAP_ABE_FORMATS, + }, + .ops = &omap_abe_dai_ops, + }, + { /* Vibra */ + .name = "Vibra", + .suspend = omap_abe_dai_suspend, + .resume = omap_abe_dai_resume, + .playback = { + .stream_name = "Vibra Playback", + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .formats = OMAP_ABE_FORMATS, + }, + .ops = &omap_abe_dai_ops, + }, + { /* MODEM Voice Playback and Capture */ + .name = "MODEM", + .suspend = omap_abe_dai_suspend, + .resume = omap_abe_dai_resume, + .playback = { + .stream_name = "MODEM Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000, + .formats = OMAP_ABE_FORMATS, + }, + .capture = { + .stream_name = "MODEM Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000, + .formats = OMAP_ABE_FORMATS, + }, + .ops = &omap_abe_dai_ops, + }, + { /* Low Power HiFi Playback */ + .name = "MultiMedia1 LP", + .suspend = omap_abe_dai_suspend, + .resume = omap_abe_dai_resume, + .playback = { + .stream_name = "MultiMedia1 LP Playback", + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, + .formats = OMAP_ABE_FORMATS, + }, + .ops = &omap_abe_dai_ops, + }, +}; + +static int __devinit omap_abe_probe(struct platform_device *pdev) +{ + return snd_soc_register_dais(&pdev->dev, omap_abe_dai, + ARRAY_SIZE(omap_abe_dai)); +} + +static int __devexit omap_abe_remove(struct platform_device *pdev) +{ + snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(omap_abe_dai)); + return 0; +} + +static struct platform_driver omap_abe_driver = { + .driver = { + .name = "omap-abe-dai", + .owner = THIS_MODULE, + }, + .probe = omap_abe_probe, + .remove = __devexit_p(omap_abe_remove), +}; + +static int __init omap_abe_init(void) +{ + return platform_driver_register(&omap_abe_driver); +} +module_init(omap_abe_init); + +static void __exit omap_abe_exit(void) +{ + platform_driver_unregister(&omap_abe_driver); +} +module_exit(omap_abe_exit); + +MODULE_AUTHOR("Liam Girdwood <lrg@ti.com>"); +MODULE_DESCRIPTION("OMAP ABE SoC Interface"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/omap/omap-abe.h b/sound/soc/omap/omap-abe.h new file mode 100644 index 0000000..91c5f1d --- /dev/null +++ b/sound/soc/omap/omap-abe.h @@ -0,0 +1,68 @@ +/* + * omap-abe.h + * + * Copyright (C) 2010 Texas Instruments + * + * Contact: Liam Girdwood <lrg@ti.com> + * + * 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 __OMAP_ABE_H__ +#define __OMAP_ABE_H__ + +#define ABE_FRONTEND_DAI_MEDIA 0 +#define ABE_FRONTEND_DAI_MEDIA_CAPTURE 1 +#define ABE_FRONTEND_DAI_VOICE 2 +#define ABE_FRONTEND_DAI_TONES 3 +#define ABE_FRONTEND_DAI_VIBRA 4 +#define ABE_FRONTEND_DAI_MODEM 5 +#define ABE_FRONTEND_DAI_LP_MEDIA 6 +#define ABE_FRONTEND_DAI_NUM 7 + +/* This must currently match the BE order in DSP */ +#define OMAP_ABE_DAI_PDM_UL 0 +#define OMAP_ABE_DAI_PDM_DL1 1 +#define OMAP_ABE_DAI_PDM_DL2 2 +#define OMAP_ABE_DAI_PDM_VIB 3 +#define OMAP_ABE_DAI_BT_VX 4 +#define OMAP_ABE_DAI_MM_FM 5 +#define OMAP_ABE_DAI_MODEM 6 +#define OMAP_ABE_DAI_DMIC0 7 +#define OMAP_ABE_DAI_DMIC1 8 +#define OMAP_ABE_DAI_DMIC2 9 +#define OMAP_ABE_DAI_NUM 10 + +#define OMAP_ABE_BE_PDM_DL1 "PDM-DL1" +#define OMAP_ABE_BE_PDM_UL1 "PDM-UL1" +#define OMAP_ABE_BE_PDM_DL2 "PDM-DL2" +#define OMAP_ABE_BE_PDM_VIB "PDM-VIB" +#define OMAP_ABE_BE_BT_VX_UL "BT-VX-UL" +#define OMAP_ABE_BE_BT_VX_DL "BT-VX-DL" +#define OMAP_ABE_BE_MM_EXT0 "FM-EXT" +#define OMAP_ABE_BE_MM_EXT1 "MODEM-EXT" +#define OMAP_ABE_BE_DMIC0 "DMIC0" +#define OMAP_ABE_BE_DMIC1 "DMIC1" +#define OMAP_ABE_BE_DMIC2 "DMIC2" + +#define OMAP_ABE_DL1_NO_PDM 0 +#define OMAP_ABE_DL1_HEADSET_LP 1 +#define OMAP_ABE_DL1_HEADSET_HP 2 +#define OMAP_ABE_DL1_EARPIECE 3 + +int omap_abe_set_dl1_output(int output); + +#endif /* End of __OMAP_MCPDM_H__ */ diff --git a/sound/soc/omap/omap-hdmi.c b/sound/soc/omap/omap-hdmi.c new file mode 100644 index 0000000..69dd059 --- /dev/null +++ b/sound/soc/omap/omap-hdmi.c @@ -0,0 +1,158 @@ +/* + * omap-hdmi.c + * + * OMAP ALSA SoC DAI driver for HDMI audio on OMAP4 processors. + * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/ + * Authors: Jorge Candelaria <jorge.candelaria@ti.com> + * Ricardo Neri <ricardo.neri@ti.com> + * + * 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/init.h> +#include <linux/module.h> +#include <linux/device.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/initval.h> +#include <sound/soc.h> + +#include <plat/dma.h> +#include "omap-pcm.h" +#include "omap-hdmi.h" + +#define DRV_NAME "hdmi-audio-dai" + +static struct omap_pcm_dma_data omap_hdmi_dai_dma_params = { + .name = "HDMI playback", + .sync_mode = OMAP_DMA_SYNC_PACKET, +}; + +static int omap_hdmi_dai_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + int err; + /* + * Make sure that the period bytes are multiple of the DMA packet size. + * Largest packet size we use is 32 32-bit words = 128 bytes + */ + err = snd_pcm_hw_constraint_step(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 128); + if (err < 0) + return err; + + return 0; +} + +static int omap_hdmi_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + int err = 0; + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + omap_hdmi_dai_dma_params.packet_size = 16; + break; + case SNDRV_PCM_FORMAT_S24_LE: + omap_hdmi_dai_dma_params.packet_size = 32; + break; + default: + err = -EINVAL; + } + + omap_hdmi_dai_dma_params.data_type = OMAP_DMA_DATA_TYPE_S32; + + snd_soc_dai_set_dma_data(dai, substream, + &omap_hdmi_dai_dma_params); + + return err; +} + +static struct snd_soc_dai_ops omap_hdmi_dai_ops = { + .startup = omap_hdmi_dai_startup, + .hw_params = omap_hdmi_dai_hw_params, +}; + +static struct snd_soc_dai_driver omap_hdmi_dai = { + .playback = { + .channels_min = 2, + .channels_max = 8, + .rates = OMAP_HDMI_RATES, + .formats = OMAP_HDMI_FORMATS, + }, + .ops = &omap_hdmi_dai_ops, +}; + +static __devinit int omap_hdmi_probe(struct platform_device *pdev) +{ + int ret; + struct resource *hdmi_rsrc; + + hdmi_rsrc = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!hdmi_rsrc) { + dev_err(&pdev->dev, "Cannot obtain IORESOURCE_MEM HDMI\n"); + return -EINVAL; + } + + omap_hdmi_dai_dma_params.port_addr = hdmi_rsrc->start + + OMAP_HDMI_AUDIO_DMA_PORT; + + hdmi_rsrc = platform_get_resource(pdev, IORESOURCE_DMA, 0); + if (!hdmi_rsrc) { + dev_err(&pdev->dev, "Cannot obtain IORESOURCE_DMA HDMI\n"); + return -EINVAL; + } + + omap_hdmi_dai_dma_params.dma_req = hdmi_rsrc->start; + + ret = snd_soc_register_dai(&pdev->dev, &omap_hdmi_dai); + return ret; +} + +static int __devexit omap_hdmi_remove(struct platform_device *pdev) +{ + snd_soc_unregister_dai(&pdev->dev); + return 0; +} + +static struct platform_driver hdmi_dai_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, + .probe = omap_hdmi_probe, + .remove = __devexit_p(omap_hdmi_remove), +}; + +static int __init hdmi_dai_init(void) +{ + return platform_driver_register(&hdmi_dai_driver); +} +module_init(hdmi_dai_init); + +static void __exit hdmi_dai_exit(void) +{ + platform_driver_unregister(&hdmi_dai_driver); +} +module_exit(hdmi_dai_exit); + +MODULE_AUTHOR("Jorge Candelaria <jorge.candelaria@ti.com>"); +MODULE_AUTHOR("Ricardo Neri <ricardo.neri@ti.com>"); +MODULE_DESCRIPTION("OMAP HDMI SoC Interface"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" DRV_NAME); diff --git a/sound/soc/omap/omap-hdmi.h b/sound/soc/omap/omap-hdmi.h new file mode 100644 index 0000000..34c298d --- /dev/null +++ b/sound/soc/omap/omap-hdmi.h @@ -0,0 +1,36 @@ +/* + * omap-hdmi.h + * + * Definitions for OMAP ALSA SoC DAI driver for HDMI audio on OMAP4 processors. + * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/ + * Authors: Jorge Candelaria <jorge.candelaria@ti.com> + * Ricardo Neri <ricardo.neri@ti.com> + * + * 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 __OMAP_HDMI_H__ +#define __OMAP_HDMI_H__ + +#define OMAP_HDMI_AUDIO_DMA_PORT 0x8c + +#define OMAP_HDMI_RATES (SNDRV_PCM_RATE_32000 | \ + SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) + +#define OMAP_HDMI_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE) + +#endif diff --git a/sound/soc/omap/omap-mcasp.c b/sound/soc/omap/omap-mcasp.c new file mode 100644 index 0000000..e0a6e24 --- /dev/null +++ b/sound/soc/omap/omap-mcasp.c @@ -0,0 +1,722 @@ +/* + * ALSA SoC McASP Audio Layer for TI OMAP processor + * + * Multi-channel Audio Serial Port Driver + * + * Author: Jon Hunter <jon-hunter@ti.com>, + * Dan Milea <dan.milea@ti.com>, + * + * Based upon McASP driver written for TI DaVinci + * + * Copyright: (C) 2011 Texas Instruments + * + * 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. + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/device.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/interrupt.h> +#include <linux/clk.h> +#include <linux/pm_runtime.h> + +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/initval.h> +#include <sound/soc.h> + +#include <plat/omap_hwmod.h> +#include <plat/clock.h> +#include <plat/dma.h> +#include <plat/dma-44xx.h> + +#include "omap-pcm.h" +#include "omap-mcasp.h" + +/* + * McASP register definitions + */ +#define OMAP_MCASP_PID_REG 0x00 +#define OMAP_MCASP_SYSCONFIG_REG 0x04 + +#define OMAP_MCASP_PFUNC_REG 0x10 +#define OMAP_MCASP_PDIR_REG 0x14 +#define OMAP_MCASP_PDOUT_REG 0x18 +#define OMAP_MCASP_PDIN_REG 0x1c +#define OMAP_MCASP_PDSET_REG 0x1c +#define OMAP_MCASP_PDCLR_REG 0x20 + +#define OMAP_MCASP_GBLCTL_REG 0x44 +#define OMAP_MCASP_AMUTE_REG 0x48 + +#define OMAP_MCASP_TXDITCTL_REG 0x50 + +#define OMAP_MCASP_TXMASK_REG 0xa4 +#define OMAP_MCASP_TXFMT_REG 0xa8 +#define OMAP_MCASP_TXFMCTL_REG 0xac + +#define OMAP_MCASP_ACLKXCTL_REG 0xb0 +#define OMAP_MCASP_AHCLKXCTL_REG 0xb4 +#define OMAP_MCASP_TXTDM_REG 0xb8 +#define OMAP_MCASP_EVTCTLX_REG 0xbc + +#define OMAP_MCASP_TXSTAT_REG 0xc0 +#define OMAP_MCASP_TXSTAT_MASK 0x1ff + +#define OMAP_MCASP_TXTDMSLOT_REG 0xc4 +#define OMAP_MCASP_TXCLKCHK_REG 0xc8 +#define OMAP_MCASP_TXEVTCTL_REG 0xcc + +/* Left(even TDM Slot) Channel Status Register File */ +#define OMAP_MCASP_DITCSRA_REG 0x100 +/* Right(odd TDM slot) Channel Status Register File */ +#define OMAP_MCASP_DITCSRB_REG 0x118 +/* Left(even TDM slot) User Data Register File */ +#define OMAP_MCASP_DITUDRA_REG 0x130 +/* Right(odd TDM Slot) User Data Register File */ +#define OMAP_MCASP_DITUDRB_REG 0x148 + +/* Serializer n Control Register */ +#define OMAP_MCASP_XRSRCTL0_REG 0x180 + +/* Transmit Buffer for Serializer */ +#define OMAP_MCASP_TXBUF0_REG 0x200 + +/* + * OMAP_MCASP_PFUNC_REG - Pin Function / GPIO Enable Register Bits + */ +#define AXR0 BIT(0) +#define PFUNC_AMUTE BIT(25) +#define ACLKX BIT(26) +#define AHCLKX BIT(27) +#define AFSX BIT(28) + +/* + * OMAP_MCASP_PDIR_REG - Pin Direction Register Bits + */ +#define AXR0 BIT(0) +#define PDIR_AMUTE BIT(25) +#define ACLKX BIT(26) +#define AHCLKX BIT(27) +#define AFSX BIT(28) + +/* + * OMAP_MCASP_TXDITCTL_REG - Transmit DIT Control Register Bits + */ +#define DITEN BIT(0) /* Transmit DIT mode enable/disable */ +#define VA BIT(2) +#define VB BIT(3) + +/* + * OMAP_MCASP_TXFMT_REG - Transmit Bitstream Format Register Bits + */ +#define TXROT(val) (val) +#define TXROT_MASK TXROT(0x7) +#define TXSEL BIT(3) +#define TXSSZ(val) (val<<4) +#define TXSSZ_MASK TXSSZ(0xf<<4) +#define TXPAD(val) (val<<13) +#define TXORD BIT(15) +#define FSXDLY(val) (val<<16) + +#define ROTATE_24 0x6 +#define SLOTSIZE_32 0xf + +/* + * OMAP_MCASP_TXFMCTL_REG - Transmit Frame Control Register Bits + */ +#define FSXPOL BIT(0) +#define AFSXE BIT(1) +#define FSXDUR BIT(4) +#define FSXMOD(val) (val<<7) + +/* + * OMAP_MCASP_ACLKXCTL_REG - Transmit Clock Control Register Bits + */ +#define ACLKXDIV(val) (val) +#define ACLKXE BIT(5) +#define TX_ASYNC BIT(6) + +/* + * OMAP_MCASP_AHCLKXCTL_REG - High Frequency Transmit Clock Control + * Register Bits + */ +#define AHCLKXDIV(val) (val) +#define AHCLKXE BIT(15) + +/* + * OMAP_MCASP_EVTCTLX_REG - Transmitter Interrupt Control Register bits + */ +#define EVTCTLX_XUNDRN BIT(0) + +/* + * OMAP_MCASP_TXSTAT_REG - Transmit Status Register Bits + */ +#define TXSTAT_XUNDRN (0x1 << 0) +#define TXSTAT_XSYNCERR (0x1 << 1) +#define TXSTAT_XCKFAIL (0x1 << 2) +#define TXSTAT_XDMSLOT (0x1 << 3) +#define TXSTAT_XLAST (0x1 << 4) +#define TXSTAT_XDATA (0x1 << 5) +#define TXSTAT_XSTAFRM (0x1 << 6) +#define TXSTAT_XDMAERR (0x1 << 7) +#define TXSTAT_XERR (0x1 << 8) + +/* + * OMAP_MCASP_XRSRCTL_BASE_REG - Serializer Control Register Bits + */ +#define MODE(val) (val) +#define TXSTATE BIT(4) + +/* + * OMAP_MCASP_TXTDMSLOT_REG - Transmit TDM Slot Register configuration + */ +#define TXTDMS(n) (1<<n) + +/* + * OMAP_MCASP_GBLCTL_REG - Global Control Register Bits + */ +#define TXCLKRST BIT(8) /* Transmitter Clock Divider Reset */ +#define TXHCLKRST BIT(9) /* Transmitter High Frequency Clock Divider*/ +#define TXSERCLR BIT(10) /* Transmit Serializer Clear */ +#define TXSMRST BIT(11) /* Transmitter State Machine Reset */ +#define TXFSRST BIT(12) /* Frame Sync Generator Reset */ + +/* + * OMAP_MCASP_AMUTE_REG - Mute Control Register Bits + */ +#define MUTENA(val) (val) +#define MUTEINPOL BIT(2) +#define MUTEINENA BIT(3) +#define MUTEIN BIT(4) +#define MUTEX BIT(6) +#define MUTEFSX BIT(8) +#define MUTEBADCLKX BIT(10) +#define MUTETXDMAERR BIT(12) + +/* + * OMAP_MCASP_TXEVTCTL_REG - Transmitter DMA Event Control Register bits + */ +#define TXDATADMADIS BIT(0) + +#define MCASP_ALLOWED_PPM 100 + +/* + * OMAP_MCASP_DITCSRA_REG/OMAP_MCASP_DITCSRB_REG + */ +#define OMAP_MCASP_DITCSR_44100HZ (0x0 << 24) +#define OMAP_MCASP_DITCSR_48000HZ (0x2 << 24) +#define OMAP_MCASP_DITCSR_32000HZ (0x3 << 24) +#define OMAP_MCASP_DITCSR_22050HZ (0x4 << 24) +#define OMAP_MCASP_DITCSR_24000HZ (0x6 << 24) +#define OMAP_MCASP_DITCSR_88200HZ (0x8 << 24) +#define OMAP_MCASP_DITCSR_96000HZ (0xA << 24) +#define OMAP_MCASP_DITCSR_176400HZ (0xC << 24) +#define OMAP_MCASP_DITCSR_192000HZ (0xE << 24) + +/* + * Stream DMA parameters + */ +static struct omap_pcm_dma_data omap_mcasp_dai_dma_params[] = { + { + .name = "Audio playback", + .dma_req = OMAP44XX_DMA_MCASP1_AXEVT, + .data_type = OMAP_DMA_DATA_TYPE_S16, + .sync_mode = OMAP_DMA_SYNC_ELEMENT, + .port_addr = OMAP44XX_MCASP_DAT_BASE + OMAP_MCASP_TXBUF0_REG, + }, +}; + +static inline void mcasp_set_bits(void __iomem *reg, u32 val) +{ + __raw_writel(__raw_readl(reg) | val, reg); +} + +static inline void mcasp_clr_bits(void __iomem *reg, u32 val) +{ + __raw_writel((__raw_readl(reg) & ~(val)), reg); +} + +static inline void mcasp_mod_bits(void __iomem *reg, u32 val, u32 mask) +{ + __raw_writel((__raw_readl(reg) & ~mask) | val, reg); +} + +static inline void mcasp_set_reg(void __iomem *reg, u32 val) +{ + __raw_writel(val, reg); +} + +static inline u32 mcasp_get_reg(void __iomem *reg) +{ + return (unsigned int)__raw_readl(reg); +} + +static inline void mcasp_set_ctl_reg(void __iomem *regs, u32 val) +{ + int i = 0; + + mcasp_set_bits(regs, val); + + /* programming GBLCTL needs to read back from GBLCTL and verfiy */ + /* loop count is to avoid the lock-up */ + for (i = 0; i < 1000; i++) { + if ((mcasp_get_reg(regs) & val) == val) + break; + } + + if (i == 1000 && ((mcasp_get_reg(regs) & val) != val)) + printk(KERN_ERR "GBLCTL write error\n"); +} + +static int mcasp_compute_clock_dividers(long fclk_rate, int tgt_sample_rate, + int *out_div_lo, int *out_div_hi) +{ + /* Given a particular functional clock rate and a target audio sample + * rate, determine the proper values for the ACLKXCTL and AHCLKXCTL, the + * dividers which produce the high frequency transmit master clock and + * the transmit clock. + */ + long divisor; + unsigned long ppm; + int sample_rate, i; + BUG_ON(!out_div_lo); + BUG_ON(!out_div_hi); + + /* A single S/PDIF frame requires 128 clocks */ + divisor = DIV_ROUND_CLOSEST(fclk_rate, tgt_sample_rate << 7); + if (!divisor) + return -EINVAL; + + sample_rate = (fclk_rate >> 7) / divisor; + + /* ppm calculation in two steps to avoid overflow */ + ppm = abs(tgt_sample_rate - sample_rate); + ppm = (1000000 * ppm) / tgt_sample_rate; + + if (ppm > MCASP_ALLOWED_PPM) + return -EINVAL; + + /* At this point, divisor holds the product of the two divider values we + * need to use for ACLKXCTL and AHCLKXCTL. ACLKXCTL holds a 5 bit + * divider [1, 32], while AHCLKXCTL holds a 12 bit divider [1, 4096]. + * We need to make sure that we can factor divisor into two integers + * which will fit into these divider registers. Find the largest 5-bit + * + 1 value which divides divisor and use that as our smaller divider. + * After removing this factor from divisor, if the result is <= 4096, + * then we have succeeded and will be able to produce the target sample + * rate. + */ + for (i = 32; (i > 1) && (divisor % i); --i) + ; /* no body */ + + /* Make sure to subtract one, registers hold the value of the divider + * minus one (IOW, to divide by 5, the register gets programmed with the + * value 4. */ + *out_div_lo = i - 1; + *out_div_hi = (divisor / i) - 1; + + return (*out_div_hi <= 4096) ? 0 : -EINVAL; +} + +static int omap_mcasp_start(struct omap_mcasp *mcasp) +{ + int i; + mcasp_set_ctl_reg(mcasp->base + OMAP_MCASP_GBLCTL_REG, TXHCLKRST); + mcasp_set_ctl_reg(mcasp->base + OMAP_MCASP_GBLCTL_REG, TXCLKRST); + mcasp_set_ctl_reg(mcasp->base + OMAP_MCASP_GBLCTL_REG, TXSERCLR); + + /* Wait until the DMA has loaded the first sample into TXBUF before we + * let the TX state machine and frame sync generator out of reset. */ + i = 0; + while (1) { + u32 reg = mcasp_get_reg(mcasp->base + OMAP_MCASP_TXSTAT_REG); + if (!(reg & TXSTAT_XDATA)) + break; + + if (++i > 1000) { + printk(KERN_ERR "Timeout waiting for DMA to load first" + " sample of audio.\n"); + return -ETIMEDOUT; + } + + udelay(1); + } + + mcasp_set_ctl_reg(mcasp->base + OMAP_MCASP_GBLCTL_REG, TXSMRST); + mcasp_set_ctl_reg(mcasp->base + OMAP_MCASP_GBLCTL_REG, TXFSRST); + mcasp_clr_bits(mcasp->base + OMAP_MCASP_TXEVTCTL_REG, TXDATADMADIS); + + /* enable IRQ sources */ + mcasp_set_bits(mcasp->base + OMAP_MCASP_EVTCTLX_REG, EVTCTLX_XUNDRN); + + return 0; +} + +static void omap_mcasp_stop(struct omap_mcasp *mcasp) +{ + /* disable IRQ sources */ + mcasp_set_reg(mcasp->base + OMAP_MCASP_EVTCTLX_REG, 0); + + mcasp_set_reg(mcasp->base + OMAP_MCASP_GBLCTL_REG, 0); + mcasp_set_reg(mcasp->base + OMAP_MCASP_TXSTAT_REG, + OMAP_MCASP_TXSTAT_MASK); +} + +/* S/PDIF */ +static int omap_mcasp_setup(struct omap_mcasp *mcasp, unsigned int rate) +{ + u32 aclkxdiv, ahclkxdiv, ditcsr; + int res; + + /* Set TX frame synch : DIT Mode, 1 bit width, internal, rising edge */ + mcasp_set_reg(mcasp->base + OMAP_MCASP_TXFMCTL_REG, + AFSXE | FSXMOD(0x180)); + + /* Set the TX clock controls : div = 1 and internal */ + mcasp_set_reg(mcasp->base + OMAP_MCASP_ACLKXCTL_REG, + ACLKXE | TX_ASYNC); + + /* Set the HS TX clock controls : div = 1 and internal */ + mcasp_set_reg(mcasp->base + OMAP_MCASP_AHCLKXCTL_REG, AHCLKXE); + + /* The SPDIF bit clock is derived from the McASP functional clock. + * The McASP has two programmable clock dividers (aclkxdiv and + * ahclkxdiv) that are configured via the registers MCASP_ACLKXCTL + * and MCASP_AHCLKXCTL. For SPDIF the bit clock frequency should be + * 128 * sample rate freq. The dividers are defined as part of + * platform data as they are dependent upon the functional clock + * setting. Lookup the appropriate dividers for the sampling + * frequency that we are playing. + */ + res = mcasp_compute_clock_dividers(clk_get_rate(mcasp->fclk), + rate, + &aclkxdiv, + &ahclkxdiv); + if (res) { + dev_err(mcasp->dev, + "%s: No valid McASP config for sampling rate (%d)!\n", + __func__, rate); + return res; + } + + switch (rate) { + case 22050: + ditcsr = OMAP_MCASP_DITCSR_22050HZ; + break; + case 24000: + ditcsr = OMAP_MCASP_DITCSR_24000HZ; + break; + case 32000: + ditcsr = OMAP_MCASP_DITCSR_32000HZ; + break; + case 44100: + ditcsr = OMAP_MCASP_DITCSR_44100HZ; + break; + case 48000: + ditcsr = OMAP_MCASP_DITCSR_48000HZ; + break; + case 88200: + ditcsr = OMAP_MCASP_DITCSR_88200HZ; + break; + case 96000: + ditcsr = OMAP_MCASP_DITCSR_96000HZ; + break; + case 176400: + ditcsr = OMAP_MCASP_DITCSR_176400HZ; + break; + case 192000: + ditcsr = OMAP_MCASP_DITCSR_192000HZ; + break; + default: + dev_err(mcasp->dev, "%s: Invalid sampling rate: %d\n", + __func__, rate); + return -EINVAL; + } + mcasp_set_reg(mcasp->base + OMAP_MCASP_DITCSRA_REG, ditcsr); + mcasp_set_reg(mcasp->base + OMAP_MCASP_DITCSRB_REG, ditcsr); + mcasp_set_bits(mcasp->base + OMAP_MCASP_AHCLKXCTL_REG, + AHCLKXDIV(ahclkxdiv)); + mcasp_set_bits(mcasp->base + OMAP_MCASP_ACLKXCTL_REG, + AHCLKXDIV(aclkxdiv)); + + /* Configure McASP formatter */ + mcasp_mod_bits(mcasp->base + OMAP_MCASP_TXFMT_REG, + TXSSZ(SLOTSIZE_32), TXSSZ_MASK); + mcasp_mod_bits(mcasp->base + OMAP_MCASP_TXFMT_REG, TXROT(ROTATE_24), + TXROT_MASK); + mcasp_set_reg(mcasp->base + OMAP_MCASP_TXMASK_REG, 0xFFFF); + + /* Set the TX tdm : for all the slots */ + mcasp_set_reg(mcasp->base + OMAP_MCASP_TXTDM_REG, 0xFFFFFFFF); + + /* configure the serializer for transmit mode operation */ + mcasp_set_bits(mcasp->base + OMAP_MCASP_XRSRCTL0_REG, MODE(1)); + + /* All PINS as McASP */ + mcasp_set_reg(mcasp->base + OMAP_MCASP_PFUNC_REG, 0); + + mcasp_set_bits(mcasp->base + OMAP_MCASP_PDIR_REG, AXR0); + + /* Enable the DIT */ + mcasp_set_bits(mcasp->base + OMAP_MCASP_TXDITCTL_REG, DITEN); + + mcasp_set_reg(mcasp->base + OMAP_MCASP_TXSTAT_REG, 0xFF); + + return 0; +} + +static irqreturn_t omap_mcasp_irq_handler(int irq, void *data) +{ + struct omap_mcasp *mcasp = data; + u32 txstat; + + txstat = mcasp_get_reg(mcasp->base + OMAP_MCASP_TXSTAT_REG); + if (txstat & TXSTAT_XUNDRN) { + dev_err(mcasp->dev, "%s: Underrun (0x%08x)\n", __func__, + txstat); + + /* Try to recover from this state */ + spin_lock(&mcasp->lock); + if (likely(mcasp->stream_rate)) { + dev_err(mcasp->dev, "%s: Trying to recover\n", + __func__); + omap_mcasp_stop(mcasp); + omap_mcasp_setup(mcasp, mcasp->stream_rate); + omap_mcasp_start(mcasp); + } + spin_unlock(&mcasp->lock); + } + + mcasp_set_reg(mcasp->base + OMAP_MCASP_TXSTAT_REG, txstat); + + return IRQ_HANDLED; +} + +static int omap_mcasp_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct omap_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); + + /* HACK: Only allow C2 state */ + pm_qos_add_request(mcasp->pm_qos, PM_QOS_CPU_DMA_LATENCY, 1150); + + pm_runtime_get_sync(mcasp->dev); + + return 0; +} + +static void omap_mcasp_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct omap_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); + + pm_runtime_put_sync(mcasp->dev); + + /* HACK: remove qos */ + pm_qos_remove_request(mcasp->pm_qos); +} + +static int omap_mcasp_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct omap_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); + int stream = substream->stream; + + omap_mcasp_stop(mcasp); + + if (omap_mcasp_setup(mcasp, params_rate(params)) < 0) + return -EPERM; + + snd_soc_dai_set_dma_data(dai, substream, + &omap_mcasp_dai_dma_params[stream]); + + return 0; +} + +static int omap_mcasp_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *cpu_dai) +{ + struct omap_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai); + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&mcasp->lock, flags); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + mcasp->stream_rate = substream->runtime->rate; + ret = omap_mcasp_start(mcasp); + break; + + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + mcasp->stream_rate = 0; + omap_mcasp_stop(mcasp); + break; + + default: + ret = -EINVAL; + } + + spin_unlock_irqrestore(&mcasp->lock, flags); + + return ret; +} + +static struct snd_soc_dai_ops omap_mcasp_dai_ops = { + .startup = omap_mcasp_startup, + .shutdown = omap_mcasp_shutdown, + .trigger = omap_mcasp_trigger, + .hw_params = omap_mcasp_hw_params, + +}; + +#define MCASP_RATES (SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | \ + SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \ + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | \ + SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000) + +static struct snd_soc_dai_driver omap_mcasp_dai[] = { + { + .name = "omap-mcasp-dai", + .playback = { + .channels_min = 1, + .channels_max = 384, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rates = MCASP_RATES, + }, + .ops = &omap_mcasp_dai_ops, + }, +}; + +static __devinit int omap_mcasp_probe(struct platform_device *pdev) +{ + struct omap_mcasp *mcasp; + struct resource *res; + long fclk_rate; + int ret = 0; + + mcasp = kzalloc(sizeof(struct omap_mcasp), GFP_KERNEL); + if (!mcasp) + return -ENOMEM; + + spin_lock_init(&mcasp->lock); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "no resource\n"); + ret = -ENODEV; + goto err_res; + } + + mcasp->base = ioremap(res->start, resource_size(res)); + if (!mcasp->base) { + ret = -ENOMEM; + goto err_res; + } + + mcasp->irq = platform_get_irq(pdev, 0); + if (mcasp->irq < 0) { + ret = mcasp->irq; + goto err_irq; + } + + ret = request_threaded_irq(mcasp->irq, NULL, omap_mcasp_irq_handler, + 0, "McASP", mcasp); + if (ret) { + dev_err(mcasp->dev, "IRQ request failed\n"); + goto err_irq; + } + + mcasp->fclk = clk_get(&pdev->dev, "mcasp_fck"); + if (!mcasp->fclk) { + ret = -ENODEV; + goto err_clk; + } + + pm_runtime_enable(&pdev->dev); + pm_runtime_get_sync(&pdev->dev); + + fclk_rate = clk_get_rate(mcasp->fclk); + + platform_set_drvdata(pdev, mcasp); + mcasp->dev = &pdev->dev; + + ret = snd_soc_register_dai(&pdev->dev, omap_mcasp_dai); + if (ret < 0) + goto err_dai; + + /* HACK: qos */ + mcasp->pm_qos = kzalloc(sizeof(struct pm_qos_request_list), GFP_KERNEL); + if (!mcasp->pm_qos) { + ret = -ENOMEM; + goto err_dai; + } + + pm_runtime_put_sync(&pdev->dev); + + return 0; + +err_dai: + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); +err_clk: + free_irq(mcasp->irq, (void *)mcasp); +err_irq: + iounmap(mcasp->base); +err_res: + kfree(mcasp); + return ret; +} + +static __devexit int omap_mcasp_remove(struct platform_device *pdev) +{ + struct omap_mcasp *mcasp = dev_get_drvdata(&pdev->dev); + + snd_soc_unregister_dai(&pdev->dev); + pm_runtime_disable(&pdev->dev); + clk_put(mcasp->fclk); + free_irq(mcasp->irq, (void *)mcasp); + iounmap(mcasp->base); + /* HACK: qos */ + kfree(mcasp->pm_qos); + kfree(mcasp); + + return 0; +} + +static struct platform_driver omap_mcasp_driver = { + .probe = omap_mcasp_probe, + .remove = omap_mcasp_remove, + .driver = { + .name = "omap-mcasp-dai", + .owner = THIS_MODULE, + }, +}; + +static int __init omap_mcasp_init(void) +{ + return platform_driver_register(&omap_mcasp_driver); +} +module_init(omap_mcasp_init); + +static void __exit omap_mcasp_exit(void) +{ + platform_driver_unregister(&omap_mcasp_driver); +} +module_exit(omap_mcasp_exit); + +MODULE_AUTHOR("Jon Hunter <jon-hunter@ti.com>"); +MODULE_DESCRIPTION("TI OMAP McASP SoC Interface"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/omap/omap-mcasp.h b/sound/soc/omap/omap-mcasp.h new file mode 100644 index 0000000..30ce3f0 --- /dev/null +++ b/sound/soc/omap/omap-mcasp.h @@ -0,0 +1,37 @@ +/* + * ALSA SoC McASP Audio Layer for TI OMAP processor + * + * MCASP related definitions + * + * Author: Jon Hunter <jon-hunter@ti.com>, + * Dan Milea <dan.milea@ti.com>, + * + * Based upon McASP driver written for TI DaVinci + * + * Copyright: (C) 2011 Texas Instruments + * + * 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. + */ + +#ifndef OMAP_MCASP_H +#define OMAP_MCASP_H + +#include <linux/io.h> +#include <plat/mcasp.h> + +#define OMAP44XX_MCASP_CFG_BASE 0x49028000 +#define OMAP44XX_MCASP_DAT_BASE 0x4902A000 + +struct omap_mcasp { + struct device *dev; + void __iomem *base; + spinlock_t lock; + struct clk *fclk; + int irq; + unsigned int stream_rate; + struct pm_qos_request_list *pm_qos; +}; + +#endif /* OMAP_MCASP_H */ diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 4b82290..8b6a510 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -258,7 +258,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, default: return -EINVAL; } - if (cpu_is_omap34xx()) { + if (cpu_is_omap34xx() || cpu_is_omap44xx()) { dma_data->set_threshold = omap_mcbsp_set_threshold; /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */ if (omap_mcbsp_get_dma_op_mode(bus_id) == diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c index bed09c2..601082e 100644 --- a/sound/soc/omap/omap-mcpdm.c +++ b/sound/soc/omap/omap-mcpdm.c @@ -25,7 +25,16 @@ #include <linux/init.h> #include <linux/module.h> -#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/wait.h> +#include <linux/interrupt.h> +#include <linux/err.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/slab.h> +#include <linux/pm_runtime.h> + #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> @@ -33,33 +42,54 @@ #include <sound/soc.h> #include <plat/dma.h> -#include <plat/mcbsp.h> -#include "mcpdm.h" +#include <plat/omap_hwmod.h> +#include <plat/mcpdm.h> +#include "../../../arch/arm/mach-omap2/cm1_44xx.h" +#include "omap-mcpdm.h" #include "omap-pcm.h" - -struct omap_mcpdm_data { - struct omap_mcpdm_link *links; +#if defined(CONFIG_SND_OMAP_SOC_ABE_DSP) ||\ + defined(CONFIG_SND_OMAP_SOC_ABE_DSP_MODULE) +#include "omap-abe-dsp.h" +#include "abe/abe_main.h" +#include "abe/port_mgr.h" +#endif + +#define MCPDM_LEGACY_DAI_DL1 0 +#define MCPDM_LEGACY_DAI_UL1 1 +#define MCPDM_ABE_DAI_DL1 2 +#define MCPDM_ABE_DAI_DL2 3 +#define MCPDM_ABE_DAI_VIB 4 +#define MCPDM_ABE_DAI_UL1 5 + +#define CLKCTRL_MODULEMODE_MASK 0x0003 +#define CLKCTRL_MODULEMODE_DISABLED 0x0000 +#define CLKCTRL_MODULEMODE_ENABLED 0x0002 + +struct omap_mcpdm { + struct device *dev; + unsigned long phys_base; + void __iomem *io_base; + int irq; + + struct mutex mutex; + struct omap_mcpdm_platform_data *pdata; + struct completion irq_completion; + struct delayed_work esd_work; + struct abe *abe; + struct omap_abe_port *dl_port; + struct omap_abe_port *ul_port; + + u32 *reg_cache; + + /* channel data */ + u32 dn_channels; + u32 up_channels; int active; -}; - -static struct omap_mcpdm_link omap_mcpdm_links[] = { - /* downlink */ - { - .irq_mask = MCPDM_DN_IRQ_EMPTY | MCPDM_DN_IRQ_FULL, - .threshold = 1, - .format = PDMOUTFORMAT_LJUST, - }, - /* uplink */ - { - .irq_mask = MCPDM_UP_IRQ_EMPTY | MCPDM_UP_IRQ_FULL, - .threshold = 1, - .format = PDMOUTFORMAT_LJUST, - }, -}; + int abe_mode; -static struct omap_mcpdm_data mcpdm_data = { - .links = omap_mcpdm_links, - .active = 0, + /* DC offset */ + unsigned long dl1_offset; + unsigned long dl2_offset; }; /* @@ -84,64 +114,362 @@ static struct omap_pcm_dma_data omap_mcpdm_dai_dma_params[] = { }, }; +static inline void omap_mcpdm_write(struct omap_mcpdm *mcpdm, + u16 reg, u32 val) +{ + __raw_writel(val, mcpdm->io_base + reg); +} + +static inline int omap_mcpdm_read(struct omap_mcpdm *mcpdm, u16 reg) +{ + return __raw_readl(mcpdm->io_base + reg); +} + +static inline void omap_mcpdm_write_cache(struct omap_mcpdm *mcpdm, + u16 reg, u32 val) +{ + mcpdm->reg_cache[reg / sizeof(u32)] = val; +} + +static inline int omap_mcpdm_read_cache(struct omap_mcpdm *mcpdm, u16 reg) +{ + return mcpdm->reg_cache[reg / sizeof(u32)]; +} + +#ifdef DEBUG +static void omap_mcpdm_reg_dump(struct omap_mcpdm *mcpdm) +{ + dev_dbg(mcpdm->dev, "***********************\n"); + dev_dbg(mcpdm->dev, "IRQSTATUS_RAW: 0x%04x\n", + omap_mcpdm_read(mcpdm, MCPDM_IRQSTATUS_RAW)); + dev_dbg(mcpdm->dev, "IRQSTATUS: 0x%04x\n", + omap_mcpdm_read(mcpdm, MCPDM_IRQSTATUS)); + dev_dbg(mcpdm->dev, "IRQENABLE_SET: 0x%04x\n", + omap_mcpdm_read(mcpdm, MCPDM_IRQENABLE_SET)); + dev_dbg(mcpdm->dev, "IRQENABLE_CLR: 0x%04x\n", + omap_mcpdm_read(mcpdm, MCPDM_IRQENABLE_CLR)); + dev_dbg(mcpdm->dev, "IRQWAKE_EN: 0x%04x\n", + omap_mcpdm_read(mcpdm, MCPDM_IRQWAKE_EN)); + dev_dbg(mcpdm->dev, "DMAENABLE_SET: 0x%04x\n", + omap_mcpdm_read(mcpdm, MCPDM_DMAENABLE_SET)); + dev_dbg(mcpdm->dev, "DMAENABLE_CLR: 0x%04x\n", + omap_mcpdm_read(mcpdm, MCPDM_DMAENABLE_CLR)); + dev_dbg(mcpdm->dev, "DMAWAKEEN: 0x%04x\n", + omap_mcpdm_read(mcpdm, MCPDM_DMAWAKEEN)); + dev_dbg(mcpdm->dev, "CTRL: 0x%04x\n", + omap_mcpdm_read(mcpdm, MCPDM_CTRL)); + dev_dbg(mcpdm->dev, "DN_DATA: 0x%04x\n", + omap_mcpdm_read(mcpdm, MCPDM_DN_DATA)); + dev_dbg(mcpdm->dev, "UP_DATA: 0x%04x\n", + omap_mcpdm_read(mcpdm, MCPDM_UP_DATA)); + dev_dbg(mcpdm->dev, "FIFO_CTRL_DN: 0x%04x\n", + omap_mcpdm_read(mcpdm, MCPDM_FIFO_CTRL_DN)); + dev_dbg(mcpdm->dev, "FIFO_CTRL_UP: 0x%04x\n", + omap_mcpdm_read(mcpdm, MCPDM_FIFO_CTRL_UP)); + dev_dbg(mcpdm->dev, "DN_OFFSET: 0x%04x\n", + omap_mcpdm_read(mcpdm, MCPDM_DN_OFFSET)); + dev_dbg(mcpdm->dev, "***********************\n"); +} +#else +static void omap_mcpdm_reg_dump(struct omap_mcpdm *mcpdm) {} +#endif + +/* + * Enables the transfer through the PDM interface to/from the Phoenix + * codec by enabling the corresponding UP and DN channels. + */ +static void omap_mcpdm_start(struct omap_mcpdm *mcpdm) +{ + u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_CTRL); + + ctrl |= (SW_UP_RST | SW_DN_RST); + omap_mcpdm_write(mcpdm, MCPDM_CTRL, ctrl); + ctrl |= (mcpdm->up_channels | mcpdm->dn_channels); + omap_mcpdm_write(mcpdm, MCPDM_CTRL, ctrl); + ctrl &= ~(SW_UP_RST | SW_DN_RST); + omap_mcpdm_write(mcpdm, MCPDM_CTRL, ctrl); +} + +/* + * Disables the transfer through the PDM interface to/from the Phoenix + * codec by disabling the corresponding UP and DN channels. + */ +static void omap_mcpdm_stop(struct omap_mcpdm *mcpdm) +{ + u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_CTRL); + + ctrl |= (SW_UP_RST | SW_DN_RST); + omap_mcpdm_write(mcpdm, MCPDM_CTRL, ctrl); + ctrl &= ~(mcpdm->up_channels | mcpdm->dn_channels); + omap_mcpdm_write(mcpdm, MCPDM_CTRL, ctrl); + ctrl &= ~(SW_UP_RST | SW_DN_RST); + omap_mcpdm_write(mcpdm, MCPDM_CTRL, ctrl); +} + +/* + * Is the physical McPDM interface active. + */ +static inline int omap_mcpdm_active(struct omap_mcpdm *mcpdm) +{ + return omap_mcpdm_read(mcpdm, MCPDM_CTRL) & (PDM_DN_MASK | PDM_UP_MASK); +} + +/* + * Configures McPDM uplink/downlink for audio recording/playback + * This function should be called before omap_mcpdm_start. + */ +static void omap_mcpdm_open(struct omap_mcpdm *mcpdm) +{ + /* Enable irq request generation */ + omap_mcpdm_write(mcpdm, MCPDM_IRQENABLE_SET, + MCPDM_UP_IRQ_EMPTY | MCPDM_UP_IRQ_FULL | + MCPDM_DN_IRQ_EMPTY | MCPDM_DN_IRQ_FULL); + + /* Configure uplink threshold */ + omap_mcpdm_write(mcpdm, MCPDM_FIFO_CTRL_UP, 2); + omap_mcpdm_write(mcpdm, MCPDM_FIFO_CTRL_DN, 2); + + /* Configure DMA controller */ + omap_mcpdm_write(mcpdm, MCPDM_DMAENABLE_SET, + DMA_UP_ENABLE | DMA_DN_ENABLE); +} + +/* + * Cleans McPDM uplink/downlink configuration. + * This function should be called when the stream is closed. + */ +static void omap_mcpdm_close(struct omap_mcpdm *mcpdm) +{ + /* Disable irq request generation */ + omap_mcpdm_write(mcpdm, MCPDM_IRQENABLE_CLR, + MCPDM_UP_IRQ_EMPTY | MCPDM_UP_IRQ_FULL | + MCPDM_DN_IRQ_EMPTY | MCPDM_DN_IRQ_FULL); + + /* Disable DMA request generation */ + omap_mcpdm_write(mcpdm, MCPDM_DMAENABLE_CLR, + DMA_UP_ENABLE | DMA_DN_ENABLE); +} + +static irqreturn_t omap_mcpdm_irq_handler(int irq, void *dev_id) +{ + struct omap_mcpdm *mcpdm = dev_id; + int irq_status; + + irq_status = omap_mcpdm_read(mcpdm, MCPDM_IRQSTATUS); + + /* Acknowledge irq event */ + omap_mcpdm_write(mcpdm, MCPDM_IRQSTATUS, irq_status); + + if (irq & MCPDM_DN_IRQ_FULL) + dev_err(mcpdm->dev, "DN FIFO error %x\n", irq_status); + + if (irq & MCPDM_DN_IRQ_EMPTY) + dev_err(mcpdm->dev, "DN FIFO error %x\n", irq_status); + + if (irq & MCPDM_DN_IRQ) + dev_dbg(mcpdm->dev, "DN write request\n"); + + if (irq & MCPDM_UP_IRQ_FULL) + dev_err(mcpdm->dev, "UP FIFO error %x\n", irq_status); + + if (irq & MCPDM_UP_IRQ_EMPTY) + dev_err(mcpdm->dev, "UP FIFO error %x\n", irq_status); + + if (irq & MCPDM_UP_IRQ) + dev_dbg(mcpdm->dev, "UP write request\n"); + + return IRQ_HANDLED; +} + +/* Enable/disable DC offset cancelation for the analog + * headset path (PDM channels 1 and 2). + */ +static void omap_mcpdm_set_offset(struct omap_mcpdm *mcpdm) +{ + int offset; + + if (mcpdm->dl1_offset > DN_OFST_MAX) { + dev_err(mcpdm->dev, "DC DL1 offset out of range\n"); + return; + } + + if (mcpdm->dl2_offset > DN_OFST_MAX) { + dev_err(mcpdm->dev, "DC DL2 offset out of range\n"); + return; + } + + offset = (mcpdm->dl1_offset << DN_OFST_RX1) | + (mcpdm->dl2_offset << DN_OFST_RX2); + + /* offset cancellation for channel 1 */ + if (mcpdm->dl1_offset) + offset |= DN_OFST_RX1_EN; + else + offset &= ~DN_OFST_RX1_EN; + + /* offset cancellation for channel 2 */ + if (mcpdm->dl2_offset) + offset |= DN_OFST_RX2_EN; + else + offset &= ~DN_OFST_RX2_EN; + + omap_mcpdm_write(mcpdm, MCPDM_DN_OFFSET, offset); +} + +static ssize_t mcpdm_dl1_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct omap_mcpdm *mcpdm = dev_get_drvdata(dev); + + return sprintf(buf, "%ld\n", mcpdm->dl1_offset); +} + +static ssize_t mcpdm_dl1_set(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct omap_mcpdm *mcpdm = dev_get_drvdata(dev); + int ret; + unsigned long value; + + ret = strict_strtol(buf, 10, &value); + if (ret) + return ret; + + if (value > DN_OFST_MAX) + return -EINVAL; + + mcpdm->dl1_offset = value; + return count; +} + +static ssize_t mcpdm_dl2_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct omap_mcpdm *mcpdm = dev_get_drvdata(dev); + + return sprintf(buf, "%ld\n", mcpdm->dl2_offset); +} + +static ssize_t mcpdm_dl2_set(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct omap_mcpdm *mcpdm = dev_get_drvdata(dev); + int ret; + unsigned long value; + + ret = strict_strtol(buf, 10, &value); + if (ret) + return ret; + + if (value > DN_OFST_MAX) + return -EINVAL; + + mcpdm->dl2_offset = value; + return count; +} + +static DEVICE_ATTR(dl1, 0644, mcpdm_dl1_show, mcpdm_dl1_set); +static DEVICE_ATTR(dl2, 0644, mcpdm_dl2_show, mcpdm_dl2_set); + static int omap_mcpdm_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { + struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); + u32 ctrl; + u32 val; int err = 0; - if (!dai->active) - err = omap_mcpdm_request(); + dev_dbg(dai->dev, "%s: active %d\n", __func__, dai->active); + + mutex_lock(&mcpdm->mutex); + + /* nothing to do if already active */ + if (mcpdm->active++) + goto out; + + if (dai->id >= MCPDM_ABE_DAI_DL1) + mcpdm->abe_mode = 1; + else + mcpdm->abe_mode = 0; + + pm_runtime_get_sync(mcpdm->dev); + + val = __raw_readl(OMAP4430_CM1_ABE_PDM_CLKCTRL); + if ((val & CLKCTRL_MODULEMODE_MASK) != CLKCTRL_MODULEMODE_ENABLED) { + WARN(1, "Clock not enabled: PDM_CLKCTRL=0x%x\n", val); + mcpdm->active--; + pm_runtime_put_sync(mcpdm->dev); + err = -ENODEV; + goto out; + } + /* Enable McPDM watch dog for ES above ES 1.0 to avoid saturation */ + if (omap_rev() != OMAP4430_REV_ES1_0) { + ctrl = omap_mcpdm_read(mcpdm, MCPDM_CTRL); + omap_mcpdm_write(mcpdm, MCPDM_CTRL, ctrl | WD_EN); + } + + omap_mcpdm_set_offset(mcpdm); + omap_mcpdm_open(mcpdm); + schedule_delayed_work(&mcpdm->esd_work, msecs_to_jiffies(250)); +out: + mutex_unlock(&mcpdm->mutex); return err; } static void omap_mcpdm_dai_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - if (!dai->active) - omap_mcpdm_free(); -} + struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); -static int omap_mcpdm_dai_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) -{ - struct omap_mcpdm_data *mcpdm_priv = snd_soc_dai_get_drvdata(dai); - int stream = substream->stream; - int err = 0; + dev_dbg(dai->dev, "%s: active %d\n", __func__, dai->active); - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - if (!mcpdm_priv->active++) - omap_mcpdm_start(stream); - break; + mutex_lock(&mcpdm->mutex); - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - if (!--mcpdm_priv->active) - omap_mcpdm_stop(stream); - break; - default: - err = -EINVAL; + if (--mcpdm->active) + goto out; + + if (mcpdm->abe_mode) { + if (omap_mcpdm_active(mcpdm)) { + omap_abe_port_disable(mcpdm->abe, mcpdm->dl_port); + omap_abe_port_disable(mcpdm->abe, mcpdm->ul_port); + udelay(250); + abe_remove_opp_req(mcpdm->dev); + omap_mcpdm_stop(mcpdm); + } + } else { + omap_mcpdm_stop(mcpdm); } - return err; + cancel_delayed_work_sync(&mcpdm->esd_work); + omap_mcpdm_close(mcpdm); + + pm_runtime_put_sync(mcpdm->dev); + +out: + mutex_unlock(&mcpdm->mutex); } static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { - struct omap_mcpdm_data *mcpdm_priv = snd_soc_dai_get_drvdata(dai); - struct omap_mcpdm_link *mcpdm_links = mcpdm_priv->links; + struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); int stream = substream->stream; - int channels, err, link_mask = 0; + int channels, link_mask = 0; snd_soc_dai_set_dma_data(dai, substream, &omap_mcpdm_dai_dma_params[stream]); + /* ABE DAIs have fixed channels */ + if (mcpdm->abe_mode) { + mcpdm->dn_channels = PDM_DN_MASK | PDM_CMD_MASK; + mcpdm->up_channels = PDM_UP1_EN | PDM_UP2_EN; + return 0; + } + channels = params_channels(params); switch (channels) { case 4: @@ -164,58 +492,224 @@ static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - if (stream == SNDRV_PCM_STREAM_PLAYBACK) { - mcpdm_links[stream].channels = link_mask << 3; - err = omap_mcpdm_playback_open(&mcpdm_links[stream]); - } else { - mcpdm_links[stream].channels = link_mask << 0; - err = omap_mcpdm_capture_open(&mcpdm_links[stream]); - } + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + /* Downlink channels */ + mcpdm->dn_channels = (link_mask << 3) & (PDM_DN_MASK | PDM_CMD_MASK); + else + /* Uplink channels */ + mcpdm->up_channels = link_mask & (PDM_UP_MASK | PDM_STATUS_MASK); - return err; + return 0; } -static int omap_mcpdm_dai_hw_free(struct snd_pcm_substream *substream, +static int omap_mcpdm_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct omap_mcpdm_data *mcpdm_priv = snd_soc_dai_get_drvdata(dai); - struct omap_mcpdm_link *mcpdm_links = mcpdm_priv->links; - int stream = substream->stream; - int err; + struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - err = omap_mcpdm_playback_close(&mcpdm_links[stream]); - else - err = omap_mcpdm_capture_close(&mcpdm_links[stream]); + mutex_lock(&mcpdm->mutex); - return err; + if (omap_mcpdm_active(mcpdm)) + goto out; + + if (mcpdm->abe_mode) { + /* Check if ABE McPDM is already started */ + if (omap_abe_port_is_enabled(mcpdm->abe, mcpdm->ul_port) || + omap_abe_port_is_enabled(mcpdm->abe, mcpdm->dl_port)) + goto out; + + /* PDM tasks require ABE OPP 50 */ + abe_add_opp_req(mcpdm->dev, ABE_OPP_50); + + /* start ATC before McPDM IP */ + omap_abe_port_enable(mcpdm->abe, mcpdm->dl_port); + omap_abe_port_enable(mcpdm->abe, mcpdm->ul_port); + + /* wait 250us for ABE tick */ + udelay(250); + } + + omap_mcpdm_start(mcpdm); + +out: + mutex_unlock(&mcpdm->mutex); + return 0; +} + +static int omap_mcpdm_dai_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) +{ + struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); + + dev_dbg(dai->dev, "cmd %d\n", cmd); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + break; + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + break; + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + break; + case SNDRV_PCM_TRIGGER_STOP: + break; + default: + break; + } + omap_mcpdm_reg_dump(mcpdm); + return 0; +} + +static void mcpdm_esd_work(struct work_struct *work) +{ + struct omap_mcpdm *mcpdm = container_of(work, struct omap_mcpdm, + esd_work.work); + + if (omap_mcpdm_read(mcpdm, MCPDM_STATUS)) { + if (mcpdm->abe_mode) { + omap_abe_port_disable(mcpdm->abe, mcpdm->dl_port); + omap_abe_port_disable(mcpdm->abe, mcpdm->ul_port); + udelay(250); + } + omap_mcpdm_stop(mcpdm); + + if (mcpdm->abe_mode) { + omap_abe_port_enable(mcpdm->abe, mcpdm->dl_port); + omap_abe_port_enable(mcpdm->abe, mcpdm->ul_port); + udelay(250); + } + omap_mcpdm_start(mcpdm); + } + schedule_delayed_work(&mcpdm->esd_work, msecs_to_jiffies(250)); } static struct snd_soc_dai_ops omap_mcpdm_dai_ops = { .startup = omap_mcpdm_dai_startup, .shutdown = omap_mcpdm_dai_shutdown, - .trigger = omap_mcpdm_dai_trigger, .hw_params = omap_mcpdm_dai_hw_params, - .hw_free = omap_mcpdm_dai_hw_free, + .prepare = omap_mcpdm_prepare, + .trigger = omap_mcpdm_dai_trigger, }; -#define OMAP_MCPDM_RATES (SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) -#define OMAP_MCPDM_FORMATS (SNDRV_PCM_FMTBIT_S32_LE) +#ifdef CONFIG_PM +static int omap_mcpdm_suspend(struct snd_soc_dai *dai) +{ + struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); + + /* save context only if we are streaming */ + if (!mcpdm->active) + return 0; + + omap_mcpdm_write_cache(mcpdm, MCPDM_DN_OFFSET, + omap_mcpdm_read(mcpdm, MCPDM_DN_OFFSET)); + omap_mcpdm_write_cache(mcpdm, MCPDM_IRQENABLE_SET, + omap_mcpdm_read(mcpdm, MCPDM_IRQENABLE_SET)); + omap_mcpdm_write_cache(mcpdm, MCPDM_DMAENABLE_SET, + omap_mcpdm_read(mcpdm, MCPDM_DMAENABLE_SET)); + omap_mcpdm_write_cache(mcpdm, MCPDM_FIFO_CTRL_DN, + omap_mcpdm_read(mcpdm, MCPDM_FIFO_CTRL_DN)); + omap_mcpdm_write_cache(mcpdm, MCPDM_FIFO_CTRL_UP, + omap_mcpdm_read(mcpdm, MCPDM_FIFO_CTRL_UP)); + omap_mcpdm_write_cache(mcpdm, MCPDM_CTRL, + omap_mcpdm_read(mcpdm, MCPDM_CTRL)); + + pm_runtime_put_sync(mcpdm->dev); + + return 0; +} + +static int omap_mcpdm_resume(struct snd_soc_dai *dai) +{ + struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); + struct omap_mcpdm_platform_data *pdata = mcpdm->pdata; + + /* restore context only if we were streaming */ + if (!mcpdm->active) + return 0; + + if (!pdata->was_context_lost(mcpdm->dev)) + return 0; + + pm_runtime_get_sync(mcpdm->dev); + + /* restore from reg cache */ + omap_mcpdm_write(mcpdm, MCPDM_DN_OFFSET, + omap_mcpdm_read_cache(mcpdm, MCPDM_DN_OFFSET)); + omap_mcpdm_write(mcpdm, MCPDM_IRQENABLE_SET, + omap_mcpdm_read_cache(mcpdm, MCPDM_IRQENABLE_SET)); + omap_mcpdm_write(mcpdm, MCPDM_DMAENABLE_SET, + omap_mcpdm_read_cache(mcpdm, MCPDM_DMAENABLE_SET)); + omap_mcpdm_write(mcpdm, MCPDM_FIFO_CTRL_DN, + omap_mcpdm_read_cache(mcpdm, MCPDM_FIFO_CTRL_DN)); + omap_mcpdm_write(mcpdm, MCPDM_FIFO_CTRL_UP, + omap_mcpdm_read_cache(mcpdm, MCPDM_FIFO_CTRL_UP)); + omap_mcpdm_write(mcpdm, MCPDM_CTRL, + omap_mcpdm_read_cache(mcpdm, MCPDM_CTRL)); -static int omap_mcpdm_dai_probe(struct snd_soc_dai *dai) + return 0; +} +#else +#define omap_mcpdm_suspend NULL +#define omap_mcpdm_resume NULL +#endif + +static int omap_mcpdm_probe(struct snd_soc_dai *dai) +{ + struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); + int ret; + + pm_runtime_enable(mcpdm->dev); + + /* Disable lines while request is ongoing */ + pm_runtime_get_sync(mcpdm->dev); + omap_mcpdm_write(mcpdm, MCPDM_CTRL, 0x00); + + ret = request_irq(mcpdm->irq, omap_mcpdm_irq_handler, + 0, "McPDM", (void *)mcpdm); + if (ret) + dev_err(mcpdm->dev, "Request for McPDM IRQ failed\n"); + + pm_runtime_put_sync(mcpdm->dev); + return ret; +} + +static int omap_mcpdm_remove(struct snd_soc_dai *dai) { - snd_soc_dai_set_drvdata(dai, &mcpdm_data); + struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); + + free_irq(mcpdm->irq, (void *)mcpdm); + pm_runtime_disable(mcpdm->dev); + return 0; } -static struct snd_soc_dai_driver omap_mcpdm_dai = { - .probe = omap_mcpdm_dai_probe, +#define OMAP_MCPDM_RATES (SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) +#define OMAP_MCPDM_FORMATS SNDRV_PCM_FMTBIT_S32_LE + +static struct snd_soc_dai_driver omap_mcpdm_dai[] = { +{ + .name = "mcpdm-dl", + .id = MCPDM_LEGACY_DAI_DL1, + .probe = omap_mcpdm_probe, + .remove = omap_mcpdm_remove, + .probe_order = SND_SOC_COMP_ORDER_LATE, + .remove_order = SND_SOC_COMP_ORDER_EARLY, + .suspend = omap_mcpdm_suspend, + .resume = omap_mcpdm_resume, .playback = { .channels_min = 1, .channels_max = 4, .rates = OMAP_MCPDM_RATES, .formats = OMAP_MCPDM_FORMATS, }, + .ops = &omap_mcpdm_dai_ops, +}, +{ + .name = "mcpdm-ul", + .id = MCPDM_LEGACY_DAI_UL1, + .probe_order = SND_SOC_COMP_ORDER_LATE, + .remove_order = SND_SOC_COMP_ORDER_EARLY, + .suspend = omap_mcpdm_suspend, + .resume = omap_mcpdm_resume, .capture = { .channels_min = 1, .channels_max = 2, @@ -223,31 +717,196 @@ static struct snd_soc_dai_driver omap_mcpdm_dai = { .formats = OMAP_MCPDM_FORMATS, }, .ops = &omap_mcpdm_dai_ops, -}; +}, +#if defined(CONFIG_SND_OMAP_SOC_ABE_DSP) ||\ + defined(CONFIG_SND_OMAP_SOC_ABE_DSP_MODULE) +{ + .name = "mcpdm-dl1", + .id = MCPDM_ABE_DAI_DL1, + .probe_order = SND_SOC_COMP_ORDER_LATE, + .remove_order = SND_SOC_COMP_ORDER_EARLY, + .suspend = omap_mcpdm_suspend, + .resume = omap_mcpdm_resume, + .playback = { + .channels_min = 1, + .channels_max = 2, + .rates = OMAP_MCPDM_RATES, + .formats = OMAP_MCPDM_FORMATS, + }, + .ops = &omap_mcpdm_dai_ops, +}, +{ + .name = "mcpdm-dl2", + .id = MCPDM_ABE_DAI_DL2, + .probe_order = SND_SOC_COMP_ORDER_LATE, + .remove_order = SND_SOC_COMP_ORDER_EARLY, + .suspend = omap_mcpdm_suspend, + .resume = omap_mcpdm_resume, + .playback = { + .channels_min = 1, + .channels_max = 2, + .rates = OMAP_MCPDM_RATES, + .formats = OMAP_MCPDM_FORMATS, + }, + .ops = &omap_mcpdm_dai_ops, +}, +{ + .name = "mcpdm-vib", + .id = MCPDM_ABE_DAI_VIB, + .probe_order = SND_SOC_COMP_ORDER_LATE, + .remove_order = SND_SOC_COMP_ORDER_EARLY, + .suspend = omap_mcpdm_suspend, + .resume = omap_mcpdm_resume, + .playback = { + .channels_min = 1, + .channels_max = 2, + .rates = OMAP_MCPDM_RATES, + .formats = OMAP_MCPDM_FORMATS, + }, + .ops = &omap_mcpdm_dai_ops, +}, +{ + .name = "mcpdm-ul1", + .id = MCPDM_ABE_DAI_UL1, + .probe_order = SND_SOC_COMP_ORDER_LATE, + .remove_order = SND_SOC_COMP_ORDER_EARLY, + .suspend = omap_mcpdm_suspend, + .resume = omap_mcpdm_resume, + .capture = { + .channels_min = 1, + .channels_max = 2, + .rates = OMAP_MCPDM_RATES, + .formats = OMAP_MCPDM_FORMATS, + }, + .ops = &omap_mcpdm_dai_ops, +}, +#endif + }; static __devinit int asoc_mcpdm_probe(struct platform_device *pdev) { - int ret; + struct omap_mcpdm_platform_data *pdata = pdev->dev.platform_data; + struct omap_mcpdm *mcpdm; + struct resource *res; + int ret = 0, err; - ret = omap_mcpdm_probe(pdev); - if (ret < 0) - return ret; - ret = snd_soc_register_dai(&pdev->dev, &omap_mcpdm_dai); + mcpdm = kzalloc(sizeof(struct omap_mcpdm), GFP_KERNEL); + if (!mcpdm) + return -ENOMEM; + + platform_set_drvdata(pdev, mcpdm); + + mutex_init(&mcpdm->mutex); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) { + dev_err(&pdev->dev, "no resource\n"); + goto err_res; + } + + mcpdm->io_base = ioremap(res->start, resource_size(res)); + if (!mcpdm->io_base) { + ret = -ENOMEM; + goto err_iomap; + } + + mcpdm->reg_cache = kzalloc(resource_size(res), GFP_KERNEL); + if (!mcpdm->reg_cache) { + ret = -ENOMEM; + goto err_cache; + } + + mcpdm->irq = platform_get_irq(pdev, 0); + if (mcpdm->irq < 0) { + ret = mcpdm->irq; + goto err_irq; + } + + mcpdm->dev = &pdev->dev; + mcpdm->pdata = pdata; + + /* DL1 and DL2 DC offset values will be different for each device */ + mcpdm->dl1_offset = DN_OFST_MAX >> 1; + mcpdm->dl2_offset = DN_OFST_MAX >> 1; + err = device_create_file(mcpdm->dev, &dev_attr_dl1); + if (err < 0) + dev_err(mcpdm->dev,"failed to DL1 DC offset sysfs: %d\n", err); + err = device_create_file(mcpdm->dev, &dev_attr_dl2); + if (err < 0) + dev_err(mcpdm->dev,"failed to DL2 DC offset sysfs: %d\n", err); + +#if defined(CONFIG_SND_OMAP_SOC_ABE_DSP) ||\ + defined(CONFIG_SND_OMAP_SOC_ABE_DSP_MODULE) + + mcpdm->abe = omap_abe_port_mgr_get(); + if (!mcpdm->abe) + goto err_irq; + + mcpdm->ul_port = omap_abe_port_open(mcpdm->abe, OMAP_ABE_BE_PORT_PDM_UL1); + if (!mcpdm->ul_port) + goto err_ul; + + mcpdm->dl_port = omap_abe_port_open(mcpdm->abe, OMAP_ABE_BE_PORT_PDM_DL1); + if (!mcpdm->dl_port) + goto err_dl; +#endif + + INIT_DELAYED_WORK(&mcpdm->esd_work, mcpdm_esd_work); + + ret = snd_soc_register_dais(&pdev->dev, omap_mcpdm_dai, + ARRAY_SIZE(omap_mcpdm_dai)); if (ret < 0) - omap_mcpdm_remove(pdev); + goto err_dai; + + return 0; + +err_dai: +#if defined(CONFIG_SND_OMAP_SOC_ABE_DSP) ||\ + defined(CONFIG_SND_OMAP_SOC_ABE_DSP_MODULE) + omap_abe_port_close(mcpdm->abe, mcpdm->dl_port); +err_dl: + omap_abe_port_close(mcpdm->abe, mcpdm->ul_port); +err_ul: + omap_abe_port_mgr_put(mcpdm->abe); +#endif +err_irq: + kfree(mcpdm->reg_cache); +err_cache: + iounmap(mcpdm->io_base); +err_iomap: + release_mem_region(res->start, resource_size(res)); +err_res: + kfree(mcpdm); return ret; } static int __devexit asoc_mcpdm_remove(struct platform_device *pdev) { - snd_soc_unregister_dai(&pdev->dev); - omap_mcpdm_remove(pdev); + struct omap_mcpdm *mcpdm = platform_get_drvdata(pdev); + struct resource *res; + + snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(omap_mcpdm_dai)); + + device_remove_file(&pdev->dev, &dev_attr_dl1); + device_remove_file(&pdev->dev, &dev_attr_dl2); + +#if defined(CONFIG_SND_OMAP_SOC_ABE_DSP) ||\ + defined(CONFIG_SND_OMAP_SOC_ABE_DSP_MODULE) + omap_abe_port_close(mcpdm->abe, mcpdm->dl_port); + omap_abe_port_close(mcpdm->abe, mcpdm->ul_port); + omap_abe_port_mgr_put(mcpdm->abe); +#endif + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + iounmap(mcpdm->io_base); + kfree(mcpdm->reg_cache); + kfree(mcpdm); return 0; } static struct platform_driver asoc_mcpdm_driver = { .driver = { - .name = "omap-mcpdm-dai", + .name = "omap-mcpdm", .owner = THIS_MODULE, }, diff --git a/sound/soc/omap/omap-mcpdm.h b/sound/soc/omap/omap-mcpdm.h new file mode 100644 index 0000000..3aa5011 --- /dev/null +++ b/sound/soc/omap/omap-mcpdm.h @@ -0,0 +1,120 @@ +/* + * omap-mcpdm.h + * + * Copyright (C) 2009 Texas Instruments + * + * Contact: Misael Lopez Cruz <x0052729@ti.com> + * + * 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 __OMAP_MCPDM_H__ +#define __OMAP_MCPDM_H__ + +#include <linux/platform_device.h> + +#define MCPDM_REVISION 0x00 +#define MCPDM_SYSCONFIG 0x10 +#define MCPDM_IRQSTATUS_RAW 0x24 +#define MCPDM_IRQSTATUS 0x28 +#define MCPDM_IRQENABLE_SET 0x2C +#define MCPDM_IRQENABLE_CLR 0x30 +#define MCPDM_IRQWAKE_EN 0x34 +#define MCPDM_DMAENABLE_SET 0x38 +#define MCPDM_DMAENABLE_CLR 0x3C +#define MCPDM_DMAWAKEEN 0x40 +#define MCPDM_CTRL 0x44 +#define MCPDM_DN_DATA 0x48 +#define MCPDM_UP_DATA 0x4C +#define MCPDM_FIFO_CTRL_DN 0x50 +#define MCPDM_FIFO_CTRL_UP 0x54 +#define MCPDM_DN_OFFSET 0x58 +#define MCPDM_STATUS 0x68 + +/* + * MCPDM_IRQ bit fields + * IRQSTATUS_RAW, IRQSTATUS, IRQENABLE_SET, IRQENABLE_CLR + */ + +#define MCPDM_DN_IRQ (1 << 0) +#define MCPDM_DN_IRQ_EMPTY (1 << 1) +#define MCPDM_DN_IRQ_ALMST_EMPTY (1 << 2) +#define MCPDM_DN_IRQ_FULL (1 << 3) + +#define MCPDM_UP_IRQ (1 << 8) +#define MCPDM_UP_IRQ_EMPTY (1 << 9) +#define MCPDM_UP_IRQ_ALMST_FULL (1 << 10) +#define MCPDM_UP_IRQ_FULL (1 << 11) + +#define MCPDM_DOWNLINK_IRQ_MASK 0x00F +#define MCPDM_UPLINK_IRQ_MASK 0xF00 + +/* + * MCPDM_DMAENABLE bit fields + */ + +#define DMA_DN_ENABLE 0x1 +#define DMA_UP_ENABLE 0x2 + +/* + * MCPDM_CTRL bit fields + */ + +#define PDM_UP1_EN 0x0001 +#define PDM_UP2_EN 0x0002 +#define PDM_UP3_EN 0x0004 +#define PDM_DN1_EN 0x0008 +#define PDM_DN2_EN 0x0010 +#define PDM_DN3_EN 0x0020 +#define PDM_DN4_EN 0x0040 +#define PDM_DN5_EN 0x0080 +#define PDMOUTFORMAT 0x0100 +#define CMD_INT 0x0200 +#define STATUS_INT 0x0400 +#define SW_UP_RST 0x0800 +#define SW_DN_RST 0x1000 +#define WD_EN 0x4000 +#define PDM_UP_MASK 0x007 +#define PDM_DN_MASK 0x0F8 +#define PDM_CMD_MASK 0x200 +#define PDM_STATUS_MASK 0x400 + + +#define PDMOUTFORMAT_LJUST (0 << 8) +#define PDMOUTFORMAT_RJUST (1 << 8) + +/* + * MCPDM_FIFO_CTRL bit fields + */ + +#define UP_THRES_MAX 0xF +#define DN_THRES_MAX 0xF + +/* + * MCPDM_DN_OFFSET bit fields + */ + +#define DN_OFST_RX1_EN 0x0001 +#define DN_OFST_RX2_EN 0x0100 + +#define DN_OFST_RX1 1 +#define DN_OFST_RX2 9 +#define DN_OFST_MAX 0x1F + +#define MCPDM_UPLINK 1 +#define MCPDM_DOWNLINK 2 + +#endif /* End of __OMAP_MCPDM_H__ */ diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c index e6a6b99..a2a464f 100644 --- a/sound/soc/omap/omap-pcm.c +++ b/sound/soc/omap/omap-pcm.c @@ -198,6 +198,14 @@ static int omap_pcm_prepare(struct snd_pcm_substream *substream) OMAP_DMA_LAST_IRQ | OMAP_DMA_BLOCK_IRQ); else if (!substream->runtime->no_period_wakeup) omap_enable_dma_irq(prtd->dma_ch, OMAP_DMA_FRAME_IRQ); + else { + /* + * No period wakeup: + * we need to disable BLOCK_IRQ, which is enabled by the omap + * dma core at request dma time. + */ + omap_disable_dma_irq(prtd->dma_ch, OMAP_DMA_BLOCK_IRQ); + } if (!(cpu_class_is_omap1())) { omap_set_dma_src_burst_mode(prtd->dma_ch, @@ -235,6 +243,11 @@ static int omap_pcm_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_PAUSE_PUSH: prtd->period_index = -1; omap_stop_dma(prtd->dma_ch); + /* Since we are using self linking, there is a + chance that the DMA as re-enabled the channel + just after disabling it */ + while (omap_get_dma_active_status(prtd->dma_ch)) + omap_stop_dma(prtd->dma_ch); break; default: ret = -EINVAL; @@ -280,6 +293,15 @@ static int omap_pcm_open(struct snd_pcm_substream *substream) SNDRV_PCM_HW_PARAM_PERIODS); if (ret < 0) goto out; + if (cpu_is_omap44xx()) { + /* ABE needs a step of 24 * 4 data bits, and HDMI 32 * 4 + * Ensure buffer size satisfies both constraints. + */ + ret = snd_pcm_hw_constraint_step(runtime, 0, + SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 384); + if (ret < 0) + goto out; + } prtd = kzalloc(sizeof(*prtd), GFP_KERNEL); if (prtd == NULL) { @@ -366,9 +388,10 @@ static void omap_pcm_free_dma_buffers(struct snd_pcm *pcm) } } -static int omap_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, - struct snd_pcm *pcm) +static int omap_pcm_new(struct snd_soc_pcm_runtime *rtd) { + struct snd_card *card = rtd->card->snd_card; + struct snd_pcm *pcm = rtd->pcm; int ret = 0; if (!card->dev->dma_mask) @@ -376,14 +399,14 @@ static int omap_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, if (!card->dev->coherent_dma_mask) card->dev->coherent_dma_mask = DMA_BIT_MASK(64); - if (dai->driver->playback.channels_min) { + if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) { ret = omap_pcm_preallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK); if (ret) goto out; } - if (dai->driver->capture.channels_min) { + if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { ret = omap_pcm_preallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_CAPTURE); if (ret) diff --git a/sound/soc/omap/omap4-hdmi-card.c b/sound/soc/omap/omap4-hdmi-card.c new file mode 100644 index 0000000..9024735 --- /dev/null +++ b/sound/soc/omap/omap4-hdmi-card.c @@ -0,0 +1,133 @@ +/* + * omap4-hdmi-card.c + * + * OMAP ALSA SoC machine driver for TI OMAP4 HDMI + * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ + * Author: Ricardo Neri <ricardo.neri@ti.com> + * + * 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/delay.h> +#include <sound/pcm.h> +#include <sound/soc.h> +#include <asm/mach-types.h> +#include <video/omapdss.h> + +#define DRV_NAME "omap4-hdmi-audio" + +static int omap4_hdmi_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + int i, count = 0; + struct omap_overlay_manager *mgr = NULL; + struct device *dev = substream->pcm->card->dev; + + /* Find DSS HDMI device */ + for (i = 0; i < omap_dss_get_num_overlay_managers(); i++) { + mgr = omap_dss_get_overlay_manager(i); + if (mgr && mgr->device + && mgr->device->type == OMAP_DISPLAY_TYPE_HDMI) + break; + } + + if (i == omap_dss_get_num_overlay_managers()) { + dev_err(dev, "HDMI display device not found!\n"); + return -ENODEV; + } + + /* Make sure HDMI is power-on to avoid L3 interconnect errors */ + while (mgr->device->state != OMAP_DSS_DISPLAY_ACTIVE) { + msleep(50); + if (count > 5) + return -EIO; + dev_err(dev, "HDMI display is not active!\n"); + count++; + } + + return 0; +} + +static struct snd_soc_ops omap4_hdmi_dai_ops = { + .hw_params = omap4_hdmi_dai_hw_params, +}; + +static struct snd_soc_dai_link omap4_hdmi_dai = { + .name = "HDMI", + .stream_name = "HDMI", + .cpu_dai_name = "hdmi-audio-dai", + .platform_name = "omap-pcm-audio", + .codec_name = "omap-hdmi-codec", + .codec_dai_name = "hdmi-audio-codec", + .ops = &omap4_hdmi_dai_ops, +}; + +static struct snd_soc_card snd_soc_omap4_hdmi = { + .name = "OMAP4HDMI", + .dai_link = &omap4_hdmi_dai, + .num_links = 1, +}; + +static __devinit int omap4_hdmi_probe(struct platform_device *pdev) +{ + struct snd_soc_card *card = &snd_soc_omap4_hdmi; + int ret; + + card->dev = &pdev->dev; + + ret = snd_soc_register_card(card); + if (ret) { + dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); + card->dev = NULL; + return ret; + } + return 0; +} + +static int __devexit omap4_hdmi_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + + snd_soc_unregister_card(card); + card->dev = NULL; + return 0; +} + +static struct platform_driver omap4_hdmi_driver = { + .driver = { + .name = "omap4-hdmi-audio", + .owner = THIS_MODULE, + }, + .probe = omap4_hdmi_probe, + .remove = __devexit_p(omap4_hdmi_remove), +}; + +static int __init omap4_hdmi_init(void) +{ + return platform_driver_register(&omap4_hdmi_driver); +} +module_init(omap4_hdmi_init); + +static void __exit omap4_hdmi_exit(void) +{ + platform_driver_unregister(&omap4_hdmi_driver); +} +module_exit(omap4_hdmi_exit); + +MODULE_AUTHOR("Ricardo Neri <ricardo.neri@ti.com>"); +MODULE_DESCRIPTION("OMAP4 HDMI machine ASoC driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" DRV_NAME); diff --git a/sound/soc/omap/sdp4430.c b/sound/soc/omap/sdp4430.c index 189e039..9fc42e7 100644..100755 --- a/sound/soc/omap/sdp4430.c +++ b/sound/soc/omap/sdp4430.c @@ -21,34 +21,133 @@ #include <linux/clk.h> #include <linux/platform_device.h> +#include <linux/i2c.h> #include <sound/core.h> #include <sound/pcm.h> +#include <sound/pcm_params.h> #include <sound/soc.h> +#include <sound/soc-dapm.h> #include <sound/jack.h> +#include <sound/soc-dsp.h> #include <asm/mach-types.h> #include <plat/hardware.h> #include <plat/mux.h> +#include <plat/mcbsp.h> -#include "mcpdm.h" +#include "omap-mcpdm.h" +#include "omap-abe.h" +#include "omap-abe-dsp.h" #include "omap-pcm.h" +#include "omap-mcbsp.h" #include "../codecs/twl6040.h" static int twl6040_power_mode; +static int mcbsp_cfg; +static struct snd_soc_codec *twl6040_codec; -static int sdp4430_hw_params(struct snd_pcm_substream *substream, +static int sdp4430_modem_mcbsp_configure(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, int flag) +{ + int ret = 0; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_pcm_substream *modem_substream[2]; + struct snd_soc_pcm_runtime *modem_rtd; + int channels; + + if (flag) { + modem_substream[substream->stream] = + snd_soc_get_dai_substream(rtd->card, + OMAP_ABE_BE_MM_EXT1, + substream->stream); + if (unlikely(modem_substream[substream->stream] == NULL)) + return -ENODEV; + + modem_rtd = + modem_substream[substream->stream]->private_data; + + if (!mcbsp_cfg) { + /* Set cpu DAI configuration */ + ret = snd_soc_dai_set_fmt(modem_rtd->cpu_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM); + + if (unlikely(ret < 0)) { + printk(KERN_ERR "can't set Modem cpu DAI configuration\n"); + goto exit; + } else { + mcbsp_cfg = 1; + } + } + + if (params != NULL) { + /* Configure McBSP internal buffer usage */ + /* this need to be done for playback and/or record */ + channels = params_channels(params); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + omap_mcbsp_set_rx_threshold( + modem_rtd->cpu_dai->id, channels); + else + omap_mcbsp_set_tx_threshold( + modem_rtd->cpu_dai->id, channels); + } + } else { + mcbsp_cfg = 0; + } + +exit: + return ret; +} + +static int sdp4430_modem_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { + int ret; + + ret = sdp4430_modem_mcbsp_configure(substream, params, 1); + if (ret) + printk(KERN_ERR "can't set modem cpu DAI configuration\n"); + + return ret; +} + +static int sdp4430_modem_hw_free(struct snd_pcm_substream *substream) +{ + int ret; + + ret = sdp4430_modem_mcbsp_configure(substream, NULL, 0); + if (ret) + printk(KERN_ERR "can't clear modem cpu DAI configuration\n"); + + return ret; +} + +static struct snd_soc_ops sdp4430_modem_ops = { + .hw_params = sdp4430_modem_hw_params, + .hw_free = sdp4430_modem_hw_free, +}; + +static int sdp4430_mcpdm_startup(struct snd_pcm_substream *substream) +{ struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec *codec = rtd->codec; struct snd_soc_dai *codec_dai = rtd->codec_dai; - int clk_id, freq; - int ret; + struct twl6040 *twl6040 = codec->control_data; + int clk_id, freq, ret; + + /* TWL6040 supplies McPDM PAD_CLKS */ + ret = twl6040_enable(twl6040); + if (ret) { + printk(KERN_ERR "failed to enable TWL6040\n"); + return ret; + } if (twl6040_power_mode) { - clk_id = TWL6040_SYSCLK_SEL_HPPLL; + clk_id = TWL6040_HPPLL_ID; freq = 38400000; } else { - clk_id = TWL6040_SYSCLK_SEL_LPPLL; + clk_id = TWL6040_LPPLL_ID; freq = 32768; } @@ -57,15 +156,95 @@ static int sdp4430_hw_params(struct snd_pcm_substream *substream, SND_SOC_CLOCK_IN); if (ret) { printk(KERN_ERR "can't set codec system clock\n"); + goto err; + } + + return 0; + +err: + twl6040_disable(twl6040); + return ret; +} + +static void sdp4430_mcpdm_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec *codec = rtd->codec; + struct twl6040 *twl6040 = codec->control_data; + + /* TWL6040 supplies McPDM PAD_CLKS */ + twl6040_disable(twl6040); +} + +static struct snd_soc_ops sdp4430_mcpdm_ops = { + .startup = sdp4430_mcpdm_startup, + .shutdown = sdp4430_mcpdm_shutdown, +}; + +static int sdp4430_mcbsp_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + int ret = 0; + unsigned int be_id; + + + be_id = rtd->dai_link->be_id; + + if (be_id == OMAP_ABE_DAI_MM_FM) { + /* Set cpu DAI configuration */ + ret = snd_soc_dai_set_fmt(cpu_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM); + } else if (be_id == OMAP_ABE_DAI_BT_VX) { + ret = snd_soc_dai_set_fmt(cpu_dai, + SND_SOC_DAIFMT_DSP_B | + SND_SOC_DAIFMT_NB_IF | + SND_SOC_DAIFMT_CBM_CFM); + } + + if (ret < 0) { + printk(KERN_ERR "can't set cpu DAI configuration\n"); return ret; } + + /* + * TODO: where does this clock come from (external source??) - + * do we need to enable it. + */ + /* Set McBSP clock to external */ + ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_MCBSP_SYSCLK_CLKS_FCLK, + 64 * params_rate(params), + SND_SOC_CLOCK_IN); + if (ret < 0) + printk(KERN_ERR "can't set cpu system clock\n"); + return ret; } -static struct snd_soc_ops sdp4430_ops = { - .hw_params = sdp4430_hw_params, +static struct snd_soc_ops sdp4430_mcbsp_ops = { + .hw_params = sdp4430_mcbsp_hw_params, }; +static int mcbsp_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + unsigned int be_id = rtd->dai_link->be_id; + + if (be_id == OMAP_ABE_DAI_MM_FM) + channels->min = 2; + else if (be_id == OMAP_ABE_DAI_BT_VX) + channels->min = 1; + snd_mask_set(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT - + SNDRV_PCM_HW_PARAM_FIRST_MASK], + SNDRV_PCM_FORMAT_S16_LE); + return 0; +} + /* Headset jack */ static struct snd_soc_jack hs_jack; @@ -95,6 +274,7 @@ static int sdp4430_set_power_mode(struct snd_kcontrol *kcontrol, return 0; twl6040_power_mode = ucontrol->value.integer.value[0]; + abe_dsp_set_power_mode(twl6040_power_mode); return 1; } @@ -146,11 +326,34 @@ static const struct snd_soc_dapm_route audio_map[] = { {"AFMR", NULL, "Aux/FM Stereo In"}, }; +static int sdp4430_set_pdm_dl1_gains(struct snd_soc_dapm_context *dapm) +{ + int output, val; + + if (snd_soc_dapm_get_pin_power(dapm, "Earphone Spk")) { + output = OMAP_ABE_DL1_EARPIECE; + } else if (snd_soc_dapm_get_pin_power(dapm, "Headset Stereophone")) { + val = snd_soc_read(twl6040_codec, TWL6040_REG_HSLCTL); + if (val & TWL6040_HSDACMODEL) + /* HSDACL in LP mode */ + output = OMAP_ABE_DL1_HEADSET_LP; + else + /* HSDACL in HP mode */ + output = OMAP_ABE_DL1_HEADSET_HP; + } else { + output = OMAP_ABE_DL1_NO_PDM; + } + + return omap_abe_set_dl1_output(output); +} + static int sdp4430_twl6040_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_codec *codec = rtd->codec; + struct twl6040 *twl6040 = codec->control_data; struct snd_soc_dapm_context *dapm = &codec->dapm; - int ret; + int hsotrim, left_offset, right_offset, mode, ret; + /* Add SDP4430 specific controls */ ret = snd_soc_add_controls(codec, sdp4430_controls, @@ -175,6 +378,14 @@ static int sdp4430_twl6040_init(struct snd_soc_pcm_runtime *rtd) snd_soc_dapm_enable_pin(dapm, "Headset Mic"); snd_soc_dapm_enable_pin(dapm, "Headset Stereophone"); + /* allow audio paths from the audio modem to run during suspend */ + snd_soc_dapm_ignore_suspend(dapm, "Ext Mic"); + snd_soc_dapm_ignore_suspend(dapm, "Ext Spk"); + snd_soc_dapm_ignore_suspend(dapm, "AFML"); + snd_soc_dapm_ignore_suspend(dapm, "AFMR"); + snd_soc_dapm_ignore_suspend(dapm, "Headset Mic"); + snd_soc_dapm_ignore_suspend(dapm, "Headset Stereophone"); + ret = snd_soc_dapm_sync(dapm); if (ret) return ret; @@ -193,37 +404,454 @@ static int sdp4430_twl6040_init(struct snd_soc_pcm_runtime *rtd) else snd_soc_jack_report(&hs_jack, SND_JACK_HEADSET, SND_JACK_HEADSET); + /* DC offset cancellation computation */ + hsotrim = snd_soc_read(codec, TWL6040_REG_HSOTRIM); + right_offset = (hsotrim & TWL6040_HSRO) >> TWL6040_HSRO_OFFSET; + left_offset = hsotrim & TWL6040_HSLO; + + if (twl6040_get_icrev(twl6040) < TWL6040_REV_1_3) + /* For ES under ES_1.3 HS step is 2 mV */ + mode = 2; + else + /* For ES_1.3 HS step is 1 mV */ + mode = 1; + + abe_dsp_set_hs_offset(left_offset, right_offset, mode); + + /* don't wait before switching of HS power */ + rtd->pmdown_time = 0; + return ret; } +static int sdp4430_twl6040_dl2_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_codec *codec = rtd->codec; + int hfotrim, left_offset, right_offset; + + /* DC offset cancellation computation */ + hfotrim = snd_soc_read(codec, TWL6040_REG_HFOTRIM); + right_offset = (hfotrim & TWL6040_HFRO) >> TWL6040_HFRO_OFFSET; + left_offset = hfotrim & TWL6040_HFLO; + + abe_dsp_set_hf_offset(left_offset, right_offset); + + /* don't wait before switching of HF power */ + rtd->pmdown_time = 0; + + return 0; +} + +static int sdp4430_twl6040_fe_init(struct snd_soc_pcm_runtime *rtd) +{ + + /* don't wait before switching of FE power */ + rtd->pmdown_time = 0; + + return 0; +} + +static int sdp4430_bt_init(struct snd_soc_pcm_runtime *rtd) +{ + + /* don't wait before switching of BT power */ + rtd->pmdown_time = 0; + + return 0; +} + +static int sdp4430_stream_event(struct snd_soc_dapm_context *dapm) +{ + /* + * set DL1 gains dynamically according to the active output + * (Headset, Earpiece) and HSDAC power mode + */ + return sdp4430_set_pdm_dl1_gains(dapm); +} + +/* TODO: make this a separate BT CODEC driver or DUMMY */ +static struct snd_soc_dai_driver dai[] = { +{ + .name = "Bluetooth", + .playback = { + .stream_name = "BT Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | + SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .capture = { + .stream_name = "BT Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | + SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, +}, +/* TODO: make this a separate FM CODEC driver or DUMMY */ +{ + .name = "FM Digital", + .playback = { + .stream_name = "FM Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .capture = { + .stream_name = "FM Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, +}, +{ + .name = "HDMI", + .playback = { + .stream_name = "HDMI Playback", + .channels_min = 2, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, + }, +}, +}; + +struct snd_soc_dsp_link fe_media = { + .playback = true, + .capture = true, + .trigger = + {SND_SOC_DSP_TRIGGER_BESPOKE, SND_SOC_DSP_TRIGGER_BESPOKE}, +}; + +struct snd_soc_dsp_link fe_media_capture = { + .capture = true, + .trigger = + {SND_SOC_DSP_TRIGGER_BESPOKE, SND_SOC_DSP_TRIGGER_BESPOKE}, +}; + +struct snd_soc_dsp_link fe_tones = { + .playback = true, + .trigger = + {SND_SOC_DSP_TRIGGER_BESPOKE, SND_SOC_DSP_TRIGGER_BESPOKE}, +}; + +struct snd_soc_dsp_link fe_vib = { + .playback = true, + .trigger = + {SND_SOC_DSP_TRIGGER_BESPOKE, SND_SOC_DSP_TRIGGER_BESPOKE}, +}; + +struct snd_soc_dsp_link fe_modem = { + .playback = true, + .capture = true, + .trigger = + {SND_SOC_DSP_TRIGGER_BESPOKE, SND_SOC_DSP_TRIGGER_BESPOKE}, +}; + +struct snd_soc_dsp_link fe_lp_media = { + .playback = true, + .trigger = + {SND_SOC_DSP_TRIGGER_BESPOKE, SND_SOC_DSP_TRIGGER_BESPOKE}, +}; /* Digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link sdp4430_dai = { - .name = "TWL6040", - .stream_name = "TWL6040", - .cpu_dai_name ="omap-mcpdm-dai", - .codec_dai_name = "twl6040-hifi", - .platform_name = "omap-pcm-audio", - .codec_name = "twl6040-codec", - .init = sdp4430_twl6040_init, - .ops = &sdp4430_ops, +static struct snd_soc_dai_link sdp4430_dai[] = { + +/* + * Frontend DAIs - i.e. userspace visible interfaces (ALSA PCMs) + */ + + { + .name = "SDP4430 Media", + .stream_name = "Multimedia", + + /* ABE components - MM-UL & MM_DL */ + .cpu_dai_name = "MultiMedia1", + .platform_name = "omap-pcm-audio", + + .dynamic = 1, /* BE is dynamic */ + .init = sdp4430_twl6040_fe_init, + .dsp_link = &fe_media, + }, + { + .name = "SDP4430 Media Capture", + .stream_name = "Multimedia Capture", + + /* ABE components - MM-UL2 */ + .cpu_dai_name = "MultiMedia2", + .platform_name = "omap-pcm-audio", + + .dynamic = 1, /* BE is dynamic */ + .dsp_link = &fe_media_capture, + }, + { + .name = "SDP4430 Voice", + .stream_name = "Voice", + + /* ABE components - VX-UL & VX-DL */ + .cpu_dai_name = "Voice", + .platform_name = "omap-pcm-audio", + + .dynamic = 1, /* BE is dynamic */ + .dsp_link = &fe_media, + .no_host_mode = SND_SOC_DAI_LINK_OPT_HOST, + }, + { + .name = "SDP4430 Tones Playback", + .stream_name = "Tone Playback", + + /* ABE components - TONES_DL */ + .cpu_dai_name = "Tones", + .platform_name = "omap-pcm-audio", + + .dynamic = 1, /* BE is dynamic */ + .dsp_link = &fe_tones, + }, + { + .name = "SDP4430 Vibra Playback", + .stream_name = "VIB-DL", + + /* ABE components - DMIC UL 2 */ + .cpu_dai_name = "Vibra", + .platform_name = "omap-pcm-audio", + + .dynamic = 1, /* BE is dynamic */ + .dsp_link = &fe_vib, + }, + { + .name = "SDP4430 MODEM", + .stream_name = "MODEM", + + /* ABE components - MODEM <-> McBSP2 */ + .cpu_dai_name = "MODEM", + .platform_name = "aess", + + .dynamic = 1, /* BE is dynamic */ + .init = sdp4430_twl6040_fe_init, + .dsp_link = &fe_modem, + .ops = &sdp4430_modem_ops, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + }, + { + .name = "SDP4430 Media LP", + .stream_name = "Multimedia", + + /* ABE components - MM-DL (mmap) */ + .cpu_dai_name = "MultiMedia1 LP", + .platform_name = "aess", + + .dynamic = 1, /* BE is dynamic */ + .dsp_link = &fe_lp_media, + }, + { + .name = "Legacy McBSP", + .stream_name = "Multimedia", + + /* ABE components - MCBSP2 - MM-EXT */ + .cpu_dai_name = "omap-mcbsp-dai.1", + .platform_name = "omap-pcm-audio", + + /* FM */ + .codec_dai_name = "FM Digital", + + .no_codec = 1, /* TODO: have a dummy CODEC */ + .ops = &sdp4430_mcbsp_ops, + .ignore_suspend = 1, + }, + { + .name = "Legacy McPDM", + .stream_name = "Headset Playback", + + /* ABE components - DL1 */ + .cpu_dai_name = "mcpdm-dl", + .platform_name = "omap-pcm-audio", + + /* Phoenix - DL1 DAC */ + .codec_dai_name = "twl6040-dl1", + .codec_name = "twl6040-codec", + + .ops = &sdp4430_mcpdm_ops, + .ignore_suspend = 1, + }, + +/* + * Backend DAIs - i.e. dynamically matched interfaces, invisible to userspace. + * Matched to above interfaces at runtime, based upon use case. + */ + + { + .name = OMAP_ABE_BE_PDM_DL1, + .stream_name = "HS Playback", + + /* ABE components - DL1 */ + .cpu_dai_name = "mcpdm-dl1", + .platform_name = "aess", + + /* Phoenix - DL1 DAC */ + .codec_dai_name = "twl6040-dl1", + .codec_name = "twl6040-codec", + + .no_pcm = 1, /* don't create ALSA pcm for this */ + .init = sdp4430_twl6040_init, + .ops = &sdp4430_mcpdm_ops, + .be_id = OMAP_ABE_DAI_PDM_DL1, + .ignore_suspend = 1, + }, + { + .name = OMAP_ABE_BE_PDM_UL1, + .stream_name = "Analog Capture", + + /* ABE components - UL1 */ + .cpu_dai_name = "mcpdm-ul1", + .platform_name = "aess", + + /* Phoenix - UL ADC */ + .codec_dai_name = "twl6040-ul", + .codec_name = "twl6040-codec", + + .no_pcm = 1, /* don't create ALSA pcm for this */ + .ops = &sdp4430_mcpdm_ops, + .be_id = OMAP_ABE_DAI_PDM_UL, + .ignore_suspend = 1, + }, + { + .name = OMAP_ABE_BE_PDM_DL2, + .stream_name = "HF Playback", + + /* ABE components - DL2 */ + .cpu_dai_name = "mcpdm-dl2", + .platform_name = "aess", + + /* Phoenix - DL2 DAC */ + .codec_dai_name = "twl6040-dl2", + .codec_name = "twl6040-codec", + + .no_pcm = 1, /* don't create ALSA pcm for this */ + .init = sdp4430_twl6040_dl2_init, + .ops = &sdp4430_mcpdm_ops, + .be_id = OMAP_ABE_DAI_PDM_DL2, + .ignore_suspend = 1, + }, + { + .name = OMAP_ABE_BE_PDM_VIB, + .stream_name = "Vibra", + + /* ABE components - VIB1 DL */ + .cpu_dai_name = "mcpdm-vib", + .platform_name = "aess", + + /* Phoenix - PDM to PWM */ + .codec_dai_name = "twl6040-vib", + .codec_name = "twl6040-codec", + + .no_pcm = 1, /* don't create ALSA pcm for this */ + .ops = &sdp4430_mcpdm_ops, + .be_id = OMAP_ABE_DAI_PDM_VIB, + }, + { + .name = OMAP_ABE_BE_BT_VX_UL, + .stream_name = "BT Capture", + + /* ABE components - MCBSP1 - BT-VX */ + .cpu_dai_name = "omap-mcbsp-dai.0", + .platform_name = "aess", + + /* Bluetooth */ + .codec_dai_name = "Bluetooth", + + .no_pcm = 1, /* don't create ALSA pcm for this */ + .no_codec = 1, /* TODO: have a dummy CODEC */ + .be_hw_params_fixup = mcbsp_be_hw_params_fixup, + .ops = &sdp4430_mcbsp_ops, + .be_id = OMAP_ABE_DAI_BT_VX, + .ignore_suspend = 1, + }, + { + .name = OMAP_ABE_BE_BT_VX_DL, + .stream_name = "BT Playback", + + /* ABE components - MCBSP1 - BT-VX */ + .cpu_dai_name = "omap-mcbsp-dai.0", + .platform_name = "aess", + + /* Bluetooth */ + .codec_dai_name = "Bluetooth", + + .no_pcm = 1, /* don't create ALSA pcm for this */ + .no_codec = 1, /* TODO: have a dummy CODEC */ + .init = sdp4430_bt_init, + .be_hw_params_fixup = mcbsp_be_hw_params_fixup, + .ops = &sdp4430_mcbsp_ops, + .be_id = OMAP_ABE_DAI_BT_VX, + .ignore_suspend = 1, + }, + { + .name = OMAP_ABE_BE_MM_EXT0, + .stream_name = "FM", + + /* ABE components - MCBSP2 - MM-EXT */ + .cpu_dai_name = "omap-mcbsp-dai.1", + .platform_name = "aess", + + /* FM */ + .codec_dai_name = "FM Digital", + + .no_pcm = 1, /* don't create ALSA pcm for this */ + .no_codec = 1, /* TODO: have a dummy CODEC */ + .be_hw_params_fixup = mcbsp_be_hw_params_fixup, + .ops = &sdp4430_mcbsp_ops, + .be_id = OMAP_ABE_DAI_MM_FM, + }, + { + .name = OMAP_ABE_BE_MM_EXT1, + .stream_name = "MODEM", + + /* ABE components - MCBSP2 - MM-EXT */ + .cpu_dai_name = "omap-mcbsp-dai.1", + .platform_name = "aess", + + /* MODEM */ + .codec_dai_name = "MODEM", + + .no_pcm = 1, /* don't create ALSA pcm for this */ + .no_codec = 1, /* TODO: have a dummy CODEC */ + .be_hw_params_fixup = mcbsp_be_hw_params_fixup, + .ops = &sdp4430_mcbsp_ops, + .be_id = OMAP_ABE_DAI_MODEM, + .ignore_suspend = 1, + }, }; /* Audio machine driver */ static struct snd_soc_card snd_soc_sdp4430 = { - .name = "SDP4430", - .dai_link = &sdp4430_dai, - .num_links = 1, + .driver_name = "OMAP4", + .long_name = "TI OMAP4 Board", + .dai_link = sdp4430_dai, + .num_links = ARRAY_SIZE(sdp4430_dai), + .stream_event = sdp4430_stream_event, }; static struct platform_device *sdp4430_snd_device; +struct i2c_adapter *adapter; static int __init sdp4430_soc_init(void) { int ret; - if (!machine_is_omap_4430sdp()) + if (!machine_is_omap_4430sdp() && !machine_is_omap4_panda()) { + pr_debug("Not SDP4430 or PandaBoard!\n"); return -ENODEV; + } printk(KERN_INFO "SDP4430 SoC init\n"); + if (machine_is_omap_4430sdp()) + snd_soc_sdp4430.name = "SDP4430"; + else if (machine_is_omap4_panda()) + snd_soc_sdp4430.name = "Panda"; sdp4430_snd_device = platform_device_alloc("soc-audio", -1); if (!sdp4430_snd_device) { @@ -231,14 +859,17 @@ static int __init sdp4430_soc_init(void) return -ENOMEM; } + ret = snd_soc_register_dais(&sdp4430_snd_device->dev, dai, ARRAY_SIZE(dai)); + if (ret < 0) + goto err; platform_set_drvdata(sdp4430_snd_device, &snd_soc_sdp4430); ret = platform_device_add(sdp4430_snd_device); if (ret) goto err; - /* Codec starts in HP mode */ - twl6040_power_mode = 1; + twl6040_codec = snd_soc_card_get_codec(&snd_soc_sdp4430, + "twl6040-codec"); return 0; diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c index fab20a5..da28394 100644 --- a/sound/soc/pxa/pxa2xx-pcm.c +++ b/sound/soc/pxa/pxa2xx-pcm.c @@ -85,9 +85,11 @@ static struct snd_pcm_ops pxa2xx_pcm_ops = { static u64 pxa2xx_pcm_dmamask = DMA_BIT_MASK(32); -static int pxa2xx_soc_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, - struct snd_pcm *pcm) +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; if (!card->dev->dma_mask) diff --git a/sound/soc/s6000/s6000-pcm.c b/sound/soc/s6000/s6000-pcm.c index ab3ccae..80c85fd 100644 --- a/sound/soc/s6000/s6000-pcm.c +++ b/sound/soc/s6000/s6000-pcm.c @@ -443,10 +443,11 @@ static void s6000_pcm_free(struct snd_pcm *pcm) static u64 s6000_pcm_dmamask = DMA_BIT_MASK(32); -static int s6000_pcm_new(struct snd_card *card, - struct snd_soc_dai *dai, struct snd_pcm *pcm) +static int s6000_pcm_new(struct snd_soc_pcm_runtime *runtime) { - struct snd_soc_pcm_runtime *runtime = pcm->private_data; + struct snd_card *card = runtime->card->snd_card; + struct snd_soc_dai *dai = runtime->cpu_dai; + struct snd_pcm *pcm = runtime->pcm; struct s6000_pcm_dma_params *params; int res; diff --git a/sound/soc/samsung/dma.c b/sound/soc/samsung/dma.c index 5cb3b88..9465588 100644 --- a/sound/soc/samsung/dma.c +++ b/sound/soc/samsung/dma.c @@ -425,9 +425,11 @@ static void dma_free_dma_buffers(struct snd_pcm *pcm) static u64 dma_mask = DMA_BIT_MASK(32); -static int dma_new(struct snd_card *card, - struct snd_soc_dai *dai, struct snd_pcm *pcm) +static int dma_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; pr_debug("Entered %s\n", __func__); diff --git a/sound/soc/sh/dma-sh7760.c b/sound/soc/sh/dma-sh7760.c index c326d29..db74005 100644 --- a/sound/soc/sh/dma-sh7760.c +++ b/sound/soc/sh/dma-sh7760.c @@ -327,10 +327,10 @@ static void camelot_pcm_free(struct snd_pcm *pcm) snd_pcm_lib_preallocate_free_for_all(pcm); } -static int camelot_pcm_new(struct snd_card *card, - struct snd_soc_dai *dai, - struct snd_pcm *pcm) +static int camelot_pcm_new(struct snd_soc_pcm_runtime *rtd) { + struct snd_pcm *pcm = rtd->pcm; + /* dont use SNDRV_DMA_TYPE_DEV, since it will oops the SH kernel * in MMAP mode (i.e. aplay -M) */ diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 4a9da6b..339a1df 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -1129,10 +1129,10 @@ static void fsi_pcm_free(struct snd_pcm *pcm) snd_pcm_lib_preallocate_free_for_all(pcm); } -static int fsi_pcm_new(struct snd_card *card, - struct snd_soc_dai *dai, - struct snd_pcm *pcm) +static int fsi_pcm_new(struct snd_soc_pcm_runtime *rtd) { + struct snd_pcm *pcm = rtd->pcm; + /* * dont use SNDRV_DMA_TYPE_DEV, since it will oops the SH kernel * in MMAP mode (i.e. aplay -M) diff --git a/sound/soc/sh/siu_pcm.c b/sound/soc/sh/siu_pcm.c index a423bab..f8f6816 100644 --- a/sound/soc/sh/siu_pcm.c +++ b/sound/soc/sh/siu_pcm.c @@ -527,10 +527,11 @@ static snd_pcm_uframes_t siu_pcm_pointer_dma(struct snd_pcm_substream *ss) return bytes_to_frames(ss->runtime, ptr); } -static int siu_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, - struct snd_pcm *pcm) +static int siu_pcm_new(struct snd_soc_pcm_runtime *rtd) { /* card->dev == socdev->dev, see snd_soc_new_pcms() */ + struct snd_card *card = rtd->card->snd_card; + struct snd_pcm *pcm = rtd->pcm; struct siu_info *info = siu_i2s_data; struct platform_device *pdev = to_platform_device(card->dev); int ret; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index e2bfe1d..c171182 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -38,6 +38,7 @@ #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/soc.h> +#include <sound/soc-dsp.h> #include <sound/initval.h> #define CREATE_TRACE_POINTS @@ -45,7 +46,6 @@ #define NAME_SIZE 32 -static DEFINE_MUTEX(pcm_mutex); static DECLARE_WAIT_QUEUE_HEAD(soc_pm_waitq); #ifdef CONFIG_DEBUG_FS @@ -60,6 +60,7 @@ static LIST_HEAD(platform_list); static LIST_HEAD(codec_list); static int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num); +int soc_dsp_debugfs_add(struct snd_soc_pcm_runtime *rtd); /* * This is a timeout to do a DAPM powerdown after a stream is closed(). @@ -123,6 +124,24 @@ static int format_register_str(struct snd_soc_codec *codec, return 0; } +/* ASoC no host IO hardware. + * TODO: fine tune these values for all host less transfers. + */ +static const struct snd_pcm_hardware no_host_hardware = { + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_RESUME, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE, + .period_bytes_min = PAGE_SIZE >> 2, + .period_bytes_max = PAGE_SIZE >> 1, + .periods_min = 2, + .periods_max = 4, + .buffer_bytes_max = PAGE_SIZE, +}; + /* codec register dump */ static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf, size_t count, loff_t pos) @@ -527,7 +546,7 @@ static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream) * then initialized and any private data can be allocated. This also calls * startup for the cpu DAI, platform, machine and codec DAI. */ -static int soc_pcm_open(struct snd_pcm_substream *substream) +int soc_pcm_open(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_pcm_runtime *runtime = substream->runtime; @@ -538,7 +557,19 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) struct snd_soc_dai_driver *codec_dai_drv = codec_dai->driver; int ret = 0; - mutex_lock(&pcm_mutex); + mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + + if (rtd->dai_link->no_host_mode == SND_SOC_DAI_LINK_NO_HOST) + snd_soc_set_runtime_hwparams(substream, &no_host_hardware); + + if (rtd->dai_link->ops && rtd->dai_link->ops->startup) { + ret = rtd->dai_link->ops->startup(substream); + if (ret < 0) { + printk(KERN_ERR "asoc: %s startup failed\n", + rtd->dai_link->name); + goto machine_err; + } + } /* startup the audio subsystem */ if (cpu_dai->driver->ops->startup) { @@ -546,7 +577,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) if (ret < 0) { printk(KERN_ERR "asoc: can't open interface %s\n", cpu_dai->name); - goto out; + goto cpu_err; } } @@ -567,13 +598,9 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) } } - if (rtd->dai_link->ops && rtd->dai_link->ops->startup) { - ret = rtd->dai_link->ops->startup(substream); - if (ret < 0) { - printk(KERN_ERR "asoc: %s startup failed\n", rtd->dai_link->name); - goto machine_err; - } - } + /* DSP DAI links compat checks are different */ + if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm) + goto dynamic; /* Check that the codec and cpu DAIs are compatible */ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { @@ -658,6 +685,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) pr_debug("asoc: min rate %d max rate %d\n", runtime->hw.rate_min, runtime->hw.rate_max); +dynamic: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { cpu_dai->playback_active++; codec_dai->playback_active++; @@ -668,14 +696,11 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) cpu_dai->active++; codec_dai->active++; rtd->codec->active++; - mutex_unlock(&pcm_mutex); + rtd->dai_link->active++; + mutex_unlock(&rtd->pcm_mutex); return 0; config_err: - if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown) - rtd->dai_link->ops->shutdown(substream); - -machine_err: if (codec_dai->driver->ops->shutdown) codec_dai->driver->ops->shutdown(substream, codec_dai); @@ -686,8 +711,12 @@ codec_dai_err: platform_err: if (cpu_dai->driver->ops->shutdown) cpu_dai->driver->ops->shutdown(substream, cpu_dai); -out: - mutex_unlock(&pcm_mutex); +cpu_err: + if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown) + rtd->dai_link->ops->shutdown(substream); + +machine_err: + mutex_unlock(&rtd->pcm_mutex); return ret; } @@ -702,7 +731,7 @@ static void close_delayed_work(struct work_struct *work) container_of(work, struct snd_soc_pcm_runtime, delayed_work.work); struct snd_soc_dai *codec_dai = rtd->codec_dai; - mutex_lock(&pcm_mutex); + mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); pr_debug("pop wq checking: %s status: %s waiting: %s\n", codec_dai->driver->playback.stream_name, @@ -717,7 +746,7 @@ static void close_delayed_work(struct work_struct *work) SND_SOC_DAPM_STREAM_STOP); } - mutex_unlock(&pcm_mutex); + mutex_unlock(&rtd->pcm_mutex); } /* @@ -725,7 +754,7 @@ static void close_delayed_work(struct work_struct *work) * freed here. The cpu DAI, codec DAI, machine and platform are also * shutdown. */ -static int soc_codec_close(struct snd_pcm_substream *substream) +int soc_pcm_close(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_platform *platform = rtd->platform; @@ -733,7 +762,7 @@ static int soc_codec_close(struct snd_pcm_substream *substream) struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_codec *codec = rtd->codec; - mutex_lock(&pcm_mutex); + mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { cpu_dai->playback_active--; @@ -746,6 +775,7 @@ static int soc_codec_close(struct snd_pcm_substream *substream) cpu_dai->active--; codec_dai->active--; codec->active--; + rtd->dai_link->active--; /* Muting the DAC suppresses artifacts caused during digital * shutdown, for example from stopping clocks. @@ -759,11 +789,12 @@ static int soc_codec_close(struct snd_pcm_substream *substream) if (codec_dai->driver->ops->shutdown) codec_dai->driver->ops->shutdown(substream, codec_dai); + if (platform->driver->ops && platform->driver->ops->close) + platform->driver->ops->close(substream); + if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown) rtd->dai_link->ops->shutdown(substream); - if (platform->driver->ops && platform->driver->ops->close) - platform->driver->ops->close(substream); cpu_dai->runtime = NULL; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { @@ -778,7 +809,7 @@ static int soc_codec_close(struct snd_pcm_substream *substream) SND_SOC_DAPM_STREAM_STOP); } - mutex_unlock(&pcm_mutex); + mutex_unlock(&rtd->pcm_mutex); return 0; } @@ -787,7 +818,7 @@ static int soc_codec_close(struct snd_pcm_substream *substream) * rate, etc. This function is non atomic and can be called multiple times, * it can refer to the runtime info. */ -static int soc_pcm_prepare(struct snd_pcm_substream *substream) +int soc_pcm_prepare(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_platform *platform = rtd->platform; @@ -795,7 +826,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) struct snd_soc_dai *codec_dai = rtd->codec_dai; int ret = 0; - mutex_lock(&pcm_mutex); + mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); if (rtd->dai_link->ops && rtd->dai_link->ops->prepare) { ret = rtd->dai_link->ops->prepare(substream); @@ -848,7 +879,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) snd_soc_dai_digital_mute(codec_dai, 0); out: - mutex_unlock(&pcm_mutex); + mutex_unlock(&rtd->pcm_mutex); return ret; } @@ -857,7 +888,7 @@ out: * function can also be called multiple times and can allocate buffers * (using snd_pcm_lib_* ). It's non-atomic. */ -static int soc_pcm_hw_params(struct snd_pcm_substream *substream, +int soc_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; @@ -866,7 +897,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *codec_dai = rtd->codec_dai; int ret = 0; - mutex_lock(&pcm_mutex); + mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); if (rtd->dai_link->ops && rtd->dai_link->ops->hw_params) { ret = rtd->dai_link->ops->hw_params(substream, params); @@ -905,8 +936,21 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, rtd->rate = params_rate(params); + /* malloc a page for hostless IO. + * FIXME: rework with alsa-lib changes so that this malloc is not required. + */ + if (rtd->dai_link->no_host_mode == SND_SOC_DAI_LINK_NO_HOST) { + substream->dma_buffer.dev.type = SNDRV_DMA_TYPE_DEV; + substream->dma_buffer.dev.dev = &rtd->dev; + substream->dma_buffer.dev.dev->coherent_dma_mask = ISA_DMA_THRESHOLD; + substream->dma_buffer.private_data = NULL; + + ret = snd_pcm_lib_malloc_pages(substream, PAGE_SIZE); + if (ret < 0) + goto platform_err; + } out: - mutex_unlock(&pcm_mutex); + mutex_unlock(&rtd->pcm_mutex); return ret; platform_err: @@ -921,14 +965,14 @@ codec_err: if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free) rtd->dai_link->ops->hw_free(substream); - mutex_unlock(&pcm_mutex); + mutex_unlock(&rtd->pcm_mutex); return ret; } /* * Frees resources allocated by hw_params, can be called multiple times */ -static int soc_pcm_hw_free(struct snd_pcm_substream *substream) +int soc_pcm_hw_free(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_platform *platform = rtd->platform; @@ -936,7 +980,7 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_codec *codec = rtd->codec; - mutex_lock(&pcm_mutex); + mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); /* apply codec digital mute */ if (!codec->active) @@ -957,11 +1001,13 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) if (cpu_dai->driver->ops->hw_free) cpu_dai->driver->ops->hw_free(substream, cpu_dai); - mutex_unlock(&pcm_mutex); + if (rtd->dai_link->no_host_mode == SND_SOC_DAI_LINK_NO_HOST) + snd_pcm_lib_free_pages(substream); + mutex_unlock(&rtd->pcm_mutex); return 0; } -static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_platform *platform = rtd->platform; @@ -989,12 +1035,40 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) return 0; } +int soc_pcm_bespoke_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_platform *platform = rtd->platform; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + int ret; + + if (codec_dai->driver->ops->bespoke_trigger) { + ret = codec_dai->driver->ops->bespoke_trigger(substream, cmd, codec_dai); + if (ret < 0) + return ret; + } + + if (platform->driver->bespoke_trigger) { + ret = platform->driver->bespoke_trigger(substream, cmd); + if (ret < 0) + return ret; + } + + if (cpu_dai->driver->ops->bespoke_trigger) { + ret = cpu_dai->driver->ops->bespoke_trigger(substream, cmd, cpu_dai); + if (ret < 0) + return ret; + } + return 0; +} + /* * soc level wrapper for pointer callback * If cpu_dai, codec_dai, platform driver has the delay callback, than * the runtime->delay will be updated accordingly. */ -static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream) +snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_platform *platform = rtd->platform; @@ -1021,16 +1095,74 @@ static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream) return offset; } -/* ASoC PCM operations */ -static struct snd_pcm_ops soc_pcm_ops = { - .open = soc_pcm_open, - .close = soc_codec_close, - .hw_params = soc_pcm_hw_params, - .hw_free = soc_pcm_hw_free, - .prepare = soc_pcm_prepare, - .trigger = soc_pcm_trigger, - .pointer = soc_pcm_pointer, -}; +static int soc_pcm_ioctl(struct snd_pcm_substream *substream, + unsigned int cmd, void *arg) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_platform *platform = rtd->platform; + + if (platform->driver->ops->ioctl) + return platform->driver->ops->ioctl(substream, cmd, arg); + return snd_pcm_lib_ioctl(substream, cmd, arg); +} + +struct snd_soc_codec *snd_soc_card_get_codec(struct snd_soc_card *card, + const char *codec_name) +{ + struct snd_soc_codec *codec = NULL; + + list_for_each_entry(codec, &card->codec_dev_list, card_list) { + if (!strcmp(codec->name, codec_name)) + return codec; + } + + return codec; +} +EXPORT_SYMBOL(snd_soc_card_get_codec); + +int snd_soc_card_active_links(struct snd_soc_card *card) +{ + int i; + int count = 0; + + for (i = 0; i < card->num_rtd; i++) { + /* count FEs: dynamic and legacy */ + if (!card->rtd[i].dai_link->no_pcm) + count += card->rtd[i].dai_link->active; + } + + return count; +} +EXPORT_SYMBOL(snd_soc_card_active_links); + +struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card, + const char *dai_link, int stream) +{ + int i; + + for (i = 0; i < card->num_links; i++) { + if (card->rtd[i].dai_link->no_pcm && + !strcmp(card->rtd[i].dai_link->name, dai_link)) + return card->rtd[i].pcm->streams[stream].substream; + } + dev_dbg(card->dev, "failed to find dai link %s\n", dai_link); + return NULL; +} +EXPORT_SYMBOL_GPL(snd_soc_get_dai_substream); + +struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card, + const char *dai_link) +{ + int i; + + for (i = 0; i < card->num_links; i++) { + if (!strcmp(card->rtd[i].dai_link->name, dai_link)) + return &card->rtd[i]; + } + dev_dbg(card->dev, "failed to find rtd %s\n", dai_link); + return NULL; +} +EXPORT_SYMBOL_GPL(snd_soc_get_pcm_runtime); #ifdef CONFIG_PM_SLEEP /* powers down audio subsystem for suspend */ @@ -1040,6 +1172,9 @@ int snd_soc_suspend(struct device *dev) struct snd_soc_codec *codec; int i; + /* cancel pending deferred resume if any */ + cancel_work_sync(&card->deferred_resume_work); + /* If the initialization of this soc device failed, there is no codec * associated with it. Just bail out in this case. */ @@ -1061,16 +1196,22 @@ int snd_soc_suspend(struct device *dev) struct snd_soc_dai *dai = card->rtd[i].codec_dai; struct snd_soc_dai_driver *drv = dai->driver; - if (card->rtd[i].dai_link->ignore_suspend) + if (card->rtd[i].dai_link->ignore_suspend || + card->rtd[i].dai_link->no_pcm) continue; - if (drv->ops->digital_mute && dai->playback_active) - drv->ops->digital_mute(dai, 1); + if (card->rtd[i].dai_link->dynamic) + soc_dsp_be_digital_mute(&card->rtd[i], 1); + else { + if (drv->ops->digital_mute && dai->playback_active) + drv->ops->digital_mute(dai, 1); + } } /* suspend all pcms */ for (i = 0; i < card->num_rtd; i++) { - if (card->rtd[i].dai_link->ignore_suspend) + if (card->rtd[i].dai_link->ignore_suspend || + card->rtd[i].dai_link->no_pcm) continue; snd_pcm_suspend_all(card->rtd[i].pcm); @@ -1083,14 +1224,19 @@ int snd_soc_suspend(struct device *dev) struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; struct snd_soc_platform *platform = card->rtd[i].platform; - if (card->rtd[i].dai_link->ignore_suspend) + if (card->rtd[i].dai_link->ignore_suspend || + card->rtd[i].dai_link->no_pcm) continue; - if (cpu_dai->driver->suspend && !cpu_dai->driver->ac97_control) - cpu_dai->driver->suspend(cpu_dai); - if (platform->driver->suspend && !platform->suspended) { - platform->driver->suspend(cpu_dai); - platform->suspended = 1; + if (card->rtd[i].dai_link->dynamic) { + soc_dsp_fe_suspend(&card->rtd[i]); + } else { + if (cpu_dai->driver->suspend && !cpu_dai->driver->ac97_control) + cpu_dai->driver->suspend(cpu_dai); + if (platform->driver->suspend && !platform->suspended) { + platform->driver->suspend(cpu_dai); + platform->suspended = 1; + } } } @@ -1103,7 +1249,8 @@ int snd_soc_suspend(struct device *dev) for (i = 0; i < card->num_rtd; i++) { struct snd_soc_dai_driver *driver = card->rtd[i].codec_dai->driver; - if (card->rtd[i].dai_link->ignore_suspend) + if (card->rtd[i].dai_link->ignore_suspend || + card->rtd[i].dai_link->no_pcm) continue; if (driver->playback.stream_name != NULL) @@ -1137,11 +1284,15 @@ int snd_soc_suspend(struct device *dev) for (i = 0; i < card->num_rtd; i++) { struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; - if (card->rtd[i].dai_link->ignore_suspend) + if (card->rtd[i].dai_link->ignore_suspend || + card->rtd[i].dai_link->no_pcm) continue; - if (cpu_dai->driver->suspend && cpu_dai->driver->ac97_control) - cpu_dai->driver->suspend(cpu_dai); + if (card->rtd[i].dai_link->dynamic) + soc_dsp_be_ac97_cpu_dai_suspend(&card->rtd[i]); + else + if (cpu_dai->driver->suspend && cpu_dai->driver->ac97_control) + cpu_dai->driver->suspend(cpu_dai); } if (card->suspend_post) @@ -1177,11 +1328,15 @@ static void soc_resume_deferred(struct work_struct *work) for (i = 0; i < card->num_rtd; i++) { struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; - if (card->rtd[i].dai_link->ignore_suspend) + if (card->rtd[i].dai_link->ignore_suspend || + card->rtd[i].dai_link->no_pcm) continue; - if (cpu_dai->driver->resume && cpu_dai->driver->ac97_control) - cpu_dai->driver->resume(cpu_dai); + if (card->rtd[i].dai_link->dynamic) + soc_dsp_be_ac97_cpu_dai_resume(&card->rtd[i]); + else + if (cpu_dai->driver->resume && cpu_dai->driver->ac97_control) + cpu_dai->driver->resume(cpu_dai); } list_for_each_entry(codec, &card->codec_dev_list, card_list) { @@ -1206,7 +1361,8 @@ static void soc_resume_deferred(struct work_struct *work) for (i = 0; i < card->num_rtd; i++) { struct snd_soc_dai_driver *driver = card->rtd[i].codec_dai->driver; - if (card->rtd[i].dai_link->ignore_suspend) + if (card->rtd[i].dai_link->ignore_suspend || + card->rtd[i].dai_link->no_pcm) continue; if (driver->playback.stream_name != NULL) @@ -1223,25 +1379,35 @@ static void soc_resume_deferred(struct work_struct *work) struct snd_soc_dai *dai = card->rtd[i].codec_dai; struct snd_soc_dai_driver *drv = dai->driver; - if (card->rtd[i].dai_link->ignore_suspend) + if (card->rtd[i].dai_link->ignore_suspend || + card->rtd[i].dai_link->no_pcm) continue; - if (drv->ops->digital_mute && dai->playback_active) - drv->ops->digital_mute(dai, 0); + if (card->rtd[i].dai_link->dynamic) + soc_dsp_be_digital_mute(&card->rtd[i], 0); + else { + if (drv->ops->digital_mute && dai->playback_active) + drv->ops->digital_mute(dai, 0); + } } for (i = 0; i < card->num_rtd; i++) { struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; struct snd_soc_platform *platform = card->rtd[i].platform; - if (card->rtd[i].dai_link->ignore_suspend) + if (card->rtd[i].dai_link->ignore_suspend || + card->rtd[i].dai_link->no_pcm) continue; - if (cpu_dai->driver->resume && !cpu_dai->driver->ac97_control) - cpu_dai->driver->resume(cpu_dai); - if (platform->driver->resume && platform->suspended) { - platform->driver->resume(cpu_dai); - platform->suspended = 0; + if (card->rtd[i].dai_link->dynamic) { + soc_dsp_fe_resume(&card->rtd[i]); + } else { + if (cpu_dai->driver->resume && !cpu_dai->driver->ac97_control) + cpu_dai->driver->resume(cpu_dai); + if (platform->driver->resume && platform->suspended) { + platform->driver->resume(cpu_dai); + platform->suspended = 0; + } } } @@ -1286,8 +1452,30 @@ EXPORT_SYMBOL_GPL(snd_soc_resume); #define snd_soc_resume NULL #endif +#define NULL_FORMATS \ + (SNDRV_PCM_FMTBIT_S16 | SNDRV_PCM_FMTBIT_U16 |\ + SNDRV_PCM_FMTBIT_S24 | SNDRV_PCM_FMTBIT_U24 |\ + SNDRV_PCM_FMTBIT_S32 | SNDRV_PCM_FMTBIT_U32) + static struct snd_soc_dai_ops null_dai_ops = { }; +static struct snd_soc_dai_driver null_codec_dai_drv = { + .name = "null-codec-dai", + .ops = &null_dai_ops, + .capture = { + .channels_min = 1 , + .channels_max = 16, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .formats = NULL_FORMATS, + }, + .playback = { + .channels_min = 1 , + .channels_max = 16, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .formats = NULL_FORMATS, + }, +}; +static struct snd_soc_codec_driver null_codec_drv = {}; static int soc_bind_dai_link(struct snd_soc_card *card, int num) { @@ -1329,7 +1517,7 @@ find_codec: /* CODEC found, so find CODEC DAI from registered DAIs from this CODEC*/ list_for_each_entry(codec_dai, &dai_list, list) { - if (codec->dev == codec_dai->dev && + if ((codec->dev == codec_dai->dev || codec->driver == &null_codec_drv) && !strcmp(codec_dai->name, dai_link->codec_dai_name)) { rtd->codec_dai = codec_dai; goto find_platform; @@ -1396,7 +1584,7 @@ static void soc_remove_codec(struct snd_soc_codec *codec) module_put(codec->dev->driver->owner); } -static void soc_remove_dai_link(struct snd_soc_card *card, int num) +static void soc_remove_dai_link(struct snd_soc_card *card, int num, int order) { struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; struct snd_soc_codec *codec = rtd->codec; @@ -1413,7 +1601,8 @@ static void soc_remove_dai_link(struct snd_soc_card *card, int num) } /* remove the CODEC DAI */ - if (codec_dai && codec_dai->probed) { + if (codec_dai && codec_dai->probed && + codec_dai->driver->remove_order == order) { if (codec_dai->driver->remove) { err = codec_dai->driver->remove(codec_dai); if (err < 0) @@ -1421,10 +1610,12 @@ static void soc_remove_dai_link(struct snd_soc_card *card, int num) } codec_dai->probed = 0; list_del(&codec_dai->card_list); + module_put(codec_dai->dev->driver->owner); } /* remove the platform */ - if (platform && platform->probed) { + if (platform && platform->probed && + platform->driver->remove_order == order) { if (platform->driver->remove) { err = platform->driver->remove(platform); if (err < 0) @@ -1436,11 +1627,13 @@ static void soc_remove_dai_link(struct snd_soc_card *card, int num) } /* remove the CODEC */ - if (codec && codec->probed) + if (codec && codec->probed && + codec->driver->remove_order == order) soc_remove_codec(codec); /* remove the cpu_dai */ - if (cpu_dai && cpu_dai->probed) { + if (cpu_dai && cpu_dai->probed && + cpu_dai->driver->remove_order == order) { if (cpu_dai->driver->remove) { err = cpu_dai->driver->remove(cpu_dai); if (err < 0) @@ -1454,11 +1647,13 @@ static void soc_remove_dai_link(struct snd_soc_card *card, int num) static void soc_remove_dai_links(struct snd_soc_card *card) { - int i; - - for (i = 0; i < card->num_rtd; i++) - soc_remove_dai_link(card, i); + int dai, order; + for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; + order++) { + for (dai = 0; dai < card->num_rtd; dai++) + soc_remove_dai_link(card, dai, order); + } card->num_rtd = 0; } @@ -1575,6 +1770,11 @@ static int soc_post_component_init(struct snd_soc_card *card, rtd->dev.parent = card->dev; rtd->dev.release = rtd_release; rtd->dev.init_name = name; + mutex_init(&rtd->pcm_mutex); + INIT_LIST_HEAD(&rtd->dsp[SNDRV_PCM_STREAM_PLAYBACK].be_clients); + INIT_LIST_HEAD(&rtd->dsp[SNDRV_PCM_STREAM_CAPTURE].be_clients); + INIT_LIST_HEAD(&rtd->dsp[SNDRV_PCM_STREAM_PLAYBACK].fe_clients); + INIT_LIST_HEAD(&rtd->dsp[SNDRV_PCM_STREAM_CAPTURE].fe_clients); ret = device_register(&rtd->dev); if (ret < 0) { dev_err(card->dev, @@ -1596,10 +1796,21 @@ static int soc_post_component_init(struct snd_soc_card *card, dev_err(codec->dev, "asoc: failed to add codec sysfs files: %d\n", ret); +#ifdef CONFIG_DEBUG_FS + /* add DSP sysfs entries */ + if (!dai_link->dynamic) + goto out; + + ret = soc_dsp_debugfs_add(rtd); + if (ret < 0) + dev_err(&rtd->dev, "asoc: failed to add dsp sysfs entries: %d\n", ret); + +out: +#endif return 0; } -static int soc_probe_dai_link(struct snd_soc_card *card, int num) +static int soc_probe_dai_link(struct snd_soc_card *card, int num, int order) { struct snd_soc_dai_link *dai_link = &card->dai_link[num]; struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; @@ -1608,19 +1819,22 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num) struct snd_soc_dai *codec_dai = rtd->codec_dai, *cpu_dai = rtd->cpu_dai; int ret; - dev_dbg(card->dev, "probe %s dai link %d\n", card->name, num); + dev_dbg(card->dev, "probe %s dai link %d late %d\n", + card->name, num, order); /* config components */ codec_dai->codec = codec; cpu_dai->platform = platform; codec_dai->card = card; cpu_dai->card = card; + codec->dapm.card = platform->dapm.card = card; /* set default power off timeout */ rtd->pmdown_time = pmdown_time; /* probe the cpu_dai */ - if (!cpu_dai->probed) { + if (!cpu_dai->probed && + cpu_dai->driver->probe_order == order) { if (!try_module_get(cpu_dai->dev->driver->owner)) return -ENODEV; @@ -1639,17 +1853,20 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num) } /* probe the CODEC */ - if (!codec->probed) { + if (!codec->probed && + codec->driver->probe_order == order) { ret = soc_probe_codec(card, codec); if (ret < 0) return ret; } /* probe the platform */ - if (!platform->probed) { + if (!platform->probed && + platform->driver->probe_order == order) { if (!try_module_get(platform->dev->driver->owner)) return -ENODEV; + platform->card = card; if (platform->driver->probe) { ret = platform->driver->probe(platform); if (ret < 0) { @@ -1665,12 +1882,15 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num) } /* probe the CODEC DAI */ - if (!codec_dai->probed) { + if (!codec_dai->probed && codec_dai->driver->probe_order == order) { + if (!try_module_get(codec_dai->dev->driver->owner)) + return -ENODEV; if (codec_dai->driver->probe) { ret = codec_dai->driver->probe(codec_dai); if (ret < 0) { printk(KERN_ERR "asoc: failed to probe CODEC DAI %s\n", codec_dai->name); + module_put(codec_dai->dev->driver->owner); return ret; } } @@ -1680,6 +1900,10 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num) list_add(&codec_dai->card_list, &card->dai_dev_list); } + /* complete DAI probe during last probe */ + if (order != SND_SOC_COMP_ORDER_LAST) + return 0; + /* DAPM dai link stream work */ INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work); @@ -1820,7 +2044,7 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card) struct snd_soc_codec *codec; struct snd_soc_codec_conf *codec_conf; enum snd_soc_compress_type compress_type; - int ret, i; + int ret, i, order; mutex_lock(&card->mutex); @@ -1876,6 +2100,7 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card) card->dapm.bias_level = SND_SOC_BIAS_OFF; card->dapm.dev = card->dev; card->dapm.card = card; + card->dapm.stream_event = card->stream_event; list_add(&card->dapm.list, &card->dapm_list); #ifdef CONFIG_DEBUG_FS @@ -1898,12 +2123,16 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card) goto card_probe_error; } - for (i = 0; i < card->num_links; i++) { - ret = soc_probe_dai_link(card, i); - if (ret < 0) { - pr_err("asoc: failed to instantiate card %s: %d\n", + /* early DAI link probe */ + for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; + order++) { + for (i = 0; i < card->num_links; i++) { + ret = soc_probe_dai_link(card, i, order); + if (ret < 0) { + pr_err("asoc: failed to instantiate card %s: %d\n", card->name, ret); - goto probe_dai_err; + goto probe_dai_err; + } } } @@ -2092,6 +2321,11 @@ int snd_soc_poweroff(struct device *dev) } EXPORT_SYMBOL_GPL(snd_soc_poweroff); +void soc_shutdown(struct platform_device *pdev) +{ + snd_soc_poweroff(&pdev->dev); +} + const struct dev_pm_ops snd_soc_pm_ops = { .suspend = snd_soc_suspend, .resume = snd_soc_resume, @@ -2108,6 +2342,7 @@ static struct platform_driver soc_driver = { }, .probe = soc_probe, .remove = soc_remove, + .shutdown = soc_shutdown, }; /* create a new pcm */ @@ -2117,6 +2352,7 @@ static int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) struct snd_soc_platform *platform = rtd->platform; struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_pcm_substream *substream[2]; struct snd_pcm *pcm; char new_name[64]; int ret = 0, playback = 0, capture = 0; @@ -2125,10 +2361,15 @@ static int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) snprintf(new_name, sizeof(new_name), "%s %s-%d", rtd->dai_link->stream_name, codec_dai->name, num); - if (codec_dai->driver->playback.channels_min) - playback = 1; - if (codec_dai->driver->capture.channels_min) - capture = 1; + if (rtd->dai_link->dynamic) { + playback = rtd->dai_link->dsp_link->playback; + capture = rtd->dai_link->dsp_link->capture; + } else { + if (codec_dai->driver->playback.channels_min) + playback = 1; + if (codec_dai->driver->capture.channels_min) + capture = 1; + } dev_dbg(rtd->card->dev, "registered pcm #%d %s\n",num,new_name); ret = snd_pcm_new(rtd->card->snd_card, new_name, @@ -2140,25 +2381,67 @@ static int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) rtd->pcm = pcm; pcm->private_data = rtd; + + substream[SNDRV_PCM_STREAM_PLAYBACK] = + pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; + substream[SNDRV_PCM_STREAM_CAPTURE] = + pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; + + if (rtd->dai_link->no_pcm) { + if (playback) + substream[SNDRV_PCM_STREAM_PLAYBACK]->private_data = rtd; + if (capture) + substream[SNDRV_PCM_STREAM_CAPTURE]->private_data = rtd; + goto out; + } + + /* setup any hostless PCMs - i.e. no host IO is performed */ + if (rtd->dai_link->no_host_mode) { + substream[SNDRV_PCM_STREAM_PLAYBACK]->hw_no_buffer = 1; + substream[SNDRV_PCM_STREAM_CAPTURE]->hw_no_buffer = 1; + snd_soc_set_runtime_hwparams(substream[SNDRV_PCM_STREAM_PLAYBACK], + &no_host_hardware); + snd_soc_set_runtime_hwparams(substream[SNDRV_PCM_STREAM_CAPTURE], + &no_host_hardware); + } + + /* ASoC PCM operations */ + if (rtd->dai_link->dynamic) { + rtd->ops.open = soc_dsp_fe_dai_open; + rtd->ops.hw_params = soc_dsp_fe_dai_hw_params; + rtd->ops.prepare = soc_dsp_fe_dai_prepare; + rtd->ops.trigger = soc_dsp_fe_dai_trigger; + rtd->ops.hw_free = soc_dsp_fe_dai_hw_free; + rtd->ops.close = soc_dsp_fe_dai_close; + rtd->ops.pointer = soc_pcm_pointer; + rtd->ops.ioctl = soc_pcm_ioctl; + } else { + rtd->ops.open = soc_pcm_open; + rtd->ops.hw_params = soc_pcm_hw_params; + rtd->ops.prepare = soc_pcm_prepare; + rtd->ops.trigger = soc_pcm_trigger; + rtd->ops.hw_free = soc_pcm_hw_free; + rtd->ops.close = soc_pcm_close; + rtd->ops.pointer = soc_pcm_pointer; + rtd->ops.ioctl = soc_pcm_ioctl; + } + if (platform->driver->ops) { - soc_pcm_ops.mmap = platform->driver->ops->mmap; - soc_pcm_ops.pointer = platform->driver->ops->pointer; - soc_pcm_ops.ioctl = platform->driver->ops->ioctl; - soc_pcm_ops.copy = platform->driver->ops->copy; - soc_pcm_ops.silence = platform->driver->ops->silence; - soc_pcm_ops.ack = platform->driver->ops->ack; - soc_pcm_ops.page = platform->driver->ops->page; + rtd->ops.ack = platform->driver->ops->ack; + rtd->ops.copy = platform->driver->ops->copy; + rtd->ops.silence = platform->driver->ops->silence; + rtd->ops.page = platform->driver->ops->page; + rtd->ops.mmap = platform->driver->ops->mmap; } if (playback) - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &soc_pcm_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &rtd->ops); if (capture) - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &soc_pcm_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &rtd->ops); if (platform->driver->pcm_new) { - ret = platform->driver->pcm_new(rtd->card->snd_card, - codec_dai, pcm); + ret = platform->driver->pcm_new(rtd); if (ret < 0) { pr_err("asoc: platform pcm constructor failed\n"); return ret; @@ -2166,6 +2449,7 @@ static int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) } pcm->private_free = platform->driver->pcm_free; +out: printk(KERN_INFO "asoc: %s <-> %s mapping ok\n", codec_dai->name, cpu_dai->name); return ret; @@ -2189,6 +2473,28 @@ int snd_soc_codec_volatile_register(struct snd_soc_codec *codec, } EXPORT_SYMBOL_GPL(snd_soc_codec_volatile_register); +unsigned int snd_soc_platform_read(struct snd_soc_platform *platform, + unsigned int reg) +{ + unsigned int ret; + + 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; +} +EXPORT_SYMBOL_GPL(snd_soc_platform_read); + +unsigned int snd_soc_platform_write(struct snd_soc_platform *platform, + unsigned int reg, unsigned int val) +{ + 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); + /** * snd_soc_codec_readable_register: Report if a register is readable. * @@ -2411,6 +2717,8 @@ int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream, const struct snd_pcm_hardware *hw) { struct snd_pcm_runtime *runtime = substream->runtime; + if (!runtime) + return 0; runtime->hw.info = hw->info; runtime->hw.formats = hw->formats; runtime->hw.period_bytes_min = hw->period_bytes_min; @@ -2504,6 +2812,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 * @uinfo: control element information @@ -2525,7 +2863,8 @@ int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol, if (uinfo->value.enumerated.item > e->max - 1) uinfo->value.enumerated.item = e->max - 1; strcpy(uinfo->value.enumerated.name, - e->texts[uinfo->value.enumerated.item]); + snd_soc_get_enum_text(e, uinfo->value.enumerated.item)); + return 0; } EXPORT_SYMBOL_GPL(snd_soc_info_enum_double); @@ -2689,7 +3028,7 @@ int snd_soc_info_enum_ext(struct snd_kcontrol *kcontrol, if (uinfo->value.enumerated.item > e->max - 1) uinfo->value.enumerated.item = e->max - 1; strcpy(uinfo->value.enumerated.name, - e->texts[uinfo->value.enumerated.item]); + snd_soc_get_enum_text(e, uinfo->value.enumerated.item)); return 0; } EXPORT_SYMBOL_GPL(snd_soc_info_enum_ext); @@ -3370,6 +3709,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute); int snd_soc_register_card(struct snd_soc_card *card) { int i; + int ret = 0; if (!card->name || !card->dev) return -EINVAL; @@ -3387,12 +3727,43 @@ int snd_soc_register_card(struct snd_soc_card *card) return -ENOMEM; card->rtd_aux = &card->rtd[card->num_links]; - for (i = 0; i < card->num_links; i++) + for (i = 0; i < card->num_links; i++) { card->rtd[i].dai_link = &card->dai_link[i]; + if (card->rtd[i].dai_link->dynamic) { + + card->rtd[i].dai_link->codec_name = "null-codec"; + card->rtd[i].dai_link->codec_dai_name = "null-codec-dai"; + + ret = snd_soc_register_codec(card->dev, &null_codec_drv, + &null_codec_dai_drv, 1); + if (ret < 0) { + printk(KERN_ERR "%s: failed to register dynamic DAI link %d\n", + __func__, ret); + goto out; + } + + continue; + } + if (card->rtd[i].dai_link->no_codec) { + card->rtd[i].dai_link->codec_name = "null-codec"; + + ret = snd_soc_register_codec(card->dev, &null_codec_drv, + &null_codec_dai_drv, 1); + if (ret < 0) { + printk(KERN_ERR "%s: failed to register dynamic DAI link %d\n", + __func__, ret); + goto out; + } + continue; + } + } INIT_LIST_HEAD(&card->list); card->instantiated = 0; mutex_init(&card->mutex); + mutex_init(&card->dapm_mutex); + mutex_init(&card->dsp_mutex); + mutex_init(&card->power_mutex); mutex_lock(&client_mutex); list_add(&card->list, &card_list); @@ -3401,7 +3772,8 @@ int snd_soc_register_card(struct snd_soc_card *card) dev_dbg(card->dev, "Registered card '%s'\n", card->name); - return 0; +out: + return ret; } EXPORT_SYMBOL_GPL(snd_soc_register_card); @@ -3646,7 +4018,10 @@ int snd_soc_register_platform(struct device *dev, } platform->dev = dev; + platform->dapm.platform = platform; platform->driver = platform_drv; + platform->dapm.dev = dev; + platform->dapm.stream_event = platform_drv->stream_event; mutex_lock(&client_mutex); list_add(&platform->list, &platform_list); @@ -3739,7 +4114,10 @@ int snd_soc_register_codec(struct device *dev, return -ENOMEM; /* create CODEC component name */ - codec->name = fmt_single_name(dev, &codec->id); + if (codec_drv == &null_codec_drv) + codec->name = kstrdup("null-codec", GFP_KERNEL); + else + codec->name = fmt_single_name(dev, &codec->id); if (codec->name == NULL) { kfree(codec); return -ENOMEM; @@ -3759,6 +4137,7 @@ int snd_soc_register_codec(struct device *dev, codec->dapm.dev = dev; codec->dapm.codec = codec; codec->dapm.seq_notifier = codec_drv->seq_notifier; + codec->dapm.stream_event = codec_drv->stream_event; codec->dev = dev; codec->driver = codec_drv; codec->num_dai = num_dai; diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 0c9dee2..042d4ae 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -48,6 +48,10 @@ #include <trace/events/asoc.h> +#define PATH_MAX_HOPS 16 + +int soc_dsp_runtime_update(struct snd_soc_dapm_widget *); + /* dapm power sequences - make this per codec in the future */ static int dapm_up_seq[] = { [snd_soc_dapm_pre] = 0, @@ -126,6 +130,390 @@ static inline struct snd_soc_dapm_widget *dapm_cnew_widget( return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL); } +static inline struct snd_card *dapm_get_card(struct snd_soc_dapm_context *dapm) +{ + if (dapm->codec) + return dapm->codec->card->snd_card; + else if (dapm->platform) + return dapm->platform->card->snd_card; + else + BUG(); +} + +static inline struct snd_soc_card *dapm_get_soc_card( + struct snd_soc_dapm_context *dapm) +{ + if (dapm->codec) + return dapm->codec->card; + else if (dapm->platform) + return dapm->platform->card; + else + BUG(); +} + +static int soc_widget_read(struct snd_soc_dapm_widget *w, int reg) +{ + if (w->codec) + return snd_soc_read(w->codec, reg); + else if (w->platform) + return snd_soc_platform_read(w->platform, reg); + return 0; +} + +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); + else if (w->platform) + return snd_soc_platform_write(w->platform, reg, val); + return 0; +} + +int soc_widget_update_bits(struct snd_soc_dapm_widget *w, unsigned short reg, + unsigned int mask, unsigned int value) +{ + int change; + unsigned int old, new; + + old = soc_widget_read(w, reg); + new = (old & ~mask) | value; + change = old != new; + if (change) + soc_widget_write(w, reg, new); + + return change; +} + +int soc_widget_test_bits(struct snd_soc_dapm_widget *w, unsigned short reg, + unsigned int mask, unsigned int value) +{ + int change; + unsigned int old, new; + + old = soc_widget_read(w, reg); + new = (old & ~mask) | value; + change = old != new; + + return change; +} + +/* reset 'walked' bit for each dapm path */ +static inline void dapm_clear_walk(struct snd_soc_dapm_context *dapm) +{ + struct snd_soc_dapm_path *p; + + list_for_each_entry(p, &dapm->card->paths, list) + p->walked = 0; +} + +static void dapm_clear_paths(struct snd_soc_dapm_context *dapm) +{ + struct snd_soc_dapm_path *p; + struct snd_soc_dapm_widget *w; + struct list_head *l; + + list_for_each(l, &dapm->card->paths) { + p = list_entry(l, struct snd_soc_dapm_path, list); + p->length = 0; + } + list_for_each(l, &dapm->card->widgets) { + w = list_entry(l, struct snd_soc_dapm_widget, list); + w->hops = 0; + } + dapm_clear_walk(dapm); +} + +static int dapm_add_unique_widget(struct snd_soc_dapm_context *dapm, + struct snd_soc_dapm_widget_list **list, struct snd_soc_dapm_widget *w) +{ + struct snd_soc_dapm_widget_list *wlist; + int wlistsize, wlistentries, i; + + /* is the list empty ? */ + if (*list == NULL) { + + wlistsize = sizeof(struct snd_soc_dapm_widget_list) + + sizeof(struct snd_soc_dapm_widget *); + *list = kzalloc(wlistsize, GFP_KERNEL); + if (*list == NULL) { + dev_err(dapm->dev, "can't allocate widget list for %s\n", w->name); + return -ENOMEM; + } + } else { + + wlist = *list; + /* is this widget already in the list */ + for (i = 0; i < wlist->num_widgets; i++) { + if (wlist->widgets[i] == w) + return 0; + } + + wlistentries = wlist->num_widgets + 1; + wlistsize = sizeof(struct snd_soc_dapm_widget_list) + + wlistentries * sizeof(struct snd_soc_dapm_widget *); + *list = krealloc(wlist, wlistsize, GFP_KERNEL); + if (*list == NULL) { + dev_err(dapm->dev, "can't allocate widget list for %s\n", w->name); + return -ENOMEM; + } + } + wlist = *list; + + /* insert the widget */ + dev_dbg(dapm->dev, "added %s in widget list pos %d\n", + w->name, wlist->num_widgets); + wlist->widgets[wlist->num_widgets] = w; + wlist->num_widgets++; + return 1; +} + +static int is_output_widget_ep(struct snd_soc_dapm_widget *widget) +{ + switch (widget->id) { + case snd_soc_dapm_adc: + case snd_soc_dapm_aif_out: + return 1; + case snd_soc_dapm_output: + if (widget->connected && !widget->ext) + return 1; + else + return 0; + case snd_soc_dapm_hp: + case snd_soc_dapm_spk: + case snd_soc_dapm_line: + return !list_empty(&widget->sources); + default: + return 0; + } +} + +static int is_input_widget_ep(struct snd_soc_dapm_widget *widget) +{ + switch (widget->id) { + case snd_soc_dapm_dac: + case snd_soc_dapm_aif_in: + return 1; + case snd_soc_dapm_input: + if (widget->connected && !widget->ext) + return 1; + else + return 0; + case snd_soc_dapm_mic: + return !list_empty(&widget->sources); + default: + return 0; + } +} + +/* + * find all the paths between source and sink + */ +static int dapm_find_playback_paths(struct snd_soc_dapm_context *dapm, + struct snd_soc_dapm_widget *root, + struct snd_soc_dapm_widget_list **list, int hops) +{ + struct list_head *lp; + struct snd_soc_dapm_path *path; + int dist = 0; + + if (hops > PATH_MAX_HOPS) + return 0; + + if (is_output_widget_ep(root) && hops != 1) { + dev_dbg(dapm->dev," ! %d: valid playback route found\n", hops); + dapm->num_valid_paths++; + return 1; + } + + if (root->hops && root->hops <= hops) + return 0; + root->hops = hops; + + /* check all the output paths on this source widget by walking + * from source to sink */ + list_for_each(lp, &root->sinks) { + path = list_entry(lp, struct snd_soc_dapm_path, list_source); + + dev_dbg(dapm->dev," %c %d: %s -> %s -> %s\n", + path->connect ? '*' : ' ', hops, + root->name, path->name, path->sink->name); + + /* been here before ? */ + if (path->length && path->length <= hops) + continue; + + /* check down the next path if connected */ + if (path->sink && path->connect && + dapm_find_playback_paths(dapm, path->sink, list, hops + 1)) { + path->length = hops; + + /* add widget to list */ + dapm_add_unique_widget(dapm, list, path->sink); + + if (!dist || dist > path->length) + dist = path->length; + } + } + + return dist; +} + +static int dapm_find_capture_paths(struct snd_soc_dapm_context *dapm, + struct snd_soc_dapm_widget *root, + struct snd_soc_dapm_widget_list **list, int hops) +{ + struct list_head *lp; + struct snd_soc_dapm_path *path; + int dist = 0; + + if (hops > PATH_MAX_HOPS) + return 0; + + if (is_input_widget_ep(root) && hops != 1) { + dev_dbg(dapm->dev," ! %d: valid capture route found\n", hops); + dapm->num_valid_paths++; + return 1; + } + + if (root->hops && root->hops <= hops) + return 0; + root->hops = hops; + + /* check all the output paths on this source widget by walking from + * sink to source */ + list_for_each(lp, &root->sources) { + path = list_entry(lp, struct snd_soc_dapm_path, list_sink); + + dev_dbg(dapm->dev," %c %d: %s <- %s <- %s\n", + path->connect ? '*' : ' ', hops, + root->name, path->name, path->source->name); + + /* been here before ? */ + if (path->length && path->length <= hops) + continue; + + /* check down the next path if connected */ + if (path->source && path->connect && + dapm_find_capture_paths(dapm, path->source, list, hops + 1)) { + path->length = hops; + + /* add widget to list */ + dapm_add_unique_widget(dapm, list, path->source); + + if (!dist || dist > path->length) + dist = path->length; + } + } + + return dist; +} + +/* + * traverse the tree from sink to source via the shortest path + */ +static int dapm_get_playback_paths(struct snd_soc_dapm_context *dapm, + struct snd_soc_dapm_widget *root, + struct snd_soc_dapm_widget_list **list) +{ + dev_dbg(dapm->dev, "Playback: checking paths from %s\n",root->name); + dapm_find_playback_paths(dapm, root, list, 1); + return dapm->num_valid_paths; +} + +static int dapm_get_capture_paths(struct snd_soc_dapm_context *dapm, + struct snd_soc_dapm_widget *root, + struct snd_soc_dapm_widget_list **list) +{ + dev_dbg(dapm->dev, "Capture: checking paths to %s\n", root->name); + dapm_find_capture_paths(dapm, root, list, 1); + return dapm->num_valid_paths; +} + +/** + * snd_soc_dapm_get_connected_widgets_type - query audio path and it's widgets. + * @dapm: the dapm context. + * @stream_name: stream name. + * @list: list of active widgets for this stream. + * @stream: stream direction. + * @type: Initial widget type. + * + * Queries DAPM graph as to whether an valid audio stream path exists for + * the DAPM stream and initial widget type specified. This takes into account + * current mixer and mux kcontrol settings. Creates list of valid widgets. + * + * Returns the number of valid paths or negative error. + */ +int snd_soc_dapm_get_connected_widgets_type(struct snd_soc_dapm_context *dapm, + const char *stream_name, struct snd_soc_dapm_widget_list **list, + int stream, enum snd_soc_dapm_type type) +{ + struct snd_soc_dapm_widget *w; + int paths; + + /* get stream root widget AIF, DAC or ADC from stream string and direction */ + list_for_each_entry(w, &dapm->card->widgets, list) { + + if (!w->sname) + continue; + + if (w->id != type) + continue; + + if (strstr(w->sname, stream_name)) + goto found; + } + dev_err(dapm->dev, "root widget not found\n"); + return 0; + +found: + dapm->num_valid_paths = 0; + *list = NULL; + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + paths = dapm_get_playback_paths(dapm, w, list); + else + paths = dapm_get_capture_paths(dapm, w, list); + + dapm_clear_paths(dapm); + return paths; +} +/** + * snd_soc_dapm_get_connected_widgets_name - query audio path and it's widgets. + * @dapm: the dapm context. + * @name: initial widget name. + * @list: list of active widgets for this stream. + * @stream: stream direction. + * + * Queries DAPM graph as to whether an valid audio stream path exists for + * the initial widget specified by name. This takes into account + * current mixer and mux kcontrol settings. Creates list of valid widgets. + * + * Returns the number of valid paths or negative error. + */ +int snd_soc_dapm_get_connected_widgets_name(struct snd_soc_dapm_context *dapm, + const char *name, struct snd_soc_dapm_widget_list **list, int stream) +{ + struct snd_soc_dapm_widget *w; + int paths; + + /* get stream root widget AIF, DAC or ADC from stream string and direction */ + list_for_each_entry(w, &dapm->card->widgets, list) { + + if (strstr(w->name, name)) + goto found; + } + dev_err(dapm->dev, "root widget %s not found\n", name); + return 0; + +found: + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + paths = dapm_get_playback_paths(dapm, w, list); + else + paths = dapm_get_capture_paths(dapm, w, list); + + dapm_clear_paths(dapm); + return paths; +} + /** * snd_soc_dapm_set_bias_level - set the bias level for the system * @dapm: DAPM context @@ -196,7 +584,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, unsigned int mask = (1 << fls(max)) - 1; unsigned int invert = mc->invert; - val = snd_soc_read(w->codec, reg); + val = soc_widget_read(w, reg); val = (val >> shift) & mask; if ((invert && !val) || (!invert && val)) @@ -212,12 +600,12 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, for (bitmask = 1; bitmask < e->max; bitmask <<= 1) ; - val = snd_soc_read(w->codec, e->reg); + val = soc_widget_read(w, e->reg); item = (val >> e->shift_l) & (bitmask - 1); p->connect = 0; for (i = 0; i < e->max; i++) { - if (!(strcmp(p->name, e->texts[i])) && item == i) + if (!(strcmp(p->name, snd_soc_get_enum_text(e, i))) && item == i) p->connect = 1; } } @@ -233,7 +621,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, * that the default mux choice (the first) will be * correctly powered up during initialization. */ - if (!strcmp(p->name, e->texts[0])) + if (!strcmp(p->name, snd_soc_get_enum_text(e, 0))) p->connect = 1; } break; @@ -242,7 +630,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, w->kcontrol_news[i].private_value; int val, item; - val = snd_soc_read(w->codec, e->reg); + val = soc_widget_read(w, e->reg); val = (val >> e->shift_l) & e->mask; for (item = 0; item < e->max; item++) { if (val == e->values[item]) @@ -251,7 +639,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, p->connect = 0; for (i = 0; i < e->max; i++) { - if (!(strcmp(p->name, e->texts[i])) && item == i) + if (!(strcmp(p->name, snd_soc_get_enum_text(e, i))) && item == i) p->connect = 1; } } @@ -292,11 +680,11 @@ static int dapm_connect_mux(struct snd_soc_dapm_context *dapm, int i; for (i = 0; i < e->max; i++) { - if (!(strcmp(control_name, e->texts[i]))) { + if (!(strcmp(control_name, snd_soc_get_enum_text(e, i)))) { list_add(&path->list, &dapm->card->paths); list_add(&path->list_sink, &dest->sources); list_add(&path->list_source, &src->sinks); - path->name = (char*)e->texts[i]; + path->name = (char*)snd_soc_get_enum_text(e, i); dapm_set_path_status(dest, path, 0); return 0; } @@ -494,7 +882,7 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w) wlist->widgets[wlistentries - 1] = w; if (!kcontrol) { - if (dapm->codec) + if (dapm->codec && dapm->codec->name_prefix) prefix = dapm->codec->name_prefix; else prefix = NULL; @@ -516,7 +904,7 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w) * cut the prefix off the front of the widget name. */ kcontrol = snd_soc_cnew(&w->kcontrol_news[0], wlist, - name + prefix_len, prefix); + name, prefix); ret = snd_ctl_add(card, kcontrol); if (ret < 0) { dev_err(dapm->dev, @@ -546,15 +934,6 @@ static int dapm_new_pga(struct snd_soc_dapm_widget *w) return 0; } -/* reset 'walked' bit for each dapm path */ -static inline void dapm_clear_walk(struct snd_soc_dapm_context *dapm) -{ - struct snd_soc_dapm_path *p; - - list_for_each_entry(p, &dapm->card->paths, list) - p->walked = 0; -} - /* We implement power down on suspend by checking the power state of * the ALSA card - when we are suspending the ALSA state for the card * is set to D3. @@ -683,7 +1062,7 @@ int dapm_reg_event(struct snd_soc_dapm_widget *w, else val = w->off_val; - snd_soc_update_bits(w->codec, -(w->reg + 1), + soc_widget_update_bits(w, -(w->reg + 1), w->mask << w->shift, val << w->shift); return 0; @@ -855,14 +1234,15 @@ static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm, struct list_head *pending) { struct snd_soc_card *card = dapm->card; - struct snd_soc_dapm_widget *w; + struct snd_soc_dapm_widget *w, *_w; int reg, power; unsigned int value = 0; unsigned int mask = 0; unsigned int cur_mask; - reg = list_first_entry(pending, struct snd_soc_dapm_widget, - power_list)->reg; + _w = list_first_entry(pending, struct snd_soc_dapm_widget, + power_list); + reg = _w->reg; list_for_each_entry(w, pending, power_list) { cur_mask = 1 << w->shift; @@ -887,11 +1267,17 @@ static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm, } if (reg >= 0) { + /* Any widget will do, they should all be updating the + * same register. + */ + w = list_first_entry(pending, struct snd_soc_dapm_widget, + power_list); + pop_dbg(dapm->dev, card->pop_time, "pop test : Applying 0x%x/0x%x to %x in %dms\n", value, mask, reg, card->pop_time); pop_wait(card->pop_time); - snd_soc_update_bits(dapm->codec, reg, mask, value); + soc_widget_update_bits(_w, reg, mask, value); } list_for_each_entry(w, pending, power_list) { @@ -1114,12 +1500,14 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) trace_snd_soc_dapm_start(card); list_for_each_entry(d, &card->dapm_list, list) - if (d->n_widgets || d->codec == NULL) + if (d->n_widgets || d->codec == NULL || + strstr(d->codec->name, "null-codec")) d->dev_power = 0; /* Check which widgets we need to power and store them in * lists indicating if they should be powered up or down. */ + mutex_lock(&card->power_mutex); list_for_each_entry(w, &card->widgets, list) { switch (w->id) { case snd_soc_dapm_pre: @@ -1165,7 +1553,11 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) dapm->dev_power = 1; break; case SND_SOC_DAPM_STREAM_STOP: - dapm->dev_power = !!dapm->codec->active; +#warning need re-work + if (dapm->codec) + dapm->dev_power = !!dapm->codec->active; + else + dapm->dev_power = 0; break; case SND_SOC_DAPM_STREAM_SUSPEND: dapm->dev_power = 0; @@ -1221,6 +1613,8 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) trace_snd_soc_dapm_done(card); + mutex_unlock(&card->power_mutex); + return 0; } @@ -1399,7 +1793,7 @@ static inline void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm) #endif /* test and update the power status of a mux widget */ -static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, +int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget, struct snd_kcontrol *kcontrol, int change, int mux, struct soc_enum *e) { @@ -1416,29 +1810,33 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, /* find dapm widget path assoc with kcontrol */ list_for_each_entry(path, &widget->dapm->card->paths, list) { + if (path->kcontrol != kcontrol) continue; - if (!path->name || !e->texts[mux]) + if (!path->name || !snd_soc_get_enum_text(e, mux)) continue; found = 1; /* we now need to match the string in the enum to the path */ - if (!(strcmp(path->name, e->texts[mux]))) + if (!(strcmp(path->name, snd_soc_get_enum_text(e, mux)))) path->connect = 1; /* new connection */ else path->connect = 0; /* old connection must be powered down */ } - if (found) + if (found) { dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP); + soc_dsp_runtime_update(widget); + } return 0; } +EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power); /* test and update the power status of a mixer or switch widget */ -static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, - struct snd_kcontrol *kcontrol, int connect) +int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, + struct snd_kcontrol *kcontrol, int connect) { struct snd_soc_dapm_path *path; int found = 0; @@ -1459,26 +1857,25 @@ static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, break; } - if (found) + if (found) { dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP); + soc_dsp_runtime_update(widget); + } return 0; } +EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power); /* show dapm widget status in sys fs */ -static ssize_t dapm_widget_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t widget_show(struct snd_soc_dapm_context *dapm, + const char *name, char *buf, ssize_t count) { - struct snd_soc_pcm_runtime *rtd = - container_of(dev, struct snd_soc_pcm_runtime, dev); - struct snd_soc_codec *codec =rtd->codec; struct snd_soc_dapm_widget *w; - int count = 0; char *state = "not set"; - list_for_each_entry(w, &codec->card->widgets, list) { - if (w->dapm != &codec->dapm) - continue; + count += sprintf(buf + count, "\n%s\n", name); + + list_for_each_entry(w, &dapm->card->widgets, list) { /* only display widgets that burnm power */ switch (w->id) { @@ -1503,7 +1900,7 @@ static ssize_t dapm_widget_show(struct device *dev, } } - switch (codec->dapm.bias_level) { + switch (dapm->bias_level) { case SND_SOC_BIAS_ON: state = "On"; break; @@ -1522,6 +1919,21 @@ static ssize_t dapm_widget_show(struct device *dev, return count; } +/* show dapm widget status in sys fs */ +static ssize_t dapm_widget_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct snd_soc_pcm_runtime *rtd = + container_of(dev, struct snd_soc_pcm_runtime, dev); + struct snd_soc_codec *codec = rtd->codec; + struct snd_soc_platform *platform = rtd->platform; + ssize_t count = 0; + + count += widget_show(&codec->dapm, codec->name, buf, count); + count += widget_show(&platform->dapm, platform->name, buf, count); + return count; +} + static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL); int snd_soc_dapm_sys_add(struct device *dev) @@ -1867,7 +2279,7 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm) /* Read the initial power state from the device */ if (w->reg >= 0) { - val = snd_soc_read(w->codec, w->reg); + val = soc_widget_read(w, w->reg); val &= 1 << w->shift; if (w->invert) val = !val; @@ -1886,6 +2298,24 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm) } EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets); +const char *snd_soc_dapm_get_aif(struct snd_soc_dapm_context *dapm, + const char *stream_name, enum snd_soc_dapm_type type) +{ + struct snd_soc_dapm_widget *w; + + list_for_each_entry(w, &dapm->card->widgets, list) { + + if (!w->sname) + continue; + + if (w->id == type && strstr(w->sname, stream_name)) + return w->name; + + } + return NULL; +} +EXPORT_SYMBOL_GPL(snd_soc_dapm_get_aif); + /** * snd_soc_dapm_get_volsw - dapm mixer get callback * @kcontrol: mixer control @@ -1983,7 +2413,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, update.val = val; widget->dapm->update = &update; - dapm_mixer_update_power(widget, kcontrol, connect); + snd_soc_dapm_mixer_update_power(widget, kcontrol, connect); widget->dapm->update = NULL; } @@ -2074,7 +2504,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, update.val = val; widget->dapm->update = &update; - dapm_mux_update_power(widget, kcontrol, change, mux, e); + snd_soc_dapm_mux_update_power(widget, kcontrol, change, mux, e); widget->dapm->update = NULL; } @@ -2135,8 +2565,8 @@ int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol, widget->value = ucontrol->value.enumerated.item[0]; - dapm_mux_update_power(widget, kcontrol, change, - widget->value, e); + snd_soc_dapm_mux_update_power(widget, kcontrol, change, + widget->value, e); } } @@ -2239,7 +2669,7 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, update.val = val; widget->dapm->update = &update; - dapm_mux_update_power(widget, kcontrol, change, mux, e); + snd_soc_dapm_mux_update_power(widget, kcontrol, change, mux, e); widget->dapm->update = NULL; } @@ -2355,6 +2785,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); @@ -2401,6 +2832,9 @@ static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm, { struct snd_soc_dapm_widget *w; + if (!dapm) + return; + list_for_each_entry(w, &dapm->card->widgets, list) { if (!w->sname || w->dapm != dapm) @@ -2425,8 +2859,41 @@ static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm, } dapm_power_widgets(dapm, event); + /* do we need to notify any clients that DAPM stream is complete */ + if (dapm->stream_event) + dapm->stream_event(dapm); +} + +static void soc_dapm_platform_stream_event(struct snd_soc_platform *platform, + const char *stream, int event) +{ + soc_dapm_stream_event(&platform->dapm, stream, event); } +static void soc_dapm_codec_stream_event(struct snd_soc_codec *codec, + const char *stream, int event) +{ + soc_dapm_stream_event(&codec->dapm, stream, event); +} + +void snd_soc_dapm_platform_stream_event(struct snd_soc_platform *platform, + const char *stream, int event) +{ + mutex_lock(&platform->card->dapm_mutex); + soc_dapm_platform_stream_event(platform, stream, event); + mutex_unlock(&platform->card->dapm_mutex); +} +EXPORT_SYMBOL(snd_soc_dapm_platform_stream_event); + +void snd_soc_dapm_codec_stream_event(struct snd_soc_codec *codec, + const char *stream, int event) +{ + mutex_lock(&codec->card->dapm_mutex); + soc_dapm_codec_stream_event(codec, stream, event); + mutex_unlock(&codec->card->dapm_mutex); +} +EXPORT_SYMBOL(snd_soc_dapm_codec_stream_event); + /** * snd_soc_dapm_stream_event - send a stream event to the dapm core * @rtd: PCM runtime data @@ -2441,14 +2908,16 @@ static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm, int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, const char *stream, int event) { - struct snd_soc_codec *codec = rtd->codec; - if (stream == NULL) return 0; - mutex_lock(&codec->mutex); - soc_dapm_stream_event(&codec->dapm, stream, event); - mutex_unlock(&codec->mutex); + mutex_lock(&rtd->card->dapm_mutex); + + soc_dapm_platform_stream_event(rtd->platform, stream, event); + soc_dapm_codec_stream_event(rtd->codec, stream, event); + soc_dapm_stream_event(&rtd->card->dapm, stream, event); + + mutex_unlock(&rtd->card->dapm_mutex); return 0; } @@ -2556,6 +3025,27 @@ int snd_soc_dapm_get_pin_status(struct snd_soc_dapm_context *dapm, EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_status); /** + * snd_soc_dapm_get_pin_power - get audio pin power state + * @dapm: DAPM context + * @pin: audio signal pin endpoint (or start point) + * + * Get audio pin power state - powered or not-powered. + * + * Returns 1 if powered, otherwise 0. + */ +int snd_soc_dapm_get_pin_power(struct snd_soc_dapm_context *dapm, + const char *pin) +{ + struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true); + + if (w) + return w->power; + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_power); + +/** * snd_soc_dapm_ignore_suspend - ignore suspend status for DAPM endpoint * @dapm: DAPM context * @pin: audio signal pin endpoint (or start point) @@ -2633,6 +3123,7 @@ static void soc_dapm_shutdown_codec(struct snd_soc_dapm_context *dapm) void snd_soc_dapm_shutdown(struct snd_soc_card *card) { struct snd_soc_codec *codec; + struct snd_soc_platform *platform; list_for_each_entry(codec, &card->codec_dev_list, card_list) { soc_dapm_shutdown_codec(&codec->dapm); @@ -2640,6 +3131,11 @@ void snd_soc_dapm_shutdown(struct snd_soc_card *card) snd_soc_dapm_set_bias_level(&codec->dapm, SND_SOC_BIAS_OFF); } + + list_for_each_entry(platform, &card->platform_dev_list, card_list) { + soc_dapm_shutdown_codec(&platform->dapm); + snd_soc_dapm_set_bias_level(&platform->dapm, SND_SOC_BIAS_OFF); + } } /* Module information */ diff --git a/sound/soc/soc-dsp.c b/sound/soc/soc-dsp.c new file mode 100644 index 0000000..199b428 --- /dev/null +++ b/sound/soc/soc-dsp.c @@ -0,0 +1,1737 @@ +/* + * soc-dsp.c -- ALSA SoC Audio DSP + * + * Copyright (C) 2010 Texas Instruments Inc. + * + * Author: Liam Girdwood <lrg@slimlogic.co.uk> + * + * 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. + * + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/bitops.h> +#include <linux/debugfs.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <sound/ac97_codec.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <sound/soc-dsp.h> + +int soc_pcm_open(struct snd_pcm_substream *); +void soc_pcm_close(struct snd_pcm_substream *); +int soc_pcm_hw_params(struct snd_pcm_substream *, struct snd_pcm_hw_params *); +int soc_pcm_hw_free(struct snd_pcm_substream *); +int soc_pcm_prepare(struct snd_pcm_substream *); +int soc_pcm_trigger(struct snd_pcm_substream *, int); +int soc_pcm_bespoke_trigger(struct snd_pcm_substream *, int); + +/* count the number of FE clients in a particular state */ +int soc_dsp_fe_state_count(struct snd_soc_pcm_runtime *be, int stream, + enum snd_soc_dsp_state state) +{ + struct snd_soc_dsp_params *dsp_params; + int count = 0; + + list_for_each_entry(dsp_params, &be->dsp[stream].fe_clients, list_fe) { + if (dsp_params->fe->dsp[stream].state == state) + count++; + } + + return count; +} +EXPORT_SYMBOL(soc_dsp_fe_state_count); + +static inline int be_connect(struct snd_soc_pcm_runtime *fe, + struct snd_soc_pcm_runtime *be, int stream) +{ + struct snd_soc_dsp_params *dsp_params; + + /* only add new dsp_paramss */ + list_for_each_entry(dsp_params, &fe->dsp[stream].be_clients, list_be) { + if (dsp_params->be == be && dsp_params->fe == fe) + return 0; + } + + dsp_params = kzalloc(sizeof(struct snd_soc_dsp_params), GFP_KERNEL); + if (!dsp_params) + return -ENOMEM; + + dsp_params->be = be; + dsp_params->fe = fe; + be->dsp[stream].runtime = fe->dsp[stream].runtime; + dsp_params->state = SND_SOC_DSP_LINK_STATE_NEW; + list_add(&dsp_params->list_be, &fe->dsp[stream].be_clients); + list_add(&dsp_params->list_fe, &be->dsp[stream].fe_clients); + + dev_dbg(&fe->dev, " connected new DSP %s path %s %s %s\n", + stream ? "capture" : "playback", fe->dai_link->name, + stream ? "<-" : "->", be->dai_link->name); + +#ifdef CONFIG_DEBUG_FS + dsp_params->debugfs_state = debugfs_create_u32(be->dai_link->name, 0644, + fe->debugfs_dsp_root, &dsp_params->state); +#endif + + return 1; +} + +static inline void be_reparent(struct snd_soc_pcm_runtime *fe, + struct snd_soc_pcm_runtime *be, int stream) +{ + struct snd_soc_dsp_params *dsp_params; + struct snd_pcm_substream *fe_substream, *be_substream; + + /* reparent if BE is connected to other FEs */ + if (!be->dsp[stream].users) + return; + + be_substream = snd_soc_dsp_get_substream(be, stream); + + list_for_each_entry(dsp_params, &be->dsp[stream].fe_clients, list_fe) { + if (dsp_params->fe != fe) { + + dev_dbg(&fe->dev, " reparent %s path %s %s %s\n", + stream ? "capture" : "playback", + dsp_params->fe->dai_link->name, + stream ? "<-" : "->", dsp_params->be->dai_link->name); + + fe_substream = snd_soc_dsp_get_substream(dsp_params->fe, + stream); + be_substream->runtime = fe_substream->runtime; + break; + } + } +} + +static inline void be_disconnect(struct snd_soc_pcm_runtime *fe, int stream) +{ + struct snd_soc_dsp_params *dsp_params, *d; + + list_for_each_entry_safe(dsp_params, d, &fe->dsp[stream].be_clients, list_be) { + struct snd_soc_pcm_runtime *be = dsp_params->be; + + dev_dbg(&fe->dev, "BE %s disconnect check for %s\n", + stream ? "capture" : "playback", + be->dai_link->name); + + if (dsp_params->state == SND_SOC_DSP_LINK_STATE_FREE) { + dev_dbg(&fe->dev, " freed DSP %s path %s %s %s\n", + stream ? "capture" : "playback", + fe->dai_link->name, stream ? "<-" : "->", + be->dai_link->name); + + /* BEs still alive need new FE */ + be_reparent(fe, be, stream); + +#ifdef CONFIG_DEBUG_FS + debugfs_remove(dsp_params->debugfs_state); +#endif + + list_del(&dsp_params->list_be); + list_del(&dsp_params->list_fe); + kfree(dsp_params); + } + } +} + +static struct snd_soc_pcm_runtime *be_get_rtd(struct snd_soc_card *card, + struct snd_soc_dapm_widget *widget) +{ + struct snd_soc_pcm_runtime *be; + int i; + + if (!widget->sname) + return NULL; + + for (i = 0; i < card->num_links; i++) { + be = &card->rtd[i]; + + if (!strcmp(widget->sname, be->dai_link->stream_name)) + return be; + } + + return NULL; +} + +static struct snd_soc_dapm_widget *be_get_widget(struct snd_soc_card *card, + struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_dapm_widget *widget; + + list_for_each_entry(widget, &card->widgets, list) { + + if (!widget->sname) + continue; + + if (!strcmp(widget->sname, rtd->dai_link->stream_name)) + return widget; + } + + return NULL; +} + +static int widget_in_list(struct snd_soc_dapm_widget_list *list, + struct snd_soc_dapm_widget *widget) +{ + int i; + + for (i = 0; i < list->num_widgets; i++) { + if (widget == list->widgets[i]) + return 1; + } + + return 0; +} + +/* + * Find the corresponding BE DAIs that source or sink audio to this + * FE substream. + */ +static int dsp_add_new_paths(struct snd_soc_pcm_runtime *fe, + int stream, int pending) +{ + struct snd_soc_dai *cpu_dai = fe->cpu_dai; + struct snd_soc_card *card = fe->card; + struct snd_soc_dapm_widget_list *list = NULL; + enum snd_soc_dapm_type fe_type, be_type; + int i, count = 0, err, paths; + + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + fe_type = snd_soc_dapm_aif_in; + be_type = snd_soc_dapm_aif_out; + } else { + fe_type = snd_soc_dapm_aif_out; + be_type = snd_soc_dapm_aif_in; + } + + /* get number of valid playback paths and their widgets */ + paths = snd_soc_dapm_get_connected_widgets_type(&card->dapm, + cpu_dai->driver->name, &list, stream, fe_type); + + dev_dbg(&fe->dev, "found %d audio %s paths\n", paths, + stream ? "capture" : "playback"); + if (!paths) + goto out; + + /* find BE DAI widgets and and connect the to FE */ + for (i = 0; i < list->num_widgets; i++) { + + if (list->widgets[i]->id == be_type) { + struct snd_soc_pcm_runtime *be; + + /* is there a valid BE rtd for this widget */ + be = be_get_rtd(card, list->widgets[i]); + if (!be) { + dev_err(&fe->dev, "no BE found for %s\n", + list->widgets[i]->name); + continue; + } + + /* don't connect if FE is not running */ + if (!fe->dsp[stream].runtime) + continue; + + /* newly connected FE and BE */ + err = be_connect(fe, be, stream); + if (err < 0) { + dev_err(&fe->dev, "can't connect %s\n", list->widgets[i]->name); + break; + } else if (err == 0) + continue; + + be->dsp[stream].runtime_update = pending; + count++; + } + } + +out: + /* list could be not initialized if root widget not found */ + if (list != NULL) + kfree(list); + return count; +} + +/* + * Find the corresponding BE DAIs that source or sink audio to this + * FE substream. + */ +static int dsp_prune_old_paths(struct snd_soc_pcm_runtime *fe, int stream, + int pending) +{ + struct snd_soc_dai *cpu_dai = fe->cpu_dai; + struct snd_soc_card *card = fe->card; + struct snd_soc_dsp_params *dsp_params; + struct snd_soc_dapm_widget_list *list = NULL; + int count = 0, paths; + enum snd_soc_dapm_type fe_type, be_type; + struct snd_soc_dapm_widget *widget; + + dev_dbg(&fe->dev, "scan for old %s %s streams\n", fe->dai_link->name, + stream ? "capture" : "playback"); + + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + fe_type = snd_soc_dapm_aif_in; + be_type = snd_soc_dapm_aif_out; + } else { + fe_type = snd_soc_dapm_aif_out; + be_type = snd_soc_dapm_aif_in; + } + + /* get number of valid playback paths and their widgets */ + paths = snd_soc_dapm_get_connected_widgets_type(&card->dapm, + cpu_dai->driver->name, &list, stream, fe_type); + + dev_dbg(&fe->dev, "found %d audio %s paths\n", paths, + stream ? "capture" : "playback"); + if (!paths) { + /* prune all BEs */ + list_for_each_entry(dsp_params, &fe->dsp[stream].be_clients, list_be) { + + dsp_params->state = SND_SOC_DSP_LINK_STATE_FREE; + dsp_params->be->dsp[stream].runtime_update = pending; + count++; + } + + dev_dbg(&fe->dev, "pruned all %s BE for FE %s\n", fe->dai_link->name, + stream ? "capture" : "playback"); + goto out; + } + + /* search card for valid BE AIFs */ + list_for_each_entry(dsp_params, &fe->dsp[stream].be_clients, list_be) { + + /* is there a valid widget for this BE */ + widget = be_get_widget(card, dsp_params->be); + if (!widget) { + dev_err(&fe->dev, "no widget found for %s\n", + dsp_params->be->dai_link->name); + continue; + } + + /* prune the BE if it's no longer in our active list */ + if (widget_in_list(list, widget)) + continue; + + dev_dbg(&fe->dev, "pruning %s BE %s for %s\n", + stream ? "capture" : "playback", dsp_params->be->dai_link->name, + fe->dai_link->name); + dsp_params->state = SND_SOC_DSP_LINK_STATE_FREE; + dsp_params->be->dsp[stream].runtime_update = pending; + count++; + } + + /* the number of old paths pruned */ +out: + /* list could be not initialized if root widget not found */ + if (list != NULL) + kfree(list); + return count; +} + +/* + * Clear the runtime pending state of all BE's. + */ +static void fe_clear_pending(struct snd_soc_pcm_runtime *fe, int stream) +{ + struct snd_soc_dsp_params *dsp_params; + + list_for_each_entry(dsp_params, &fe->dsp[stream].be_clients, list_be) + dsp_params->be->dsp[stream].runtime_update = + SND_SOC_DSP_UPDATE_NO; +} + +/* Unwind the BE startup */ +static void soc_dsp_be_dai_startup_unwind(struct snd_soc_pcm_runtime *fe, int stream) +{ + struct snd_soc_dsp_params *dsp_params; + + /* disable any enabled and non active backends */ + list_for_each_entry(dsp_params, &fe->dsp[stream].be_clients, list_be) { + + struct snd_soc_pcm_runtime *be = dsp_params->be; + struct snd_pcm_substream *be_substream = + snd_soc_dsp_get_substream(be, stream); + + if (--be->dsp[stream].users != 0) + continue; + + if (be->dsp[stream].state != SND_SOC_DSP_STATE_OPEN) + continue; + + soc_pcm_close(be_substream); + be_substream->runtime = NULL; + + be->dsp[stream].state = SND_SOC_DSP_STATE_CLOSE; + } +} + +/* Startup all new BE */ +static int soc_dsp_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream) +{ + struct snd_soc_dsp_params *dsp_params; + int err, count = 0; + + /* only startup BE DAIs that are either sinks or sources to this FE DAI */ + list_for_each_entry(dsp_params, &fe->dsp[stream].be_clients, list_be) { + + struct snd_soc_pcm_runtime *be = dsp_params->be; + struct snd_pcm_substream *be_substream = + snd_soc_dsp_get_substream(be, stream); + + /* is this op for this BE ? */ + if (!snd_soc_dsp_is_op_for_be(fe, be, stream)) + continue; + + /* first time the dsp_params is open ? */ + if (be->dsp[stream].users++ != 0) + continue; + + if ((be->dsp[stream].state != SND_SOC_DSP_STATE_NEW) && + (be->dsp[stream].state != SND_SOC_DSP_STATE_CLOSE)) + continue; + + dev_dbg(&be->dev, "dsp: open BE %s\n", be->dai_link->name); + + be_substream->runtime = be->dsp[stream].runtime; + err = soc_pcm_open(be_substream); + if (err < 0) { + dev_err(&be->dev, "BE open failed %d\n", err); + be->dsp[stream].users--; + be->dsp[stream].state = SND_SOC_DSP_STATE_CLOSE; + be_substream->runtime = NULL; + goto unwind; + } + be->dsp[stream].state = SND_SOC_DSP_STATE_OPEN; + count++; + } + + return count; + +unwind: + /* disable any enabled and non active backends */ + list_for_each_entry_continue_reverse(dsp_params, &fe->dsp[stream].be_clients, list_be) { + struct snd_soc_pcm_runtime *be = dsp_params->be; + struct snd_pcm_substream *be_substream = + snd_soc_dsp_get_substream(be, stream); + + if (!snd_soc_dsp_is_op_for_be(fe, be, stream)) + continue; + + if (--be->dsp[stream].users != 0) + continue; + + if (be->dsp[stream].state != SND_SOC_DSP_STATE_OPEN) + continue; + + soc_pcm_close(be_substream); + be_substream->runtime = NULL; + + be->dsp[stream].state = SND_SOC_DSP_STATE_CLOSE; + } + + return err; +} + +void soc_dsp_set_dynamic_runtime(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai_driver *cpu_dai_drv = cpu_dai->driver; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + runtime->hw.rate_min = cpu_dai_drv->playback.rate_min; + runtime->hw.rate_max = cpu_dai_drv->playback.rate_max; + runtime->hw.channels_min = cpu_dai_drv->playback.channels_min; + runtime->hw.channels_max = cpu_dai_drv->playback.channels_max; + runtime->hw.formats &= cpu_dai_drv->playback.formats; + runtime->hw.rates = cpu_dai_drv->playback.rates; + } else { + runtime->hw.rate_min = cpu_dai_drv->capture.rate_min; + runtime->hw.rate_max = cpu_dai_drv->capture.rate_max; + runtime->hw.channels_min = cpu_dai_drv->capture.channels_min; + runtime->hw.channels_max = cpu_dai_drv->capture.channels_max; + runtime->hw.formats &= cpu_dai_drv->capture.formats; + runtime->hw.rates = cpu_dai_drv->capture.rates; + } +} + +static int soc_dsp_fe_dai_startup(struct snd_pcm_substream *fe_substream) +{ + struct snd_soc_pcm_runtime *fe = fe_substream->private_data; + struct snd_pcm_runtime *runtime = fe_substream->runtime; + int runtime_update, stream = fe_substream->stream, ret = 0; + + mutex_lock(&fe->card->dsp_mutex); + + runtime_update = fe->dsp[stream].runtime_update; + fe->dsp[stream].runtime_update = SND_SOC_DSP_UPDATE_FE; + + ret = soc_dsp_be_dai_startup(fe, fe_substream->stream); + if (ret < 0) + goto be_err; + + dev_dbg(&fe->dev, "dsp: open FE %s\n", fe->dai_link->name); + + /* start the DAI frontend */ + ret = soc_pcm_open(fe_substream); + if (ret < 0) { + dev_err(&fe->dev,"dsp: failed to start FE %d\n", ret); + goto unwind; + } + + fe->dsp[stream].state = SND_SOC_DSP_STATE_OPEN; + + soc_dsp_set_dynamic_runtime(fe_substream); + snd_pcm_limit_hw_rates(runtime); + + mutex_unlock(&fe->card->dsp_mutex); + return 0; + +unwind: + soc_dsp_be_dai_startup_unwind(fe, fe_substream->stream); +be_err: + fe->dsp[stream].runtime_update = runtime_update; + mutex_unlock(&fe->card->dsp_mutex); + return ret; +} + +/* BE shutdown - called on DAPM sync updates (i.e. FE is already running)*/ +static int soc_dsp_be_dai_shutdown(struct snd_soc_pcm_runtime *fe, int stream) +{ + struct snd_soc_dsp_params *dsp_params; + + /* only shutdown backends that are either sinks or sources to this frontend DAI */ + list_for_each_entry(dsp_params, &fe->dsp[stream].be_clients, list_be) { + + struct snd_soc_pcm_runtime *be = dsp_params->be; + struct snd_pcm_substream *be_substream = + snd_soc_dsp_get_substream(be, stream); + + /* is this op for this BE ? */ + if (!snd_soc_dsp_is_op_for_be(fe, be, stream)) + continue; + + if (--be->dsp[stream].users != 0) + continue; + + if ((be->dsp[stream].state != SND_SOC_DSP_STATE_HW_FREE) && + (be->dsp[stream].state != SND_SOC_DSP_STATE_OPEN)) + continue; + + dev_dbg(&be->dev, "dsp: close BE %s\n", + dsp_params->fe->dai_link->name); + + soc_pcm_close(be_substream); + be_substream->runtime = NULL; + + be->dsp[stream].state = SND_SOC_DSP_STATE_CLOSE; + } + return 0; +} + +/* FE +BE shutdown - called on FE PCM ops */ +static int soc_dsp_fe_dai_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *fe = substream->private_data; + int runtime_update, stream = substream->stream; + + mutex_lock(&fe->card->dsp_mutex); + + runtime_update = fe->dsp[stream].runtime_update; + fe->dsp[stream].runtime_update = SND_SOC_DSP_UPDATE_FE; + + /* shutdown the BEs */ + soc_dsp_be_dai_shutdown(fe, substream->stream); + + dev_dbg(&fe->dev, "dsp: close FE %s\n", fe->dai_link->name); + + /* now shutdown the frontend */ + soc_pcm_close(substream); + + /* run the stream event for each BE */ + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + soc_dsp_dapm_stream_event(fe, stream, + fe->cpu_dai->driver->playback.stream_name, + SND_SOC_DAPM_STREAM_STOP); + else + soc_dsp_dapm_stream_event(fe, stream, + fe->cpu_dai->driver->capture.stream_name, + SND_SOC_DAPM_STREAM_STOP); + + fe->dsp[stream].state = SND_SOC_DSP_STATE_CLOSE; + fe->dsp[stream].runtime_update = runtime_update; + + mutex_unlock(&fe->card->dsp_mutex); + return 0; +} + +static int soc_dsp_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream) +{ + struct snd_soc_dsp_params *dsp_params; + int ret; + + list_for_each_entry(dsp_params, &fe->dsp[stream].be_clients, list_be) { + + struct snd_soc_pcm_runtime *be = dsp_params->be; + struct snd_pcm_substream *be_substream = + snd_soc_dsp_get_substream(be, stream); + + /* is this op for this BE ? */ + if (!snd_soc_dsp_is_op_for_be(fe, be, stream)) + continue; + + /* first time the dsp_params is open ? */ + if (be->dsp[stream].users != 1) + continue; + + if ((be->dsp[stream].state != SND_SOC_DSP_STATE_OPEN) && + (be->dsp[stream].state != SND_SOC_DSP_STATE_HW_FREE)) + continue; + + dev_dbg(&be->dev, "dsp: hw_params BE %s\n", + dsp_params->fe->dai_link->name); + + /* copy params for each dsp_params */ + memcpy(&dsp_params->hw_params, &fe->dsp[stream].hw_params, + sizeof(struct snd_pcm_hw_params)); + + /* perform any hw_params fixups */ + if (be->dai_link->be_hw_params_fixup) { + ret = be->dai_link->be_hw_params_fixup(be, + &dsp_params->hw_params); + if (ret < 0) { + dev_err(&be->dev, + "dsp: hw_params BE fixup failed %d\n", + ret); + return ret; + } + } + + ret = soc_pcm_hw_params(be_substream, &dsp_params->hw_params); + if (ret < 0) { + dev_err(&dsp_params->be->dev, "dsp: hw_params BE failed %d\n", ret); + return ret; + } + + be->dsp[stream].state = SND_SOC_DSP_STATE_HW_PARAMS; + } + return 0; +} + +int soc_dsp_fe_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *fe = substream->private_data; + int ret, runtime_update, stream = substream->stream; + + mutex_lock(&fe->card->dsp_mutex); + + runtime_update = fe->dsp[stream].runtime_update; + fe->dsp[stream].runtime_update = SND_SOC_DSP_UPDATE_FE; + + memcpy(&fe->dsp[substream->stream].hw_params, params, + sizeof(struct snd_pcm_hw_params)); + ret = soc_dsp_be_dai_hw_params(fe, substream->stream); + if (ret < 0) + goto out; + + dev_dbg(&fe->dev, "dsp: hw_params FE %s\n", fe->dai_link->name); + + /* call hw_params on the frontend */ + ret = soc_pcm_hw_params(substream, params); + if (ret < 0) + dev_err(&fe->dev,"dsp: hw_params FE failed %d\n", ret); + + fe->dsp[stream].state = SND_SOC_DSP_STATE_HW_PARAMS; + +out: + fe->dsp[stream].runtime_update = runtime_update; + mutex_unlock(&fe->card->dsp_mutex); + return ret; +} + +static int dsp_do_trigger(struct snd_soc_dsp_params *dsp_params, + struct snd_pcm_substream *substream, int cmd) +{ + int ret; + + dev_dbg(&dsp_params->be->dev, "dsp: trigger BE %s cmd %d\n", + dsp_params->fe->dai_link->name, cmd); + + ret = soc_pcm_trigger(substream, cmd); + if (ret < 0) + dev_err(&dsp_params->be->dev,"dsp: trigger BE failed %d\n", ret); + + return ret; +} + +int soc_dsp_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, int cmd) +{ + struct snd_soc_dsp_params *dsp_params; + int ret = 0; + + list_for_each_entry(dsp_params, &fe->dsp[stream].be_clients, list_be) { + + struct snd_soc_pcm_runtime *be = dsp_params->be; + struct snd_pcm_substream *be_substream = + snd_soc_dsp_get_substream(be, stream); + + /* is this op for this BE ? */ + if (!snd_soc_dsp_is_op_for_be(fe, be, stream)) + continue; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + if ((be->dsp[stream].state != SND_SOC_DSP_STATE_PREPARE) && + (be->dsp[stream].state != SND_SOC_DSP_STATE_STOP)) + continue; + + ret = dsp_do_trigger(dsp_params, be_substream, cmd); + if (ret) + return ret; + + be->dsp[stream].state = SND_SOC_DSP_STATE_START; + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + if (be->dsp[stream].state != SND_SOC_DSP_STATE_START) + continue; + + if (soc_dsp_fe_state_count(be, stream, + SND_SOC_DSP_STATE_START) > 1) + continue; + + ret = dsp_do_trigger(dsp_params, be_substream, cmd); + if (ret) + return ret; + + be->dsp[stream].state = SND_SOC_DSP_STATE_STOP; + break; + } + } + + return ret; +} +EXPORT_SYMBOL_GPL(soc_dsp_be_dai_trigger); + +int soc_dsp_fe_dai_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_soc_pcm_runtime *fe = substream->private_data; + struct snd_soc_dsp_link *dsp_link = fe->dai_link->dsp_link; + int stream = substream->stream, ret; + int runtime_update = fe->dsp[stream].runtime_update; + + fe->dsp[stream].runtime_update = SND_SOC_DSP_UPDATE_FE; + + switch (dsp_link->trigger[stream]) { + case SND_SOC_DSP_TRIGGER_PRE: + /* call trigger on the frontend before the backend. */ + + dev_dbg(&fe->dev, "dsp: pre trigger FE %s cmd %d\n", + fe->dai_link->name, cmd); + + ret = soc_pcm_trigger(substream, cmd); + if (ret < 0) { + dev_err(&fe->dev,"dsp: trigger FE failed %d\n", ret); + goto out; + } + + ret = soc_dsp_be_dai_trigger(fe, substream->stream, cmd); + break; + case SND_SOC_DSP_TRIGGER_POST: + /* call trigger on the frontend after the backend. */ + + ret = soc_dsp_be_dai_trigger(fe, substream->stream, cmd); + if (ret < 0) { + dev_err(&fe->dev,"dsp: trigger FE failed %d\n", ret); + goto out; + } + + dev_dbg(&fe->dev, "dsp: post trigger FE %s cmd %d\n", + fe->dai_link->name, cmd); + + ret = soc_pcm_trigger(substream, cmd); + break; + case SND_SOC_DSP_TRIGGER_BESPOKE: + /* bespoke trigger() - handles both FE and BEs */ + + dev_dbg(&fe->dev, "dsp: bespoke trigger FE %s cmd %d\n", + fe->dai_link->name, cmd); + + ret = soc_pcm_bespoke_trigger(substream, cmd); + if (ret < 0) { + dev_err(&fe->dev,"dsp: trigger FE failed %d\n", ret); + goto out; + } + break; + default: + dev_err(&fe->dev, "dsp: invalid trigger cmd %d for %s\n", cmd, + fe->dai_link->name); + ret = -EINVAL; + goto out; + } + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + fe->dsp[stream].state = SND_SOC_DSP_STATE_START; + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + fe->dsp[stream].state = SND_SOC_DSP_STATE_STOP; + break; + } + +out: + fe->dsp[stream].runtime_update = runtime_update; + return ret; +} + +static int soc_dsp_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream) +{ + struct snd_soc_dsp_params *dsp_params; + int ret = 0; + + list_for_each_entry(dsp_params, &fe->dsp[stream].be_clients, list_be) { + + struct snd_soc_pcm_runtime *be = dsp_params->be; + struct snd_pcm_substream *be_substream = + snd_soc_dsp_get_substream(be, stream); + + /* is this op for this BE ? */ + if (!snd_soc_dsp_is_op_for_be(fe, be, stream)) + continue; + + if ((be->dsp[stream].state != SND_SOC_DSP_STATE_HW_PARAMS) && + (be->dsp[stream].state != SND_SOC_DSP_STATE_STOP)) + continue; + + dev_dbg(&be->dev, "dsp: prepare BE %s\n", + dsp_params->fe->dai_link->name); + + ret = soc_pcm_prepare(be_substream); + if (ret < 0) { + dev_err(&be->dev, "dsp: backend prepare failed %d\n", + ret); + break; + } + + be->dsp[stream].state = SND_SOC_DSP_STATE_PREPARE; + } + return ret; +} + +int soc_dsp_fe_dai_prepare(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *fe = substream->private_data; + int runtime_update, stream = substream->stream, ret = 0; + + mutex_lock(&fe->card->dsp_mutex); + + dev_dbg(&fe->dev, "dsp: prepare FE %s\n", fe->dai_link->name); + + runtime_update = fe->dsp[stream].runtime_update; + fe->dsp[stream].runtime_update = SND_SOC_DSP_UPDATE_FE; + + /* there is no point preparing this FE if there are no BEs */ + if (list_empty(&fe->dsp[stream].be_clients)) { + dev_err(&fe->dev, "dsp: no backend DAIs enabled for %s\n", + fe->dai_link->name); + ret = -EINVAL; + goto out; + } + + ret = soc_dsp_be_dai_prepare(fe, substream->stream); + if (ret < 0) + goto out; + + /* call prepare on the frontend */ + ret = soc_pcm_prepare(substream); + if (ret < 0) { + dev_err(&fe->dev,"dsp: prepare FE %s failed\n", fe->dai_link->name); + goto out; + } + + /* run the stream event for each BE */ + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + soc_dsp_dapm_stream_event(fe, stream, + fe->cpu_dai->driver->playback.stream_name, + SNDRV_PCM_TRIGGER_START); + else + soc_dsp_dapm_stream_event(fe, stream, + fe->cpu_dai->driver->capture.stream_name, + SNDRV_PCM_TRIGGER_START); + + fe->dsp[stream].state = SND_SOC_DSP_STATE_PREPARE; + +out: + fe->dsp[stream].runtime_update = runtime_update; + mutex_unlock(&fe->card->dsp_mutex); + return ret; +} + +static int soc_dsp_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream) +{ + struct snd_soc_dsp_params *dsp_params; + + /* only hw_params backends that are either sinks or sources + * to this frontend DAI */ + list_for_each_entry(dsp_params, &fe->dsp[stream].be_clients, list_be) { + + struct snd_soc_pcm_runtime *be = dsp_params->be; + struct snd_pcm_substream *be_substream = + snd_soc_dsp_get_substream(be, stream); + + /* is this op for this BE ? */ + if (!snd_soc_dsp_is_op_for_be(fe, be, stream)) + continue; + + /* only free hw when no longer used */ + if (be->dsp[stream].users != 1) + continue; + + if ((be->dsp[stream].state != SND_SOC_DSP_STATE_HW_PARAMS) && + (be->dsp[stream].state != SND_SOC_DSP_STATE_PREPARE) && + (be->dsp[stream].state != SND_SOC_DSP_STATE_STOP)) + continue; + + dev_dbg(&be->dev, "dsp: hw_free BE %s\n", + dsp_params->fe->dai_link->name); + + soc_pcm_hw_free(be_substream); + + be->dsp[stream].state = SND_SOC_DSP_STATE_HW_FREE; + } + + return 0; +} + +int soc_dsp_fe_dai_hw_free(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *fe = substream->private_data; + int ret, runtime_update, stream = substream->stream; + + mutex_lock(&fe->card->dsp_mutex); + + runtime_update = fe->dsp[stream].runtime_update; + fe->dsp[stream].runtime_update = SND_SOC_DSP_UPDATE_FE; + + dev_dbg(&fe->dev, "dsp: hw_free FE %s\n", fe->dai_link->name); + + /* call hw_free on the frontend */ + ret = soc_pcm_hw_free(substream); + if (ret < 0) + dev_err(&fe->dev,"dsp: hw_free FE %s failed\n", fe->dai_link->name); + + /* only hw_params backends that are either sinks or sources + * to this frontend DAI */ + ret = soc_dsp_be_dai_hw_free(fe, stream); + + fe->dsp[stream].state = SND_SOC_DSP_STATE_HW_FREE; + fe->dsp[stream].runtime_update = runtime_update; + + mutex_unlock(&fe->card->dsp_mutex); + return ret; +} + +/* + * FE stream event, send event to all active BEs. + */ +int soc_dsp_dapm_stream_event(struct snd_soc_pcm_runtime *fe, + int dir, const char *stream, int event) +{ + struct snd_soc_dsp_params *dsp_params; + + /* resume for playback */ + list_for_each_entry(dsp_params, &fe->dsp[dir].be_clients, list_be) { + + struct snd_soc_pcm_runtime *be = dsp_params->be; + + dev_dbg(&be->dev, "pm: BE %s stream %s event %d dir %d\n", + be->dai_link->name, stream, event, dir); + + snd_soc_dapm_stream_event(be, stream, event); + } + + return 0; +} + +static int dsp_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream) +{ + struct snd_soc_dsp_link *dsp_link = fe->dai_link->dsp_link; + struct snd_pcm_substream *substream = snd_soc_dsp_get_substream(fe, stream); + int ret; + + dev_dbg(&fe->dev, "runtime %s close on FE %s\n", + stream ? "capture" : "playback", fe->dai_link->name); + + if (dsp_link->trigger[stream] == SND_SOC_DSP_TRIGGER_BESPOKE) { + /* call bespoke trigger - FE takes care of all BE triggers */ + dev_dbg(&fe->dev, "dsp: bespoke trigger FE %s cmd stop\n", + fe->dai_link->name); + + ret = soc_pcm_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_STOP); + if (ret < 0) { + dev_err(&fe->dev,"dsp: trigger FE failed %d\n", ret); + return ret; + } + } else { + dev_dbg(&fe->dev, "dsp: trigger FE %s cmd stop\n", + fe->dai_link->name); + + ret = soc_dsp_be_dai_trigger(fe, stream, SNDRV_PCM_TRIGGER_STOP); + if (ret < 0) + return ret; + } + + ret = soc_dsp_be_dai_hw_free(fe, stream); + if (ret < 0) + return ret; + + ret = soc_dsp_be_dai_shutdown(fe, stream); + if (ret < 0) + return ret; + + /* run the stream event for each BE */ + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + soc_dsp_dapm_stream_event(fe, stream, + fe->cpu_dai->driver->playback.stream_name, + SNDRV_PCM_TRIGGER_STOP); + else + soc_dsp_dapm_stream_event(fe, stream, + fe->cpu_dai->driver->capture.stream_name, + SNDRV_PCM_TRIGGER_STOP); + + return 0; +} + +static int dsp_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream) +{ + struct snd_soc_dsp_link *dsp_link = fe->dai_link->dsp_link; + struct snd_pcm_substream *substream = snd_soc_dsp_get_substream(fe, stream); + struct snd_soc_dsp_params *dsp_params; + int ret; + + dev_dbg(&fe->dev, "runtime %s open on FE %s\n", + stream ? "capture" : "playback", fe->dai_link->name); + + ret = soc_dsp_be_dai_startup(fe, stream); + if (ret < 0) { + goto disconnect; + return ret; + } + + ret = soc_dsp_be_dai_hw_params(fe, stream); + if (ret < 0) { + goto close; + return ret; + } + ret = soc_dsp_be_dai_prepare(fe, stream); + if (ret < 0) { + goto hw_free; + return ret; + } + + /* run the stream event for each BE */ + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + soc_dsp_dapm_stream_event(fe, stream, + fe->cpu_dai->driver->playback.stream_name, + SNDRV_PCM_TRIGGER_START); + else + soc_dsp_dapm_stream_event(fe, stream, + fe->cpu_dai->driver->capture.stream_name, + SNDRV_PCM_TRIGGER_START); + + if (dsp_link->trigger[stream] == SND_SOC_DSP_TRIGGER_BESPOKE) { + /* call trigger on the frontend - FE takes care of all BE triggers */ + dev_dbg(&fe->dev, "dsp: bespoke trigger FE %s cmd start\n", + fe->dai_link->name); + + ret = soc_pcm_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_START); + if (ret < 0) { + dev_err(&fe->dev,"dsp: bespoke trigger FE failed %d\n", ret); + goto stream_stop; + } + } else { + dev_dbg(&fe->dev, "dsp: trigger FE %s cmd start\n", + fe->dai_link->name); + + ret = soc_dsp_be_dai_trigger(fe, stream, + SNDRV_PCM_TRIGGER_START); + if (ret < 0) { + dev_err(&fe->dev,"dsp: trigger FE failed %d\n", ret); + goto stream_stop; + } + } + + return 0; + +stream_stop: + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + soc_dsp_dapm_stream_event(fe, stream, + fe->cpu_dai->driver->playback.stream_name, + SNDRV_PCM_TRIGGER_STOP); + else + soc_dsp_dapm_stream_event(fe, stream, + fe->cpu_dai->driver->capture.stream_name, + SNDRV_PCM_TRIGGER_STOP); +hw_free: + soc_dsp_be_dai_hw_free(fe, stream); +close: + soc_dsp_be_dai_shutdown(fe, stream); +disconnect: + /* disconnect any non started BEs */ + list_for_each_entry(dsp_params, &fe->dsp[stream].be_clients, list_be) { + struct snd_soc_pcm_runtime *be = dsp_params->be; + if (be->dsp[stream].state != SND_SOC_DSP_STATE_START) + dsp_params->state = SND_SOC_DSP_LINK_STATE_FREE; + } + + return ret; +} + +static int dsp_run_new_update(struct snd_soc_pcm_runtime *fe, int stream) +{ + int ret; + + fe->dsp[stream].runtime_update = SND_SOC_DSP_UPDATE_BE; + ret = dsp_run_update_startup(fe, stream); + if (ret < 0) + dev_err(&fe->dev, "failed to startup some BEs\n"); + fe->dsp[stream].runtime_update = SND_SOC_DSP_UPDATE_NO; + + return ret; +} + +static int dsp_run_old_update(struct snd_soc_pcm_runtime *fe, int stream) +{ + int ret; + + fe->dsp[stream].runtime_update = SND_SOC_DSP_UPDATE_BE; + ret = dsp_run_update_shutdown(fe, stream); + if (ret < 0) + dev_err(&fe->dev, "failed to shutdown some BEs\n"); + fe->dsp[stream].runtime_update = SND_SOC_DSP_UPDATE_NO; + + return ret; +} + +/* called when any mixer updates change FE -> BE the stream */ +int soc_dsp_runtime_update(struct snd_soc_dapm_widget *widget) +{ + struct snd_soc_card *card; + int i, ret = 0, start, stop; + + if (widget->codec) + card = widget->codec->card; + else if (widget->platform) + card = widget->platform->card; + else + return -EINVAL; + + mutex_lock(&widget->dapm->card->dsp_mutex); + + for (i = 0; i < card->num_rtd; i++) { + struct snd_soc_pcm_runtime *fe = &card->rtd[i]; + + /* make sure link is BE */ + if (!fe->dai_link->dsp_link) + continue; + + /* only check active links */ + if (!fe->cpu_dai->active) { + continue; + } + + /* DAPM sync will call this to update DSP paths */ + dev_dbg(card->dev, "DSP runtime update for FE %s\n", fe->dai_link->name); + + /* skip if FE doesn't have playback capability */ + if (!fe->cpu_dai->driver->playback.channels_min) + goto capture; + + /* update new playback paths */ + start = dsp_add_new_paths(fe, SNDRV_PCM_STREAM_PLAYBACK, 1); + if (start) { + dsp_run_new_update(fe, SNDRV_PCM_STREAM_PLAYBACK); + fe_clear_pending(fe, SNDRV_PCM_STREAM_PLAYBACK); + } + + /* update old playback paths */ + stop = dsp_prune_old_paths(fe, SNDRV_PCM_STREAM_PLAYBACK, 1); + if (stop) { + dsp_run_old_update(fe, SNDRV_PCM_STREAM_PLAYBACK); + fe_clear_pending(fe, SNDRV_PCM_STREAM_PLAYBACK); + be_disconnect(fe, SNDRV_PCM_STREAM_PLAYBACK); + } + +capture: + /* skip if FE doesn't have capture capability */ + if (!fe->cpu_dai->driver->capture.channels_min) + continue; + + /* update new capture paths */ + start = dsp_add_new_paths(fe, SNDRV_PCM_STREAM_CAPTURE, 1); + if (start) { + dsp_run_new_update(fe, SNDRV_PCM_STREAM_CAPTURE); + fe_clear_pending(fe, SNDRV_PCM_STREAM_CAPTURE); + } + + /* update old capture paths */ + stop = dsp_prune_old_paths(fe, SNDRV_PCM_STREAM_CAPTURE, 1); + if (stop) { + dsp_run_old_update(fe, SNDRV_PCM_STREAM_CAPTURE); + fe_clear_pending(fe, SNDRV_PCM_STREAM_CAPTURE); + be_disconnect(fe, SNDRV_PCM_STREAM_CAPTURE); + } + } + + mutex_unlock(&widget->dapm->card->dsp_mutex); + return ret; +} + +int soc_dsp_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute) +{ + struct snd_soc_dsp_params *dsp_params; + + list_for_each_entry(dsp_params, + &fe->dsp[SNDRV_PCM_STREAM_PLAYBACK].be_clients, list_be) { + + struct snd_soc_pcm_runtime *be = dsp_params->be; + struct snd_soc_dai *dai = be->codec_dai; + struct snd_soc_dai_driver *drv = dai->driver; + + dev_dbg(&be->dev, "BE digital mute %s\n", be->dai_link->name); + + if (be->dai_link->ignore_suspend) + continue; + + if (drv->ops->digital_mute && dai->playback_active) + drv->ops->digital_mute(dai, mute); + } + + return 0; +} + +int soc_dsp_be_cpu_dai_suspend(struct snd_soc_pcm_runtime *fe) +{ + struct snd_soc_dsp_params *dsp_params; + + /* suspend for playback */ + list_for_each_entry(dsp_params, + &fe->dsp[SNDRV_PCM_STREAM_PLAYBACK].be_clients, list_be) { + + struct snd_soc_pcm_runtime *be = dsp_params->be; + struct snd_soc_dai *dai = be->cpu_dai; + struct snd_soc_dai_driver *drv = dai->driver; + + dev_dbg(&be->dev, "pm: BE CPU DAI playback suspend %s\n", + be->dai_link->name); + + if (be->dai_link->ignore_suspend) + continue; + + if (drv->suspend && !drv->ac97_control) + drv->suspend(dai); + } + + /* suspend for capture */ + list_for_each_entry(dsp_params, + &fe->dsp[SNDRV_PCM_STREAM_CAPTURE].be_clients, list_be) { + + struct snd_soc_pcm_runtime *be = dsp_params->be; + struct snd_soc_dai *dai = be->cpu_dai; + struct snd_soc_dai_driver *drv = dai->driver; + + dev_dbg(&be->dev, "pm: BE CPU DAI capture suspend %s\n", + be->dai_link->name); + + if (be->dai_link->ignore_suspend) + continue; + + if (drv->suspend && !drv->ac97_control) + drv->suspend(dai); + } + + return 0; +} + +int soc_dsp_be_ac97_cpu_dai_suspend(struct snd_soc_pcm_runtime *fe) +{ + struct snd_soc_dsp_params *dsp_params; + + /* suspend for playback */ + list_for_each_entry(dsp_params, + &fe->dsp[SNDRV_PCM_STREAM_PLAYBACK].be_clients, list_be) { + + struct snd_soc_pcm_runtime *be = dsp_params->be; + struct snd_soc_dai *dai = be->cpu_dai; + struct snd_soc_dai_driver *drv = dai->driver; + + dev_dbg(&be->dev, "pm: BE CPU DAI playback suspend %s\n", + be->dai_link->name); + + if (be->dai_link->ignore_suspend) + continue; + + if (drv->suspend && drv->ac97_control) + drv->suspend(dai); + } + + /* suspend for capture */ + list_for_each_entry(dsp_params, + &fe->dsp[SNDRV_PCM_STREAM_CAPTURE].be_clients, list_be) { + + struct snd_soc_pcm_runtime *be = dsp_params->be; + struct snd_soc_dai *dai = be->cpu_dai; + struct snd_soc_dai_driver *drv = dai->driver; + + dev_dbg(&be->dev, "pm: BE CPU DAI capture suspend %s\n", + be->dai_link->name); + + if (be->dai_link->ignore_suspend) + continue; + + if (drv->suspend && drv->ac97_control) + drv->suspend(dai); + } + + return 0; +} + +int soc_dsp_be_platform_suspend(struct snd_soc_pcm_runtime *fe) +{ + struct snd_soc_dsp_params *dsp_params; + + /* suspend for playback */ + list_for_each_entry(dsp_params, + &fe->dsp[SNDRV_PCM_STREAM_PLAYBACK].be_clients, list_be) { + + struct snd_soc_pcm_runtime *be = dsp_params->be; + struct snd_soc_platform *platform = be->platform; + struct snd_soc_platform_driver *drv = platform->driver; + struct snd_soc_dai *dai = be->cpu_dai; + + dev_dbg(&be->dev, "pm: BE platform playback suspend %s\n", + be->dai_link->name); + + if (be->dai_link->ignore_suspend) + continue; + + if (drv->suspend && !platform->suspended) { + drv->suspend(dai); + platform->suspended = 1; + } + } + + /* suspend for capture */ + list_for_each_entry(dsp_params, + &fe->dsp[SNDRV_PCM_STREAM_CAPTURE].be_clients, list_be) { + + struct snd_soc_pcm_runtime *be = dsp_params->be; + struct snd_soc_platform *platform = be->platform; + struct snd_soc_platform_driver *drv = platform->driver; + struct snd_soc_dai *dai = be->cpu_dai; + + dev_dbg(&be->dev, "pm: BE platform capture suspend %s\n", + be->dai_link->name); + + if (be->dai_link->ignore_suspend) + continue; + + if (drv->suspend && !platform->suspended) { + drv->suspend(dai); + platform->suspended = 1; + } + } + + return 0; +} + +int soc_dsp_fe_suspend(struct snd_soc_pcm_runtime *fe) +{ + struct snd_soc_dai *dai = fe->cpu_dai; + struct snd_soc_dai_driver *dai_drv = dai->driver; + struct snd_soc_platform *platform = fe->platform; + struct snd_soc_platform_driver *plat_drv = platform->driver; + + if (dai_drv->suspend && !dai_drv->ac97_control) + dai_drv->suspend(dai); + + if (plat_drv->suspend && !platform->suspended) { + plat_drv->suspend(dai); + platform->suspended = 1; + } + + soc_dsp_be_cpu_dai_suspend(fe); + soc_dsp_be_platform_suspend(fe); + + return 0; +} + +int soc_dsp_be_cpu_dai_resume(struct snd_soc_pcm_runtime *fe) +{ + struct snd_soc_dsp_params *dsp_params; + + /* resume for playback */ + list_for_each_entry(dsp_params, + &fe->dsp[SNDRV_PCM_STREAM_PLAYBACK].be_clients, list_be) { + + struct snd_soc_pcm_runtime *be = dsp_params->be; + struct snd_soc_dai *dai = be->cpu_dai; + struct snd_soc_dai_driver *drv = dai->driver; + + dev_dbg(&be->dev, "pm: BE CPU DAI playback resume %s\n", + be->dai_link->name); + + if (be->dai_link->ignore_suspend) + continue; + + if (drv->resume && !drv->ac97_control) + drv->resume(dai); + } + + /* suspend for capture */ + list_for_each_entry(dsp_params, + &fe->dsp[SNDRV_PCM_STREAM_CAPTURE].be_clients, list_be) { + + struct snd_soc_pcm_runtime *be = dsp_params->be; + struct snd_soc_dai *dai = be->cpu_dai; + struct snd_soc_dai_driver *drv = dai->driver; + + dev_dbg(&be->dev, "pm: BE CPU DAI capture resume %s\n", + be->dai_link->name); + + if (be->dai_link->ignore_suspend) + continue; + + if (drv->resume && !drv->ac97_control) + drv->resume(dai); + } + + return 0; +} + +int soc_dsp_be_ac97_cpu_dai_resume(struct snd_soc_pcm_runtime *fe) +{ + struct snd_soc_dsp_params *dsp_params; + + /* resume for playback */ + list_for_each_entry(dsp_params, + &fe->dsp[SNDRV_PCM_STREAM_PLAYBACK].be_clients, list_be) { + + struct snd_soc_pcm_runtime *be = dsp_params->be; + struct snd_soc_dai *dai = be->cpu_dai; + struct snd_soc_dai_driver *drv = dai->driver; + + dev_dbg(&be->dev, "pm: BE CPU DAI playback resume %s\n", + be->dai_link->name); + + if (be->dai_link->ignore_suspend) + continue; + + if (drv->resume && drv->ac97_control) + drv->resume(dai); + } + + /* suspend for capture */ + list_for_each_entry(dsp_params, + &fe->dsp[SNDRV_PCM_STREAM_CAPTURE].be_clients, list_be) { + + struct snd_soc_pcm_runtime *be = dsp_params->be; + struct snd_soc_dai *dai = be->cpu_dai; + struct snd_soc_dai_driver *drv = dai->driver; + + dev_dbg(&be->dev, "pm: BE CPU DAI capture resume %s\n", + be->dai_link->name); + + if (be->dai_link->ignore_suspend) + continue; + + if (drv->resume && drv->ac97_control) + drv->resume(dai); + } + + return 0; +} + +int soc_dsp_be_platform_resume(struct snd_soc_pcm_runtime *fe) +{ + struct snd_soc_dsp_params *dsp_params; + + /* resume for playback */ + list_for_each_entry(dsp_params, + &fe->dsp[SNDRV_PCM_STREAM_PLAYBACK].be_clients, list_be) { + + struct snd_soc_pcm_runtime *be = dsp_params->be; + struct snd_soc_platform *platform = be->platform; + struct snd_soc_platform_driver *drv = platform->driver; + struct snd_soc_dai *dai = be->cpu_dai; + + dev_dbg(&be->dev, "pm: BE platform playback resume %s\n", + be->dai_link->name); + + if (be->dai_link->ignore_suspend) + continue; + + if (drv->resume && platform->suspended) { + drv->resume(dai); + platform->suspended = 0; + } + } + + /* resume for capture */ + list_for_each_entry(dsp_params, + &fe->dsp[SNDRV_PCM_STREAM_CAPTURE].be_clients, list_be) { + + struct snd_soc_pcm_runtime *be = dsp_params->be; + struct snd_soc_platform *platform = be->platform; + struct snd_soc_platform_driver *drv = platform->driver; + struct snd_soc_dai *dai = be->cpu_dai; + + dev_dbg(&be->dev, "pm: BE platform capture resume %s\n", + be->dai_link->name); + + if (be->dai_link->ignore_suspend) + continue; + + if (drv->resume && platform->suspended) { + drv->resume(dai); + platform->suspended = 0; + } + } + + return 0; +} + +int soc_dsp_fe_resume(struct snd_soc_pcm_runtime *fe) +{ + struct snd_soc_dai *dai = fe->cpu_dai; + struct snd_soc_dai_driver *dai_drv = dai->driver; + struct snd_soc_platform *platform = fe->platform; + struct snd_soc_platform_driver *plat_drv = platform->driver; + + soc_dsp_be_cpu_dai_resume(fe); + soc_dsp_be_platform_resume(fe); + + if (dai_drv->resume && !dai_drv->ac97_control) + dai_drv->resume(dai); + + if (plat_drv->resume && platform->suspended) { + plat_drv->resume(dai); + platform->suspended = 0; + } + + return 0; +} + +/* called when opening FE stream */ +int soc_dsp_fe_dai_open(struct snd_pcm_substream *fe_substream) +{ + struct snd_soc_pcm_runtime *fe = fe_substream->private_data; + struct snd_soc_dsp_params *dsp_params; + int err, ret; + int stream = fe_substream->stream; + + fe->dsp[fe_substream->stream].runtime = fe_substream->runtime; + + /* calculate valid and active FE <-> BE dsp_paramss */ + err = dsp_add_new_paths(fe, fe_substream->stream, 0); + if (err <= 0) { + dev_warn(&fe->dev, "asoc: %s no valid %s route from source to sink\n", + fe->dai_link->name, fe_substream->stream ? "capture" : "playback"); + } + + ret = soc_dsp_fe_dai_startup(fe_substream); + if (ret < 0) { + /* clean up all links */ + list_for_each_entry(dsp_params, &fe->dsp[stream].be_clients, list_be) + dsp_params->state = SND_SOC_DSP_LINK_STATE_FREE; + + be_disconnect(fe, stream); + fe->dsp[stream].runtime = NULL; + } + return ret; +} + +/* called when closing FE stream */ +int soc_dsp_fe_dai_close(struct snd_pcm_substream *fe_substream) +{ + struct snd_soc_pcm_runtime *fe = fe_substream->private_data; + struct snd_soc_dsp_params *dsp_params; + int stream = fe_substream->stream, ret; + + ret = soc_dsp_fe_dai_shutdown(fe_substream); + + /* mark FE's links ready to prune */ + list_for_each_entry(dsp_params, &fe->dsp[stream].be_clients, list_be) + dsp_params->state = SND_SOC_DSP_LINK_STATE_FREE; + + be_disconnect(fe, stream); + + fe->dsp[stream].runtime = NULL; + + return ret; +} + +#ifdef CONFIG_DEBUG_FS +static char *dsp_state_string(enum snd_soc_dsp_state state) +{ + switch (state) { + case SND_SOC_DSP_STATE_NEW: + return "new"; + case SND_SOC_DSP_STATE_OPEN: + return "open"; + case SND_SOC_DSP_STATE_HW_PARAMS: + return "hw_params"; + case SND_SOC_DSP_STATE_PREPARE: + return "prepare"; + case SND_SOC_DSP_STATE_START: + return "start"; + case SND_SOC_DSP_STATE_STOP: + return "stop"; + case SND_SOC_DSP_STATE_HW_FREE: + return "hw_free"; + case SND_SOC_DSP_STATE_CLOSE: + return "close"; + } + + return "unknown"; +} + +static int soc_dsp_state_open_file(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t soc_dsp_show_state(struct snd_soc_pcm_runtime *fe, + int stream, char *buf, size_t size) +{ + struct snd_pcm_hw_params *params = &fe->dsp[stream].hw_params; + struct snd_soc_dsp_params *dsp_params; + ssize_t offset = 0; + + /* FE state */ + offset += snprintf(buf + offset, size - offset, + "[%s - %s]\n", fe->dai_link->name, + stream ? "Capture" : "Playback"); + + offset += snprintf(buf + offset, size - offset, "State: %s\n", + dsp_state_string(fe->dsp[stream].state)); + + if ((fe->dsp[stream].state >= SND_SOC_DSP_STATE_HW_PARAMS) && + (fe->dsp[stream].state <= SND_SOC_DSP_STATE_STOP)) + offset += snprintf(buf + offset, size - offset, + "Hardware Params: " + "Format = %s, Channels = %d, Rate = %d\n", + snd_pcm_format_name(params_format(params)), + params_channels(params), + params_rate(params)); + + /* BEs state */ + offset += snprintf(buf + offset, size - offset, "Backends:\n"); + + if (list_empty(&fe->dsp[stream].be_clients)) { + offset += snprintf(buf + offset, size - offset, + " No active DSP links\n"); + goto out; + } + + list_for_each_entry(dsp_params, &fe->dsp[stream].be_clients, list_be) { + struct snd_soc_pcm_runtime *be = dsp_params->be; + + offset += snprintf(buf + offset, size - offset, + "- %s\n", be->dai_link->name); + + offset += snprintf(buf + offset, size - offset, + " State: %s\n", + dsp_state_string(fe->dsp[stream].state)); + + if ((be->dsp[stream].state >= SND_SOC_DSP_STATE_HW_PARAMS) && + (be->dsp[stream].state <= SND_SOC_DSP_STATE_STOP)) + offset += snprintf(buf + offset, size - offset, + " Hardware Params: " + "Format = %s, Channels = %d, Rate = %d\n", + snd_pcm_format_name(params_format(params)), + params_channels(params), + params_rate(params)); + } + +out: + return offset; +} + +static ssize_t soc_dsp_state_read_file(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct snd_soc_pcm_runtime *fe = file->private_data; + ssize_t out_count = PAGE_SIZE, offset = 0, ret = 0; + char *buf; + + buf = kmalloc(out_count, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + if (fe->cpu_dai->driver->playback.channels_min) + offset += soc_dsp_show_state(fe, SNDRV_PCM_STREAM_PLAYBACK, + buf + offset, out_count - offset); + + if (fe->cpu_dai->driver->capture.channels_min) + offset += soc_dsp_show_state(fe, SNDRV_PCM_STREAM_CAPTURE, + buf + offset, out_count - offset); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, offset); + + kfree(buf); + + return ret; +} + +static const struct file_operations soc_dsp_state_fops = { + .open = soc_dsp_state_open_file, + .read = soc_dsp_state_read_file, + .llseek = default_llseek, +}; + +int soc_dsp_debugfs_add(struct snd_soc_pcm_runtime *rtd) +{ + rtd->debugfs_dsp_root = debugfs_create_dir(rtd->dai_link->name, + rtd->card->debugfs_card_root); + if (!rtd->debugfs_dsp_root) { + dev_dbg(&rtd->dev, + "ASoC: Failed to create dsp debugfs directory %s\n", + rtd->dai_link->name); + return -EINVAL; + } + + rtd->debugfs_dsp_state = debugfs_create_file("state", 0644, + rtd->debugfs_dsp_root, + rtd, &soc_dsp_state_fops); + + return 0; +} +#endif + +/* Module information */ +MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk"); +MODULE_DESCRIPTION("ALSA SoC DSP Core"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/txx9/txx9aclc.c b/sound/soc/txx9/txx9aclc.c index f4aa4e0..34aa972 100644 --- a/sound/soc/txx9/txx9aclc.c +++ b/sound/soc/txx9/txx9aclc.c @@ -288,9 +288,10 @@ static void txx9aclc_pcm_free_dma_buffers(struct snd_pcm *pcm) snd_pcm_lib_preallocate_free_for_all(pcm); } -static int txx9aclc_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, - struct snd_pcm *pcm) +static int txx9aclc_pcm_new(struct snd_soc_pcm_runtime *rtd) { + struct snd_soc_dai *dai = rtd->cpu_dai; + struct snd_pcm *pcm = rtd->pcm; struct platform_device *pdev = to_platform_device(dai->platform->dev); struct txx9aclc_soc_device *dev; struct resource *r; |