commit a5576ea521f5e7c79bd2983d331971905607cd17
Author: sk <sk@sx.net.eu.org>
Date:   Tue Nov 17 10:52:15 2009 +0300

    sound driver, ASOC based

---
 arch/arm/mach-s3c2410/include/mach/h1940-latch.h |    4 	3 +	1 -	0 !
 sound/soc/codecs/uda1380.c                       |    2 	2 +	0 -	0 !
 sound/soc/s3c24xx/Kconfig                        |   10 	10 +	0 -	0 !
 sound/soc/s3c24xx/Makefile                       |    2 	2 +	0 -	0 !
 sound/soc/s3c24xx/h1940_uda1380.c                |  126 	126 +	0 -	0 !
 5 files changed, 143 insertions(+), 1 deletion(-)

Index: linux-2.6/sound/soc/s3c24xx/Kconfig
===================================================================
--- linux-2.6.orig/sound/soc/s3c24xx/Kconfig	2010-07-03 22:47:14.000000000 +0200
+++ linux-2.6/sound/soc/s3c24xx/Kconfig	2010-07-03 22:50:40.869886235 +0200
@@ -125,3 +125,13 @@ config SND_SOC_SMDK_WM9713
 	select SND_S3C_SOC_AC97
 	help
 	  Sat Y if you want to add support for SoC audio on the SMDK.
+
+config SND_S3C24XX_SOC_H1940_UDA1380
+	tristate "SoC I2S Audio for IPAQ h1940"
+	depends on SND_S3C24XX_SOC && ARCH_H1940
+	select SND_S3C24XX_SOC_I2S
+	select SND_SOC_UDA1380
+ 	help
+	  Sound support for IPAQ h1940 PDA.
+
+
Index: linux-2.6/sound/soc/s3c24xx/Makefile
===================================================================
--- linux-2.6.orig/sound/soc/s3c24xx/Makefile	2010-07-03 22:47:14.000000000 +0200
+++ linux-2.6/sound/soc/s3c24xx/Makefile	2010-07-03 22:50:40.881906437 +0200
@@ -29,6 +29,7 @@ snd-soc-s3c24xx-simtec-hermes-objs := s3
 snd-soc-s3c24xx-simtec-tlv320aic23-objs := s3c24xx_simtec_tlv320aic23.o
 snd-soc-smdk64xx-wm8580-objs := smdk64xx_wm8580.o
 snd-soc-smdk-wm9713-objs := smdk_wm9713.o
+snd-soc-h1940-uda1380-objs := h1940_uda1380.o
 
 obj-$(CONFIG_SND_S3C24XX_SOC_JIVE_WM8750) += snd-soc-jive-wm8750.o
 obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o
@@ -41,3 +42,4 @@ obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_HERM
 obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_TLV320AIC23) += snd-soc-s3c24xx-simtec-tlv320aic23.o
 obj-$(CONFIG_SND_S3C64XX_SOC_WM8580) += snd-soc-smdk64xx-wm8580.o
 obj-$(CONFIG_SND_SOC_SMDK_WM9713) += snd-soc-smdk-wm9713.o
