--- linux-2.6.11-rc5/sound/arm/s3c24xx-tlv320aic23.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.11-rc5-audio9/sound/arm/s3c24xx-tlv320aic23.c	2005-03-15 12:11:48.000000000 +0000
@@ -0,0 +1,273 @@
+/* sound/arm/s3c24xx-tlv320aic23.c
+ *
+ * (c) 2004-2005 Simtec Electronics
+ *	http://armlinux.simtec.co.uk/
+ *	Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C24XX TLV320AIC23 Audio CODEC interface
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/config.h>
+#include <sound/driver.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/ioctl.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/pm.h>
+#include <linux/dma-mapping.h>
+#include <linux/i2c.h>
+
+#include <asm/hardware.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+
+#include <asm/hardware/clock.h>
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+
+#include <asm/arch/regs-iis.h>
+#include <asm/arch/audio.h>
+
+#include "tlv320aic23.h"
+#include "s3c24xx-iis.h"
+
+/* todo list:
+ *
+ * ensure that we can operate as an clock slave
+ *
+*/
+
+struct s3c24xx_tlv {
+	struct s3c24xx_iis_ops		 ops;
+	s3c24xx_card_t			*card;
+	struct clk			*clk;
+	struct device			*dev;
+	struct tlv320aic23		*tlv;	
+	struct tlv320aic23_cfg		 cfg;
+};
+
+
+static struct tlv320aic23 *ops_to_tlv(struct s3c24xx_iis_ops *ops)
+{
+	struct s3c24xx_tlv *tlv;
+
+	tlv = container_of(ops, struct s3c24xx_tlv, ops);
+	return tlv->tlv;
+}
+
+static int s3c24xx_tlv320aic32_open(struct s3c24xx_iis_ops *ops,
+				    snd_pcm_substream_t *stream)
+{
+	return tlv320aic23_open(ops_to_tlv(ops), stream);
+}
+
+static int s3c24xx_tlv320aic23_close(struct s3c24xx_iis_ops *ops,
+				     snd_pcm_substream_t *stream)
+{
+	return tlv320aic23_close(ops_to_tlv(ops), stream);
+}
+
+static int s3c24xx_tlv320aic23_prepare(struct s3c24xx_iis_ops *ops,
+				       snd_pcm_substream_t *stream,
+				       snd_pcm_runtime_t *run)
+{
+	return tlv320aic23_prepare(ops_to_tlv(ops), stream, run);
+}
+
+static int s3c24xx_tlv320aic32_startup(struct s3c24xx_iis_ops *ops)
+{
+	return tlv320aic23_startup(ops_to_tlv(ops));
+}
+
+/* sound card operations */
+
+struct s3c24xx_iis_ops s3c24xx_tlv320aic23_ops = {
+	.owner		= THIS_MODULE,
+	.startup	= s3c24xx_tlv320aic32_startup,
+	.open		= s3c24xx_tlv320aic32_open,
+	.close		= s3c24xx_tlv320aic23_close,
+	.prepare	= s3c24xx_tlv320aic23_prepare,
+};
+
+static void s3c24xx_tlv320aic23_free(struct s3c24xx_tlv *tlv)
+{
+	kfree(tlv);
+}
+
+static struct device *audio_dev;
+
+static int s3c24xx_tlv320aic23_remove(struct device *dev)
+{
+	/* shouldn't happen */
+	return 0;
+}
+
+static int s3c24xx_tlv320aic23_probe(struct device *dev)
+{
+	struct s3c24xx_platdata_iis *pdata = dev->platform_data;
+
+	if (pdata == NULL) {
+		dev_err(dev, "no platform data\n");
+		return -EINVAL;
+	}
+
+	audio_dev = dev;
+	return 0;
+}
+
+static struct device_driver s3c24xx_tlv320aic23_driver = {
+	.name		= "s3c24xx-tlv320aic23",
+	.bus		= &platform_bus_type,
+	.probe		= s3c24xx_tlv320aic23_probe,
+	.remove		= s3c24xx_tlv320aic23_remove,
+};
+
+static int s3c24xx_tlv320aic23_codec_probe(struct device *dev)
+{
+	struct s3c24xx_platdata_iis *pdata; 
+	struct s3c24xx_tlv *tlv;
+	s3c24xx_card_t *card;
+	int err;
+
+	dev_dbg(dev, "codec probe\n");
+
+	if (dev->platform_data == NULL) {
+		dev_err(dev, "no platform data\n");
+		return -EINVAL;
+	}
+
+	if (audio_dev == NULL)
+		return -EINVAL;
+
+	pdata = audio_dev->platform_data;
+	if (pdata == NULL)
+		return -EINVAL;
+
+	if (pdata->match_dev != NULL && !pdata->match_dev(dev)) {
+		dev_dbg(dev, "not attaching\n");
+		return 0;
+	}
+
+	dev_info(dev, "attached tlv320aic23 driver\n");
+
+	/* allocate a sound device */
+
+	tlv = kmalloc(sizeof(struct s3c24xx_tlv), GFP_KERNEL);
+	if (tlv == NULL) {
+		err = -ENOMEM;
+		goto exit_err;
+	}
+
+	memset(tlv, 0, sizeof(struct s3c24xx_tlv));
+
+	tlv->clk = clk_get(dev, pdata->codec_clk);
+	if (IS_ERR(tlv->clk)) {
+		err = -EINVAL;
+		goto exit_err;
+	}
+
+	tlv->dev = dev;
+	tlv->cfg.clkrate = clk_get_rate(tlv->clk);
+	tlv->cfg.master  = 1;
+
+	dev_info(dev, "clock %s, rate %ldHz\n", 
+		 pdata->codec_clk, tlv->cfg.clkrate);
+
+	card = s3c24xx_iis_probe(audio_dev);
+	if (IS_ERR(card)) {
+		err = PTR_ERR(card);
+		goto exit_err;
+	}
+
+	tlv->ops	= s3c24xx_tlv320aic23_ops;
+	card->chip_ops  = &tlv->ops;
+	card->client	= tlv;
+
+	strcpy(card->card->driver,    "tlv320aic23");
+	strcpy(card->card->shortname, "tlv");
+	strcpy(card->card->longname,  "S3C24XX TLV320AIC23");
+
+	snd_card_set_dev(card->card, audio_dev);
+
+	tlv->tlv = tlv320aic23_attach(card->card, dev, &tlv->cfg);
+	if (IS_ERR(tlv->tlv)) {
+		err = PTR_ERR(tlv->tlv);
+		goto exit_err;
+	}
+
+	/* default configuration for IIS */
+
+	s3c24xx_iismod_cfg(card, S3C2410_IISMOD_16BIT, 0x0);
+	s3c24xx_iismod_cfg(card, S3C2410_IISMOD_32FS,  0x0);
+	s3c24xx_iismod_cfg(card, 0x0, S3C2410_IISMOD_384FS);
+
+	err = s3c24xx_iis_cfgclksrc(card, pdata->codec_clk);
+	if (err)
+		goto exit_err;
+
+	err = snd_card_register(card->card);
+	if (err)
+		goto exit_err;
+
+	return 0;
+
+ exit_err:
+	s3c24xx_tlv320aic23_free(tlv);
+	s3c24xx_tlv320aic23_remove(dev);
+
+	return err;
+}
+
+static int s3c24xx_tlv320aic23_codec_remove(struct device *dev)
+{
+	s3c24xx_card_t *card;
+	struct s3c24xx_tlv *client;
+
+	card = dev_get_drvdata(dev);
+	if (card != NULL) {
+		client = card->client;
+
+		s3c24xx_iis_remove(dev);
+		s3c24xx_tlv320aic23_free(client);
+	}
+
+	return 0;
+}
+
+
+struct device_driver s3c24xx_tlv320aic23_codecdrv = {
+	.name		= "tlv320aic23",
+	.bus		= &platform_bus_type,
+	.probe		= s3c24xx_tlv320aic23_codec_probe,
+	.remove		= s3c24xx_tlv320aic23_codec_remove,
+};
+
+static int  __init s3c24xx_tlv320aic23_init(void)
+{
+	driver_register(&s3c24xx_tlv320aic23_driver);
+	return driver_register(&s3c24xx_tlv320aic23_codecdrv);
+}
+
+static void __exit s3c24xx_tlv320aic23_exit(void)
+{
+	driver_unregister(&s3c24xx_tlv320aic23_codecdrv);
+	driver_unregister(&s3c24xx_tlv320aic23_driver);
+}
+
+module_init(s3c24xx_tlv320aic23_init);
+module_exit(s3c24xx_tlv320aic23_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("S3C24XX / TLV320AIC23 Audio driver");
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");

