All pastes #437029 Raw Edit

Untitled

public text v1 · immutable
·published 2007-04-12 20:49 UTC
rendered paste body
Index: blueangel.c
===================================================================
RCS file: /cvs/linux/kernel26/sound/soc/pxa/blueangel.c,v
retrieving revision 1.1
diff -u -r1.1 blueangel.c
--- blueangel.c	6 Dec 2006 21:24:47 -0000	1.1
+++ blueangel.c	12 Apr 2007 20:48:01 -0000
@@ -1,13 +1,12 @@
 /*
- * SoC audio for HTC Blueangel
+ * SoC audio for HTC Magician
+ *
+ * Copyright (c) 2006 Philipp Zabel <philipp.zabel@gmail.com>
  *
  * based on spitz.c,
  * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
  *          Richard Purdie <richard@openedhand.com>
  *
- * based on magician.c,
- * Author: Luke Kenneth Casson Leighton <lkcl@lkcl.net>
- *
  *  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
@@ -15,12 +14,11 @@
  *
  */
 
-#include <linux/delay.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/timer.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
+#include <linux/delay.h>
 #include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -30,91 +28,83 @@
 #include <asm/hardware/scoop.h>
 #include <asm/arch/pxa-regs.h>
 #include <asm/arch/hardware.h>
-#include <asm/arch-pxa/htcblueangel-asic.h>
-#include <asm/arch-pxa/htcblueangel-gpio.h>
+#include <asm/arch/htcblueangel-asic.h>
+#include <asm/arch/htcblueangel-gpio.h>
 #include <asm/mach-types.h>
 #include "../codecs/uda1380.h"
 #include "pxa2xx-pcm.h"
+#include "pxa2xx-i2s.h"
+#include "pxa2xx-ssp.h"
 
-#include <asm/hardware/ipaq-asic3.h>
-#include <linux/soc/asic3_base.h>
+#define BLUEANGEL_HP_OFF    0
+#define BLUEANGEL_HEADSET   1
+#define BLUEANGEL_HP        2
 
-#define BLUEANGEL_HP        0
-#define BLUEANGEL_MIC       1
-#define BLUEANGEL_LINE      2
-#define BLUEANGEL_HEADSET   3
-#define BLUEANGEL_HP_OFF    4
 #define BLUEANGEL_SPK_ON    0
 #define BLUEANGEL_SPK_OFF   1
 
-static int blueangel_jack_func = 0;
-static int blueangel_spk_func = 0;
+#define BLUEANGEL_MIC       0
+#define BLUEANGEL_MIC_EXT   1
+#define BLUEANGEL_BT_HS     2
 
-extern struct platform_device blueangel_asic3;
+/*
+ * SSP GPIO's
+ */
+#define GPIO27_SSP_EXT_CLK	(27 | GPIO_ALT_FN_1_IN)
 