+obj-$(CONFIG_SND_S3C24XX_SOC_H1940_UDA1380) += snd-soc-h1940-uda1380.o
Index: linux-2.6/sound/soc/s3c24xx/h1940_uda1380.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6/sound/soc/s3c24xx/h1940_uda1380.c	2010-07-03 22:50:40.917906343 +0200
@@ -0,0 +1,203 @@
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/jack.h>
+
+#include <asm/mach-types.h>
+#include <plat/regs-iis.h>
+#include <mach/h1940-latch.h>
+#include <mach/regs-gpio.h>
+
+#include "s3c-pcm.h"
+#include "s3c24xx-i2s.h"
+#include "s3c-dma.h"
+#include "../codecs/uda1380.h"
+
+
+static struct snd_soc_jack jack;
+static struct snd_soc_card h1940_soc_card;
+
+static struct snd_soc_jack_pin jack_pins[] = {
+	{
+		.pin    = "Headphone Jack",
+		.mask   = SND_JACK_HEADPHONE,
+	},
+	{
+		.pin    = "Speaker",
+		.mask   = SND_JACK_HEADPHONE,
+		.invert	= true,
+	},
+};
+
+static struct snd_soc_jack_gpio jack_gpios[] = {
+	[0] = {
+		.name           = "hp-gpio",
+		.report         = SND_JACK_HEADPHONE,
+		/* low : inserted */
+		.gpio		= S3C2410_GPG(4),
+		.invert		= true,
+	},
+};
+
+
+static int h1940_uda_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+	int res;
+	unsigned long clkrate = s3c24xx_i2s_get_clockrate(), prescale;
+
+	prescale = clkrate / (256*params_rate(params));
+	if(prescale < 32) prescale++;
+
+	printk(KERN_DEBUG "fs: %i, iis_clkrate: %lu, prescale: %lu\n",
+		params_rate(params), clkrate, prescale);
+
+	res = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+	if(res < 0) return res;
+
+	res = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+	if(res < 0) return res;
+
+	res = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK,
+		S3C2410_IISMOD_256FS);
+	if(res < 0) return res;
+
+	res = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_BCLK,
+		S3C2410_IISMOD_32FS);
+	if(res < 0) return res;
+
+	res = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
+		S3C24XX_PRESCALE(prescale, prescale));
+	if(res < 0) return res;
+
+	return 0;
+}
+
+static struct snd_soc_ops h1940_uda_ops = {
+	.hw_params = h1940_uda_hw_params,
+};
+
+static int amp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k,
+		     int event)
+{
+	if (SND_SOC_DAPM_EVENT_ON(event))
+		h1940_latch_control(0, H1940_LATCH_AUDIO_POWER);
+	else
+		h1940_latch_control(H1940_LATCH_AUDIO_POWER, 0);
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget h1940_dapm_widgets[] = {
+	SND_SOC_DAPM_HP("Headphone Jack", NULL),
+	SND_SOC_DAPM_SPK("Speaker", amp_event),
+	SND_SOC_DAPM_MIC("Microphone", NULL),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+	/* headphone connected to VOUTLHP, VOUTRHP */
+	{"Headphone Jack", NULL, "VOUTLHP"},
+	{"Headphone Jack", NULL, "VOUTRHP"},
+
+	/* ext speaker connected to VOUTL, VOUTR  */
+	{"Speaker", NULL, "VOUTL"},
+	{"Speaker", NULL, "VOUTR"},
+
+	/* mic is connected to VINM */
+	{"VINM", NULL, "Microphone"},
+};
+
+int h1940_uda_dai_init(struct snd_soc_codec *codec)
+{
+	int err;
+
+	snd_soc_dapm_enable_pin(codec, "HeadPhone Driver");
+
+	snd_soc_dapm_new_controls(codec, h1940_dapm_widgets,
+				  ARRAY_SIZE(h1940_dapm_widgets));
+
+	err = snd_soc_dapm_add_routes(codec, audio_map,
+				      ARRAY_SIZE(audio_map));
+
+	err = snd_soc_dapm_sync(codec);
+	if (err)
+		return err;
+
+	/* Jack detection API stuff */
+	err = snd_soc_jack_new(&h1940_soc_card, "Headphone Jack",
+				SND_JACK_HEADPHONE, &jack);
+	if (err)
+		return err;
+
+	err = snd_soc_jack_add_pins(&jack, ARRAY_SIZE(jack_pins),
+				jack_pins);
+	if (err)
+		return err;
+
+	err = snd_soc_jack_add_gpios(&jack, ARRAY_SIZE(jack_gpios),
+				jack_gpios);
+
+	return err;
+}
+
+static struct snd_soc_dai_link h1940_dai[] = {
+{
+	.name = "uda1380",
+	.stream_name = "uda1380 hi-fi",
+	.cpu_dai = &s3c24xx_i2s_dai,
+	.codec_dai = &uda1380_dai[UDA1380_DAI_DUPLEX],
+	.init = h1940_uda_dai_init,
+	.ops = &h1940_uda_ops,
+},
+};
+
+static struct snd_soc_card h1940_soc_card = {
+	.name = "h1940_uda1380",
+	.platform = &s3c24xx_soc_platform,
+	.dai_link = h1940_dai,
+	.num_links = 1,
+};
+
+static struct snd_soc_device h1940_snd_devdata = {
+	.card = &h1940_soc_card,
+	.codec_dev = &soc_codec_dev_uda1380,
+};
+
+static struct platform_device *h1940_snd_device;
+
+static int __init h1940_uda_init(void)
+{
+	int res;
+
+	if(!machine_is_h1940())
+		return -ENODEV;
+
+	h1940_snd_device = platform_device_alloc("soc-audio", -1);
+	if(!h1940_snd_device)
+		return -ENOMEM;
+	platform_set_drvdata(h1940_snd_device, &h1940_snd_devdata);
+	h1940_snd_devdata.dev = &h1940_snd_device->dev;
+	res = platform_device_add(h1940_snd_device);
+	if(res) {
+		platform_device_put(h1940_snd_device);
+		return res;
+	}
+	return 0;
+}
+
+static void __exit h1940_uda_exit(void)
+{
+	platform_device_unregister(h1940_snd_device);
+}
+
+module_init(h1940_uda_init);
+module_exit(h1940_uda_exit);
+MODULE_LICENSE("GPL");
Index: linux-2.6/arch/arm/mach-s3c2410/mach-h1940.c
===================================================================
--- linux-2.6.orig/arch/arm/mach-s3c2410/mach-h1940.c	2010-07-03 22:47:14.000000000 +0200
+++ linux-2.6/arch/arm/mach-s3c2410/mach-h1940.c	2010-07-03 22:50:40.925906736 +0200
@@ -25,7 +25,10 @@
 #include <linux/input.h>
 #include <linux/gpio_keys.h>
 #include <linux/pwm_backlight.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
 #include <video/platform_lcd.h>
+#include <sound/uda1380.h>
 
 #include <linux/mmc/host.h>
 #include <linux/mtd/mtd.h>
@@ -377,6 +380,27 @@ static struct platform_device h1940_dev_
 	}
 };
 
