diff options
Diffstat (limited to 'sound/soc')
32 files changed, 848 insertions, 162 deletions
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 2eaef5b52e08..d80b7bbff2e8 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -35,8 +35,7 @@ snd-soc-stac9766-objs := stac9766.o snd-soc-tlv320aic23-objs := tlv320aic23.o snd-soc-tlv320aic26-objs := tlv320aic26.o snd-soc-tlv320aic3x-objs := tlv320aic3x.o -snd-soc-tlv320aic326x-objs := tlv320aic326x.o tlv320aic326x_minidsp_config.o -snd-soc-tlv320aic326x-objs += tlv320aic326x_mini-dsp.o aic326x_tiload.o +snd-soc-tlv320aic326x-objs := tlv320aic326x.o snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o snd-soc-tlv320dac33-objs := tlv320dac33.o snd-soc-twl4030-objs := twl4030.o diff --git a/sound/soc/codecs/aic326x_tiload.c b/sound/soc/codecs/aic326x_tiload.c index 00aa4d4ce7d7..07615dc5ebd7 100644 --- a/sound/soc/codecs/aic326x_tiload.c +++ b/sound/soc/codecs/aic326x_tiload.c @@ -61,7 +61,8 @@ static void aic3262_dump_page(struct i2c_client *i2c, u8 page); /* externs */ extern int aic3262_change_page(struct snd_soc_codec *codec, u8 new_page); extern int aic3262_change_book(struct snd_soc_codec *codec, u8 new_book); -extern int aic3262_write(struct snd_soc_codec *codec, u16 reg, u8 value); +extern int aic3262_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value); int aic3262_driver_init(struct snd_soc_codec *codec); /************** Dynamic aic3262 driver, TI LOAD support ***************/ @@ -236,7 +237,7 @@ static ssize_t tiload_write(struct file *file, const char __user * buf, return i2c_master_send(i2c, wr_data, count); } -static int tiload_ioctl( struct file *filp, +static long tiload_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { int num = 0; diff --git a/sound/soc/codecs/base_main_Rate48_pps_driver.h b/sound/soc/codecs/base_main_Rate48_pps_driver.h index 4d6f227cc42e..dff91858940e 100644 --- a/sound/soc/codecs/base_main_Rate48_pps_driver.h +++ b/sound/soc/codecs/base_main_Rate48_pps_driver.h @@ -16,17 +16,6 @@ static control base_speaker_SRS_VOLUME_controls[] = { static char * base_speaker_SRS_VOLUME_control_names[] = {
};
-/*//INSTRUCTIONS & COEFFICIENTS
-typedef struct {
- u8 reg_off;
- u8 reg_val;
-} reg_value;*/
-
-static char * base_speaker_SRS_REG_Section_names[] = {
- "miniDSP_A_reg_values",
- "miniDSP_D_reg_values",
-};
-
reg_value base_speaker_SRS_REG_init_Section_program[] = {
{ 0,0x0},
{ 0x7F,0x00},
diff --git a/sound/soc/codecs/rt5639.c b/sound/soc/codecs/rt5639.c index 06c8451a27c8..c9b14e9f0bc1 100644 --- a/sound/soc/codecs/rt5639.c +++ b/sound/soc/codecs/rt5639.c @@ -421,8 +421,18 @@ static int rt5639_readable_register( int rt5639_headset_detect(struct snd_soc_codec *codec, int jack_insert) { int jack_type; + int sclk_src; if (jack_insert) { + if (SND_SOC_BIAS_OFF == codec->dapm.bias_level) { + snd_soc_write(codec, RT5639_PWR_ANLG1, 0x2004); + snd_soc_write(codec, RT5639_MICBIAS, 0x3830); + snd_soc_write(codec, RT5639_DUMMY1 , 0x3701); + } + sclk_src = snd_soc_read(codec, RT5639_GLB_CLK) & + RT5639_SCLK_SRC_MASK; + snd_soc_update_bits(codec, RT5639_GLB_CLK, + RT5639_SCLK_SRC_MASK, 0x3 << RT5639_SCLK_SRC_SFT); snd_soc_update_bits(codec, RT5639_PWR_ANLG1, RT5639_PWR_LDO2, RT5639_PWR_LDO2); snd_soc_update_bits(codec, RT5639_PWR_ANLG2, @@ -434,13 +444,15 @@ int rt5639_headset_detect(struct snd_soc_codec *codec, int jack_insert) RT5639_PWR_MB_PU | RT5639_PWR_CLK25M_PU); snd_soc_update_bits(codec, RT5639_DUMMY1, 0x1, 0x1); - msleep(50); + msleep(100); if (snd_soc_read(codec, RT5639_IRQ_CTRL2) & 0x8) jack_type = RT5639_HEADPHO_DET; else jack_type = RT5639_HEADSET_DET; snd_soc_update_bits(codec, RT5639_IRQ_CTRL2, RT5639_MB1_OC_CLR, 0); + snd_soc_update_bits(codec, RT5639_GLB_CLK, + RT5639_SCLK_SRC_MASK, sclk_src); } else { snd_soc_update_bits(codec, RT5639_MICBIAS, RT5639_MIC1_OVCD_MASK, @@ -1186,8 +1198,6 @@ static int spk_event(struct snd_soc_dapm_widget *w, static int hp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; - switch (event) { case SND_SOC_DAPM_POST_PMU: printk("hp_event --SND_SOC_DAPM_POST_PMU\n"); diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 4f50b39cb48a..8407c638cf8a 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -25,7 +25,7 @@ #include <sound/tlv.h> #include "rt5640.h" -#if (CONFIG_SND_SOC_RT5642_MODULE | CONFIG_SND_SOC_RT5642) +#if defined(CONFIG_SND_SOC_RT5642_MODULE) || defined(CONFIG_SND_SOC_RT5642) #include "rt5640-dsp.h" #endif @@ -422,8 +422,18 @@ static int rt5640_readable_register( int rt5640_headset_detect(struct snd_soc_codec *codec, int jack_insert) { int jack_type; + int sclk_src; if (jack_insert) { + if (SND_SOC_BIAS_OFF == codec->dapm.bias_level) { + snd_soc_write(codec, RT5640_PWR_ANLG1, 0x2004); + snd_soc_write(codec, RT5640_MICBIAS, 0x3830); + snd_soc_write(codec, RT5640_DUMMY1 , 0x3701); + } + sclk_src = snd_soc_read(codec, RT5640_GLB_CLK) & + RT5640_SCLK_SRC_MASK; + snd_soc_update_bits(codec, RT5640_GLB_CLK, + RT5640_SCLK_SRC_MASK, 0x3 << RT5640_SCLK_SRC_SFT); snd_soc_update_bits(codec, RT5640_PWR_ANLG1, RT5640_PWR_LDO2, RT5640_PWR_LDO2); snd_soc_update_bits(codec, RT5640_PWR_ANLG2, @@ -435,13 +445,15 @@ int rt5640_headset_detect(struct snd_soc_codec *codec, int jack_insert) RT5640_PWR_MB_PU | RT5640_PWR_CLK25M_PU); snd_soc_update_bits(codec, RT5640_DUMMY1, 0x1, 0x1); - msleep(50); + msleep(100); if (snd_soc_read(codec, RT5640_IRQ_CTRL2) & 0x8) jack_type = RT5640_HEADPHO_DET; else jack_type = RT5640_HEADSET_DET; snd_soc_update_bits(codec, RT5640_IRQ_CTRL2, RT5640_MB1_OC_CLR, 0); + snd_soc_update_bits(codec, RT5640_GLB_CLK, + RT5640_SCLK_SRC_MASK, sclk_src); } else { snd_soc_update_bits(codec, RT5640_MICBIAS, RT5640_MIC1_OVCD_MASK, @@ -1167,8 +1179,6 @@ static int spk_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = w->codec; - static unsigned int spkl_out_enable; - static unsigned int spkr_out_enable; switch (event) { case SND_SOC_DAPM_POST_PMU: @@ -1194,9 +1204,6 @@ static int spk_event(struct snd_soc_dapm_widget *w, static int hp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; - static unsigned int hp_out_enable; - switch (event) { case SND_SOC_DAPM_POST_PMU: pr_info("hp_event --SND_SOC_DAPM_POST_PMU\n"); @@ -1808,9 +1815,8 @@ static int get_sdp_info(struct snd_soc_codec *codec, int dai_id) ret |= RT5640_U_IF3; break; -#if (CONFIG_SND_SOC_RT5643_MODULE | CONFIG_SND_SOC_RT5643 | \ - CONFIG_SND_SOC_RT5646_MODULE | CONFIG_SND_SOC_RT5646) - +#if defined(CONFIG_SND_SOC_RT5643_MODULE) || defined(CONFIG_SND_SOC_RT5643) || \ + defined(CONFIG_SND_SOC_RT5646_MODULE) || defined(CONFIG_SND_SOC_RT5646) case RT5640_AIF3: if (val == RT5640_IF_312 || val == RT5640_IF_321) ret |= RT5640_U_IF1; @@ -1910,8 +1916,8 @@ static int rt5640_hw_params(struct snd_pcm_substream *substream, RT5640_I2S_DL_MASK, val_len); snd_soc_update_bits(codec, RT5640_ADDA_CLK1, mask_clk, val_clk); } -#if (CONFIG_SND_SOC_RT5643_MODULE | CONFIG_SND_SOC_RT5643 | \ - CONFIG_SND_SOC_RT5646_MODULE | CONFIG_SND_SOC_RT5646) +#if defined(CONFIG_SND_SOC_RT5643_MODULE) || defined(CONFIG_SND_SOC_RT5643) || \ + defined(CONFIG_SND_SOC_RT5646_MODULE) || defined(CONFIG_SND_SOC_RT5646) if (dai_sel & RT5640_U_IF3) { mask_clk = RT5640_I2S_BCLK_MS3_MASK | RT5640_I2S_PD3_MASK; val_clk = bclk_ms << RT5640_I2S_BCLK_MS3_SFT | @@ -1994,8 +2000,8 @@ static int rt5640_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) RT5640_I2S_MS_MASK | RT5640_I2S_BP_MASK | RT5640_I2S_DF_MASK, reg_val); } -#if (CONFIG_SND_SOC_RT5643_MODULE | CONFIG_SND_SOC_RT5643 | \ - CONFIG_SND_SOC_RT5646_MODULE | CONFIG_SND_SOC_RT5646) +#if defined(CONFIG_SND_SOC_RT5643_MODULE) || defined(CONFIG_SND_SOC_RT5643) || \ + defined(CONFIG_SND_SOC_RT5646_MODULE) || defined(CONFIG_SND_SOC_RT5646) if (dai_sel & RT5640_U_IF3) { snd_soc_update_bits(codec, RT5640_I2S3_SDP, RT5640_I2S_MS_MASK | RT5640_I2S_BP_MASK | @@ -2123,10 +2129,8 @@ static int rt5640_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, break; case RT5640_PLL1_S_BCLK1: case RT5640_PLL1_S_BCLK2: - -#if (CONFIG_SND_SOC_RT5643_MODULE | CONFIG_SND_SOC_RT5643 | \ - CONFIG_SND_SOC_RT5646_MODULE | CONFIG_SND_SOC_RT5646) - +#if defined(CONFIG_SND_SOC_RT5643_MODULE) || defined(CONFIG_SND_SOC_RT5643) || \ + defined(CONFIG_SND_SOC_RT5646_MODULE) || defined(CONFIG_SND_SOC_RT5646) case RT5640_PLL1_S_BCLK3: #endif @@ -2346,8 +2350,7 @@ static int rt5640_probe(struct snd_soc_codec *codec) rt5640_reg_init(codec); #endif - -#if (CONFIG_SND_SOC_RT5642_MODULE | CONFIG_SND_SOC_RT5642) +#if defined(CONFIG_SND_SOC_RT5642_MODULE) || defined(CONFIG_SND_SOC_RT5642) rt5640_register_dsp(codec); #endif @@ -2446,8 +2449,8 @@ struct snd_soc_dai_driver rt5640_dai[] = { }, .ops = &rt5640_aif_dai_ops, }, -#if (CONFIG_SND_SOC_RT5643_MODULE | CONFIG_SND_SOC_RT5643 | \ - CONFIG_SND_SOC_RT5646_MODULE | CONFIG_SND_SOC_RT5646) +#if defined(CONFIG_SND_SOC_RT5643_MODULE) || defined(CONFIG_SND_SOC_RT5643) || \ + defined(CONFIG_SND_SOC_RT5646_MODULE) || defined(CONFIG_SND_SOC_RT5646) { .name = "rt5640-aif3", .id = RT5640_AIF3, diff --git a/sound/soc/codecs/second_rate_pps_driver.h b/sound/soc/codecs/second_rate_pps_driver.h index c6c128a027dd..9956c08bcd80 100644 --- a/sound/soc/codecs/second_rate_pps_driver.h +++ b/sound/soc/codecs/second_rate_pps_driver.h @@ -14,13 +14,6 @@ static control main44_VOLUME_controls[] = { static char *main44_VOLUME_control_names[] = { }; - - -static char *main44_REG_Section_names[] = { - "miniDSP_A_reg_values", - "miniDSP_D_reg_values", -}; - reg_value main44_REG_Section_init_program[] = { { 0,0x0}, { 0x7F,0x00}, diff --git a/sound/soc/codecs/spdif_transciever.c b/sound/soc/codecs/spdif_transciever.c index 7c1bf5c04eb9..6173b3a5b082 100644 --- a/sound/soc/codecs/spdif_transciever.c +++ b/sound/soc/codecs/spdif_transciever.c @@ -8,12 +8,15 @@ * Author: Steve Chen, <schen@mvista.com> * Copyright: (C) 2009 MontaVista Software, Inc., <source@mvista.com> * Copyright: (C) 2009 Texas Instruments, India + * Copyright: (C) 2009-2012, NVIDIA Corporation. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ + +#include <asm/mach-types.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/slab.h> @@ -26,9 +29,34 @@ #define STUB_RATES SNDRV_PCM_RATE_8000_96000 #define STUB_FORMATS SNDRV_PCM_FMTBIT_S16_LE - static struct snd_soc_codec_driver soc_codec_spdif_dit; +static int spdif_probe(struct snd_soc_codec *codec) { + codec->dapm.idle_bias_off = 1; + return 0; +} + +static const struct snd_soc_dapm_widget spdif_dapm_widgets[] = { + SND_SOC_DAPM_VMID("spdif dummy Vmid"), +}; + +static int spdif_write(struct snd_soc_codec * codec, unsigned int reg, + unsigned int val){ + return 0; +} + +static int spdif_read(struct snd_soc_codec * codec, unsigned int reg){ + return 0; +} + +static struct snd_soc_codec_driver soc_codec_spdif_dit1 = { + .probe = spdif_probe, + .dapm_widgets = spdif_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(spdif_dapm_widgets), + .read = spdif_read, + .write = spdif_write, +}; + static struct snd_soc_dai_driver dit_stub_dai = { .name = "dit-hifi", .playback = { @@ -49,8 +77,12 @@ static struct snd_soc_dai_driver dit_stub_dai = { static int spdif_dit_probe(struct platform_device *pdev) { - return snd_soc_register_codec(&pdev->dev, &soc_codec_spdif_dit, - &dit_stub_dai, 1); + if(machine_is_kai() || machine_is_tegra_enterprise()) + return snd_soc_register_codec(&pdev->dev, + &soc_codec_spdif_dit1, &dit_stub_dai, 1); + else + return snd_soc_register_codec(&pdev->dev, + &soc_codec_spdif_dit, &dit_stub_dai, 1); } static int spdif_dit_remove(struct platform_device *pdev) diff --git a/sound/soc/codecs/tlv320aic326x.c b/sound/soc/codecs/tlv320aic326x.c index 8bbd295a3328..5d6b92904d56 100644 --- a/sound/soc/codecs/tlv320aic326x.c +++ b/sound/soc/codecs/tlv320aic326x.c @@ -81,9 +81,6 @@ static u8 aic3262_reg_ctl; * This function reprograms the clock dividers etc. this flag can be used to * disable this when the clock dividers are programmed by pps config file */ -static int soc_static_freq_config = 1; -static struct aic3262_priv *aic3262_priv_data; -static struct i2c_client *i2c_pdev; static struct snd_soc_codec *aic3262_codec; /* @@ -849,7 +846,6 @@ static const struct aic3262_rate_divs aic3262_divs[] = { static void aic3262_multi_i2s_dump_regs(struct snd_soc_dai *dai) { struct snd_soc_codec *codec = dai->codec; - struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec); unsigned int counter; DBG(KERN_INFO "#%s: Dai Active %d ASI%d REGS DUMP\n", @@ -1965,7 +1961,7 @@ static int aic3262_multi_i2s_hw_params(struct snd_pcm_substream *substream, * We can use this function to disable the DAC and ADC specific inputs from the * individual ASI Ports of the Audio Codec. */ -static int aic3262_multi_i2s_shutdown(struct snd_pcm_substream *substream, +static void aic3262_multi_i2s_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; @@ -2106,7 +2102,7 @@ static int aic3262_multi_i2s_shutdown(struct snd_pcm_substream *substream, aic3262->active_count--; } err: - return 0; + return; } @@ -2547,13 +2543,13 @@ static const struct snd_kcontrol_new hpl_output_mixer_controls[] = { SOC_DAPM_SINGLE("MAL Switch", HP_AMP_CNTL_R1, 7, 1, 0), SOC_DAPM_SINGLE("LDAC Switch", HP_AMP_CNTL_R1, 5, 1, 0), SOC_DAPM_SINGLE_TLV("LOL-B1 Volume", HP_AMP_CNTL_R2, 0, - 0x7f, 1, lo_hp_tlv), + 0x7f, 0, lo_hp_tlv), }; /* Right HPR Mixer */ static const struct snd_kcontrol_new hpr_output_mixer_controls[] = { SOC_DAPM_SINGLE_TLV("LOR-B1 Volume", HP_AMP_CNTL_R3, 0, - 0x7f, 1, lo_hp_tlv), + 0x7f, 0, lo_hp_tlv), SOC_DAPM_SINGLE("LDAC Switch", HP_AMP_CNTL_R1, 2, 1, 0), SOC_DAPM_SINGLE("RDAC Switch", HP_AMP_CNTL_R1, 4, 1, 0), SOC_DAPM_SINGLE("MAR Switch", HP_AMP_CNTL_R1, 6, 1, 0), @@ -3565,7 +3561,7 @@ void aic3262_write_reg_cache(struct snd_soc_codec *codec, *---------------------------------------------------------------------------- */ -u8 aic3262_read(struct snd_soc_codec *codec, u16 reg) +unsigned int aic3262_read(struct snd_soc_codec *codec, unsigned int reg) { struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec); u8 value; @@ -3573,7 +3569,7 @@ u8 aic3262_read(struct snd_soc_codec *codec, u16 reg) u16 *cache = codec->reg_cache; u16 cmd; u8 buffer[2]; - int rc; + int rc = 0; reg = reg % 128; if (reg >= AIC3262_CACHEREGNUM) { @@ -3619,7 +3615,8 @@ u8 aic3262_read(struct snd_soc_codec *codec, u16 reg) * *---------------------------------------------------------------------------- */ -int aic3262_write(struct snd_soc_codec *codec, u16 reg, u8 value) +int aic3262_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) { struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec); u8 data[2]; @@ -3855,8 +3852,6 @@ int i2c_verify_book0(struct snd_soc_codec *codec) static int aic3262_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { - struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec); - u8 value; switch (level) { /* full On */ case SND_SOC_BIAS_ON: @@ -4400,6 +4395,7 @@ static int aic3262_spi_write(struct spi_device *spi, const char *data, int len) return len; } +#ifdef RUN_DELAYED_WORK /* * This function forces any delayed work to be queued and run. */ @@ -4418,6 +4414,8 @@ static int run_delayed_work(struct delayed_work *dwork) } return ret; } +#endif + static int __devinit aic3262_spi_probe(struct spi_device *spi) { int ret; diff --git a/sound/soc/codecs/tlv320aic326x.h b/sound/soc/codecs/tlv320aic326x.h index a31cc9eca5ca..bfcbefc5c079 100644 --- a/sound/soc/codecs/tlv320aic326x.h +++ b/sound/soc/codecs/tlv320aic326x.h @@ -36,7 +36,7 @@ /* Enable register caching on write */ #define EN_REG_CACHE 1 -#define MULTIBYTE_CONFIG_SUPPORT +//#define MULTIBYTE_CONFIG_SUPPORT /*Setting all codec reg/write locally*/ /* This definition is added as the snd_ direct call are @@ -45,12 +45,12 @@ page, so fix that before commenting this line*/ #define LOCAL_REG_ACCESS 1 /* Macro to enable the inclusion of tiload kernel driver */ -#define AIC3262_TiLoad +//#define AIC3262_TiLoad /* Macro enables or disables support for miniDSP in the driver */ /* Enable the AIC3262_TiLoad macro first before enabling these macros */ -#define CONFIG_MINI_DSP +//#define CONFIG_MINI_DSP /*#undef CONFIG_MINI_DSP*/ /* Enable or disable controls to have Input routing*/ @@ -657,11 +657,12 @@ extern int aic326x_headset_detect(struct snd_soc_codec *codec, extern int aic326x_headset_button_init(struct snd_soc_codec *codec, struct snd_soc_jack *jack, int jack_type); -extern u8 aic3262_read(struct snd_soc_codec *codec, u16 reg); +extern unsigned int aic3262_read(struct snd_soc_codec *codec, unsigned int reg); extern u16 aic3262_read_2byte(struct snd_soc_codec *codec, u16 reg); extern int aic3262_reset_cache(struct snd_soc_codec *codec); extern int aic3262_change_page(struct snd_soc_codec *codec, u8 new_page); -extern int aic3262_write(struct snd_soc_codec *codec, u16 reg, u8 value); +extern int aic3262_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value); extern void aic3262_write_reg_cache(struct snd_soc_codec *codec, u16 reg, u8 value); extern int aic3262_change_book(struct snd_soc_codec *codec, u8 new_book); diff --git a/sound/soc/codecs/tlv320aic326x_mini-dsp.c b/sound/soc/codecs/tlv320aic326x_mini-dsp.c index 6d55abb4dac8..0ef0fd09760c 100644 --- a/sound/soc/codecs/tlv320aic326x_mini-dsp.c +++ b/sound/soc/codecs/tlv320aic326x_mini-dsp.c @@ -601,25 +601,27 @@ struct process_flow{ int set_minidsp_mode(struct snd_soc_codec *codec, int new_mode, int new_config) { - - if (codec == NULL) { - printk(KERN_INFO "%s codec is NULL\n",__func__); - } - struct aic3262_priv *aic326x = snd_soc_codec_get_drvdata(codec); - struct snd_soc_dapm_context *dapm = &codec->dapm; + struct aic3262_priv *aic326x; + struct snd_soc_dapm_context *dapm; struct process_flow * pflows = &miniDSP_programs[new_mode]; - u8 reg63, reg81, pll_pow, ndac_pow, mdac_pow, nadc_pow, madc_pow; - + u8 pll_pow, ndac_pow, mdac_pow, nadc_pow; u8 adc_status,dac_status; - u8 reg, val; - u8 shift; - volatile u16 counter; - int (*ptransfer)(struct snd_soc_codec *codec, - reg_value *program_ptr, - int size); + int (*ptransfer)(struct snd_soc_codec *codec, reg_value *program_ptr, + int size); printk("%s:New Switch mode = %d New Config= %d\n", __func__, new_mode,new_config); + + if (codec == NULL) { + printk(KERN_INFO "%s codec is NULL\n", __func__); + return 0; + } + aic326x = snd_soc_codec_get_drvdata(codec); + dapm = &codec->dapm; + + printk(KERN_INFO "%s:New Switch mode = %d New Config= %d\n", __func__, + new_mode, new_config); + if (new_mode >= ARRAY_SIZE(miniDSP_programs)) return 0; // error condition if (new_config > MAXCONFIG) @@ -1231,7 +1233,7 @@ static int __new_control_put_minidsp_mux(struct snd_kcontrol *kcontrol, int ret_val = -1, array_size; control *array; char **array_names; - char *control_name, *control_name1, *control_name2; + char *control_name, *control_name1; struct aic3262_priv *aic326x = snd_soc_codec_get_drvdata(codec); i2c = codec->control_data; diff --git a/sound/soc/codecs/tlv320aic326x_minidsp_config.c b/sound/soc/codecs/tlv320aic326x_minidsp_config.c index e34ffbe2ca82..97a41c3ecf2b 100644 --- a/sound/soc/codecs/tlv320aic326x_minidsp_config.c +++ b/sound/soc/codecs/tlv320aic326x_minidsp_config.c @@ -347,17 +347,12 @@ int aic3262_add_multiconfig_controls(struct snd_soc_codec *codec) *--------------------------------------------------------------------------- */ void minidsp_multiconfig(struct snd_soc_codec *codec, - reg_value *a_patch, int a_size, - reg_value *d_patch, int d_size) + reg_value *a_patch, int a_size, reg_value *d_patch, int d_size) { - struct aic3262_priv *aic326x = snd_soc_codec_get_drvdata(codec); - int val1,val2; int adc_status,dac_status; int (*ptransfer)(struct snd_soc_codec *codec, - reg_value *program_ptr, - int size); - -printk("======in the config_multiconfiguration function==== \n"); + reg_value *program_ptr, int size); + printk(KERN_INFO "======in the config_multiconfiguration function====\n"); #ifndef MULTIBYTE_I2C ptransfer = byte_i2c_array_transfer; #else diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index 0218d6ce0557..2a2d16886989 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -1404,6 +1404,7 @@ static struct { { 1500, 0x9, 0x2, 2 }, }; +#ifdef SYS_BCLK_RATIO /* CLK_SYS/BCLK ratios - multiplied by 10 due to .5s */ static struct { int ratio; @@ -1427,6 +1428,7 @@ static struct { { 440, 19 }, { 480, 20 }, }; +#endif /* Sample rates for DSP */ static struct { @@ -1778,9 +1780,6 @@ static int wm8903_resume(struct snd_soc_codec *codec) if (wm8903->irq) enable_irq(wm8903->irq); - /* Bring the codec back up to standby first to minimise pop/clicks */ - wm8903_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - /* Sync back everything else */ if (tmp_cache) { for (i = 2; i < ARRAY_SIZE(wm8903_reg_defaults); i++) @@ -1791,6 +1790,9 @@ static int wm8903_resume(struct snd_soc_codec *codec) dev_err(codec->dev, "Failed to allocate temporary cache\n"); } + /* Bring the codec back up to standby first to minimise pop/clicks */ + wm8903_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + return 0; } diff --git a/sound/soc/sh/siu_pcm.c b/sound/soc/sh/siu_pcm.c index de9abd032fd4..5cfcc655e95f 100644 --- a/sound/soc/sh/siu_pcm.c +++ b/sound/soc/sh/siu_pcm.c @@ -180,13 +180,8 @@ static int siu_pcm_rd_set(struct siu_port *port_info, sg_dma_len(&sg) = size; sg_dma_address(&sg) = buff; -<<<<<<< HEAD - desc = siu_stream->chan->device->device_prep_slave_sg(siu_stream->chan, - &sg, 1, DMA_FROM_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); -======= desc = dmaengine_prep_slave_sg(siu_stream->chan, &sg, 1, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); ->>>>>>> 1605282... dmaengine/dma_slave: introduce inline wrappers if (!desc) { dev_err(dev, "Failed to allocate dma descriptor\n"); return -ENOMEM; diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile index d546046d1e1d..9c4346aa265c 100644 --- a/sound/soc/tegra/Makefile +++ b/sound/soc/tegra/Makefile @@ -2,6 +2,7 @@ GCOV_PROFILE := y # Tegra platform Support snd-soc-tegra-pcm-objs := tegra_pcm.o +snd-soc-tegra-tdm-pcm-objs := tegra_tdm_pcm.o snd-soc-tegra20-spdif-objs := tegra20_spdif.o snd-soc-tegra-utils-objs += tegra_asoc_utils.o snd-soc-tegra20-das-objs := tegra20_das.o @@ -13,6 +14,7 @@ snd-soc-tegra30-dam-objs := tegra30_dam.o obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-pcm.o obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-utils.o +obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-tdm-pcm.o obj-$(CONFIG_SND_SOC_TEGRA20_DAS) += snd-soc-tegra20-das.o obj-$(CONFIG_SND_SOC_TEGRA20_I2S) += snd-soc-tegra20-i2s.o obj-$(CONFIG_SND_SOC_TEGRA30_AHUB) += snd-soc-tegra30-ahub.o diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c index e6de1c07a399..d90c0991ed65 100644 --- a/sound/soc/tegra/tegra20_i2s.c +++ b/sound/soc/tegra/tegra20_i2s.c @@ -191,8 +191,9 @@ static int tegra20_i2s_hw_params(struct snd_pcm_substream *substream, struct tegra20_i2s *i2s = snd_soc_dai_get_drvdata(dai); u32 reg; int ret, sample_size, srate, i2sclock, bitcnt, i2sclk_div; + u32 bit_format = i2s->reg_ctrl & TEGRA20_I2S_CTRL_BIT_FORMAT_MASK; - if ((i2s->reg_ctrl & TEGRA20_I2S_CTRL_BIT_FORMAT_I2S) && + if ((bit_format == TEGRA20_I2S_CTRL_BIT_FORMAT_I2S) && (params_channels(params) != 2)) { dev_err(dev, "Only Stereo is supported in I2s mode\n"); return -EINVAL; diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c index 710d9465b4b0..30b7e481acc4 100644 --- a/sound/soc/tegra/tegra30_ahub.c +++ b/sound/soc/tegra/tegra30_ahub.c @@ -116,6 +116,15 @@ void tegra30_ahub_disable_clocks(void) clk_disable(ahub->clk_d_audio); } +/* + * for TDM mode, ahub has to run faster than I2S controller. This will avoid + * FIFO overflow/underflow, the causes of slot-hopping symptoms + */ +void tegra30_ahub_clock_set_rate(int rate) +{ + clk_set_rate(ahub->clk_d_audio, rate); +} + #ifdef CONFIG_DEBUG_FS static inline u32 tegra30_ahub_read(u32 space, u32 reg) { @@ -272,6 +281,75 @@ int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif, return 0; } +int tegra30_ahub_rx_fifo_is_enabled(int i2s_id) +{ + int val, mask; + + val = tegra30_apbif_read(TEGRA30_AHUB_I2S_LIVE_STATUS); + mask = (TEGRA30_AHUB_I2S_LIVE_STATUS_I2S0_RX_FIFO_ENABLED << (i2s_id*2)); + val &= mask; + return val; +} + +int tegra30_ahub_tx_fifo_is_enabled(int i2s_id) +{ + int val, mask; + + val = tegra30_apbif_read(TEGRA30_AHUB_I2S_LIVE_STATUS); + mask = (TEGRA30_AHUB_I2S_LIVE_STATUS_I2S0_TX_FIFO_ENABLED << (i2s_id*2)); + val &= mask; + + return val; +} + +int tegra30_ahub_set_rx_fifo_pack_mode(enum tegra30_ahub_rxcif rxcif, + unsigned int pack_mode) +{ + int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0; + int reg, val; + + tegra30_ahub_enable_clocks(); + reg = TEGRA30_AHUB_CHANNEL_CTRL + + (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE); + val = tegra30_apbif_read(reg); + + val &= ~TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_MASK; + val &= ~TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_EN; + + if ((pack_mode == TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_16) || + (pack_mode == TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_8_4)) + val |= (TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_EN | + pack_mode); + tegra30_apbif_write(reg, val); + tegra30_ahub_disable_clocks(); + + return 0; +} + +int tegra30_ahub_set_tx_fifo_pack_mode(enum tegra30_ahub_txcif txcif, + unsigned int pack_mode) +{ + int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0; + int reg, val; + + tegra30_ahub_enable_clocks(); + reg = TEGRA30_AHUB_CHANNEL_CTRL + + (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE); + val = tegra30_apbif_read(reg); + + val &= ~TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_MASK; + val &= ~TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_EN; + + if ((pack_mode == TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_16) || + (pack_mode == TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_8_4)) + val |= (TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_EN | + pack_mode); + tegra30_apbif_write(reg, val); + tegra30_ahub_disable_clocks(); + + return 0; +} + int tegra30_ahub_enable_rx_fifo(enum tegra30_ahub_rxcif rxcif) { int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0; @@ -480,6 +558,54 @@ int tegra30_ahub_set_tx_cif_channels(enum tegra30_ahub_txcif txcif, return 0; } +int tegra30_ahub_set_rx_cif_bits(enum tegra30_ahub_rxcif rxcif, + unsigned int audio_bits, + unsigned int client_bits) +{ + int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0; + unsigned int reg, val; + + tegra30_ahub_enable_clocks(); + + reg = TEGRA30_AHUB_CIF_RX_CTRL + + (channel * TEGRA30_AHUB_CIF_RX_CTRL_STRIDE); + val = tegra30_apbif_read(reg); + val &= ~(TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_MASK | + TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_MASK); + val |= ((audio_bits) << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) | + ((client_bits) << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT); + tegra30_apbif_write(reg, val); + + tegra30_ahub_disable_clocks(); + + return 0; +} + +int tegra30_ahub_set_tx_cif_bits(enum tegra30_ahub_txcif txcif, + unsigned int audio_bits, + unsigned int client_bits) +{ + int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0; + unsigned int reg, val; + + tegra30_ahub_enable_clocks(); + + reg = TEGRA30_AHUB_CIF_TX_CTRL + + (channel * TEGRA30_AHUB_CIF_TX_CTRL_STRIDE); + val = tegra30_apbif_read(reg); + val &= ~(TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_MASK | + TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_MASK); + val |= ((audio_bits) << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) | + ((client_bits) << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT); + + tegra30_apbif_write(reg, val); + + tegra30_ahub_disable_clocks(); + + return 0; +} + + static int __devinit tegra30_ahub_probe(struct platform_device *pdev) { struct resource *res0, *res1, *region; @@ -507,6 +633,7 @@ static int __devinit tegra30_ahub_probe(struct platform_device *pdev) goto err_free; } clkm_rate = clk_get_rate(clk_get_parent(ahub->clk_d_audio)); + while (clkm_rate > 12000000) clkm_rate >>= 1; diff --git a/sound/soc/tegra/tegra30_ahub.h b/sound/soc/tegra/tegra30_ahub.h index 7de1b7c86c7f..8dc27abc5aed 100644 --- a/sound/soc/tegra/tegra30_ahub.h +++ b/sound/soc/tegra/tegra30_ahub.h @@ -464,6 +464,7 @@ enum tegra30_ahub_rxcif { extern void tegra30_ahub_enable_clocks(void); extern void tegra30_ahub_disable_clocks(void); +extern void tegra30_ahub_clock_set_rate(int rate); extern int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif, unsigned long *fiforeg, @@ -471,8 +472,13 @@ extern int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif, extern int tegra30_ahub_set_rx_cif_channels(enum tegra30_ahub_rxcif rxcif, unsigned int audio_ch, unsigned int client_ch); +extern int tegra30_ahub_set_rx_cif_bits(enum tegra30_ahub_rxcif rxcif, + unsigned int audio_bits, + unsigned int client_bits); extern int tegra30_ahub_enable_rx_fifo(enum tegra30_ahub_rxcif rxcif); extern int tegra30_ahub_disable_rx_fifo(enum tegra30_ahub_rxcif rxcif); +extern int tegra30_ahub_set_rx_fifo_pack_mode(enum tegra30_ahub_rxcif rxcif, + unsigned int pack_mode); extern int tegra30_ahub_free_rx_fifo(enum tegra30_ahub_rxcif rxcif); extern int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif, @@ -481,14 +487,22 @@ extern int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif, extern int tegra30_ahub_set_tx_cif_channels(enum tegra30_ahub_txcif txcif, unsigned int audio_ch, unsigned int client_ch); +extern int tegra30_ahub_set_tx_cif_bits(enum tegra30_ahub_txcif txcif, + unsigned int audio_bits, + unsigned int client_bits); extern int tegra30_ahub_enable_tx_fifo(enum tegra30_ahub_txcif txcif); extern int tegra30_ahub_disable_tx_fifo(enum tegra30_ahub_txcif txcif); +extern int tegra30_ahub_set_tx_fifo_pack_mode(enum tegra30_ahub_txcif txcif, + unsigned int pack_mode); extern int tegra30_ahub_free_tx_fifo(enum tegra30_ahub_txcif txcif); extern int tegra30_ahub_set_rx_cif_source(enum tegra30_ahub_rxcif rxcif, enum tegra30_ahub_txcif txcif); extern int tegra30_ahub_unset_rx_cif_source(enum tegra30_ahub_rxcif rxcif); +extern int tegra30_ahub_rx_fifo_is_enabled(int i2s_id); +extern int tegra30_ahub_tx_fifo_is_enabled(int i2s_id); + #ifdef CONFIG_PM extern int tegra30_ahub_apbif_resume(void); #endif diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c index 02d1038ea36e..449359837efb 100644 --- a/sound/soc/tegra/tegra30_i2s.c +++ b/sound/soc/tegra/tegra30_i2s.c @@ -36,6 +36,7 @@ #include <linux/seq_file.h> #include <linux/slab.h> #include <linux/io.h> +#include <linux/delay.h> #include <mach/iomap.h> #include <sound/core.h> #include <sound/pcm.h> @@ -280,6 +281,194 @@ static int tegra30_i2s_set_fmt(struct snd_soc_dai *dai, return 0; } +static void tegra30_i2s_set_channel_bit_count(struct tegra30_i2s *i2s, + int i2sclock, int srate) +{ + int sym_bitclk, bitcnt; + u32 val; + + bitcnt = (i2sclock / (2 * srate)) - 1; + sym_bitclk = !(i2sclock % (2 * srate)); + + val = bitcnt << TEGRA30_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT; + + if (!sym_bitclk) + val |= TEGRA30_I2S_TIMING_NON_SYM_ENABLE; + + tegra30_i2s_write(i2s, TEGRA30_I2S_TIMING, val); +} + +static void tegra30_i2s_set_data_offset(struct tegra30_i2s *i2s) +{ + u32 val; + int rx_data_offset = i2s->dsp_config.rx_data_offset; + int tx_data_offset = i2s->dsp_config.tx_data_offset; + + val = (rx_data_offset << + TEGRA30_I2S_OFFSET_RX_DATA_OFFSET_SHIFT) | + (tx_data_offset << + TEGRA30_I2S_OFFSET_TX_DATA_OFFSET_SHIFT); + + tegra30_i2s_write(i2s, TEGRA30_I2S_OFFSET, val); +} + +static void tegra30_i2s_set_slot_control(struct tegra30_i2s *i2s, int stream) +{ + u32 val; + int tx_mask = i2s->dsp_config.tx_mask; + int rx_mask = i2s->dsp_config.rx_mask; + + val = tegra30_i2s_read(i2s, TEGRA30_I2S_SLOT_CTRL); + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + val &= ~TEGRA30_I2S_SLOT_CTRL_TX_SLOT_ENABLES_MASK; + val |= (tx_mask << TEGRA30_I2S_SLOT_CTRL_TX_SLOT_ENABLES_SHIFT); + } else { + val &= ~TEGRA30_I2S_SLOT_CTRL_RX_SLOT_ENABLES_MASK; + val |= (rx_mask << TEGRA30_I2S_SLOT_CTRL_RX_SLOT_ENABLES_SHIFT); + } + + val &= ~TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_MASK; + val |= (i2s->dsp_config.num_slots - 1) + << TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_SHIFT; + + tegra30_i2s_write(i2s, TEGRA30_I2S_SLOT_CTRL, val); +} + +static int tegra30_i2s_tdm_setup_clocks(struct device *dev, + struct tegra30_i2s *i2s, int *i2sclock) +{ + int ret; + + if (i2s->reg_ctrl & TEGRA30_I2S_CTRL_MASTER_ENABLE) { + + ret = clk_set_parent(i2s->clk_i2s, i2s->clk_pll_a_out0); + if (ret) { + dev_err(dev, "Can't set parent of I2S clock\n"); + return ret; + } + ret = clk_set_rate(i2s->clk_i2s, *i2sclock); + if (ret) { + dev_err(dev, "Can't set I2S clock rate: %d\n", ret); + return ret; + } + } else { + + ret = clk_set_rate(i2s->clk_i2s_sync, *i2sclock); + if (ret) { + dev_err(dev, "Can't set I2S sync clock rate\n"); + return ret; + } + + ret = clk_set_rate(i2s->clk_audio_2x, *i2sclock); + if (ret) { + dev_err(dev, "Can't set audio2x clock rate\n"); + return ret; + } + + ret = clk_set_parent(i2s->clk_i2s, i2s->clk_audio_2x); + if (ret) { + dev_err(dev, "Can't set parent of audio2x clock\n"); + return ret; + } + } + return ret; +} + + +static int tegra30_i2s_tdm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct device *dev = substream->pcm->card->dev; + struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai); + u32 val; + int i2s_client_ch, i2s_audio_ch, i2s_audio_bits, i2s_client_bits; + int i2sclock, srate; + int ret; + + srate = params_rate(params); + + i2sclock = srate * + i2s->dsp_config.num_slots * + i2s->dsp_config.slot_width; + + ret = tegra30_i2s_tdm_setup_clocks(dev, i2s, &i2sclock); + if (ret) + return -EINVAL; + + /* Run ahub clock greater than i2sclock */ + tegra30_ahub_clock_set_rate(i2sclock*2); + + tegra30_i2s_enable_clocks(i2s); + + tegra30_i2s_set_channel_bit_count(i2s, i2sclock*2, srate); + + i2s_client_ch = i2s->dsp_config.num_slots; + i2s_audio_ch = i2s->dsp_config.num_slots; + + i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_BIT_SIZE_MASK; + switch (i2s->dsp_config.slot_width) { + case 16: + i2s_audio_bits = TEGRA30_AUDIOCIF_BITS_16; + i2s_client_bits = TEGRA30_AUDIOCIF_BITS_16; + i2s->reg_ctrl |= TEGRA30_I2S_CTRL_BIT_SIZE_16; + break; + case 32: + i2s_audio_bits = TEGRA30_AUDIOCIF_BITS_32; + i2s_client_bits = TEGRA30_AUDIOCIF_BITS_32; + i2s->reg_ctrl |= TEGRA30_I2S_CTRL_BIT_SIZE_32; + break; + } + + val = (0 << TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) | + ((i2s_audio_ch - 1) << + TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) | + ((i2s_client_ch - 1) << + TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) | + (i2s_audio_bits << + TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) | + (i2s_client_bits << + TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + val |= TEGRA30_AUDIOCIF_CTRL_DIRECTION_RX; + tegra30_i2s_write(i2s, TEGRA30_I2S_CIF_RX_CTRL, val); + + tegra30_ahub_set_tx_cif_channels(i2s->txcif, + i2s_audio_ch, + i2s_client_ch); + tegra30_ahub_set_tx_cif_bits(i2s->txcif, + i2s_audio_bits, + i2s_client_bits); + tegra30_ahub_set_tx_fifo_pack_mode(i2s->txcif, 0); + + } else { + val |= TEGRA30_AUDIOCIF_CTRL_DIRECTION_TX; + tegra30_i2s_write(i2s, TEGRA30_I2S_CIF_TX_CTRL, val); + + tegra30_ahub_set_rx_cif_channels(i2s->rxcif, + i2s_audio_ch, + i2s_client_ch); + tegra30_ahub_set_rx_cif_bits(i2s->rxcif, + i2s_audio_bits, + i2s_client_bits); + tegra30_ahub_set_rx_fifo_pack_mode(i2s->rxcif, 0); + } + + tegra30_i2s_set_slot_control(i2s, substream->stream); + + tegra30_i2s_set_data_offset(i2s); + + i2s->reg_ch_ctrl &= ~TEGRA30_I2S_CH_CTRL_FSYNC_WIDTH_MASK; + i2s->reg_ch_ctrl |= (i2s->dsp_config.slot_width - 1) << + TEGRA30_I2S_CH_CTRL_FSYNC_WIDTH_SHIFT; + tegra30_i2s_write(i2s, TEGRA30_I2S_CH_CTRL, i2s->reg_ch_ctrl); + + tegra30_i2s_disable_clocks(i2s); + + return 0; +} + static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -300,6 +489,12 @@ static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } + /* TDM mode */ + if ((i2s->reg_ctrl & TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC) && + (i2s->dsp_config.slot_width > 2)) + return tegra30_i2s_tdm_hw_params(substream, params, dai); + + srate = params_rate(params); if (i2s->reg_ctrl & TEGRA30_I2S_CTRL_MASTER_ENABLE) { @@ -423,12 +618,15 @@ static void tegra30_i2s_start_playback(struct tegra30_i2s *i2s) static void tegra30_i2s_stop_playback(struct tegra30_i2s *i2s) { - tegra30_ahub_disable_tx_fifo(i2s->txcif); + int dcnt = 10; /* if this is the only user of i2s tx then disable it*/ + tegra30_ahub_disable_tx_fifo(i2s->txcif); if (i2s->playback_ref_count == 1) { i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_TX; tegra30_i2s_write(i2s, TEGRA30_I2S_CTRL, i2s->reg_ctrl); } + while (tegra30_ahub_tx_fifo_is_enabled(i2s->id) && dcnt--) + udelay(100); } static void tegra30_i2s_start_capture(struct tegra30_i2s *i2s) @@ -442,11 +640,14 @@ static void tegra30_i2s_start_capture(struct tegra30_i2s *i2s) static void tegra30_i2s_stop_capture(struct tegra30_i2s *i2s) { + int dcnt = 10; tegra30_ahub_disable_rx_fifo(i2s->rxcif); if (!i2s->is_call_mode_rec) { i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_RX; tegra30_i2s_write(i2s, TEGRA30_I2S_CTRL, i2s->reg_ctrl); } + while (tegra30_ahub_rx_fifo_is_enabled(i2s->id) && dcnt--) + udelay(100); } static int tegra30_i2s_trigger(struct snd_pcm_substream *substream, int cmd, @@ -500,6 +701,33 @@ static int tegra30_i2s_probe(struct snd_soc_dai *dai) tegra30_i2s_disable_clocks(i2s); #endif + /* Default values for DSP mode */ + i2s->dsp_config.num_slots = 1; + i2s->dsp_config.slot_width = 2; + i2s->dsp_config.tx_mask = 1; + i2s->dsp_config.rx_mask = 1; + i2s->dsp_config.rx_data_offset = 1; + i2s->dsp_config.tx_data_offset = 1; + + + return 0; +} + +int tegra30_i2s_set_tdm_slot(struct snd_soc_dai *cpu_dai, + unsigned int tx_mask, + unsigned int rx_mask, + int slots, + int slot_width) +{ + struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(cpu_dai); + + i2s->dsp_config.num_slots = slots; + i2s->dsp_config.slot_width = slot_width; + i2s->dsp_config.tx_mask = tx_mask; + i2s->dsp_config.rx_mask = rx_mask; + i2s->dsp_config.rx_data_offset = 0; + i2s->dsp_config.tx_data_offset = 0; + return 0; } @@ -534,6 +762,7 @@ static struct snd_soc_dai_ops tegra30_i2s_dai_ops = { .set_fmt = tegra30_i2s_set_fmt, .hw_params = tegra30_i2s_hw_params, .trigger = tegra30_i2s_trigger, + .set_tdm_slot = tegra30_i2s_set_tdm_slot, }; #define TEGRA30_I2S_DAI(id) \ @@ -543,13 +772,13 @@ static struct snd_soc_dai_ops tegra30_i2s_dai_ops = { .resume = tegra30_i2s_resume, \ .playback = { \ .channels_min = 1, \ - .channels_max = 2, \ + .channels_max = 16, \ .rates = SNDRV_PCM_RATE_8000_96000, \ .formats = SNDRV_PCM_FMTBIT_S16_LE, \ }, \ .capture = { \ .channels_min = 1, \ - .channels_max = 2, \ + .channels_max = 16, \ .rates = SNDRV_PCM_RATE_8000_96000, \ .formats = SNDRV_PCM_FMTBIT_S16_LE, \ }, \ @@ -726,10 +955,7 @@ int tegra30_make_voice_call_connections(struct codec_config *codec_info, tegra30_dam_enable(bb_i2s->dam_ifc, TEGRA30_DAM_ENABLE, TEGRA30_DAM_CHIN0_SRC); - /* if this is the only user of i2s tx then enable it*/ - if (codec_i2s->playback_ref_count == 1) - codec_i2s->reg_ctrl |= TEGRA30_I2S_CTRL_XFER_EN_TX; - + codec_i2s->reg_ctrl |= TEGRA30_I2S_CTRL_XFER_EN_TX; codec_i2s->reg_ctrl |= TEGRA30_I2S_CTRL_XFER_EN_RX; tegra30_i2s_write(codec_i2s, TEGRA30_I2S_CTRL, codec_i2s->reg_ctrl); @@ -827,7 +1053,6 @@ static __devinit int tegra30_i2s_platform_probe(struct platform_device *pdev) ret = PTR_ERR(i2s->clk_i2s); goto exit; } - i2s->clk_i2s_sync = clk_get(&pdev->dev, "ext_audio_sync"); if (IS_ERR(i2s->clk_i2s_sync)) { dev_err(&pdev->dev, "Can't retrieve i2s_sync clock\n"); diff --git a/sound/soc/tegra/tegra30_i2s.h b/sound/soc/tegra/tegra30_i2s.h index b9baddd5db8e..0992bf0d5b17 100644 --- a/sound/soc/tegra/tegra30_i2s.h +++ b/sound/soc/tegra/tegra30_i2s.h @@ -176,7 +176,7 @@ /* Number of slots in frame, minus 1 */ #define TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_SHIFT 16 #define TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_MASK_US 7 -#define TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_MASK (TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOT_MASK_US << TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOT_SHIFT) +#define TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_MASK (TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_MASK_US << TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_SHIFT) /* TDM mode slot enable bitmask */ #define TEGRA30_I2S_SLOT_CTRL_RX_SLOT_ENABLES_SHIFT 8 @@ -231,6 +231,16 @@ /* Number of i2s controllers*/ #define TEGRA30_NR_I2S_IFC 5 +struct dsp_config_t { + int num_slots; + int rx_mask; + int tx_mask; + int slot_width; + int rx_data_offset; + int tx_data_offset; +}; + + struct tegra30_i2s { int id; struct clk *clk_i2s; @@ -254,6 +264,8 @@ struct tegra30_i2s { #endif int call_record_dam_ifc; int is_call_mode_rec; + + struct dsp_config_t dsp_config; }; struct codec_config { diff --git a/sound/soc/tegra/tegra_aic326x.c b/sound/soc/tegra/tegra_aic326x.c index 93013c5e99b6..a5c6fc0aecb7 100644 --- a/sound/soc/tegra/tegra_aic326x.c +++ b/sound/soc/tegra/tegra_aic326x.c @@ -1142,8 +1142,10 @@ static __devinit int tegra_aic326x_driver_probe(struct platform_device *pdev) struct snd_soc_card *card = &snd_soc_tegra_aic326x; struct tegra_aic326x *machine; struct tegra_asoc_platform_data *pdata; - int ret, i; - + int ret; +#ifndef CONFIG_ARCH_TEGRA_2x_SOC + int i; +#endif pdata = pdev->dev.platform_data; if (!pdata) { dev_err(&pdev->dev, "No platform data supplied\n"); @@ -1158,7 +1160,7 @@ static __devinit int tegra_aic326x_driver_probe(struct platform_device *pdev) machine->pdata = pdata; - ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev); + ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev, card); if (ret) goto err_free_machine; diff --git a/sound/soc/tegra/tegra_asoc_utils.c b/sound/soc/tegra/tegra_asoc_utils.c index 04e7e3c15cd0..b134f0808afa 100644 --- a/sound/soc/tegra/tegra_asoc_utils.c +++ b/sound/soc/tegra/tegra_asoc_utils.c @@ -153,12 +153,12 @@ int tegra_asoc_utils_clk_disable(struct tegra_asoc_utils_data *data) EXPORT_SYMBOL_GPL(tegra_asoc_utils_clk_disable); int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data, - struct device *dev) + struct device *dev, struct snd_soc_card *card) { int ret; - int rate; data->dev = dev; + data->card = card; data->clk_pll_p_out1 = clk_get_sys(NULL, "pll_p_out1"); if (IS_ERR(data->clk_pll_p_out1)) { diff --git a/sound/soc/tegra/tegra_asoc_utils.h b/sound/soc/tegra/tegra_asoc_utils.h index 1c4e521cb4ba..512df0d54eb1 100644 --- a/sound/soc/tegra/tegra_asoc_utils.h +++ b/sound/soc/tegra/tegra_asoc_utils.h @@ -31,6 +31,7 @@ struct device; struct tegra_asoc_utils_data { struct device *dev; + struct snd_soc_card *card; struct clk *clk_pll_a; struct clk *clk_pll_a_out0; struct clk *clk_cdev1; @@ -47,7 +48,7 @@ int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate, void tegra_asoc_utils_lock_clk_rate(struct tegra_asoc_utils_data *data, int lock); int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data, - struct device *dev); + struct device *dev, struct snd_soc_card *card); void tegra_asoc_utils_fini(struct tegra_asoc_utils_data *data); int tegra_asoc_utils_clk_enable(struct tegra_asoc_utils_data *data); int tegra_asoc_utils_clk_disable(struct tegra_asoc_utils_data *data); diff --git a/sound/soc/tegra/tegra_max98088.c b/sound/soc/tegra/tegra_max98088.c index 9546af83b39d..8c0e3935ad02 100644 --- a/sound/soc/tegra/tegra_max98088.c +++ b/sound/soc/tegra/tegra_max98088.c @@ -96,6 +96,7 @@ struct tegra_max98088 { #endif enum snd_soc_bias_level bias_level; struct snd_soc_card *pcard; + volatile int clock_enabled; }; static int tegra_call_mode_info(struct snd_kcontrol *kcontrol, @@ -559,7 +560,7 @@ static void tegra_max98088_shutdown(struct snd_pcm_substream *substream) } else { if (!i2s->is_call_mode_rec) - return 0; + return; i2s->is_call_mode_rec = 0; @@ -926,6 +927,7 @@ static int tegra_max98088_init(struct snd_soc_pcm_runtime *rtd) machine->pcard = card; machine->bias_level = SND_SOC_BIAS_STANDBY; + machine->clock_enabled = 1; if (gpio_is_valid(pdata->gpio_spkr_en)) { ret = gpio_request(pdata->gpio_spkr_en, "spkr_en"); @@ -1065,25 +1067,30 @@ static struct snd_soc_dai_link tegra_max98088_dai[NUM_DAI_LINKS] = { }; static int tegra30_soc_set_bias_level(struct snd_soc_card *card, - enum snd_soc_bias_level level) + struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level) { struct tegra_max98088 *machine = snd_soc_card_get_drvdata(card); if (machine->bias_level == SND_SOC_BIAS_OFF && - level != SND_SOC_BIAS_OFF) + level != SND_SOC_BIAS_OFF && (!machine->clock_enabled)) { + machine->clock_enabled = 1; tegra_asoc_utils_clk_enable(&machine->util_data); + machine->bias_level = level; + } return 0; } static int tegra30_soc_set_bias_level_post(struct snd_soc_card *card, - enum snd_soc_bias_level level) + struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level) { struct tegra_max98088 *machine = snd_soc_card_get_drvdata(card); if (machine->bias_level != SND_SOC_BIAS_OFF && - level == SND_SOC_BIAS_OFF) + level == SND_SOC_BIAS_OFF && (machine->clock_enabled)) { + machine->clock_enabled = 0; tegra_asoc_utils_clk_disable(&machine->util_data); + } machine->bias_level = level; @@ -1119,7 +1126,7 @@ static __devinit int tegra_max98088_driver_probe(struct platform_device *pdev) machine->pdata = pdata; - ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev); + ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev, card); if (ret) goto err_free_machine; @@ -1156,6 +1163,7 @@ static __devinit int tegra_max98088_driver_probe(struct platform_device *pdev) tegra_max98088_i2s_dai_name[machine->codec_info[BT_SCO].i2s_id]; #endif + card->dapm.idle_bias_off = 1; ret = snd_soc_register_card(card); if (ret) { dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", diff --git a/sound/soc/tegra/tegra_max98095.c b/sound/soc/tegra/tegra_max98095.c index 2104ba849cd3..95295ef4151e 100644 --- a/sound/soc/tegra/tegra_max98095.c +++ b/sound/soc/tegra/tegra_max98095.c @@ -630,7 +630,7 @@ static __devinit int tegra_max98095_driver_probe(struct platform_device *pdev) machine->pdata = pdata; - ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev); + ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev, card); if (ret) goto err_free_machine; diff --git a/sound/soc/tegra/tegra_p1852.c b/sound/soc/tegra/tegra_p1852.c index 27a1ea590340..9506a1c842df 100644 --- a/sound/soc/tegra/tegra_p1852.c +++ b/sound/soc/tegra/tegra_p1852.c @@ -201,7 +201,7 @@ static __devinit int tegra_p1852_driver_probe(struct platform_device *pdev) pdata->codec_info[i].name; } - ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev); + ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev, card); if (ret) goto err_free_machine; diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c index 00bd7aa2e59d..1b4b949841aa 100644 --- a/sound/soc/tegra/tegra_pcm.c +++ b/sound/soc/tegra/tegra_pcm.c @@ -2,7 +2,7 @@ * tegra_pcm.c - Tegra PCM driver * * Author: Stephen Warren <swarren@nvidia.com> - * Copyright (C) 2010 - NVIDIA, Inc. + * Copyright (C) 2010-2012 - NVIDIA, Inc. * * Based on code copyright/by: * @@ -29,6 +29,7 @@ * */ +#include <asm/mach-types.h> #include <linux/module.h> #include <linux/dma-mapping.h> #include <linux/slab.h> @@ -66,7 +67,8 @@ static void tegra_pcm_queue_dma(struct tegra_runtime_data *prtd) unsigned long addr; dma_req = &prtd->dma_req[prtd->dma_req_idx]; - prtd->dma_req_idx = 1 - prtd->dma_req_idx; + if (++prtd->dma_req_idx >= prtd->dma_req_count) + prtd->dma_req_idx -= prtd->dma_req_count; addr = buf->addr + prtd->dma_pos; prtd->dma_pos += dma_req->size; @@ -130,13 +132,16 @@ static void setup_dma_rx_request(struct tegra_dma_req *req, req->req_sel = dmap->req_sel; } -static int tegra_pcm_open(struct snd_pcm_substream *substream) +int tegra_pcm_allocate(struct snd_pcm_substream *substream, + int dma_mode, + const struct snd_pcm_hardware *pcm_hardware) { struct snd_pcm_runtime *runtime = substream->runtime; struct tegra_runtime_data *prtd; struct snd_soc_pcm_runtime *rtd = substream->private_data; struct tegra_pcm_dma_params * dmap; int ret = 0; + int i = 0; prtd = kzalloc(sizeof(struct tegra_runtime_data), GFP_KERNEL); if (prtd == NULL) @@ -148,13 +153,14 @@ static int tegra_pcm_open(struct snd_pcm_substream *substream) spin_lock_init(&prtd->lock); dmap = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); + prtd->dma_req_count = MAX_DMA_REQ_COUNT; if (dmap) { - prtd->dma_req[0].dev = prtd; - prtd->dma_req[1].dev = prtd; + for (i = 0; i < prtd->dma_req_count; i++) + prtd->dma_req[i].dev = prtd; prtd->dma_chan = tegra_dma_allocate_channel( - TEGRA_DMA_MODE_CONTINUOUS_SINGLE, + dma_mode, "pcm"); if (prtd->dma_chan == NULL) { ret = -ENOMEM; @@ -163,7 +169,7 @@ static int tegra_pcm_open(struct snd_pcm_substream *substream) } /* Set HW params now that initialization is complete */ - snd_soc_set_runtime_hwparams(substream, &tegra_pcm_hardware); + snd_soc_set_runtime_hwparams(substream, pcm_hardware); /* Ensure period size is multiple of 8 */ ret = snd_pcm_hw_constraint_step(runtime, 0, @@ -189,7 +195,15 @@ err: return ret; } -static int tegra_pcm_close(struct snd_pcm_substream *substream) +static int tegra_pcm_open(struct snd_pcm_substream *substream) +{ + return tegra_pcm_allocate(substream, + TEGRA_DMA_MODE_CONTINUOUS_SINGLE, + &tegra_pcm_hardware); + +} + +int tegra_pcm_close(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct tegra_runtime_data *prtd = runtime->private_data; @@ -202,44 +216,55 @@ static int tegra_pcm_close(struct snd_pcm_substream *substream) return 0; } -static int tegra_pcm_hw_params(struct snd_pcm_substream *substream, +int tegra_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_pcm_runtime *runtime = substream->runtime; struct tegra_runtime_data *prtd = runtime->private_data; struct snd_soc_pcm_runtime *rtd = substream->private_data; struct tegra_pcm_dma_params * dmap; + int i; snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); + /* Limit dma_req_count to period count */ + if (prtd->dma_req_count > params_periods(params)) + prtd->dma_req_count = params_periods(params); dmap = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); if (dmap) { if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - setup_dma_tx_request(&prtd->dma_req[0], dmap); - setup_dma_tx_request(&prtd->dma_req[1], dmap); + for (i = 0; i < prtd->dma_req_count; i++) + setup_dma_tx_request(&prtd->dma_req[i], dmap); } else { - setup_dma_rx_request(&prtd->dma_req[0], dmap); - setup_dma_rx_request(&prtd->dma_req[1], dmap); + for (i = 0; i < prtd->dma_req_count; i++) + setup_dma_rx_request(&prtd->dma_req[i], dmap); } } - prtd->dma_req[0].size = params_period_bytes(params); - prtd->dma_req[1].size = prtd->dma_req[0].size; + for (i = 0; i < prtd->dma_req_count; i++) + prtd->dma_req[i].size = params_period_bytes(params); return 0; } -static int tegra_pcm_hw_free(struct snd_pcm_substream *substream) +int tegra_pcm_hw_free(struct snd_pcm_substream *substream) { snd_pcm_set_runtime_buffer(substream, NULL); return 0; } -static int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_pcm_runtime *runtime = substream->runtime; struct tegra_runtime_data *prtd = runtime->private_data; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct tegra_pcm_dma_params * dmap; unsigned long flags; + int i; + + dmap = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); + if (!dmap) + return 0; switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -253,8 +278,8 @@ static int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd) spin_lock_irqsave(&prtd->lock, flags); prtd->running = 1; spin_unlock_irqrestore(&prtd->lock, flags); - tegra_pcm_queue_dma(prtd); - tegra_pcm_queue_dma(prtd); + for (i = 0; i < prtd->dma_req_count; i++) + tegra_pcm_queue_dma(prtd); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: @@ -263,10 +288,11 @@ static int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd) prtd->running = 0; spin_unlock_irqrestore(&prtd->lock, flags); tegra_dma_cancel(prtd->dma_chan); - if (prtd->dma_req[0].status == -TEGRA_DMA_REQ_ERROR_ABORTED) - prtd->dma_req[0].complete(&prtd->dma_req[0]); - if (prtd->dma_req[1].status == -TEGRA_DMA_REQ_ERROR_ABORTED) - prtd->dma_req[1].complete(&prtd->dma_req[1]); + for (i = 0; i < prtd->dma_req_count; i++) { + if (prtd->dma_req[i].status == + -TEGRA_DMA_REQ_ERROR_ABORTED) + prtd->dma_req[i].complete(&prtd->dma_req[i]); + } break; default: return -EINVAL; @@ -275,7 +301,7 @@ static int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd) return 0; } -static snd_pcm_uframes_t tegra_pcm_pointer(struct snd_pcm_substream *substream) +snd_pcm_uframes_t tegra_pcm_pointer(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct tegra_runtime_data *prtd = runtime->private_data; @@ -288,7 +314,7 @@ static snd_pcm_uframes_t tegra_pcm_pointer(struct snd_pcm_substream *substream) bytes_to_frames(runtime, dma_transfer_count); } -static int tegra_pcm_mmap(struct snd_pcm_substream *substream, +int tegra_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma) { struct snd_pcm_runtime *runtime = substream->runtime; @@ -310,11 +336,11 @@ static struct snd_pcm_ops tegra_pcm_ops = { .mmap = tegra_pcm_mmap, }; -static int tegra_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) +static int tegra_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, + int stream , size_t size) { struct snd_pcm_substream *substream = pcm->streams[stream].substream; struct snd_dma_buffer *buf = &substream->dma_buffer; - size_t size = tegra_pcm_hardware.buffer_bytes_max; buf->area = dma_alloc_writecombine(pcm->card->dev, size, &buf->addr, GFP_KERNEL); @@ -329,7 +355,7 @@ static int tegra_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) return 0; } -static void tegra_pcm_deallocate_dma_buffer(struct snd_pcm *pcm, int stream) +void tegra_pcm_deallocate_dma_buffer(struct snd_pcm *pcm, int stream) { struct snd_pcm_substream *substream; struct snd_dma_buffer *buf; @@ -349,7 +375,7 @@ static void tegra_pcm_deallocate_dma_buffer(struct snd_pcm *pcm, int stream) static u64 tegra_dma_mask = DMA_BIT_MASK(32); -static int tegra_pcm_new(struct snd_soc_pcm_runtime *rtd) +int tegra_pcm_dma_allocate(struct snd_soc_pcm_runtime *rtd, size_t size) { struct snd_card *card = rtd->card->snd_card; struct snd_soc_dai *dai = rtd->cpu_dai; @@ -363,14 +389,16 @@ static int tegra_pcm_new(struct snd_soc_pcm_runtime *rtd) if (dai->driver->playback.channels_min) { ret = tegra_pcm_preallocate_dma_buffer(pcm, - SNDRV_PCM_STREAM_PLAYBACK); + SNDRV_PCM_STREAM_PLAYBACK, + size); if (ret) goto err; } if (dai->driver->capture.channels_min) { ret = tegra_pcm_preallocate_dma_buffer(pcm, - SNDRV_PCM_STREAM_CAPTURE); + SNDRV_PCM_STREAM_CAPTURE, + size); if (ret) goto err_free_play; } @@ -383,16 +411,31 @@ err: return ret; } -static void tegra_pcm_free(struct snd_pcm *pcm) +int tegra_pcm_new(struct snd_soc_pcm_runtime *rtd) +{ + return tegra_pcm_dma_allocate(rtd , + tegra_pcm_hardware.buffer_bytes_max); +} + +void tegra_pcm_free(struct snd_pcm *pcm) { tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_CAPTURE); tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK); } +static int tegra_pcm_probe(struct snd_soc_platform *platform) +{ + if(machine_is_kai() || machine_is_tegra_enterprise()) + platform->dapm.idle_bias_off = 1; + + return 0; +} + struct snd_soc_platform_driver tegra_pcm_platform = { .ops = &tegra_pcm_ops, .pcm_new = tegra_pcm_new, .pcm_free = tegra_pcm_free, + .probe = tegra_pcm_probe, }; static int __devinit tegra_pcm_platform_probe(struct platform_device *pdev) diff --git a/sound/soc/tegra/tegra_pcm.h b/sound/soc/tegra/tegra_pcm.h index dbb90339fe0d..7fe22788004b 100644 --- a/sound/soc/tegra/tegra_pcm.h +++ b/sound/soc/tegra/tegra_pcm.h @@ -33,6 +33,8 @@ #include <mach/dma.h> +#define MAX_DMA_REQ_COUNT 2 + struct tegra_pcm_dma_params { unsigned long addr; unsigned long wrap; @@ -48,8 +50,24 @@ struct tegra_runtime_data { int dma_pos_end; int period_index; int dma_req_idx; - struct tegra_dma_req dma_req[2]; + struct tegra_dma_req dma_req[MAX_DMA_REQ_COUNT]; struct tegra_dma_channel *dma_chan; + int dma_req_count; }; +int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd); +int tegra_pcm_allocate(struct snd_pcm_substream *substream, + int dma_mode, + const struct snd_pcm_hardware *pcm_hardware); +int tegra_pcm_close(struct snd_pcm_substream *substream); +int tegra_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params); +int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd); +int tegra_pcm_mmap(struct snd_pcm_substream *substream, + struct vm_area_struct *vma); +int tegra_pcm_dma_allocate(struct snd_soc_pcm_runtime *rtd, size_t size); +void tegra_pcm_free(struct snd_pcm *pcm); +snd_pcm_uframes_t tegra_pcm_pointer(struct snd_pcm_substream *substream); +int tegra_pcm_hw_free(struct snd_pcm_substream *substream); + #endif diff --git a/sound/soc/tegra/tegra_rt5640.c b/sound/soc/tegra/tegra_rt5640.c index e7d58803f7c9..231b0ee61308 100644 --- a/sound/soc/tegra/tegra_rt5640.c +++ b/sound/soc/tegra/tegra_rt5640.c @@ -69,6 +69,8 @@ struct tegra_rt5640 { #ifdef CONFIG_SWITCH int jack_status; #endif + enum snd_soc_bias_level bias_level; + volatile int clock_enabled; }; static int tegra_rt5640_hw_params(struct snd_pcm_substream *substream, @@ -279,7 +281,7 @@ static int tegra_rt5640_jack_notifier(struct notifier_block *self, struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card); struct tegra_rt5640_platform_data *pdata = machine->pdata; enum headset_state state = BIT_NO_HEADSET; - unsigned char status_jack; + unsigned char status_jack = 0; if (jack == &tegra_rt5640_hp_jack) { if (action) { @@ -532,6 +534,9 @@ static int tegra_rt5640_init(struct snd_soc_pcm_runtime *rtd) machine->gpio_requested |= GPIO_HP_DET; } + machine->bias_level = SND_SOC_BIAS_STANDBY; + machine->clock_enabled = 1; + ret = snd_soc_add_controls(codec, cardhu_controls, ARRAY_SIZE(cardhu_controls)); if (ret < 0) @@ -582,10 +587,58 @@ static struct snd_soc_dai_link tegra_rt5640_dai[] = { }, }; +static int tegra_rt5640_resume_pre(struct snd_soc_card *card) +{ + int val; + struct snd_soc_jack_gpio *gpio = &tegra_rt5640_hp_jack_gpio; + + if (gpio_is_valid(gpio->gpio)) { + val = gpio_get_value(gpio->gpio); + val = gpio->invert ? !val : val; + snd_soc_jack_report(gpio->jack, val, gpio->report); + } + + return 0; +} + +static int tegra_rt5640_set_bias_level(struct snd_soc_card *card, + struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level) +{ + struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card); + + if (machine->bias_level == SND_SOC_BIAS_OFF && + level != SND_SOC_BIAS_OFF && (!machine->clock_enabled)) { + machine->clock_enabled = 1; + tegra_asoc_utils_clk_enable(&machine->util_data); + machine->bias_level = level; + } + + return 0; +} + +static int tegra_rt5640_set_bias_level_post(struct snd_soc_card *card, + struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level) +{ + struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card); + + if (machine->bias_level != SND_SOC_BIAS_OFF && + level == SND_SOC_BIAS_OFF && machine->clock_enabled) { + machine->clock_enabled = 0; + tegra_asoc_utils_clk_disable(&machine->util_data); + } + + machine->bias_level = level; + + return 0 ; +} + static struct snd_soc_card snd_soc_tegra_rt5640 = { .name = "tegra-rt5640", .dai_link = tegra_rt5640_dai, .num_links = ARRAY_SIZE(tegra_rt5640_dai), + .resume_pre = tegra_rt5640_resume_pre, + .set_bias_level = tegra_rt5640_set_bias_level, + .set_bias_level_post = tegra_rt5640_set_bias_level_post, }; static __devinit int tegra_rt5640_driver_probe(struct platform_device *pdev) @@ -614,7 +667,7 @@ static __devinit int tegra_rt5640_driver_probe(struct platform_device *pdev) machine->pdata = pdata; - ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev); + ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev, card); if (ret) goto err_free_machine; @@ -643,7 +696,7 @@ static __devinit int tegra_rt5640_driver_probe(struct platform_device *pdev) card->dev = &pdev->dev; platform_set_drvdata(pdev, card); snd_soc_card_set_drvdata(card, machine); - + card->dapm.idle_bias_off = 1; ret = snd_soc_register_card(card); if (ret) { dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", diff --git a/sound/soc/tegra/tegra_tdm_pcm.c b/sound/soc/tegra/tegra_tdm_pcm.c new file mode 100644 index 000000000000..ae33bdbc588c --- /dev/null +++ b/sound/soc/tegra/tegra_tdm_pcm.c @@ -0,0 +1,160 @@ +/* + * tegra_tdm_pcm.c - Tegra TDM PCM driver + * + * Author: Nitin Pai <npai@nvidia.com> + * Copyright (C) 2010 - NVIDIA, Inc. + * + * Based on code copyright/by: + * + * Copyright (c) 2009-2010, NVIDIA Corporation. + * Scott Peterson <speterson@nvidia.com> + * Stephen Warren <swarren@nvidia.com> + * Vijay Mali <vmali@nvidia.com> + * + * Copyright (C) 2010 Google, Inc. + * Iliyan Malchev <malchev@google.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/dma-mapping.h> +#include <linux/slab.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> + +#include "tegra_pcm.h" + +#define DRV_NAME "tegra-tdm-pcm-audio" + +static const struct snd_pcm_hardware tegra_tdm_pcm_hardware = { + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_RESUME | + SNDRV_PCM_INFO_INTERLEAVED, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .channels_min = 8, + .channels_max = 16, + .period_bytes_min = 16 * 1024, + .period_bytes_max = 16 * 1024, + .periods_min = 4, + .periods_max = 4, + .buffer_bytes_max = 16 * 4 * 1024, + .fifo_size = 4, +}; + +static int tegra_tdm_pcm_open(struct snd_pcm_substream *substream) +{ + return tegra_pcm_allocate(substream, + TEGRA_DMA_MODE_CONTINUOUS_DOUBLE, + &tegra_tdm_pcm_hardware); + +} + +static int tegra_tdm_pcm_close(struct snd_pcm_substream *substream) +{ + return tegra_pcm_close(substream); +} + +static int tegra_tdm_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + return tegra_pcm_hw_params(substream, params); +} + +static int tegra_tdm_pcm_hw_free(struct snd_pcm_substream *substream) +{ + return tegra_pcm_hw_free(substream); +} + +static int tegra_tdm_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + return tegra_pcm_trigger(substream, cmd); +} + +static int tegra_tdm_pcm_mmap(struct snd_pcm_substream *substream, + struct vm_area_struct *vma) +{ + return tegra_pcm_mmap(substream, vma); +} + +static struct snd_pcm_ops tegra_tdm_pcm_ops = { + .open = tegra_tdm_pcm_open, + .close = tegra_tdm_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = tegra_tdm_pcm_hw_params, + .hw_free = tegra_tdm_pcm_hw_free, + .trigger = tegra_tdm_pcm_trigger, + .pointer = tegra_pcm_pointer, + .mmap = tegra_tdm_pcm_mmap, +}; + +static int tegra_tdm_pcm_new(struct snd_soc_pcm_runtime *rtd) +{ + return tegra_pcm_dma_allocate(rtd , + tegra_tdm_pcm_hardware.buffer_bytes_max); +} + +static void tegra_tdm_pcm_free(struct snd_pcm *pcm) +{ + return tegra_pcm_free(pcm); +} + +struct snd_soc_platform_driver tegra_tdm_pcm_platform = { + .ops = &tegra_tdm_pcm_ops, + .pcm_new = tegra_tdm_pcm_new, + .pcm_free = tegra_tdm_pcm_free, +}; + +static int __devinit tegra_tdm_pcm_platform_probe(struct platform_device *pdev) +{ + return snd_soc_register_platform(&pdev->dev, &tegra_tdm_pcm_platform); +} + +static int __devexit tegra_tdm_pcm_platform_remove(struct platform_device *pdev) +{ + snd_soc_unregister_platform(&pdev->dev); + return 0; +} + +static struct platform_driver tegra_tdm_pcm_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, + .probe = tegra_tdm_pcm_platform_probe, + .remove = __devexit_p(tegra_tdm_pcm_platform_remove), +}; + +static int __init snd_tegra_tdm_pcm_init(void) +{ + return platform_driver_register(&tegra_tdm_pcm_driver); +} +module_init(snd_tegra_tdm_pcm_init); + +static void __exit snd_tegra_tdm_pcm_exit(void) +{ + platform_driver_unregister(&tegra_tdm_pcm_driver); +} +module_exit(snd_tegra_tdm_pcm_exit); + +MODULE_AUTHOR("Nitin Pai <npai@nvidia.com>"); +MODULE_DESCRIPTION("Tegra PCM ASoC driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" DRV_NAME); diff --git a/sound/soc/tegra/tegra_wm8753.c b/sound/soc/tegra/tegra_wm8753.c index 2e532fcd1e46..795356875ba4 100644 --- a/sound/soc/tegra/tegra_wm8753.c +++ b/sound/soc/tegra/tegra_wm8753.c @@ -872,7 +872,7 @@ static __devinit int tegra_wm8753_driver_probe(struct platform_device *pdev) machine->pdata = pdata; - ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev); + ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev, card); if (ret) goto err_free_machine; diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c index 55e4f61edfd2..ce608b007bef 100644 --- a/sound/soc/tegra/tegra_wm8903.c +++ b/sound/soc/tegra/tegra_wm8903.c @@ -805,7 +805,7 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev) machine->pdata = pdata; - ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev); + ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev, card); if (ret) goto err_free_machine; diff --git a/sound/soc/tegra/trimslice.c b/sound/soc/tegra/trimslice.c index 8fc07e9adf2e..660479b89478 100644 --- a/sound/soc/tegra/trimslice.c +++ b/sound/soc/tegra/trimslice.c @@ -163,7 +163,7 @@ static __devinit int tegra_snd_trimslice_probe(struct platform_device *pdev) return -ENOMEM; } - ret = tegra_asoc_utils_init(&trimslice->util_data, &pdev->dev); + ret = tegra_asoc_utils_init(&trimslice->util_data, &pdev->dev, card); if (ret) goto err_free_trimslice; |