diff options
Diffstat (limited to 'packages/linux/linux-ezx-2.6.21/patches/ezx-asoc.patch')
-rw-r--r-- | packages/linux/linux-ezx-2.6.21/patches/ezx-asoc.patch | 1053 |
1 files changed, 588 insertions, 465 deletions
diff --git a/packages/linux/linux-ezx-2.6.21/patches/ezx-asoc.patch b/packages/linux/linux-ezx-2.6.21/patches/ezx-asoc.patch index 4b1f39b7d2..1dda2e544c 100644 --- a/packages/linux/linux-ezx-2.6.21/patches/ezx-asoc.patch +++ b/packages/linux/linux-ezx-2.6.21/patches/ezx-asoc.patch @@ -1,10 +1,12 @@ Index: linux-2.6.21/sound/soc/codecs/pcap2.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-2.6.21/sound/soc/codecs/pcap2.c 2007-08-04 22:20:36.000000000 -0300 -@@ -0,0 +1,709 @@ ++++ linux-2.6.21/sound/soc/codecs/pcap2.c 2007-09-07 14:28:32.000000000 -0300 +@@ -0,0 +1,796 @@ +/* -+ * pcap2.c -- Template Codec Audio driver ++ * pcap2.c - PCAP2 ASIC Audio driver ++ * ++ * Copyright (C) 2007 Daniel Ribeiro <drwyrm@gmail.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 @@ -37,18 +39,19 @@ Index: linux-2.6.21/sound/soc/codecs/pcap2.c + +extern int ezx_pcap_write(u_int8_t, u_int32_t); +extern int ezx_pcap_read(u_int8_t, u_int32_t *); ++static struct snd_soc_device *pcap2_codec_socdev; + +/* + * Debug + */ + -+#define PCAP2_DEBUG 1 ++//#define PCAP2_DEBUG + +#ifdef PCAP2_DEBUG +#define dbg(format, arg...) \ + printk(KERN_DEBUG AUDIO_NAME ": " format "\n" , ## arg) +#else -+#define dbg(format, arg...) do {} while (0) ++#define dbg(format, arg...) +#endif + +#define err(format, arg...) \ @@ -67,53 +70,89 @@ Index: linux-2.6.21/sound/soc/codecs/pcap2.c + + +/* -+ * write to the pcap2 codec register space ++ * ASoC limits register value to 16 bits and pcap uses 32 bit registers ++ * to work around this, we get 16 bits from low, mid or high positions. ++ * ASoC limits register number to 8 bits we use 0x1f for register ++ * number and 0xe0 for register offset. -WM + */ +static int pcap2_codec_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ -+ dbg("codec_write reg=%08x, val=%08x", reg, value); -+ ezx_pcap_write(reg, value); ++ unsigned int tmp; ++ ++ ezx_pcap_read((reg & 0x1f), &tmp); ++ ++ if (reg & SL) { ++ tmp &= 0xffff0000; ++ tmp |= (value & 0xffff); ++ } ++ else if (reg & SM) { ++ tmp &= 0xff0000ff; ++ tmp |= ((value << 8) & 0x00ffff00); ++ } ++ else if (reg & SH) { ++ tmp &= 0xffff; ++ tmp |= ((value << 16) & 0xffff0000); ++ } ++ else ++ tmp = value; ++ ++ dbg("codec_write reg=%x, rval=%08x, fval=%08x", reg, tmp, value); ++ ezx_pcap_write((reg & 0x1f), tmp); + return 0; + +} + +static unsigned int pcap2_codec_read(struct snd_soc_codec *codec, unsigned int reg) +{ -+ unsigned int ret; -+ -+ ezx_pcap_read(reg, &ret); -+ dbg("codec_read reg=%08x, val=%08x", reg, ret); ++ unsigned int tmp, ret; ++ ++ ezx_pcap_read((reg & 0x1f), &tmp); ++ ret = tmp; ++ if (reg & SL) ++ ret = (tmp & 0xffff); ++ else if (reg & SM) ++ ret = ((tmp >> 8) & 0xffff); ++ else if (reg & SH) ++ ret = ((tmp >> 16) & 0xffff); ++ ++ dbg("codec_read reg=%x, rval=%08x, fval=%08x", reg, tmp, ret); + return(ret); + +} + -+static const char *pcap2_amp_output[] = {"R L Stereo", "RL", "RL3db", "RL6db"}; ++static const char *pcap2_output_select[] = {"2ch", "2->1ch", "2->1ch -3db", "2->1ch -6db"}; + +static const struct soc_enum pcap2_enum[] = { -+SOC_ENUM_SINGLE(PCAP2_OUTPUT_AMP, 19, 4, pcap2_amp_output), ++SOC_ENUM_SINGLE((PCAP2_OUTPUT_AMP|SH), 3, 4, pcap2_output_select), ++}; ++ ++static const struct snd_kcontrol_new pcap2_input_mixer_controls[] = { ++SOC_DAPM_SINGLE("A3 Switch", (PCAP2_INPUT_AMP|SL), 6, 1, 0), ++SOC_DAPM_SINGLE("A5 Switch", (PCAP2_INPUT_AMP|SL), 8, 1, 0), ++}; + ++static const struct snd_kcontrol_new pcap2_output_mixer_controls[] = { ++SOC_DAPM_SINGLE("A1 Switch", (PCAP2_OUTPUT_AMP|SL), 0, 1, 0), ++SOC_DAPM_SINGLE("A2 Switch", (PCAP2_OUTPUT_AMP|SL), 1, 1, 0), ++SOC_DAPM_SINGLE("AR Switch", (PCAP2_OUTPUT_AMP|SL), 5, 1, 0), ++SOC_DAPM_SINGLE("AL Switch", (PCAP2_OUTPUT_AMP|SL), 6, 1, 0), +}; + +/* pcap2 codec non DAPM controls */ +static const struct snd_kcontrol_new pcap2_codec_snd_controls[] = { -+SOC_SINGLE("Output gain", PCAP2_OUTPUT_AMP, 13, 15, 0), -+SOC_SINGLE("Input gain", PCAP2_INPUT_AMP, 0, 31, 0), -+SOC_SINGLE("louderspeaker sw", PCAP2_OUTPUT_AMP, 1, 1, 0), -+SOC_SINGLE("Earpiece switch", PCAP2_OUTPUT_AMP, 0, 1, 0), -+SOC_SINGLE("Earpctrl switch", PCAP2_OUTPUT_AMP, 17, 1, 0), -+SOC_SINGLE("Aright switch", PCAP2_OUTPUT_AMP, 5, 1, 0), -+SOC_SINGLE("Aleft switch", PCAP2_OUTPUT_AMP, 6, 1, 0), -+//SOC_SINGLE("AHS switch", PCAP2_INPUT_AMP, 14, 1, 0), -+//SOC_SINGLE("pga in switch", PCAP2_OUTPUT_AMP, 10, 1, 0), -+SOC_ENUM("Output mode", pcap2_enum[0]), ++SOC_SINGLE("Output gain", (PCAP2_OUTPUT_AMP|SM), 5, 15, 0), ++SOC_SINGLE("Input gain", (PCAP2_INPUT_AMP|SL), 0, 31, 0), ++}; ++ ++static const struct snd_kcontrol_new pcap2_codec_dm_mux_control[] = { ++ SOC_DAPM_ENUM("Output Mode", pcap2_enum[0]), +}; + +/* add non dapm controls */ +static int pcap2_codec_add_controls(struct snd_soc_codec *codec) +{ + int err, i; -+ dbg("pcap2_codec_add_controls"); + + for (i = 0; i < ARRAY_SIZE(pcap2_codec_snd_controls); i++) { + if ((err = snd_ctl_add(codec->card, @@ -126,13 +165,67 @@ Index: linux-2.6.21/sound/soc/codecs/pcap2.c + +/* pcap2 codec DAPM controls */ +static const struct snd_soc_dapm_widget pcap2_codec_dapm_widgets[] = { ++ SND_SOC_DAPM_DAC("ST_DAC", "ST_DAC playback", SND_SOC_NOPM, 0, 0), ++ SND_SOC_DAPM_DAC("CDC_DAC", "CDC_DAC playback", SND_SOC_NOPM, 0, 0), ++ SND_SOC_DAPM_ADC("CDC_ADC", "CDC_DAC capture", SND_SOC_NOPM, 0, 0), ++ SND_SOC_DAPM_PGA("PGA_ST", (PCAP2_OUTPUT_AMP|SL), 9, 0, NULL, 0), ++ SND_SOC_DAPM_PGA("PGA_CDC", (PCAP2_OUTPUT_AMP|SL), 8, 0, NULL, 0), ++ SND_SOC_DAPM_PGA("PGA_R", (PCAP2_OUTPUT_AMP|SL), 11, 0, NULL, 0), ++ SND_SOC_DAPM_PGA("PGA_L", (PCAP2_OUTPUT_AMP|SL), 12, 0, NULL, 0), ++ SND_SOC_DAPM_MUX("Downmixer", SND_SOC_NOPM, 0, 0, pcap2_codec_dm_mux_control), ++ SND_SOC_DAPM_PGA("PGA_A1CTRL", (PCAP2_OUTPUT_AMP|SH), 1, 1, NULL, 0), ++ SND_SOC_DAPM_MIXER("Output Mixer", SND_SOC_NOPM, 0, 0, &pcap2_output_mixer_controls[0], ARRAY_SIZE(pcap2_output_mixer_controls)), ++ SND_SOC_DAPM_OUTPUT("A1"), /* Earpiece */ ++ SND_SOC_DAPM_OUTPUT("A2"), /* LoudSpeaker */ ++ SND_SOC_DAPM_OUTPUT("AR"), /* headset right */ ++ SND_SOC_DAPM_OUTPUT("AL"), /* headset left */ ++ ++ SND_SOC_DAPM_MICBIAS("BIAS1", (PCAP2_INPUT_AMP|SL), 10, 0), ++ SND_SOC_DAPM_MICBIAS("BIAS2", (PCAP2_INPUT_AMP|SL), 11, 0), ++ SND_SOC_DAPM_MIXER("Input Mixer", SND_SOC_NOPM, 0, 0, &pcap2_input_mixer_controls[0], ARRAY_SIZE(pcap2_input_mixer_controls)), ++ SND_SOC_DAPM_INPUT("A3"), /* Headset Mic */ ++ SND_SOC_DAPM_INPUT("A5"), /* Builtin Mic */ +}; + -+/* -+ * template codec audio interconnectiosn between sink and source. -+ */ +static const char *audio_map[][3] = { ++ { "A1", NULL, "Output Mixer" }, ++ { "A2", NULL, "Output Mixer" }, ++ { "AR", NULL, "Output Mixer" }, ++ { "AL", NULL, "Output Mixer" }, ++ ++ { "Output Mixer", "A1 Switch", "PGA_A1CTRL" }, ++ { "Output Mixer", "A2 Switch", "Downmixer" }, ++ { "Output Mixer", "AR Switch", "PGA_R" }, ++ { "Output Mixer", "AL Switch", "PGA_L" }, ++ ++ { "PGA_A1CTRL", NULL, "Downmixer" }, ++ ++ { "Downmixer", "2->1ch", "PGA_L" }, ++ { "Downmixer", "2->1ch", "PGA_R" }, ++ { "Downmixer", "2->1ch -3db", "PGA_L" }, ++ { "Downmixer", "2->1ch -3db", "PGA_R" }, ++ { "Downmixer", "2->1ch -6db", "PGA_L" }, ++ { "Downmixer", "2->1ch -6db", "PGA_R" }, ++ { "Downmixer", "2ch", "PGA_R" }, ++ ++ { "PGA_R", NULL, "PGA_ST" }, ++ { "PGA_L", NULL, "PGA_ST" }, ++ { "PGA_R", NULL, "PGA_CDC" }, ++ ++ { "PGA_ST", NULL, "ST_DAC" }, ++ { "PGA_CDC", NULL, "CDC_DAC" }, ++ ++ /* input path */ ++ { "BIAS1", NULL, "A3" }, ++ { "BIAS2", NULL, "A5" }, + ++ { "Input Mixer", "A3 Switch", "BIAS1" }, ++ { "Input Mixer", "A5 Switch", "BIAS2" }, ++ ++ { "PGA_R", NULL, "Input Mixer" }, ++ ++ { "PGA_CDC", NULL, "PGA_R" }, ++ { "CDC_ADC", NULL, "PGA_CDC" }, + + /* terminator */ + {NULL, NULL, NULL}, @@ -141,7 +234,6 @@ Index: linux-2.6.21/sound/soc/codecs/pcap2.c +static int pcap2_codec_add_widgets(struct snd_soc_codec *codec) +{ + int i; -+ dbg("pcap2_codec_add_widgets"); + + for(i = 0; i < ARRAY_SIZE(pcap2_codec_dapm_widgets); i++) { + snd_soc_dapm_new_control(codec, &pcap2_codec_dapm_widgets[i]); @@ -157,118 +249,213 @@ Index: linux-2.6.21/sound/soc/codecs/pcap2.c + return 0; +} + -+/* -+ * Alsa operations -+ * Only implement the required operations for your platform. -+ * These operations are specific to the codec only. -+ */ -+ -+ /* -+ * Called by ALSA when a PCM substream is opened, private data can be allocated. -+ */ -+static int pcap2mono_codec_startup(struct snd_pcm_substream *substream) ++static int pcap2_codec_dapm_event(struct snd_soc_codec *codec, int event) +{ -+ dbg("pcap2 codec startup"); ++ unsigned int input = pcap2_codec_read(codec, PCAP2_INPUT_AMP); + ++ input &= ~PCAP2_INPUT_AMP_LOWPWR; ++ ++ switch (event) { ++ case SNDRV_CTL_POWER_D0: ++ case SNDRV_CTL_POWER_D1: ++ case SNDRV_CTL_POWER_D2: ++ case SNDRV_CTL_POWER_D3hot: /* Off, with power */ ++ dbg("dapm: ON\n"); ++ break; ++ case SNDRV_CTL_POWER_D3cold: /* Off, without power */ ++ input |= PCAP2_INPUT_AMP_LOWPWR; ++ dbg("dapm: OFF\n"); ++ break; ++ } ++ codec->dapm_state = event; ++ pcap2_codec_write(codec, PCAP2_INPUT_AMP, input); + return 0; +} + -+/* -+ * Called by ALSA when a PCM substream is closed. Private data can be -+ * freed here. -+ */ -+static int pcap2mono_codec_shutdown(struct snd_pcm_substream *substream) ++static int pcap2_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_device *socdev = rtd->socdev; -+ struct snd_soc_codec *codec = socdev->codec; ++ struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; ++ struct snd_soc_codec *codec = codec_dai->codec; ++ unsigned int tmp; + -+ dbg("pcap2mono codec shutdown"); ++ if (codec_dai->id == PCAP2_STEREO_DAI) { ++ tmp = pcap2_codec_read(codec, PCAP2_ST_DAC); + -+ pcap2_codec_write(codec, PCAP2_CODEC, 0); -+ return 0; -+} ++ tmp &= ~PCAP2_ST_DAC_RATE_MASK; ++ switch(params_rate(params)) { ++ case 8000: ++ break; ++ case 11025: ++ tmp |= PCAP2_ST_DAC_RATE_11025; ++ break; ++ case 12000: ++ tmp |= PCAP2_ST_DAC_RATE_12000; ++ break; ++ case 16000: ++ tmp |= PCAP2_ST_DAC_RATE_16000; ++ break; ++ case 22050: ++ tmp |= PCAP2_ST_DAC_RATE_22050; ++ break; ++ case 24000: ++ tmp |= PCAP2_ST_DAC_RATE_24000; ++ break; ++ case 32000: ++ tmp |= PCAP2_ST_DAC_RATE_32000; ++ break; ++ case 44100: ++ tmp |= PCAP2_ST_DAC_RATE_44100; ++ break; ++ case 48000: ++ tmp |= PCAP2_ST_DAC_RATE_48000; ++ break; ++ default: ++ return -EINVAL; ++ } ++ tmp |= PCAP2_ST_DAC_RESET_DF; ++ pcap2_codec_write(codec, PCAP2_ST_DAC, tmp); ++ } ++ else { ++ tmp = pcap2_codec_read(codec, PCAP2_CODEC); + -+/* -+ * Called by ALSA when the hardware params are set by application. This -+ * function can also be called multiple times and can allocate buffers -+ * (using snd_pcm_lib_* ). It's non-atomic. -+ */ -+static int pcap2mono_codec_hw_params(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *params) -+{ -+// u_int32_t tmp; -+ dbg("pcap2mono_codec_hw_params"); ++ tmp &= ~PCAP2_CODEC_RATE_MASK; ++ switch(params_rate(params)) { ++ case 8000: ++ break; ++ case 16000: ++ tmp |= PCAP2_CODEC_RATE_16000; ++ break; ++ default: ++ return -EINVAL; ++ } ++ tmp |= PCAP2_CODEC_RESET_DF; ++ pcap2_codec_write(codec, PCAP2_CODEC, tmp); ++ } + + return 0; +} + -+/* -+ * Free's resources allocated by hw_params, can be called multiple times -+ */ -+static int pcap2mono_codec_hw_free(struct snd_pcm_substream *substream) ++static int pcap2_hw_free(struct snd_pcm_substream *substream) +{ -+ dbg("pcap2mono_codec_hw_free"); -+ return 0; -+} ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; ++ struct snd_soc_codec *codec = codec_dai->codec; ++ struct snd_soc_dapm_widget *w; ++ unsigned int tmp; + -+static int pcap2_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai, -+ int clk_id, unsigned int freq, int dir) -+{ ++ if (codec_dai->id == PCAP2_STEREO_DAI) { ++ snd_soc_dapm_set_endpoint(codec, "ST_DAC", 0); ++ tmp = pcap2_codec_read(codec, PCAP2_ST_DAC); ++ tmp &= ~(PCAP2_ST_DAC_EN | PCAP2_ST_DAC_CLK_EN); ++ pcap2_codec_write(codec, PCAP2_ST_DAC, tmp); ++ } ++ else { ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ++ snd_soc_dapm_set_endpoint(codec, "CDC_DAC", 0); ++ else ++ snd_soc_dapm_set_endpoint(codec, "CDC_ADC", 0); ++ list_for_each_entry(w, &codec->dapm_widgets, list) { ++ if ((!strcmp(w->name, "CDC_DAC") || !strcmp(w->name, "CDC_ADC")) && w->connected) ++ goto in_use; ++ } ++ tmp = pcap2_codec_read(codec, PCAP2_CODEC); ++ tmp &= ~(PCAP2_CODEC_EN | PCAP2_CODEC_CLK_EN); ++ pcap2_codec_write(codec, PCAP2_CODEC, tmp); ++ } ++in_use: ++ snd_soc_dapm_sync_endpoints(codec); + -+ dbg("pcap2 set dai sysclk"); + return 0; +} + -+static int pcap2_set_dai_pll(struct snd_soc_codec_dai *codec_dai, -+ int pll_id, unsigned int freq_in, unsigned int freq_out) ++static int pcap2_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai, ++ int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = codec_dai->codec; -+ u_int32_t tmp; -+ -+ dbg("pcap2 set dai pll"); + ++ unsigned int tmp; + if (codec_dai->id == PCAP2_STEREO_DAI) { + /* ST_DAC */ -+ dbg("stereo codec not supported yet."); -+ return -ENODEV; ++ ++ tmp = pcap2_codec_read(codec, PCAP2_ST_DAC); ++ ++ tmp &= ~PCAP2_ST_DAC_CLKSEL_MASK; ++ switch (clk_id) { ++ case PCAP2_CLK_AP: ++ tmp |= PCAP2_ST_DAC_CLKSEL_AP; ++ break; ++ case PCAP2_CLK_BP: ++ break; ++ default: ++ return -ENODEV; ++ } ++ ++ tmp &= ~PCAP2_ST_DAC_CLK_MASK; ++ switch (freq) { ++ case 13000000: ++ break; ++/* case 15M36: ++ tmp |= PCAP2_ST_DAC_CLK_15M36; ++ break; ++ case 16M8: ++ tmp |= PCAP2_ST_DAC_CLK_16M8; ++ break; ++ case 19M44: ++ tmp |= PCAP2_ST_DAC_CLK_19M44; ++ break; ++*/ case 26000000: ++ tmp |= PCAP2_ST_DAC_CLK_26M; ++ break; ++/* case EXT_MCLK: ++ tmp |= PCAP2_ST_DAC_CLK_MCLK; ++ break; ++ case FSYNC: ++ tmp |= PCAP2_ST_DAC_CLK_FSYNC; ++ break; ++ case BITCLK: ++ tmp |= PCAP2_ST_DAC_CLK_BITCLK; ++ break; ++*/ default: ++ return -EINVAL; ++ } ++ pcap2_codec_write(codec, PCAP2_ST_DAC, tmp); + } + else { + /* MONO_DAC */ + tmp = pcap2_codec_read(codec, PCAP2_CODEC); + -+ tmp &= ~0x10000; -+ switch (pll_id) { -+ case PCAP2_PLL_AP: -+ tmp |= 0x10000; ++ tmp &= ~PCAP2_CODEC_CLKSEL_MASK; ++ switch (clk_id) { ++ case PCAP2_CLK_AP: ++ tmp |= PCAP2_CODEC_CLKSEL_AP; + break; -+ case PCAP2_PLL_BP: ++ case PCAP2_CLK_BP: + break; + default: + return -ENODEV; + } + -+ tmp &= ~0x1c0; -+ switch (freq_in) { ++ tmp &= ~PCAP2_CODEC_CLK_MASK; ++ switch (freq) { + case 13000000: + break; +/* case 15M36: -+ tmp |= 0x40; ++ tmp |= PCAP2_CODEC_CLK_15M36; + break; + case 16M8: -+ tmp |= 0x80; ++ tmp |= PCAP2_CODEC_CLK_16M8; + break; + case 19M44: -+ tmp |= 0xc0; ++ tmp |= PCAP2_CODEC_CLK_19M44; + break; +*/ case 26000000: -+ tmp |= 0x100; ++ tmp |= PCAP2_CODEC_CLK_26M; + break; + default: + return -EINVAL; + } -+ -+ + pcap2_codec_write(codec, PCAP2_CODEC, tmp); + } + return 0; @@ -278,26 +465,19 @@ Index: linux-2.6.21/sound/soc/codecs/pcap2.c + unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; -+ u_int32_t tmp = 0; -+ -+ dbg("pcap2_set_dai_fmt"); ++ unsigned int tmp = 0; + + if (codec_dai->id == PCAP2_STEREO_DAI) { + /* ST_DAC */ -+ dbg("stereo codec not supported yet."); -+ return -ENODEV; -+ } -+ else { -+ /* MONO_DAC */ + -+ /* disable ST_DAC */ -+ pcap2_codec_write(codec, PCAP2_ST_DAC, 0); ++ /* disable CODEC */ ++ pcap2_codec_write(codec, PCAP2_CODEC, 0); + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + break; + case SND_SOC_DAIFMT_CBS_CFS: -+ tmp |= 0x2; ++ tmp |= 0x1; + break; + default: + return -EINVAL; @@ -320,6 +500,50 @@ Index: linux-2.6.21/sound/soc/codecs/pcap2.c + case SND_SOC_DAIFMT_IB_IF: + break; + case SND_SOC_DAIFMT_NB_NF: ++ tmp |= 0x60000; ++ break; ++ case SND_SOC_DAIFMT_IB_NF: ++ tmp |= 0x40000; ++ break; ++ case SND_SOC_DAIFMT_NB_IF: ++ tmp |= 0x20000; ++ break; ++ } ++ /* set dai to AP */ ++ tmp |= 0x1000; ++ ++ /* set BCLK */ ++ tmp |= 0x18000; ++ ++ pcap2_codec_write(codec, PCAP2_ST_DAC, tmp); ++ } ++ else { ++ /* MONO_DAC */ ++ ++ /* disable ST_DAC */ ++ pcap2_codec_write(codec, PCAP2_ST_DAC, 0); ++ ++ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { ++ case SND_SOC_DAIFMT_CBM_CFM: ++ break; ++ case SND_SOC_DAIFMT_CBS_CFS: ++ tmp |= 0x2; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { ++ case SND_SOC_DAIFMT_DSP_B: ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ switch (fmt & SND_SOC_DAIFMT_INV_MASK) { ++ case SND_SOC_DAIFMT_IB_IF: ++ break; ++ case SND_SOC_DAIFMT_NB_NF: + tmp |= 0x600; + break; + case SND_SOC_DAIFMT_IB_NF: @@ -333,173 +557,44 @@ Index: linux-2.6.21/sound/soc/codecs/pcap2.c + /* set dai to AP */ + tmp |= 0x8000; + ++ tmp |= 0x5; /* IHF / OHF */ ++ + pcap2_codec_write(codec, PCAP2_CODEC, tmp); + } + return 0; +} + ++static int pcap2_prepare(struct snd_pcm_substream *substream) ++{ + -+#if 0 -+// ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A1_CONFIG, 1); -+// ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG, 1); -+ -+// ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_ST_DAC_ST_CLK_EN, 0); -+// ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_ST_DAC_ST_DAC_EN, 0); -+// ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_ST_DAC_SMB_ST_DAC,1); -+ -+// dbg ("configure pcap to use ap clock"); -+// OSCC |= 0x00000008; -+// pxa_gpio_mode(AP_13MHZ_OUTPUT_PIN | GPIO_ALT_FN_3_OUT); -+ -+// ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_CLK_IN_SEL, 1); -+// ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_ST_DAC_ST_DAC_CLK_IN_SEL, 1); -+ -+ -+ -+// ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_V2_EN_2, 1); -+ -+ -+ -+ -+ /* configure bitclk, pllclock, mode */ -+ ezx_pcap_write(PCAP2_ST_DAC, 0); -+ -+ tmp = PCAP_CDC_CLK_IN_13M0; -+ ezx_pcap_write(PCAP2_CODEC, tmp); -+ -+ /* codec 0=master 1=slave */ -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_SMB, 0); -+ -+ /* bitrate 0=8k 1=16k */ -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_FS_8K_16K, 0); -+ -+ /* clock source */ -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_CLK_IN_SEL,1); -+ -+ /* dai select 0=neptune 1=pxa */ -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_DIG_AUD_IN,1); -+ -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_AUDIHPF,1); -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_AUDOHPF,1); -+ -+ /* clock/frame inv */ -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_CLK_INV,0); -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_FS_INV,0); -+ -+ /*(3) reset digital filter(DF_RESET=1) */ -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_DF_RESET,1); -+ -+// ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_ADITH,0); -+ -+ /* (4) enable pcap clk(CDC_CLK_EN=1),enable CODEC(CDC_EN=1) */ -+ -+// ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_CD_BYP,0); -+ -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_CLK_EN,1); -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_EN,1); ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; ++ struct snd_soc_codec *codec = codec_dai->codec; ++ unsigned int tmp; ++ /* FIXME enable clock only if codec is master */ ++ if (codec_dai->id == PCAP2_STEREO_DAI) { ++ snd_soc_dapm_set_endpoint(codec, "ST_DAC", 1); ++ snd_soc_dapm_set_endpoint(codec, "CDC_DAC", 0); ++ snd_soc_dapm_set_endpoint(codec, "CDC_ADC", 0); ++ tmp = pcap2_codec_read(codec, PCAP2_ST_DAC); ++ tmp |= (PCAP2_ST_DAC_EN | PCAP2_ST_DAC_CLK_EN); ++ pcap2_codec_write(codec, PCAP2_ST_DAC, tmp); ++ } ++ else { ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ++ snd_soc_dapm_set_endpoint(codec, "CDC_DAC", 1); ++ else ++ snd_soc_dapm_set_endpoint(codec, "CDC_ADC", 1); ++ snd_soc_dapm_set_endpoint(codec, "ST_DAC", 0); ++ tmp = pcap2_codec_read(codec, PCAP2_CODEC); ++ tmp |= (PCAP2_CODEC_EN | PCAP2_CODEC_CLK_EN); ++ pcap2_codec_write(codec, PCAP2_CODEC, tmp); ++ } ++ snd_soc_dapm_sync_endpoints(codec); + mdelay(1); -+ -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ST_DAC_SW, 0); -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_CDC_SW, 1); -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW, 0); -+ -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_R_EN, 1); -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_L_EN, 0); -+ -+ /* set default output to louderspeaker while developing */ -+ ezx_pcap_read(SSP_PCAP_ADJ_AUD_RX_AMPS_REGISTER, &tmp); -+ tmp &= ~SSP_PCAP_MONO_PGA_MASK; -+ tmp |= PCAP_MONO_PGA_RL; -+ ezx_pcap_write(SSP_PCAP_ADJ_AUD_RX_AMPS_REGISTER, tmp); -+// ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A1CTRL, 1); -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A2_EN, 1); -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A2_CONFIG, 1); -+ -+ /* set default input to handset while developing */ -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_MB_ON1, 1); -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A5_EN, 0); -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A5_MUX, 1); -+ -+ -+ ++#ifdef PCAP2_DEBUG + dump_registers(); -+ -+ -+ return 0; -+} -+ +#endif -+ -+/* -+ * Starts (Triggers) audio playback or capture. -+ * Usually only needed for DMA -+ */ -+static int pcap2mono_codec_trigger(struct snd_pcm_substream *substream, int cmd) -+{ -+ struct snd_soc_pcm_runtime *rtd = substream->private_data; -+ struct snd_soc_device *socdev = rtd->socdev; -+ struct snd_soc_codec *codec = socdev->codec; -+ u_int32_t tmp; -+ -+ dbg("pcap2mono_codec_trigger"); -+ tmp = pcap2_codec_read(codec, PCAP2_CODEC); -+ -+ -+ /* reset digital filter */ -+ tmp |= 0x800; -+ -+ /* enable codec */ -+ tmp |= 0x1000; -+ -+ /* enable codec clock */ -+ tmp |= 0x2000; -+ -+ pcap2_codec_write(codec, PCAP2_CODEC, tmp); -+ -+ dump_registers(); -+ return 0; -+} -+ -+/* -+ * Called by ALSA when the PCM substream is prepared, can set format, sample -+ * rate, etc. This function is non atomic and can be called multiple times, -+ * it can refer to the runtime info. -+ */ -+static int pcap2mono_codec_prepare(struct snd_pcm_substream *substream) -+{ -+ dbg("pcap2mono_codec_prepare"); -+ return 0; -+} -+ -+/* -+ * Codec DAPM event handler -+ * This handles codec level DAPM events -+ */ -+static int pcap2_codec_dapm_event(struct snd_soc_codec *codec, int event) -+{ -+ switch (event) { -+ case SNDRV_CTL_POWER_D0: /* full On */ -+ /* e.g. vref/mid, osc on, */ -+// ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AUDIO_LOWPWR, 0); -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_V2_EN_2, 1); -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_V2_EN_2, 1); -+ break; -+ case SNDRV_CTL_POWER_D1: /* partial On */ -+ case SNDRV_CTL_POWER_D2: /* partial On */ -+ break; -+ case SNDRV_CTL_POWER_D3hot: /* Off, with power */ -+ /* everything off except vref/vmid, */ -+ dbg("power on pcap codec"); -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AUDIO_LOWPWR, 0); -+// ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_V2_EN_2, 1); -+// ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_V2_EN_2, 1); -+ break; -+ case SNDRV_CTL_POWER_D3cold: /* Off, without power */ -+ /* everything off, dac mute, inactive */ -+ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AUDIO_LOWPWR, 1); -+ break; -+ } -+ codec->dapm_state = event; + return 0; +} + @@ -510,35 +605,28 @@ Index: linux-2.6.21/sound/soc/codecs/pcap2.c +{ + .name = "PCAP2 MONO", + .id = 0, -+ /* playback and capture stream info */ + .playback = { -+ .stream_name = "mono playback", ++ .stream_name = "CDC_DAC playback", + .channels_min = 1, + .channels_max = 1, + .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000), + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .capture = { -+ .stream_name = "mono capture", ++ .stream_name = "CDC_DAC capture", + .channels_min = 1, + .channels_max = 1, + .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000), + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, -+ /* codec operations */ -+ /* alsa PCM operations */ + .ops = { -+ .startup = pcap2mono_codec_startup, -+ .shutdown = pcap2mono_codec_shutdown, -+ .prepare = pcap2mono_codec_prepare, -+ .trigger = pcap2mono_codec_trigger, -+ .hw_params = pcap2mono_codec_hw_params, -+ .hw_free = pcap2mono_codec_hw_free,}, ++ .prepare = pcap2_prepare, ++ .hw_params = pcap2_hw_params, ++ .hw_free = pcap2_hw_free, ++ }, + .dai_ops = { +// .digital_mute = pcap2_mute, + .set_fmt = pcap2_set_dai_fmt, -+// .set_clkdiv = pcap2_set_dai_clkdiv, -+ .set_pll = pcap2_set_dai_pll, + .set_sysclk = pcap2_set_dai_sysclk, + }, +}, @@ -546,25 +634,33 @@ Index: linux-2.6.21/sound/soc/codecs/pcap2.c + .name = "PCAP2 STEREO", + .id = 1, + .playback = { -+ .stream_name = "stereo playback", -+ .channels_min = 2, ++ .stream_name = "ST_DAC playback", ++ .channels_min = 1, + .channels_max = 2, -+ .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_44100), ++ .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | ++ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | ++ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | ++ SNDRV_PCM_RATE_48000), ++ .formats = SNDRV_PCM_FMTBIT_S16_LE, ++ }, ++ .capture = { /* FIXME: PCAP support this?? */ ++ .stream_name = "ST_DAC capture", ++ .channels_min = 1, ++ .channels_max = 1, ++ .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | ++ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | ++ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | ++ SNDRV_PCM_RATE_48000), + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .ops = { -+// .startup = pcap2stereo_codec_startup, -+// .shutdown = pcap2stereo_codec_shutdown, -+// .prepare = pcap2stereo_codec_prepare, -+// .trigger = pcap2stereo_codec_trigger, -+// .hw_params = pcap2stereo_codec_hw_params, -+// .hw_free = pcap2stereo_codec_hw_free, ++ .prepare = pcap2_prepare, ++ .hw_params = pcap2_hw_params, ++ .hw_free = pcap2_hw_free, + }, + .dai_ops = { +// .digital_mute = pcap2_mute, + .set_fmt = pcap2_set_dai_fmt, -+// .set_clkdiv = pcap2_set_dai_clkdiv, -+ .set_pll = pcap2_set_dai_pll, + .set_sysclk = pcap2_set_dai_sysclk, + }, +}, @@ -572,25 +668,20 @@ Index: linux-2.6.21/sound/soc/codecs/pcap2.c + .name = "PCAP2 BP", + .id = 2, + .playback = { -+ .stream_name = "baseband playback", ++ .stream_name = "BP playback", + .channels_min = 1, + .channels_max = 1, + .rates = SNDRV_PCM_RATE_8000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .ops = { -+ .startup = pcap2mono_codec_startup, -+// .shutdown = pcap2mono_codec_shutdown, -+ .prepare = pcap2mono_codec_prepare, -+ .trigger = pcap2mono_codec_trigger, -+ .hw_params = pcap2mono_codec_hw_params, -+ .hw_free = pcap2mono_codec_hw_free, ++ .prepare = pcap2_prepare, ++ .hw_params = pcap2_hw_params, ++ .hw_free = pcap2_hw_free, + }, + .dai_ops = { +// .digital_mute = pcap2_mute, + .set_fmt = pcap2_set_dai_fmt, -+// .set_clkdiv = pcap2_set_dai_clkdiv, -+ .set_pll = pcap2_set_dai_pll, + .set_sysclk = pcap2_set_dai_sysclk, + }, +}, @@ -625,8 +716,8 @@ Index: linux-2.6.21/sound/soc/codecs/pcap2.c +static int pcap2_codec_init(struct snd_soc_device *socdev) +{ + struct snd_soc_codec *codec = socdev->codec; -+ int reg, ret = 0; -+ ++ int ret = 0; ++ + dbg("pcap2_codec_init"); + codec->name = "PCAP2 Audio"; + codec->owner = THIS_MODULE; @@ -651,15 +742,11 @@ Index: linux-2.6.21/sound/soc/codecs/pcap2.c + if (ret < 0) { + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); -+ dbg("erro registrando\n"); + } + + return ret; +} + -+static struct snd_soc_device *pcap2_codec_socdev; -+ -+ +static int pcap2_codec_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); @@ -703,8 +790,8 @@ Index: linux-2.6.21/sound/soc/codecs/pcap2.c +struct snd_soc_codec_device soc_codec_dev_pcap2 = { + .probe = pcap2_codec_probe, + .remove = pcap2_codec_remove, -+// .suspend = pcap2_codec_suspend, -+// .resume = pcap2_codec_resume, ++ .suspend = pcap2_codec_suspend, ++ .resume = pcap2_codec_resume, +}; + +EXPORT_SYMBOL_GPL(soc_codec_dev_pcap2); @@ -715,8 +802,8 @@ Index: linux-2.6.21/sound/soc/codecs/pcap2.c Index: linux-2.6.21/sound/soc/codecs/pcap2.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-2.6.21/sound/soc/codecs/pcap2.h 2007-08-04 02:06:01.000000000 -0300 -@@ -0,0 +1,31 @@ ++++ linux-2.6.21/sound/soc/codecs/pcap2.h 2007-09-07 12:13:49.000000000 -0300 +@@ -0,0 +1,81 @@ +/* + * 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 @@ -726,23 +813,73 @@ Index: linux-2.6.21/sound/soc/codecs/pcap2.h +#ifndef _PCAP2_H +#define _PCAP2_H + -+/* PCAP2 register space */ -+ -+#define PCAP2_OUTPUT_AMP 0x0c -+#define PCAP2_ST_DAC 0x0d -+#define PCAP2_INPUT_AMP 0x1a -+#define PCAP2_CODEC 0x0b ++/* 16 bit reads/writes on pcap registers (ugly workaround) */ ++#define SL (1 << 5) /* lower 16 bits */ ++#define SM (1 << 6) /* mid 16 bits */ ++#define SH (1 << 7) /* higher 16 bits */ + -+#define PCAP2_MONO_DAI 0 -+#define PCAP2_STEREO_DAI 1 -+#define PCAP2_BP_DAI 2 -+ -+#define PCAP2_PLL_BP 0 -+#define PCAP2_PLL_AP 1 -+ -+//struct template_codec_setup_data { -+// unsigned short i2c_address; -+//}; ++/* PCAP2 register space */ ++#define PCAP2_CODEC 0x0b ++#define PCAP2_OUTPUT_AMP 0x0c ++#define PCAP2_ST_DAC 0x0d ++#define PCAP2_INPUT_AMP 0x1a ++ ++#define PCAP2_MONO_DAI 0 ++#define PCAP2_STEREO_DAI 1 ++#define PCAP2_BP_DAI 2 ++ ++#define PCAP2_CLK_BP 0 ++#define PCAP2_CLK_AP 1 ++ ++#define PCAP2_CODEC_EN 0x2000 ++#define PCAP2_CODEC_CLK_EN 0x1000 ++#define PCAP2_CODEC_RESET_DF 0x800 ++#define PCAP2_CODEC_RATE_MASK 0x4000 ++#define PCAP2_CODEC_RATE_8000 0x0 ++#define PCAP2_CODEC_RATE_16000 0x4000 ++#define PCAP2_CODEC_CLKSEL_MASK 0x10000 ++#define PCAP2_CODEC_CLKSEL_AP 0x10000 ++#define PCAP2_CODEC_CLKSEL_BP 0x0 ++#define PCAP2_CODEC_CLK_MASK 0x1c0 ++#define PCAP2_CODEC_CLK_13M 0x0 ++#define PCAP2_CODEC_CLK_15M36 0x40 ++#define PCAP2_CODEC_CLK_16M8 0x80 ++#define PCAP2_CODEC_CLK_19M44 0xc0 ++#define PCAP2_CODEC_CLK_26M 0x100 ++ ++#define PCAP2_ST_DAC_EN 0x80 ++#define PCAP2_ST_DAC_CLK_EN 0x20 ++#define PCAP2_ST_DAC_RESET_DF 0x40 ++#define PCAP2_ST_DAC_RATE_MASK 0xf00 ++#define PCAP2_ST_DAC_RATE_8000 0x0 ++#define PCAP2_ST_DAC_RATE_11025 0x100 ++#define PCAP2_ST_DAC_RATE_12000 0x200 ++#define PCAP2_ST_DAC_RATE_16000 0x300 ++#define PCAP2_ST_DAC_RATE_22050 0x400 ++#define PCAP2_ST_DAC_RATE_24000 0x500 ++#define PCAP2_ST_DAC_RATE_32000 0x600 ++#define PCAP2_ST_DAC_RATE_44100 0x700 ++#define PCAP2_ST_DAC_RATE_48000 0x800 ++#define PCAP2_ST_DAC_CLKSEL_MASK 0x80000 ++#define PCAP2_ST_DAC_CLKSEL_AP 0x80000 ++#define PCAP2_ST_DAC_CLKSEL_BP 0x0 ++#define PCAP2_ST_DAC_CLK_MASK 0x1c ++#define PCAP2_ST_DAC_CLK_13M 0x0 ++#define PCAP2_ST_DAC_CLK_15M36 0x4 ++#define PCAP2_ST_DAC_CLK_16M8 0x8 ++#define PCAP2_ST_DAC_CLK_19M44 0xc ++#define PCAP2_ST_DAC_CLK_26M 0x10 ++#define PCAP2_ST_DAC_CLK_MCLK 0x14 ++#define PCAP2_ST_DAC_CLK_FSYNC 0x18 ++#define PCAP2_ST_DAC_CLK_BITCLK 0x1c ++ ++#define PCAP2_INPUT_AMP_LOWPWR 0x80000 ++#define PCAP2_INPUT_AMP_V2EN2 0x200000 ++ ++#define PCAP2_OUTPUT_AMP_PGAR_EN 0x800 ++#define PCAP2_OUTPUT_AMP_PGAL_EN 0x1000 ++#define PCAP2_OUTPUT_AMP_CDC_SW 0x100 ++#define PCAP2_OUTPUT_AMP_ST_DAC_SW 0x200 + +extern struct snd_soc_codec_dai pcap2_dai[]; +extern struct snd_soc_codec_device soc_codec_dev_pcap2; @@ -750,8 +887,8 @@ Index: linux-2.6.21/sound/soc/codecs/pcap2.h +#endif Index: linux-2.6.21/sound/soc/pxa/Kconfig =================================================================== ---- linux-2.6.21.orig/sound/soc/pxa/Kconfig 2007-08-02 22:58:17.000000000 -0300 -+++ linux-2.6.21/sound/soc/pxa/Kconfig 2007-08-02 22:58:34.000000000 -0300 +--- linux-2.6.21.orig/sound/soc/pxa/Kconfig 2007-09-07 12:13:43.000000000 -0300 ++++ linux-2.6.21/sound/soc/pxa/Kconfig 2007-09-07 12:13:49.000000000 -0300 @@ -60,4 +60,13 @@ Say Y if you want to add support for SoC audio on Sharp Zaurus SL-C6000x models (Tosa). @@ -769,9 +906,13 @@ Index: linux-2.6.21/sound/soc/pxa/Kconfig Index: linux-2.6.21/sound/soc/pxa/ezx.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-2.6.21/sound/soc/pxa/ezx.c 2007-08-04 22:35:25.000000000 -0300 -@@ -0,0 +1,296 @@ ++++ linux-2.6.21/sound/soc/pxa/ezx.c 2007-09-07 13:12:24.000000000 -0300 +@@ -0,0 +1,349 @@ +/* ++ * ezx.c - Machine specific code for EZX phones ++ * ++ * Copyright (C) 2007 Daniel Ribeiro <drwyrm@gmail.com> ++ * + * 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 @@ -794,11 +935,37 @@ Index: linux-2.6.21/sound/soc/pxa/ezx.c +#include <asm/arch/pxa-regs.h> +#include <asm/arch/hardware.h> + ++#include <asm/arch/ezx-pcap.h> ++ +#include "../codecs/pcap2.h" +#include "pxa2xx-pcm.h" +#include "pxa2xx-ssp.h" + +#define GPIO_HW_ATTENUATE_A780 96 ++ ++static struct snd_soc_codec *control_codec; ++ ++static void ezx_ext_control(struct snd_soc_codec *codec) ++{ ++ if (ezx_pcap_read_bit(pbit(PCAP_REG_PSTAT, PCAP_IRQ_A1))) ++ snd_soc_dapm_set_endpoint(codec, "Headset", 1); ++ else ++ snd_soc_dapm_set_endpoint(codec, "Headset", 0); ++ if (ezx_pcap_read_bit(pbit(PCAP_REG_PSTAT, PCAP_IRQ_MB2))) ++ snd_soc_dapm_set_endpoint(codec, "External Mic", 1); ++ else ++ snd_soc_dapm_set_endpoint(codec, "External Mic", 0); ++ ++ snd_soc_dapm_sync_endpoints(codec); ++} ++ ++static irqreturn_t jack_irq(int irq, void *data) ++{ ++ ezx_ext_control(control_codec); ++ return IRQ_HANDLED; ++} ++ ++ +/* + * Alsa operations + * Only implement the required operations for your platform. @@ -810,7 +977,11 @@ Index: linux-2.6.21/sound/soc/pxa/ezx.c + */ +static int ezx_machine_startup(struct snd_pcm_substream *substream) +{ -+ printk("ezx_machine_startup\n"); ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ struct snd_soc_codec *codec = rtd->socdev->codec; ++ ++ /* check the jack status at stream startup */ ++ ezx_ext_control(codec); + return 0; +} + @@ -827,21 +998,28 @@ Index: linux-2.6.21/sound/soc/pxa/ezx.c + struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; + int ret; + -+ + /* set codec DAI configuration */ -+ ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B | -+ SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM); ++ if (codec_dai->id == PCAP2_STEREO_DAI) ++ ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B | ++ SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBM_CFM); ++ else ++ ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B | ++ SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM); + if(ret < 0) + return ret; + -+ /* set PLL source */ -+ ret = codec_dai->dai_ops.set_pll(codec_dai, PCAP2_PLL_AP, 13000000, -1); ++ /* Turn on clock output on CLK_PIO */ ++ OSCC |= 0x8; ++ ++ /* set clock source */ ++ ret = codec_dai->dai_ops.set_sysclk(codec_dai, PCAP2_CLK_AP, ++ 13000000, SND_SOC_CLOCK_IN); + if(ret < 0) + return ret; + + /* set cpu DAI configuration */ + ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_B | -+ SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM); ++ SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM); + if (ret < 0) + return ret; + @@ -849,10 +1027,11 @@ Index: linux-2.6.21/sound/soc/pxa/ezx.c + if (ret < 0) + return ret; + -+ ret = cpu_dai->dai_ops.set_sysclk(cpu_dai,PXA2XX_SSP_CLK_PLL, 0, SND_SOC_CLOCK_IN); ++ ret = cpu_dai->dai_ops.set_sysclk(cpu_dai,PXA2XX_SSP_CLK_EXT, ++ 0, SND_SOC_CLOCK_IN); + if (ret < 0) + return ret; -+ ++ + return 0; +} + @@ -861,26 +1040,22 @@ Index: linux-2.6.21/sound/soc/pxa/ezx.c + */ +static int ezx_machine_hw_free(struct snd_pcm_substream *substream) +{ -+ -+ printk("ezx_machine_hw_free\n"); ++ OSCC &= ~0x8; /* turn off clock output on CLK_PIO */ + + return 0; +} + +static int ezx_machine_prepare(struct snd_pcm_substream *substream) +{ -+ int timeout = 0; -+ while(((SSSR_P(3) & SSSR_CSS) != 0) && (timeout++ < 10000000)); -+ -+ if (timeout >= 10000000) -+ printk("clock sync timeout!\n"); -+ else -+ printk("clock sync passed %d\n", timeout); ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; ++ struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; + -+// printk("SSCR0 %x SSCR1 %x SSTO %x SSPSP %x SSSR %x SSACD %x\n", -+// SSCR0_P(3), SSCR1_P(3), -+// SSTO_P(3), SSPSP_P(3), -+// SSSR_P(3), SSACD_P(3)); ++ if (codec_dai->id == PCAP2_STEREO_DAI) { ++ /* override pxa2xx-ssp sample size for stereo/network mode */ ++ SSCR0_P(cpu_dai->id+1) &= ~(SSCR0_DSS | SSCR0_EDSS); ++ SSCR0_P(cpu_dai->id+1) |= (SSCR0_EDSS | SSCR0_DataSize(16)); ++ } + return 0; +} + @@ -897,39 +1072,41 @@ Index: linux-2.6.21/sound/soc/pxa/ezx.c +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; -+ struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; -+ int ret; -+ printk("bp_hw_params\n"); ++// struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; ++ int ret = 0; + /* set codec DAI configuration */ + ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B | + SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM); + if(ret < 0) + return ret; + -+ /* set PLL source */ -+ ret = codec_dai->dai_ops.set_pll(codec_dai, PCAP2_PLL_BP, 13000000, -1); -+ if(ret < 0) -+ return ret; ++ /* set clock source */ ++ ret = codec_dai->dai_ops.set_sysclk(codec_dai, PCAP2_CLK_BP, ++ 13000000, SND_SOC_CLOCK_IN); + -+ /* set cpu DAI configuration */ -+// ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_B | -+// SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM); -+// if (ret < 0) -+// return ret; -+ -+// ret = cpu_dai->dai_ops.set_tristate(cpu_dai, 0); -+// if (ret < 0) -+// return ret; -+ -+// ret = cpu_dai->dai_ops.set_sysclk(cpu_dai,PXA2XX_SSP_CLK_PLL, 0, SND_SOC_CLOCK_IN); -+// if (ret < 0) -+// return ret; -+ -+ return 0; ++ return ret; +} + ++ ++ ++/* machine dapm widgets */ ++static const struct snd_soc_dapm_widget ezx_dapm_widgets[] = { ++ SND_SOC_DAPM_HP("Headset", NULL), ++ SND_SOC_DAPM_SPK("Earpiece", NULL), ++ SND_SOC_DAPM_SPK("Loudspeaker", NULL), ++ SND_SOC_DAPM_MIC("Built-in Mic", NULL), ++ SND_SOC_DAPM_MIC("External Mic", NULL), ++}; ++ +/* machine audio map (connections to the codec pins) */ +static const char *audio_map[][3] = { ++ { "Headset", NULL, "AR" }, ++ { "Headset", NULL, "AL" }, ++ { "Earpiece", NULL, "A1" }, ++ { "Loudspeaker", NULL, "A2" }, ++ ++ { "Built-in Mic", NULL, "A5" }, ++ { "External Mic", NULL, "A3" }, + + {NULL, NULL, NULL}, +}; @@ -939,14 +1116,26 @@ Index: linux-2.6.21/sound/soc/pxa/ezx.c + */ +static int ezx_machine_init(struct snd_soc_codec *codec) +{ -+ printk("ezx machine init\n"); ++ int i; + /* mark unused codec pins as NC */ ++// snd_soc_dapm_set_endpoint(codec, "FIXME", 0); ++ control_codec = codec; ++ ++ /* Add ezx specific controls */ ++// for (i = 0; i < ARRAY_SIZE(ezx_controls); i++) { ++// if ((err = snd_ctl_add(codec->card, snd_soc_cnew(&ezx_controls[i], codec, NULL))) < 0) ++// return err; ++// } ++ ++ /* Add ezx specific widgets */ ++ for(i = 0; i < ARRAY_SIZE(ezx_dapm_widgets); i++) { ++ snd_soc_dapm_new_control(codec, &ezx_dapm_widgets[i]); ++ } ++ /* Set up ezx specific audio path interconnects */ ++ for(i = 0; audio_map[i][0] != NULL; i++) { ++ snd_soc_dapm_connect_input(codec, audio_map[i][0], audio_map[i][1], audio_map[i][2]); ++ } + -+ /* Add template specific controls */ -+ -+ /* Add template specific widgets */ -+ -+ /* Set up template specific audio path audio_map */ + /* synchronise subsystem */ + snd_soc_dapm_sync_endpoints(codec); + return 0; @@ -980,19 +1169,19 @@ Index: linux-2.6.21/sound/soc/pxa/ezx.c +/* template digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link ezx_dai[] = { +{ -+ .name = "PCAP2 MONO", -+ .stream_name = "mono playback", ++ .name = "PCAP2 STEREO", ++ .stream_name = "stereo playback", + .cpu_dai = &pxa_ssp_dai[PXA2XX_DAI_SSP3], -+ .codec_dai = &pcap2_dai[PCAP2_MONO_DAI], ++ .codec_dai = &pcap2_dai[PCAP2_STEREO_DAI], + .init = ezx_machine_init, + .ops = &ezx_ops, +}, +{ -+ .name = "PCAP2 STEREO", -+ .stream_name = "stereo playback", ++ .name = "PCAP2 MONO", ++ .stream_name = "mono playback", + .cpu_dai = &pxa_ssp_dai[PXA2XX_DAI_SSP3], -+ .codec_dai = &pcap2_dai[PCAP2_STEREO_DAI], -+ .init = ezx_machine_init, ++ .codec_dai = &pcap2_dai[PCAP2_MONO_DAI], ++// .init = ezx_machine_init, /* the stereo call already registered our controls */ + .ops = &ezx_ops, +}, +{ @@ -1014,17 +1203,11 @@ Index: linux-2.6.21/sound/soc/pxa/ezx.c + .num_links = ARRAY_SIZE(ezx_dai), +}; + -+/* template audio private data */ -+//static struct codec_priv_setup_data template_codec_setup = { -+// .i2c_address = 0x1b, -+//}; -+ +/* template audio subsystem */ +static struct snd_soc_device ezx_snd_devdata = { + .machine = &snd_soc_machine_ezx, + .platform = &pxa2xx_soc_platform, + .codec_dev = &soc_codec_dev_pcap2, -+// .codec_data = &ezx_pcap2_setup, +}; + +static struct platform_device *ezx_snd_device; @@ -1032,7 +1215,6 @@ Index: linux-2.6.21/sound/soc/pxa/ezx.c +static int __init ezx_init(void) +{ + int ret; -+ printk("soc: ezx_init entered\n"); + ezx_snd_device = platform_device_alloc("soc-audio", -1); + if (!ezx_snd_device) + return -ENOMEM; @@ -1043,24 +1225,32 @@ Index: linux-2.6.21/sound/soc/pxa/ezx.c + + if (ret) + platform_device_put(ezx_snd_device); -+ ++ /* configure gpio for ssp3 */ + pxa_gpio_mode(GPIO83_SFRM3_MD); /* SFRM */ + pxa_gpio_mode(GPIO81_STXD3_MD); /* TXD */ -+ pxa_gpio_mode(52 | GPIO_ALT_FN_2_IN); /* SCLK */ ++ pxa_gpio_mode(GPIO52_SCLK3_MD); /* SCLK */ + pxa_gpio_mode(GPIO89_SRXD3_MD); /* RXD */ + ++ /* configure gpio for ssp2 */ ++ pxa_gpio_mode(37 | GPIO_IN); /* SFRM */ ++ pxa_gpio_mode(38 | GPIO_IN); /* TXD */ ++ pxa_gpio_mode(22 | GPIO_IN); /* SCLK */ ++ pxa_gpio_mode(88 | GPIO_IN); /* RXD */ + + pxa_gpio_mode(GPIO_HW_ATTENUATE_A780 | GPIO_OUT); + pxa_gpio_set_value(GPIO_HW_ATTENUATE_A780, 1); + -+ -+ ++ /* request jack irq */ ++ request_irq(EZX_IRQ_HEADJACK, &jack_irq, SA_INTERRUPT, "headphone jack", NULL); ++ request_irq(EZX_IRQ_MIC, &jack_irq, SA_INTERRUPT, "mic jack", NULL); + + return ret; +} + +static void __exit ezx_exit(void) +{ ++ free_irq(EZX_IRQ_HEADJACK, NULL); ++ free_irq(EZX_IRQ_MIC, NULL); + platform_device_unregister(ezx_snd_device); +} + @@ -1069,8 +1259,8 @@ Index: linux-2.6.21/sound/soc/pxa/ezx.c + Index: linux-2.6.21/sound/soc/codecs/Makefile =================================================================== ---- linux-2.6.21.orig/sound/soc/codecs/Makefile 2007-08-02 22:57:48.000000000 -0300 -+++ linux-2.6.21/sound/soc/codecs/Makefile 2007-08-02 22:58:34.000000000 -0300 +--- linux-2.6.21.orig/sound/soc/codecs/Makefile 2007-09-07 12:13:43.000000000 -0300 ++++ linux-2.6.21/sound/soc/codecs/Makefile 2007-09-07 12:13:49.000000000 -0300 @@ -2,8 +2,10 @@ snd-soc-wm8731-objs := wm8731.o snd-soc-wm8750-objs := wm8750.o @@ -1084,8 +1274,8 @@ Index: linux-2.6.21/sound/soc/codecs/Makefile +obj-$(CONFIG_SND_SOC_PCAP2) += snd-soc-pcap2.o Index: linux-2.6.21/sound/soc/codecs/Kconfig =================================================================== ---- linux-2.6.21.orig/sound/soc/codecs/Kconfig 2007-08-02 22:57:48.000000000 -0300 -+++ linux-2.6.21/sound/soc/codecs/Kconfig 2007-08-02 22:58:34.000000000 -0300 +--- linux-2.6.21.orig/sound/soc/codecs/Kconfig 2007-09-07 12:13:43.000000000 -0300 ++++ linux-2.6.21/sound/soc/codecs/Kconfig 2007-09-07 12:13:49.000000000 -0300 @@ -13,3 +13,7 @@ config SND_SOC_WM9712 tristate @@ -1096,8 +1286,8 @@ Index: linux-2.6.21/sound/soc/codecs/Kconfig + depends on SND_SOC && EZX_PCAP Index: linux-2.6.21/sound/soc/pxa/Makefile =================================================================== ---- linux-2.6.21.orig/sound/soc/pxa/Makefile 2007-08-02 22:58:17.000000000 -0300 -+++ linux-2.6.21/sound/soc/pxa/Makefile 2007-08-02 22:58:34.000000000 -0300 +--- linux-2.6.21.orig/sound/soc/pxa/Makefile 2007-09-07 12:13:43.000000000 -0300 ++++ linux-2.6.21/sound/soc/pxa/Makefile 2007-09-07 12:13:49.000000000 -0300 @@ -14,9 +14,10 @@ snd-soc-poodle-objs := poodle.o snd-soc-tosa-objs := tosa.o @@ -1110,70 +1300,3 @@ Index: linux-2.6.21/sound/soc/pxa/Makefile obj-$(CONFIG_SND_PXA2XX_SOC_SPITZ) += snd-soc-spitz.o - +obj-$(CONFIG_SND_PXA2XX_SOC_EZX) += snd-soc-ezx.o -Index: linux-2.6.21/sound/soc/pxa/pxa2xx-ssp.c -=================================================================== ---- linux-2.6.21.orig/sound/soc/pxa/pxa2xx-ssp.c 2007-08-02 22:58:17.000000000 -0300 -+++ linux-2.6.21/sound/soc/pxa/pxa2xx-ssp.c 2007-08-02 22:58:34.000000000 -0300 -@@ -440,6 +440,12 @@ - case SND_SOC_DAIFMT_NB_NF: - SSPSP_P(port) |= SSPSP_SFRMP | SSPSP_FSRT; - break; -+ case SND_SOC_DAIFMT_NB_IF: -+ SSPSP_P(port) |= SSPSP_FSRT; -+ break; -+ case SND_SOC_DAIFMT_IB_NF: -+ SSPSP_P(port) |= SSPSP_SFRMP; -+ break; - case SND_SOC_DAIFMT_IB_IF: - break; - default: -Index: linux-2.6.21/sound/soc/pxa/pxa2xx-pcm.c -=================================================================== ---- linux-2.6.21.orig/sound/soc/pxa/pxa2xx-pcm.c 2007-08-02 22:57:48.000000000 -0300 -+++ linux-2.6.21/sound/soc/pxa/pxa2xx-pcm.c 2007-08-04 22:46:02.000000000 -0300 -@@ -61,8 +61,9 @@ - - dcsr = DCSR(dma_ch); - DCSR(dma_ch) = dcsr & ~DCSR_STOPIRQEN; -- -+ printk("dma irq dcsr=%08x ", dcsr); - if (dcsr & DCSR_ENDINTR) { -+ printk("endintr\n"); - snd_pcm_period_elapsed(substream); - } else { - printk( KERN_ERR "%s: DMA error on channel %d (DCSR=%#x)\n", -@@ -106,7 +107,8 @@ - return ret; - prtd->dma_ch = ret; - } -- -+ printk("requested dma channel %d\n", ret); -+ - snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); - runtime->dma_bytes = totsize; - -@@ -153,11 +155,13 @@ - static int pxa2xx_pcm_prepare(struct snd_pcm_substream *substream) - { - struct pxa2xx_runtime_data *prtd = substream->runtime->private_data; -- -+ printk("pcm_prepare channel %d\n", prtd->dma_ch); - DCSR(prtd->dma_ch) &= ~DCSR_RUN; - DCSR(prtd->dma_ch) = 0; - DCMD(prtd->dma_ch) = 0; -- *prtd->params->drcmr = prtd->dma_ch | DRCMR_MAPVLD; -+ -+ if (prtd->params) -+ *prtd->params->drcmr = prtd->dma_ch | DRCMR_MAPVLD; - - return 0; - } -@@ -190,7 +194,7 @@ - default: - ret = -EINVAL; - } -- -+ printk("pcm_trigger ret%d, cmd%d\n", ret, cmd); - return ret; - } - |