[1/9] SOUND: Add I2S driver

Message ID 1344923132-31803-2-git-send-email-rajeshwari.s@samsung.com
State New
Headers show

Commit Message

Rajeshwari Shinde Aug. 14, 2012, 5:45 a.m.
This patch adds driver for I2S interface

Signed-off-by: R. Chandrasekar <rcsekar@samsung.com>
Signed-off-by: Rajeshwari Shinde <rajeshwari.s@samsung.com>
---
 Makefile               |    1 +
 drivers/sound/Makefile |   47 +++++++
 drivers/sound/i2s.c    |  358 ++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/sound/sound.c  |  220 +++++++++++++++++++++++++++++
 include/i2s.h          |  127 +++++++++++++++++
 include/sound.h        |   62 +++++++++
 6 files changed, 815 insertions(+), 0 deletions(-)
 create mode 100644 drivers/sound/Makefile
 create mode 100644 drivers/sound/i2s.c
 create mode 100644 drivers/sound/sound.c
 create mode 100644 include/i2s.h
 create mode 100644 include/sound.h

Comments

Andrew Dyer Aug. 16, 2012, 2:59 p.m. | #1
I don't have any comment on the body of the patch, but calling this an i2s
patch is misleading.  I2s is a generic standard for moving stereo audio
around, and many chips support it.

This patch looks like i2s support for a specific codec chip and the
filenames should reflect that.
Rajeshwari Birje Aug. 17, 2012, 6:44 a.m. | #2
Hi Andrew,

Thank you for comments.

On Thu, Aug 16, 2012 at 8:29 PM, Andrew Dyer <amdyer@gmail.com> wrote:
> I don't have any comment on the body of the patch, but calling this an i2s
> patch is misleading.  I2s is a generic standard for moving stereo audio
> around, and many chips support it.
>
> This patch looks like i2s support for a specific codec chip and the
> filenames should reflect that.
>
In this patch we can support different codecs without doing any
changes to i2s files.
The only change would be in sound.c, where you have to check for
specific codec required and set values accordingly.
We use I2S1 here, but it is not specific to any particular codec.
> _______________________________________________
> U-Boot mailing list
> U-Boot@lists.denx.de
> http://lists.denx.de/mailman/listinfo/u-boot
>
Regards,
Rajeshwari Shinde.
Andrew Dyer Aug. 17, 2012, 12:48 p.m. | #3
The code in the i2s.c file is still full of samsung soc specific stuff, so
I think the filename is misleading.  Something like samsung-i2s.c would be
more appropriate.
On Aug 17, 2012 1:44 AM, "Rajeshwari Birje" <rajeshwari.birje@gmail.com>
wrote:

> Hi Andrew,
>
> Thank you for comments.
>
> On Thu, Aug 16, 2012 at 8:29 PM, Andrew Dyer <amdyer@gmail.com> wrote:
> > I don't have any comment on the body of the patch, but calling this an
> i2s
> > patch is misleading.  I2s is a generic standard for moving stereo audio
> > around, and many chips support it.
> >
> > This patch looks like i2s support for a specific codec chip and the
> > filenames should reflect that.
> >
> In this patch we can support different codecs without doing any
> changes to i2s files.
> The only change would be in sound.c, where you have to check for
> specific codec required and set values accordingly.
> We use I2S1 here, but it is not specific to any particular codec.
> > _______________________________________________
> > U-Boot mailing list
> > U-Boot@lists.denx.de
> > http://lists.denx.de/mailman/listinfo/u-boot
> >
> Regards,
> Rajeshwari Shinde.
>
Mike Frysinger Aug. 17, 2012, 6:53 p.m. | #4
On Friday 17 August 2012 08:48:59 Andrew Dyer wrote:
> The code in the i2s.c file is still full of samsung soc specific stuff, so
> I think the filename is misleading.  Something like samsung-i2s.c would be
> more appropriate.