-static irqreturn_t earphone_isr(int irq, void *irq_desc)
-{
-	printk("earphone irq. GPIO99 = %d\n", GPLR(99) & GPIO_bit(99)); // EXT_MIC_DETECT, EARPHONE_DET
-//	printk("earphone irq. cpld18 = %d\n", blueangel_cpld18()); // is_earphone_connected
-	return IRQ_HANDLED;
-}
+static int blueangel_jack_func = BLUEANGEL_HP_OFF;
+static int blueangel_spk_func = BLUEANGEL_SPK_ON;
+static int blueangel_in_sel = BLUEANGEL_MIC;
+
+extern struct platform_device blueangel_asic3;
 
 static void blueangel_ext_control(struct snd_soc_codec *codec)
 {
-printk("blueangel_ext_control(spk_func = %d, jack_func = %d)", blueangel_spk_func, blueangel_jack_func);
-
-  asic3_set_gpio_out_b(&blueangel_asic3.dev, 1<<15, 1<<15); /* reset on? */
-  udelay(15);
-  asic3_set_gpio_out_a(&blueangel_asic3.dev, 1<<15, 1<<15); /* power? */
-  udelay(30);
-  /* now gpio 23 gets sent and also egpio14?? */
-  udelay(15);
-  asic3_set_gpio_out_b(&blueangel_asic3.dev, 1<<15, 0); /* reset off? */
+	asic3_set_gpio_out_b(&blueangel_asic3.dev, 1<<GPIOB_CODEC_RESET, 1<<GPIOB_CODEC_RESET); /* reset on? */
+	asic3_set_clock_cdex (&blueangel_asic3.dev, 1<<CLOCK_CDEX_EX1, 1 << CLOCK_CDEX_EX1);
+	udelay(1000);
+	asic3_set_clock_cdex (&blueangel_asic3.dev, 1 << 0, 0 ); // Source 0
+	asic3_set_clock_cdex (&blueangel_asic3.dev, 1 << 1, 1 << 1); // Source 1
+	asic3_set_clock_cdex (&blueangel_asic3.dev, 1<<CLOCK_CDEX_CONTROL_CX, CLOCK_CDEX_CONTROL_CX);
+	asic3_set_gpio_out_a(&blueangel_asic3.dev, 1<<GPIOA_CODEC_PWR_ON, 1<<GPIOA_CODEC_PWR_ON); /* power? */
+	/* now gpio 23 gets sent and also egpio14?? */
+	udelay(15);
+	asic3_set_gpio_out_b(&blueangel_asic3.dev, 1<<GPIOB_CODEC_RESET, 0); /* reset off? */
 
 	if (blueangel_spk_func == BLUEANGEL_SPK_ON)
-		snd_soc_dapm_set_endpoint(codec, "Ext Spk", 1);
+		snd_soc_dapm_set_endpoint(codec, "Speaker", 1);
 	else
-		snd_soc_dapm_set_endpoint(codec, "Ext Spk", 0);
+		snd_soc_dapm_set_endpoint(codec, "Speaker", 0);
 
-#if 0
 	/* set up jack connection */
-	switch(blueangel_jack_func) {
+	switch (blueangel_jack_func) {
 	case BLUEANGEL_HP:
 		/* enable and unmute hp jack, disable mic bias */
-		snd_soc_dapm_set_endpoint(codec, "Headset Jack", 0);
 		snd_soc_dapm_set_endpoint(codec, "Mic Jack", 0);
-		snd_soc_dapm_set_endpoint(codec, "Line Jack", 0);
 		snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 1);
-		blueangel_egpio_disable(&blueangel_cpld, EGPIO_NR_BLUEANGEL_SPK_POWER);
-		blueangel_egpio_enable(&blueangel_cpld, EGPIO_NR_BLUEANGEL_EP_POWER);
-		break;
-	case BLUEANGEL_MIC:
-		/* enable mic jack and bias, mute hp */
-		snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 0);
-		snd_soc_dapm_set_endpoint(codec, "Headset Jack", 0);
-		snd_soc_dapm_set_endpoint(codec, "Line Jack", 0);
-		snd_soc_dapm_set_endpoint(codec, "Mic Jack", 1);
-//		reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L);
-//		reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R);
 		break;
 	case BLUEANGEL_HEADSET:
-		/* enable and unmute headset jack enable mic bias, mute L hp */
-		snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 0);
+		/* enable mic jack and bias, mute hp */
+		snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 1);
 		snd_soc_dapm_set_endpoint(codec, "Mic Jack", 1);
-		snd_soc_dapm_set_endpoint(codec, "Line Jack", 0);
-		snd_soc_dapm_set_endpoint(codec, "Headset Jack", 1);
-		blueangel_egpio_enable(&blueangel_cpld, EGPIO_NR_BLUEANGEL_EP_POWER);
-		blueangel_egpio_disable(&blueangel_cpld, EGPIO_NR_BLUEANGEL_SPK_POWER);
 		break;
 	case BLUEANGEL_HP_OFF:
-
 		/* jack removed, everything off */
 		snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 0);
-		snd_soc_dapm_set_endpoint(codec, "Headset Jack", 0);
 		snd_soc_dapm_set_endpoint(codec, "Mic Jack", 0);
-		snd_soc_dapm_set_endpoint(codec, "Line Jack", 0);
-		blueangel_egpio_disable(&blueangel_cpld, EGPIO_NR_BLUEANGEL_EP_POWER);
-		blueangel_egpio_enable(&blueangel_cpld, EGPIO_NR_BLUEANGEL_SPK_POWER);
+		break;
+	}
+#if 0
+	/* fixme pH5, can we detect and config the correct Mic type ? */
+	switch(blueangel_in_sel) {
+	case BLUEANGEL_IN_MIC:
+		snd_soc_dapm_set_endpoint(codec, "Mic Jack", 1);
+		break;
+	case BLUEANGEL_IN_MIC_EXT:
+		snd_soc_dapm_set_endpoint(codec, "Mic Jack", 1);
+		break;
+	case BLUEANGEL_IN_BT_HS:
+		snd_soc_dapm_set_endpoint(codec, "Mic Jack", 0);
 		break;
 	}
 #endif
