summaryrefslogtreecommitdiff
path: root/packages/linux/linux-ezx-2.6.21/patches/ezx-asoc.patch
diff options
context:
space:
mode:
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.patch1053
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;
- }
-