+static void uda1380_set_power(int enable)
+{
+	if (enable)
+		h1940_latch_control(0, H1940_LATCH_UDA_POWER);
+	else
+		h1940_latch_control(H1940_LATCH_UDA_POWER, 0);
+	mdelay(5);
+}
+
+static struct uda1380_platform_data uda1380_info = {
+	.set_power	= uda1380_set_power,
+	.dac_clk	= UDA1380_DAC_CLK_WSPLL,
+};
+
+static struct i2c_board_info h1940_i2c_devices[] = {
+	{
+		I2C_BOARD_INFO("uda1380", 0x1a),
+		.platform_data = &uda1380_info,
+	},
+};
+
 static struct platform_device *h1940_devices[] __initdata = {
 	&h1940_dev_buttons,
 	&s3c_device_ohci,
@@ -422,6 +446,7 @@ static void __init h1940_init(void)
 {
 	u32 tmp;
 
+	h1940_latch_control(0, 0);
 	s3c24xx_fb_set_platdata(&h1940_fb_info);
 	s3c24xx_mci_set_platdata(&h1940_mmc_cfg);
  	s3c24xx_udc_set_platdata(&h1940_udc_cfg);
@@ -453,6 +478,10 @@ static void __init h1940_init(void)
 	/*s3c2410_gpio_setpin(S3C2410_GPA0, 1);*/
 
 	platform_add_devices(h1940_devices, ARRAY_SIZE(h1940_devices));
+
+	i2c_register_board_info(0, h1940_i2c_devices,
+		ARRAY_SIZE(h1940_i2c_devices));
+
 }
 
 MACHINE_START(H1940, "IPAQ-H1940")