@@ -129,188 +119,377 @@
 	/* check the jack status at stream startup */
 	blueangel_ext_control(codec);
 
-	/* GPIO 99 is EXT_MIC / EARPHONE detect */
-	/* cpld+0x18 & 0x2 = is_earphone_plugged_in */
-	// EGPIO_NR_BLUEANGEL_CODEC_POWER = 0x0c000004,0x40(1<<6)
 	return 0;
 }
 
-static void blueangel_shutdown(snd_pcm_substream_t *substream)
+/*
+ * Magician uses SSP port for playback.
+ */
+static int blueangel_playback_hw_params(struct snd_pcm_substream *substream,
+				       struct snd_pcm_hw_params *params)
 {
-  asic3_set_gpio_out_a(&blueangel_asic3.dev, 1<<15, 0); /* power? */
+	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;
+	unsigned int acps, acds, div4;
+	int ret = 0;
+
+	/*
+	 * Rate = SSPSCLK / (word size(16))
+	 * SSPSCLK = (ACPS / ACDS) / SSPSCLKDIV(div4 or div1)
+	 */
+	switch (params_rate(params)) {
+	case 8000:
+		acps = 32842000;
+		acds = PXA2XX_SSP_CLK_AUDIO_DIV_32;	/* wrong - 32 bits/sample */
+		div4 = PXA2XX_SSP_CLK_SCDB_4;
+		break;
+	case 11025:
+		acps = 5622000;
+		acds = PXA2XX_SSP_CLK_AUDIO_DIV_8;	/* 16 bits/sample, 1 slot */
+		div4 = PXA2XX_SSP_CLK_SCDB_4;
+		break;
+	case 22050:
+		acps = 5622000;
+		acds = PXA2XX_SSP_CLK_AUDIO_DIV_4;
+		div4 = PXA2XX_SSP_CLK_SCDB_4;
+		break;
+	case 44100:
+		acps = 11345000;
+		acds = PXA2XX_SSP_CLK_AUDIO_DIV_4;
+		div4 = PXA2XX_SSP_CLK_SCDB_4;
+		break;
+	case 48000:
+		acps = 12235000;
+		acds = PXA2XX_SSP_CLK_AUDIO_DIV_4;
+		div4 = PXA2XX_SSP_CLK_SCDB_4;
+		break;
+	}
+
+	/* set codec DAI configuration */
+	ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_MSB |
+			SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+	if (ret < 0)
+		return ret;
+
+	/* set cpu DAI configuration */
+	ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_MSB |
+			SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+	if (ret < 0)
+		return ret;
+
+	/* set audio clock as clock source */
+	ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, PXA2XX_SSP_CLK_AUDIO, 0,
+			SND_SOC_CLOCK_OUT);
+	if (ret < 0)
+		return ret;
+
+	/* set the SSP audio system clock ACDS divider */
+	ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai,
+			PXA2XX_SSP_AUDIO_DIV_ACDS, acds);
+	if (ret < 0)
+		return ret;
+
+	/* set the SSP audio system clock SCDB divider4 */
+	ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai,
+			PXA2XX_SSP_AUDIO_DIV_SCDB, div4);
+	if (ret < 0)
+		return ret;
+
+	/* set SSP audio pll clock */
+	ret = cpu_dai->dai_ops.set_pll(cpu_dai, 0, 0, acps);
+	if (ret < 0)
+		return ret;
 
 	return 0;
 }
 