+1
-mike
Rajeshwari Birje Aug. 22, 2012, 4:17 a.m. | #5
Hi,
On Sat, Aug 18, 2012 at 12:23 AM, Mike Frysinger <vapier@gentoo.org> wrote:
> On Friday 17 August 2012 08:48:59 Andrew Dyer wrote:
>> The code in the i2s.c file is still full of samsung soc specific stuff, so
>> I think the filename is misleading.  Something like samsung-i2s.c would be
>> more appropriate.
>
> +1
Ok will do so and resend the patches.
> -mike

Regards,
Rajeshwari Shinde.

Patch

diff --git a/Makefile b/Makefile
index 6e8b5a7..b914980 100644
--- a/Makefile
+++ b/Makefile
@@ -288,6 +288,7 @@  LIBS += arch/powerpc/cpu/mpc8xxx/lib8xxx.o
 endif
 LIBS += drivers/rtc/librtc.o
 LIBS += drivers/serial/libserial.o
+LIBS += drivers/sound/libsound.o
 ifeq ($(CONFIG_GENERIC_LPC_TPM),y)
 LIBS += drivers/tpm/libtpm.o
 endif
diff --git a/drivers/sound/Makefile b/drivers/sound/Makefile
new file mode 100644
index 0000000..60d6af7
--- /dev/null
+++ b/drivers/sound/Makefile
@@ -0,0 +1,47 @@ 
+#
+# Copyright (C) 2012 Samsung Electronics
+# R. Chandrasekar <rcsekar@samsung.com>
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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 option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	:= $(obj)libsound.o
+
+COBJS-$(CONFIG_SOUND) += sound.o
+COBJS-$(CONFIG_I2S) += i2s.o
+
+COBJS	:= $(COBJS-y)
+SRCS	:= $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(COBJS))
+
+all:	$(LIB)
+
+$(LIB):	$(obj).depend $(OBJS)
+	$(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#
diff --git a/drivers/sound/i2s.c b/drivers/sound/i2s.c
new file mode 100644
index 0000000..9485980
--- /dev/null
+++ b/drivers/sound/i2s.c
@@ -0,0 +1,358 @@ 
+/*
+ * Copyright (C) 2012 Samsung Electronics
+ * R. Chandrasekar <rcsekar@samsung.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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 option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <asm/arch/clk.h>
+#include <asm/arch/pinmux.h>
+#include <asm/arch/i2s-regs.h>
+#include <asm/io.h>
+#include <common.h>
+#include <sound.h>
+#include <i2s.h>
+
+#define FIC_TX2COUNT(x)		(((x) >>  24) & 0xf)
+#define FIC_TX1COUNT(x)		(((x) >>  16) & 0xf)
+#define FIC_TXCOUNT(x)		(((x) >>  8) & 0xf)
+#define FIC_RXCOUNT(x)		(((x) >>  0) & 0xf)
+#define FICS_TXCOUNT(x)		(((x) >>  8) & 0x7f)
+
+#define TIMEOUT_I2S_TX		100	/* i2s transfer timeout */
+
+/*
+ * Sets the frame size for I2S LR clock
+ *
+ * @param i2s_reg	i2s regiter address
+ * @param rfs		Frame Size
+ */
+static void i2s_set_lr_framesize(struct i2s_reg *i2s_reg, unsigned int rfs)
+{
+	unsigned int mod = readl(&i2s_reg->mod);
+
+	mod &= ~MOD_RCLK_MASK;
+
+	switch (rfs) {
+	case 768:
+		mod |= MOD_RCLK_768FS;
+		break;
+	case 512:
+		mod |= MOD_RCLK_512FS;
+		break;
+	case 384:
+		mod |= MOD_RCLK_384FS;
+		break;
+	default:
+		mod |= MOD_RCLK_256FS;
+		break;
+	}
+
+	writel(mod, &i2s_reg->mod);
+}
+
+/*
+ * Sets the i2s transfer control
+ *
+ * @param i2s_reg	i2s regiter address
+ * @param on		1 enable tx , 0 disable tx transfer
+ */
+static void i2s_txctrl(struct i2s_reg *i2s_reg, int on)
+{
+	unsigned int con = readl(&i2s_reg->con);
+	unsigned int mod = readl(&i2s_reg->mod) & ~MOD_MASK;
+
+	if (on) {
+		con |= CON_ACTIVE;
+		con &= ~CON_TXCH_PAUSE;
+
+	} else {
+
+		con |=  CON_TXCH_PAUSE;
+		con &= ~CON_ACTIVE;
+	}
+
+	writel(mod, &i2s_reg->mod);
+	writel(con, &i2s_reg->con);
+}
+
+/*
+ * set the bit clock frame size (in multiples of LRCLK)
+ *
+ * @param i2s_reg	i2s regiter address
+ * @param bfs		bit Frame Size
+ */
+static void i2s_set_bitclk_framesize(struct i2s_reg *i2s_reg, unsigned bfs)
+{
+	unsigned int mod = readl(&i2s_reg->mod);
+
+	mod &= ~MOD_BCLK_MASK;
+
+	switch (bfs) {
+	case 48:
+		mod |= MOD_BCLK_48FS;
+		break;
+	case 32:
+		mod |= MOD_BCLK_32FS;
+		break;
+	case 24:
+		mod |= MOD_BCLK_24FS;
+		break;
+	case 16:
+		mod |= MOD_BCLK_16FS;
+		break;
+	default:
+		return;
+	}
+	writel(mod, &i2s_reg->mod);
+}
+
+/*
+ * flushes the i2stx fifo
+ *
+ * @param i2s_reg	i2s regiter address
+ * @param flush		Tx fifo flush command (0x00 - do not flush
+ *				0x80 - flush tx fifo)
+ */
+void i2s_fifo(struct i2s_reg *i2s_reg, unsigned int flush)
+{
+	/* Flush the FIFO */
+	setbits_le32(&i2s_reg->fic, flush);
+	clrbits_le32(&i2s_reg->fic, flush);
+}
+
+/*
+ * Set System Clock direction
+ *
+ * @param i2s_reg	i2s regiter address
+ * @param dir		Clock direction
+ *
+ * @return		int value 0 for success, -1 in case of error
+ */
+int i2s_set_sysclk_dir(struct i2s_reg *i2s_reg, int dir)
+{
+	unsigned int mod = readl(&i2s_reg->mod);
+
+	if (dir == SND_SOC_CLOCK_IN)
+		mod |= MOD_CDCLKCON;
+	else
+		mod &= ~MOD_CDCLKCON;
+
+	writel(mod, &i2s_reg->mod);
+
+	return 0;
+}
+
+/*
+ * Sets I2S Clcok format
+ *
+ * @param fmt		i2s clock properties
+ * @param i2s_reg	i2s regiter address
+ *
+ * @return		int value 0 for success, -1 in case of error
+ */
+int i2s_set_fmt(struct i2s_reg *i2s_reg, unsigned int fmt)
+{
+	unsigned int mod = readl(&i2s_reg->mod);
+	unsigned int tmp = 0;
+	unsigned int ret = 0;
+
+	/* Format is priority */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_RIGHT_J:
+		tmp |= MOD_LR_RLOW;
+		tmp |= MOD_SDF_MSB;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		tmp |= MOD_LR_RLOW;
+		tmp |= MOD_SDF_LSB;
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		tmp |= MOD_SDF_IIS;
+		break;
+	default:
+		debug("%s: Invalid format priority [0x%x]\n", __func__,
+			(fmt & SND_SOC_DAIFMT_FORMAT_MASK));
+		return -1;
+	}
+
+	/*
+	 * INV flag is relative to the FORMAT flag - if set it simply
+	 * flips the polarity specified by the Standard
+	 */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		if (tmp & MOD_LR_RLOW)
+			tmp &= ~MOD_LR_RLOW;
+		else
+			tmp |= MOD_LR_RLOW;
+		break;
+	default:
+		debug("%s: Invalid clock ploarity input [0x%x]\n", __func__,
+			(fmt & SND_SOC_DAIFMT_INV_MASK));
+		return -1;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		tmp |= MOD_SLAVE;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		/* Set default source clock in Master mode */
+		ret = i2s_set_sysclk_dir(i2s_reg, SND_SOC_CLOCK_OUT);
+		if (ret != 0) {
+			debug("%s:set i2s clock direction failed\n", __func__);
+			return -1;
+		}
+		break;
+	default:
+		debug("%s: Invalid master selection [0x%x]\n", __func__,
+			(fmt & SND_SOC_DAIFMT_MASTER_MASK));
+		return -1;
+	}
+
+	mod &= ~(MOD_SDF_MASK | MOD_LR_RLOW | MOD_SLAVE);
+	mod |= tmp;
+	writel(mod, &i2s_reg->mod);
+
+	return 0;
+}
+
+/*
+ * Sets the sample width in bits
+ *
+ * @param blc		samplewidth (size of sample in bits)
+ * @param i2s_reg	i2s regiter address
+ *
+ * @return		int value 0 for success, -1 in case of error
+ */
+int i2s_set_samplesize(struct i2s_reg *i2s_reg, unsigned int blc)
+{
+	unsigned int mod = readl(&i2s_reg->mod);
+
+	mod &= ~MOD_BLCP_MASK;
+	mod &= ~MOD_BLC_MASK;
+
+	switch (blc) {
+	case 8:
+		mod |= MOD_BLCP_8BIT;
+		mod |= MOD_BLC_8BIT;
+		break;
+	case 16:
+		mod |= MOD_BLCP_16BIT;
+		mod |= MOD_BLC_16BIT;
+		break;
+
+	case 24:
+		mod |= MOD_BLCP_24BIT;
+		mod |= MOD_BLC_24BIT;
+		break;
+	default:
+		debug("%s: Invalid sample size input [0x%x]\n",
+			__func__, blc);
+		return -1;
+	}
+	writel(mod, &i2s_reg->mod);
+
+	return 0;
+}
+
+int i2s_transfer_tx_data(struct i2stx_info *pi2s_tx, unsigned int *data,
+				unsigned long data_size)
+{
+	int i;
+	int start;
+	struct i2s_reg *i2s_reg =
+				(struct i2s_reg *)pi2s_tx->base_address;
+
+	if (data_size < FIFO_LENGTH) {
+		debug("%s : Invalid data size\n", __func__);
+		return -1; /* invalid pcm data size */
+	}
+
+	/* fill the tx buffer before stating the tx transmit */
+	for (i = 0; i < FIFO_LENGTH; i++)
+		writel(*data++, &i2s_reg->txd);
+
+	data_size -= FIFO_LENGTH;
+	i2s_txctrl(i2s_reg, I2S_TX_ON);
+
+	while (data_size > 0) {
+		start = get_timer(0);
+		if (!(CON_TXFIFO_FULL & (readl(&i2s_reg->con)))) {
+			writel(*data++, &i2s_reg->txd);
+			data_size--;
+		} else {
+			if (get_timer(start) > TIMEOUT_I2S_TX) {
+				i2s_txctrl(i2s_reg, I2S_TX_OFF);
+				debug("%s: I2S Transfer Timeout\n", __func__);
+				return -1;
+			}
+		}
+	}
+	i2s_txctrl(i2s_reg, I2S_TX_OFF);
+
+	return 0;
+}
+
+int i2s_tx_init(struct i2stx_info *pi2s_tx)
+{
+	int ret;
+	struct i2s_reg *i2s_reg =
+				(struct i2s_reg *)pi2s_tx->base_address;
+
+	/* Initialize GPIO for I2s */
+	exynos_pinmux_config(PERIPH_ID_I2S1, 0);
+
+	/* Set EPLL Clock */
+	ret = clock_epll_set_rate(pi2s_tx->audio_pll_clk);
+	if (ret != 0) {
+		debug("%s: epll clock set rate falied\n", __func__);
+		return -1;
+	}
+
+	/* Select Clk Source for Audio1 */
+	clock_select_i2s_clk_source();
+
+	/* Set Prescaler to get MCLK */
+	clock_set_i2s_clk_prescaler(pi2s_tx->audio_pll_clk,
+				(pi2s_tx->samplingrate * (pi2s_tx->rfs)));
+
+	/* Configure I2s format */
+	ret = i2s_set_fmt(i2s_reg, (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+				SND_SOC_DAIFMT_CBM_CFM));
+	if (ret == 0) {
+		i2s_set_lr_framesize(i2s_reg, pi2s_tx->rfs);
+		ret = i2s_set_samplesize(i2s_reg, pi2s_tx->bitspersample);
+		if (ret != 0) {
+			debug("%s:set sample rate failed\n", __func__);
+			return -1;
+		}
+
+		i2s_set_bitclk_framesize(i2s_reg, pi2s_tx->bfs);
+		/* disable i2s transfer flag and flush the fifo */
+		i2s_txctrl(i2s_reg, I2S_TX_OFF);
+		i2s_fifo(i2s_reg, FIC_TXFLUSH);
+	} else
+		debug("%s: failed\n", __func__);
+
+	return ret;
+}
diff --git a/drivers/sound/sound.c b/drivers/sound/sound.c
new file mode 100644
index 0000000..84a7281
--- /dev/null
+++ b/drivers/sound/sound.c
@@ -0,0 +1,220 @@ 
+/*
+ * Copyright (C) 2012 Samsung Electronics
+ * R. Chandrasekar <rcsekar@samsung.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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 option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <malloc.h>
+#include <common.h>
+#include <asm/io.h>
+#include <i2c.h>
+#include <i2s.h>
+#include <sound.h>
+#include "wm8994.h"
+#include <asm/arch/sound.h>
+
+/* defines */
+#define SOUND_400_HZ 400
+#define SOUND_BITS_IN_BYTE 8
+
+/* pcm values for 400hz 48k sampling rate from 1 cycle */
+unsigned short sine_table_400[120] = {
+	0, 1714, 3425, 5125, 6812, 8480, 10125, 11742, 13327, 14875, 16383,
+	17846, 19259, 20620, 21925, 23169, 24350, 25464, 26509, 27480, 28377,
+	29195, 29934, 30590, 31163, 31650, 32050, 32363, 32587, 32722, 32767,
+	32722, 32587, 32363, 32050, 31650, 31163, 30590, 29934, 29195, 28377,
+	27480, 26509, 25464, 24350, 23169, 21925, 20620, 19259, 17846, 16383,
+	14875, 13327, 11742, 10125, 8480, 6812, 5125, 3425, 1714, 0, -1714,
+	-3425, -5125, -6812, -8480, -10125, -11742, -13327, -14875, -16383,
+	-17846, -19259, -20620, -21925, -23169, -24350, -25464, -26509,
+	-27480, -28377, -29195, -29934, -30590, -31163, -31650, -32050,
+	-32363, -32587, -32722, -32767, -32722, -32587, -32363, -32050,
+	-31650, -31163, -30590, -29934, -29195, -28377, -27480, -26509,
+	-25464, -24350, -23169, -21925, -20620, -19259, -17846, -16383,
+	-14875, -13327, -11742, -10125, -8480, -6812, -5125, -3425, -1714
+};
+
+/* Globals */
+struct i2stx_info g_i2stx_pri;
+struct sound_codec_info g_codec_info;
+
+/*
+ * get_sound_fdt_values gets fdt values for i2s parameters
+ *
+ * @param i2stx_info	i2s transmitter transfer param structure
+ * @param blob		FDT blob
+ */
+static void get_sound_i2s_values(struct i2stx_info *i2s)
+{
+	i2s->base_address = samsung_get_base_i2s();
+	i2s->audio_pll_clk = I2S_PLL_CLK;
+	i2s->samplingrate = I2S_SAMPLING_RATE;
+	i2s->bitspersample = I2S_BITS_PER_SAMPLE;
+	i2s->channels = I2S_CHANNELS;
+	i2s->rfs = I2S_RFS;
+	i2s->bfs = I2S_BFS;
+}
+
+/*
+ * Gets fdt values for wm8994 config parameters
+ *
+ * @param pcodec_info	codec information structure
+ * @param blob		FDT blob
+ * @return		int value, 0 for success
+ */
+static int get_sound_wm8994_values(struct sound_codec_info *pcodec_info)
+{
+	int error = 0;
+
+	switch (AUDIO_COMPAT) {
+	case AUDIO_COMPAT_SPI:
+		debug("%s: Support not added for SPI interface\n", __func__);
+		return -1;
+		break;
+	case AUDIO_COMPAT_I2C:
+		pcodec_info->i2c_bus = AUDIO_I2C_BUS;
+		pcodec_info->i2c_dev_addr = AUDIO_I2C_REG;
+		debug("i2c dev addr = %d\n", pcodec_info->i2c_dev_addr);
+		break;
+	default:
+		debug("%s: Unknown compat id %d\n", __func__, AUDIO_COMPAT);
+		return -1;
+	}
+
+	if (error == -1) {
+		debug("fail to get wm8994 codec node properties\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * Gets fdt values for codec config parameters
+ *
+ * @param pcodec_info	codec information structure
+ * @param blob		FDT blob
+ * @return		int value, 0 for success
+ */
+static int get_sound_codec_values(struct sound_codec_info *pcodec_info)
+{
+	int error = 0;
+	const char *codectype;
+
+	codectype =  AUDIO_CODEC;
+
+	if (!strcmp(codectype, "wm8994")) {
+		pcodec_info->codec_type = CODEC_WM_8994;
+		error = get_sound_wm8994_values(pcodec_info);
+	} else
+		error = -1;
+
+	if (error == -1) {
+		debug("fail to get sound codec node properties\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+int sound_init(void)
+{
+	int ret;
+	struct i2stx_info *pi2s_tx = &g_i2stx_pri;
+	struct sound_codec_info *pcodec_info = &g_codec_info;
+
+	/* Get the I2S Values */
+	get_sound_i2s_values(pi2s_tx);
+
+	/* Get the codec Values */
+	if (get_sound_codec_values(pcodec_info) < 0)
+		return -1;
+
+	ret = i2s_tx_init(pi2s_tx);
+	if (ret) {
+		debug("%s: Failed to init i2c transmit: ret=%d\n", __func__,
+		      ret);
+		return ret;
+	}
+
+	/* Check the codec type and initialise the same */
+	if (pcodec_info->codec_type == CODEC_WM_8994) {
+		ret = wm8994_init(pcodec_info, WM8994_AIF2,
+			pi2s_tx->samplingrate,
+			(pi2s_tx->samplingrate * (pi2s_tx->rfs)),
+			pi2s_tx->bitspersample, pi2s_tx->channels);
+	} else {
+		debug("%s: Unknown code type %d\n", __func__,
+		      pcodec_info->codec_type);
+		return -1;
+	}
+	if (ret) {
+		debug("%s: Codec init failed\n", __func__);
+		return -1;
+	}
+
+	return ret;
+}
+
+/*
+ * Generates 400hz sine wave data for 1sec
+ *
+ * @param samplingrate	samplinng rate of the sinewave need to be generated
+ * @param data		data buffer pointer
+ */
+static void sound_prepare_sinewave_400hz_buffer(unsigned short *data)
+{
+	int freq = SOUND_400_HZ;
+	int i;
+
+	while (freq--) {
+		i = ARRAY_SIZE(sine_table_400);
+
+		for (i = 0; i < ARRAY_SIZE(sine_table_400); i++) {
+			*data++ = sine_table_400[i];
+			*data++ = sine_table_400[i];
+		}
+	}
+}
+
+int sound_play(void)
+{
+	unsigned int *data;
+	unsigned long data_size;
+	unsigned int ret;
+
+	/* Sine wave Buffer length computation */
+	data_size = g_i2stx_pri.samplingrate * g_i2stx_pri.channels;
+	data_size *= (g_i2stx_pri.bitspersample / SOUND_BITS_IN_BYTE);
+	data = malloc(data_size);
+
+	if (data == NULL) {
+		debug("%s: malloc failed\n", __func__);
+		return -1;
+	}
+
+	sound_prepare_sinewave_400hz_buffer((unsigned short *)data);
+
+	ret = i2s_transfer_tx_data(&g_i2stx_pri, data,
+				   (data_size / sizeof(int)));
+	free(data);
+
+	return ret;
+}
diff --git a/include/i2s.h b/include/i2s.h
new file mode 100644
index 0000000..f1b642e
--- /dev/null
+++ b/include/i2s.h
@@ -0,0 +1,127 @@ 
+/*
+ * Copyright (C) 2012 Samsung Electronics
+ * R. Chandrasekar <rcsekar@samsung.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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 option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef __I2S_H__
+#define __I2S_H__
+
+/*
+ * DAI hardware audio formats.
+ *
+ * Describes the physical PCM data formating and clocking. Add new formats
+ * to the end.
+ */
+#define SND_SOC_DAIFMT_I2S		1 /* I2S mode */
+#define SND_SOC_DAIFMT_RIGHT_J		2 /* Right Justified mode */
+#define SND_SOC_DAIFMT_LEFT_J		3 /* Left Justified mode */
+#define SND_SOC_DAIFMT_DSP_A		4 /* L data MSB after FRM LRC */
+#define SND_SOC_DAIFMT_DSP_B		5 /* L data MSB during FRM LRC */
+#define SND_SOC_DAIFMT_AC97		6 /* AC97 */
+#define SND_SOC_DAIFMT_PDM		7 /* Pulse density modulation */
+
+/* left and right justified also known as MSB and LSB respectively */
+#define SND_SOC_DAIFMT_MSB		SND_SOC_DAIFMT_LEFT_J
+#define SND_SOC_DAIFMT_LSB		SND_SOC_DAIFMT_RIGHT_J
+
+/*
+ * DAI hardware signal inversions.
+ *
+ * Specifies whether the DAI can also support inverted clocks for the specified
+ * format.
+ */
+#define SND_SOC_DAIFMT_NB_NF	(1 << 8) /* normal bit clock + frame */
+#define SND_SOC_DAIFMT_NB_IF	(2 << 8) /* normal BCLK + inv FRM */
+#define SND_SOC_DAIFMT_IB_NF	(3 << 8) /* invert BCLK + nor FRM */
+#define SND_SOC_DAIFMT_IB_IF	(4 << 8) /* invert BCLK + FRM */
+
+/*
+ * DAI hardware clock masters.
+ *
+ * This is wrt the codec, the inverse is true for the interface
+ * i.e. if the codec is clk and FRM master then the interface is
+ * clk and frame slave.
+ */
+#define SND_SOC_DAIFMT_CBM_CFM	(1 << 12) /* codec clk & FRM master */
+#define SND_SOC_DAIFMT_CBS_CFM	(2 << 12) /* codec clk slave & FRM master */
+#define SND_SOC_DAIFMT_CBM_CFS	(3 << 12) /* codec clk master & frame slave */
+#define SND_SOC_DAIFMT_CBS_CFS	(4 << 12) /* codec clk & FRM slave */
+
+#define SND_SOC_DAIFMT_FORMAT_MASK	0x000f
+#define SND_SOC_DAIFMT_CLOCK_MASK	0x00f0
+#define SND_SOC_DAIFMT_INV_MASK		0x0f00
+#define SND_SOC_DAIFMT_MASTER_MASK	0xf000
+
+/*
+ * Master Clock Directions
+ */
+#define SND_SOC_CLOCK_IN		0
+#define SND_SOC_CLOCK_OUT		1
+
+/* I2S Tx Control */
+#define I2S_TX_ON	1
+#define I2S_TX_OFF	0
+
+#define FIFO_LENGTH	64
+
+/* I2s Registers */
+struct i2s_reg {
+	unsigned int	con;		/* base + 0 , Control register */
+	unsigned int	mod;		/* Mode register */
+	unsigned int	fic;		/* FIFO control register */
+	unsigned int	psr;		/* Reserved */
+	unsigned int	txd;		/* Transmit data register */
+	unsigned int	rxd;		/* Receive Data Register */
+};
+
+/* This structure stores the i2s related information */
+struct i2stx_info {
+	unsigned int rfs;		/* LR clock frame size */
+	unsigned int bfs;		/* Bit slock frame size */
+	unsigned int audio_pll_clk;	/* Audio pll frequency in Hz */
+	unsigned int samplingrate;	/* sampling rate */
+	unsigned int bitspersample;	/* bits per sample */
+	unsigned int channels;		/* audio channels */
+	unsigned int base_address;	/* I2S Register Base */
+};
+
+/*
+ * Sends the given data through i2s tx
+ *
+ * @param pi2s_tx	pointer of i2s transmitter parameter structure.
+ * @param *data		address of the data buffer
+ * @param data_size	array size of the int buffer (total size / size of int)
+ *
+ * @return		int value 0 for success, -1 in case of error
+ */
+int i2s_transfer_tx_data(struct i2stx_info *pi2s_tx, unsigned *data,
+				unsigned long data_size);
+
+/*
+ * Initialise i2s transmiter
+ *
+ * @param pi2s_tx	pointer of i2s transmitter parameter structure.
+ *
+ * @return		int value 0 for success, -1 in case of error
+ */
+int i2s_tx_init(struct i2stx_info *pi2s_tx);
+
+#endif /* __I2S_H__ */
diff --git a/include/sound.h b/include/sound.h
new file mode 100644
index 0000000..1d29ded
--- /dev/null
+++ b/include/sound.h
@@ -0,0 +1,62 @@ 
+/*
+ * Copyright (C) 2012 Samsung Electronics
+ * R. Chandrasekar < rcsekar@samsung.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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 option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef __SOUND_H__
+#define __SOUND_H__
+
+/* sound codec enum */
+enum en_sound_codec {
+	CODEC_WM_8994,
+	CODEC_WM_8995,
+	CODEC_MAX
+};
+
+/* sound codec enum */
+enum sound_compat {
+	AUDIO_COMPAT_SPI,
+	AUDIO_COMPAT_I2C,
+};
+
+/* Codec information structure to store the info from device tree */
+struct sound_codec_info {
+	int i2c_bus;
+	int i2c_dev_addr;
+	enum en_sound_codec codec_type;
+};
+
+/*
+ * Initialises audio sub system
+ *
+ * @return	int value 0 for success, -1 for error
+ */
+int sound_init(void);
+
+/*
+ * plays the pcm data buffer in pcm_data.h through i2s1 to make the
+ * sine wave sound
+ *
+ * @return	int 0 for success, -1 for error
+ */
+int sound_play(void);
+
+#endif  /* __SOUND__H__ */