-static struct snd_soc_ops blueangel_ops = {
+/*
+ * We have to enable the SSP port early so the UDA1380 can flush
+ * it's register cache. The UDA1380 can only write it's interpolator and
+ * decimator registers when the link is running.
+ */
+static int blueangel_playback_prepare(struct snd_pcm_substream *substream)
+{
+	/* enable SSP clock - is this needed ? */
+	SSCR0_P(1) |= SSCR0_SSE;
+
+	/* FIXME: ENABLE I2S */
+	SACR0 |= SACR0_BCKD;
+	SACR0 |= SACR0_ENB;
+	pxa_set_cken(CKEN8_I2S, 1);
+
+	return 0;
+}
+
+static int blueangel_playback_hw_free(struct snd_pcm_substream *substream)
+{
+	/* FIXME: DISABLE I2S */
+	SACR0 &= ~SACR0_ENB;
+	SACR0 &= ~SACR0_BCKD;
+	pxa_set_cken(CKEN8_I2S, 0);
+	return 0;
+}
+
+/*
+ * Magician uses I2S for capture.
+ */
+static int blueangel_capture_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_codec_dai *codec_dai = rtd->dai->codec_dai;
+	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_MSB | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+	if (ret < 0)
+		return ret;
+
+	/* set cpu DAI configuration */
+	ret = cpu_dai->dai_ops.set_fmt(cpu_dai,
+			SND_SOC_DAIFMT_MSB | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+	if (ret < 0)
+		return ret;
+
+	/* set the I2S system clock as output */
+	ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0,
+			SND_SOC_CLOCK_OUT);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+/*
+ * We have to enable the I2S port early so the UDA1380 can flush
+ * it's register cache. The UDA1380 can only write it's interpolator and
+ * decimator registers when the link is running.
+ */
+static int blueangel_capture_prepare(struct snd_pcm_substream *substream)
+{
+	SACR0 |= SACR0_ENB;
+	return 0;
+}
+
+static struct snd_soc_ops blueangel_capture_ops = {
 	.startup = blueangel_startup,
-	.shutdown = blueangel_shutdown,
+	.hw_params = blueangel_capture_hw_params,
+	.prepare = blueangel_capture_prepare,
 };
 
-static int blueangel_get_jack(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+static struct snd_soc_ops blueangel_playback_ops = {
+	.startup = blueangel_startup,
+	.hw_params = blueangel_playback_hw_params,
+	.prepare = blueangel_playback_prepare,
+	.hw_free = blueangel_playback_hw_free,
+};
+
+static int blueangel_get_jack(snd_kcontrol_t * kcontrol,
+			     snd_ctl_elem_value_t * ucontrol)
 {
 	ucontrol->value.integer.value[0] = blueangel_jack_func;
 	return 0;
 }
 
-static int blueangel_set_jack(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+static int blueangel_set_jack(snd_kcontrol_t * kcontrol,
+			     snd_ctl_elem_value_t * ucontrol)
 {
-
 	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+	if (blueangel_jack_func == ucontrol->value.integer.value[0])
+		return 0;
+
 	blueangel_jack_func = ucontrol->value.integer.value[0];
 	blueangel_ext_control(codec);
-	return 0;
+	return 1;
 }
 
-static int blueangel_get_spk(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+static int blueangel_get_spk(snd_kcontrol_t * kcontrol,
+			    snd_ctl_elem_value_t * ucontrol)
 {
 	ucontrol->value.integer.value[0] = blueangel_spk_func;
 	return 0;
 }
 
-static int blueangel_set_spk(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+static int blueangel_set_spk(snd_kcontrol_t * kcontrol,
+			    snd_ctl_elem_value_t * ucontrol)
 {
-	struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+	if (blueangel_spk_func == ucontrol->value.integer.value[0])
+		return 0;
+
 	blueangel_spk_func = ucontrol->value.integer.value[0];
 	blueangel_ext_control(codec);
+	return 1;
+}
+
+static int blueangel_get_input(snd_kcontrol_t * kcontrol,
+			      snd_ctl_elem_value_t * ucontrol)
+{
+	ucontrol->value.integer.value[0] = blueangel_in_sel;
+	return 0;
+}
+
+static int blueangel_set_input(snd_kcontrol_t * kcontrol,
+			      snd_ctl_elem_value_t * ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+	if (blueangel_in_sel == ucontrol->value.integer.value[0])
+		return 0;
+
+	blueangel_in_sel = ucontrol->value.integer.value[0];
+
+	switch (blueangel_in_sel) {
+	case BLUEANGEL_MIC:
+		asic3_set_gpio_out_a(&blueangel_asic3.dev, 1<<GPIOA_MIC_PWR_ON, 1<<GPIOA_MIC_PWR_ON);
+		break;
+	case BLUEANGEL_MIC_EXT:
+		break;
+	}
+
+	return 1;
+}
+
+static int blueangel_spk_power(struct snd_soc_dapm_widget *w, int event)
+{
+	if (SND_SOC_DAPM_EVENT_ON(event))
+		asic3_set_gpio_out_a(&blueangel_asic3.dev, 1<<15, 1<<15);
+	else
+		asic3_set_gpio_out_a(&blueangel_asic3.dev, 1<<15, 0);
 	return 0;
 }
 
-static int blueangel_mic_bias(struct snd_soc_dapm_widget* w, int power)
+static int blueangel_hp_power(struct snd_soc_dapm_widget *w, int event)
 {
-  asic3_set_gpio_out_a(&blueangel_asic3.dev, 1<<GPIOA_MIC_PWR_ON, power ? (1<<GPIOA_MIC_PWR_ON) : 0);
+	if (SND_SOC_DAPM_EVENT_ON(event))
+		asic3_set_gpio_out_b(&blueangel_asic3.dev, 1 << 10, 1 << 10);
+	else
+		asic3_set_gpio_out_b(&blueangel_asic3.dev, 1 << 10, 0);
+	return 0;
+}
 
+static int blueangel_mic_bias(struct snd_soc_dapm_widget *w, int event)
+{
+	if (SND_SOC_DAPM_EVENT_ON(event))
+		asic3_set_gpio_out_a(&blueangel_asic3.dev, 1 << 8 , 1 << 8 );
+	else
+		asic3_set_gpio_out_a(&blueangel_asic3.dev, 1 << 8 , 0);
 	return 0;
 }
 
 /* blueangel machine dapm widgets */
 static const struct snd_soc_dapm_widget uda1380_dapm_widgets[] = {
-	SND_SOC_DAPM_HP("Headphone Jack", NULL),
+	SND_SOC_DAPM_HP("Headphone Jack", blueangel_hp_power),
 	SND_SOC_DAPM_MIC("Mic Jack", blueangel_mic_bias),
-	SND_SOC_DAPM_SPK("Ext Spk", NULL),
-	SND_SOC_DAPM_LINE("Line Jack", NULL),
-
-	/* headset is a mic and mono headphone */
-	SND_SOC_DAPM_HP("Headset Jack", NULL),
+	SND_SOC_DAPM_SPK("Speaker", blueangel_spk_power),
 };
 
 /* blueangel machine audio_map */
-static const char* audio_map[][3] = {
+static const char *audio_map[][3] = {
 
-	/* headphone connected to LOUT1, ROUT1 */
+	/* headphone connected to VOUTLHP, VOUTRHP */
 	{"Headphone Jack", NULL, "VOUTLHP"},
 	{"Headphone Jack", NULL, "VOUTRHP"},
 
-	/* headset connected to ROUT1 and LINPUT1 with bias (def below) */
-	{"Headset Jack", NULL, "ROUT1"},
-
-	/* ext speaker connected to LOUT2, ROUT2  */
-	{"Ext Spk", NULL , "VOUTR"},
-	{"Ext Spk", NULL , "VOUTL"},
-
-	/* mic is connected to input 1 - with bias */
-	{"LINPUT1", NULL, "Mic Bias"},
-	{"Mic Bias", NULL, "Mic Jack"},
-
-	/* line is connected to input 1 - no bias */
-	{"LINPUT1", NULL, "Line Jack"},
+	/* ext speaker connected to VOUTL, VOUTR  */
+	{"Speaker", NULL, "VOUTL"},
+	{"Speaker", NULL, "VOUTR"},
+
+	/* mic is connected to VINM */
+	{"VINM", NULL, "Mic Jack"},
+
+	/* line is connected to VINL, VINR */
+	{"VINL", NULL, "Line Jack"},
+	{"VINR", NULL, "Line Jack"},
 
 	{NULL, NULL, NULL},
 };
 
-static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset", "Off"};
-static const char *spk_function[] = {"On", "Off"};
+static const char *jack_function[] = { "Off", "Headset", "Headphone" };
+static const char *spk_function[] = { "On", "Off" };
+static const char *input_select[] = { "Internal Mic", "External Mic" };
 static const struct soc_enum blueangel_enum[] = {
-	SOC_ENUM_SINGLE_EXT(5, jack_function),
+	SOC_ENUM_SINGLE_EXT(4, jack_function),
 	SOC_ENUM_SINGLE_EXT(2, spk_function),
+	SOC_ENUM_SINGLE_EXT(2, input_select),
 };
 
 static const struct snd_kcontrol_new uda1380_blueangel_controls[] = {
-	SOC_ENUM_EXT("Jack Function", blueangel_enum[0], blueangel_get_jack, blueangel_set_jack),
-	SOC_ENUM_EXT("Speaker Function", blueangel_enum[1], blueangel_get_spk, blueangel_set_spk),
+	SOC_ENUM_EXT("Jack Function", blueangel_enum[0], blueangel_get_jack,
+			blueangel_set_jack),
+	SOC_ENUM_EXT("Speaker Function", blueangel_enum[1], blueangel_get_spk,
+			blueangel_set_spk),
+	SOC_ENUM_EXT("Input Select", blueangel_enum[2], blueangel_get_input,
+			blueangel_set_input),
 };
 
 /*
- * Logic for a uda1380 as connected on a HTC Blueangel
+ * Logic for a uda1380 as connected on a HTC Magician
  */
 static int blueangel_uda1380_init(struct snd_soc_codec *codec)
 {
 	int i, err;
 
-  printk("blueangel_uda1380_init\n");
+ 	//pxa2xx_ssp_set_clock(&pxa_ssp_dai[0], PXA2XX_SSP_CLK_AUDIO);
 
-	pxa2xx_ssp_set_clock(&pxa_ssp_dai[0], PXA2XX_SSP_CLK_AUDIO);
+	/* NC codec pins */
+	snd_soc_dapm_set_endpoint(codec, "VOUTLHP", 0);
+	snd_soc_dapm_set_endpoint(codec, "VOUTRHP", 0);
 
-	snd_soc_dapm_set_endpoint(codec, "Int Mic", 1);
-	snd_soc_dapm_set_endpoint(codec, "Ext Spk", 1);
 
-	/* NC codec pins */
-  /*
-	snd_soc_dapm_set_endpoint(codec, "RINPUT1", 0);
-	snd_soc_dapm_set_endpoint(codec, "LINPUT2", 0);
-	snd_soc_dapm_set_endpoint(codec, "RINPUT2", 0);
-	snd_soc_dapm_set_endpoint(codec, "LINPUT3", 0);
-	snd_soc_dapm_set_endpoint(codec, "RINPUT3", 0);
-	snd_soc_dapm_set_endpoint(codec, "OUT3", 0);
-	snd_soc_dapm_set_endpoint(codec, "MONO", 0);
-  */
 
 	/* Add blueangel specific controls */
 	for (i = 0; i < ARRAY_SIZE(uda1380_blueangel_controls); i++) {
 		if ((err = snd_ctl_add(codec->card,
-				snd_soc_cnew(&uda1380_blueangel_controls[i], codec, NULL))) < 0)
+				snd_soc_cnew(&uda1380_blueangel_controls[i],
+				codec, NULL))) < 0)
 			return err;
 	}
 
 	/* Add blueangel specific widgets */
-	for(i = 0; i < ARRAY_SIZE(uda1380_dapm_widgets); i++) {
+	for (i = 0; i < ARRAY_SIZE(uda1380_dapm_widgets); i++) {
 		snd_soc_dapm_new_control(codec, &uda1380_dapm_widgets[i]);
 	}
 
 	/* Set up blueangel 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]);
+	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]);
 	}
+
 	snd_soc_dapm_sync_endpoints(codec);
 	return 0;
 }
 
-unsigned int blueangel_config_sysclk(struct snd_soc_pcm_runtime *rtd,
-	struct snd_soc_clock_info *info)
-{
-
-printk("snd-soc-blueangel config-sysclk rate=%d, fs=%d\n", info->rate, info->fs);
-
-	/* config pxa i2s or SSP0 as master */
-	return rtd->cpu_dai->config_sysclk(rtd->cpu_dai, info, 0);
-}
-
 /* blueangel digital audio interface glue - connects codec <--> CPU */
 static struct snd_soc_dai_link blueangel_dai[] = {
 {
 	.name = "uda1380",
 	.stream_name = "UDA1380 Playback",
 	.cpu_dai = &pxa_ssp_dai[0],
-	.codec_dai = &uda1380_dai[1],
+	.codec_dai = &uda1380_dai[UDA1380_DAI_PLAYBACK],
 	.init = blueangel_uda1380_init,
-	.config_sysclk = blueangel_config_sysclk,
+	.ops = &blueangel_playback_ops,
 },
 {
 	.name = "uda1380",
 	.stream_name = "UDA1380 Capture",
 	.cpu_dai = &pxa_i2s_dai,
-	.codec_dai = &uda1380_dai[2],
-	.config_sysclk = blueangel_config_sysclk,
-},
+	.codec_dai = &uda1380_dai[UDA1380_DAI_CAPTURE],
+	.ops = &blueangel_capture_ops,
+}
 };
 
 /* blueangel audio machine driver */
 static struct snd_soc_machine snd_soc_machine_blueangel = {
-	.name = "Blueangel",
+	.name = "Magician",
 	.dai_link = blueangel_dai,
 	.num_links = ARRAY_SIZE(blueangel_dai),
-	.ops = &blueangel_ops,
 };
 
 /* blueangel audio private data */
@@ -335,10 +514,16 @@
 
 	if (!machine_is_blueangel())
 		return -ENODEV;
+	
+	asic3_set_gpio_out_b(&blueangel_asic3.dev, 1<<GPIOB_CODEC_RESET, 1<<GPIOB_CODEC_RESET); /* reset on? */
+	udelay(15);
+	asic3_set_gpio_out_a(&blueangel_asic3.dev, 1<<GPIOA_CODEC_PWR_ON, 1<<GPIOA_CODEC_PWR_ON); /* power? */
+	/* we may need to have the clock running here - pH5 */
+	udelay(5);
+	asic3_set_gpio_out_b(&blueangel_asic3.dev, 1<<GPIOB_CODEC_RESET, 0); /* reset on? */
 
-printk("snd-soc-blueangel init\n");
-
-//	pxa_gpio_mode(BLUEANGEL_GPIO_AK_INT | GPIO_IN); // audio connector interrupt?
+	/* correct place? we'll need it to talk to the uda1380 */
+	request_module("i2c-pxa");
 
 	blueangel_snd_device = platform_device_alloc("soc-audio", -1);
 	if (!blueangel_snd_device)
@@ -351,12 +536,15 @@
 	if (ret)
 		platform_device_put(blueangel_snd_device);
 
+	pxa_gpio_mode(GPIO27_SSP_EXT_CLK);
+
 	return ret;
 }
 
 static void __exit blueangel_exit(void)
 {
 	platform_device_unregister(blueangel_snd_device);
+
 }
 
 module_init(blueangel_init);
Index: pxa2xx-ssp.c
===================================================================
RCS file: /cvs/linux/kernel26/sound/soc/pxa/pxa2xx-ssp.c,v
retrieving revision 1.5
diff -u -r1.5 pxa2xx-ssp.c
--- pxa2xx-ssp.c	13 Feb 2007 20:28:38 -0000	1.5
+++ pxa2xx-ssp.c	12 Apr 2007 20:48:01 -0000
@@ -284,6 +284,7 @@
 	int port = cpu_dai->id + 1;
 
 	switch (div_id) {
+#ifdef CONFIG_PXA27x
 	case PXA2XX_SSP_AUDIO_DIV_ACDS:
 		SSACD_P(port) &= ~ 0x7;
 		SSACD_P(port) |= SSACD_ACDS(div);
@@ -293,6 +294,7 @@
 		if (div == PXA2XX_SSP_CLK_SCDB_1)
 			SSACD_P(port) |= SSACD_SCDB;
 		break;
+#endif
 	case PXA2XX_SSP_DIV_SCR:
 		SSCR0_P(port) &= ~SSCR0_SCR;
 		SSCR0_P(port) |= SSCR0_SerClkDiv(div);
@@ -310,6 +312,7 @@
 static int pxa2xx_ssp_set_dai_pll(struct snd_soc_cpu_dai *cpu_dai,
 	int pll_id, unsigned int freq_in, unsigned int freq_out)
 {
+#ifdef CONFIG_PXA27x
 	int port = cpu_dai->id + 1;
 
 	SSACD_P(port) &= ~0x70;
@@ -332,6 +335,7 @@
 		SSACD_P(port) |= (0x5 << 4);
 		break;
 	}
+#endif
 	return 0;
 }
 
@@ -341,6 +345,7 @@
 static int pxa2xx_ssp_set_dai_tdm_slot(struct snd_soc_cpu_dai *cpu_dai,
 	unsigned int mask, int slots)
 {
+#ifdef CONFIG_PXA27x
 	int port = cpu_dai->id + 1;
 
 	SSCR0_P(port) &= ~SSCR0_SlotsPerFrm(7);
@@ -351,6 +356,7 @@
 	/* set active slot mask */
 	SSTSA_P(port) = mask;
 	SSRSA_P(port) = mask;
+#endif
 	return 0;
 }