diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index 423e06d..8b3f503 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -35,6 +35,7 @@ config SND_SOC_GENERIC_DMAENGINE_PCM
 
 # All the supported SoCs
 source "sound/soc/atmel/Kconfig"
+source "sound/soc/ara/Kconfig"
 source "sound/soc/au1x/Kconfig"
 source "sound/soc/blackfin/Kconfig"
 source "sound/soc/cirrus/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 3d14cb82..87b79e5 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_SND_SOC)	+= snd-soc-core.o
 obj-$(CONFIG_SND_SOC)	+= codecs/
 obj-$(CONFIG_SND_SOC)	+= generic/
 obj-$(CONFIG_SND_SOC)	+= atmel/
+obj-$(CONFIG_SND_SOC)	+= ara/
 obj-$(CONFIG_SND_SOC)	+= au1x/
 obj-$(CONFIG_SND_SOC)	+= blackfin/
 obj-$(CONFIG_SND_SOC)	+= cirrus/
diff --git a/sound/soc/ara/Kconfig b/sound/soc/ara/Kconfig
new file mode 100644
index 0000000..011e6d8
--- /dev/null
+++ b/sound/soc/ara/Kconfig
@@ -0,0 +1,8 @@
+config SND_ARA_CARD
+	tristate "ASoC Ara sound card support"
+	select SND_SOC_RT5639
+	select SND_SOC_SPDIF
+	select SND_SOC_GENERIC_DMAENGINE_PCM
+	select SND_SIMPLE_CARD
+	help
+	  This option enables generic ara sound card support
diff --git a/sound/soc/ara/Makefile b/sound/soc/ara/Makefile
new file mode 100644
index 0000000..8282e4a
--- /dev/null
+++ b/sound/soc/ara/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_SND_ARA_CARD)	+= gb_audio.o
diff --git a/sound/soc/ara/gb_audio.c b/sound/soc/ara/gb_audio.c
new file mode 100644
index 0000000..7c1760b
--- /dev/null
+++ b/sound/soc/ara/gb_audio.c
@@ -0,0 +1,308 @@
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/simple_card.h>
+
+
+#define GB_RATES	SNDRV_PCM_RATE_8000_48000
+#define GB_FMTS		SNDRV_PCM_FMTBIT_S16_LE
+#define PREALLOC_BUFFER         (32 * 1024)
+#define PREALLOC_BUFFER_MAX     (32 * 1024)
+
+/***************************************************************
+ * This is the gb_pcm_timer logic which fakes DMA interrupts
+ * via a timer.
+ ***************************************************************/
+
+struct gb_pcm_timer {
+	struct snd_pcm_substream *substream;
+	struct timer_list timer;
+	int hwptr_done;
+};
+
+static void dummy_timer_start(struct gb_pcm_timer *pcm)
+{
+	pcm->timer.expires = jiffies + HZ/8;
+	add_timer(&pcm->timer);
+}
+
+static void dummy_timer_stop(struct gb_pcm_timer *pcm)
+{
+	del_timer(&pcm->timer);
+	pcm->timer.expires = 0;
+}
+
+static void dummy_timer_function(unsigned long data)
+{
+	struct gb_pcm_timer *pcm = (struct gb_pcm_timer *)data;
+	struct snd_pcm_substream *substream = pcm->substream;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	/* pretend to consume a chunk of data */
+	pcm->hwptr_done += 1024;
+	if (pcm->hwptr_done > frames_to_bytes(runtime, runtime->buffer_size))
+		pcm->hwptr_done = frames_to_bytes(runtime, runtime->buffer_size);
+
+	dummy_timer_start(pcm);
+	snd_pcm_period_elapsed(substream);
+}
+
+
+/******************************************
+ * dai op functions)
+ ******************************************/
+
+static int gb_dai_startup(struct snd_pcm_substream *substream,
+				struct snd_soc_dai *dai)
+{
+	return 0;
+}
+
+static void gb_dai_shutdown(struct snd_pcm_substream *substream,
+				struct snd_soc_dai *dai)
+{
+}
+
+static int gb_dai_trigger(struct snd_pcm_substream *substream, int cmd,
+				struct snd_soc_dai *dai)
+{
+	struct gb_pcm_timer *pcmt = substream->runtime->private_data;
+
+	printk("JDB: gb_dai_trigger!\n");
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		dummy_timer_start(pcmt);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		dummy_timer_stop(pcmt);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int gb_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	return 0;
+}
+
+static int gb_dai_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	printk("JDB: gb_dai_hw_params!\n");
+	return 0;
+}
+
+
+static const struct snd_soc_dai_ops gb_dai_ops = {
+	.startup        = gb_dai_startup,
+	.shutdown       = gb_dai_shutdown,
+	.trigger        = gb_dai_trigger,
+	.set_fmt        = gb_dai_set_fmt,
+	.hw_params      = gb_dai_hw_params,
+};
+
+static struct snd_soc_dai_driver gb_cpu_dai = {
+	/*XXX WTF, this doesn't seem to be the name of the dai that gets registered! */
+	.name                   = "gb-cpu-dai",
+	.playback = {
+		.rates          = GB_RATES,
+		.formats        = GB_FMTS,
+		.channels_min   = 2,
+		.channels_max   = 2,
+	},
+	.ops = &gb_dai_ops,
+};
+
+/******************************************************
+ * gb pcm logic
+ *****************************************************/
+static struct snd_pcm_hardware gb_plat_pcm_hardware = {
+	.info =         SNDRV_PCM_INFO_INTERLEAVED,
+	.formats                = GB_FMTS,
+	.rates                  = GB_RATES,
+	.rate_min               = 8000,
+	.rate_max               = 48000,
+	.channels_min           = 2,
+	.channels_max           = 2,
+	/* XXX - All the values below are junk */
+	.buffer_bytes_max       = 64 * 1024,
+	.period_bytes_min       = 32,
+	.period_bytes_max       = 8192,
+	.periods_min            = 1,
+	.periods_max            = 32,
+	.fifo_size              = 256,
+};
+
+static snd_pcm_uframes_t gb_pcm_pointer(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct gb_pcm_timer *pcmt = substream->runtime->private_data;
+	int hwptr_done;
+
+	hwptr_done = pcmt->hwptr_done;
+
+	return hwptr_done;
+}
+
+static int gb_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct gb_pcm_timer *pcmt = substream->runtime->private_data;
+
+	pcmt->hwptr_done = 0;
+
+	return 0;
+}
+
+static int gb_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct gb_pcm_timer *pcmt;
+
+	pcmt = kzalloc(sizeof(*pcmt), GFP_KERNEL);
+	if (!pcmt)
+		return -ENOMEM;
+	pcmt->substream = substream;
+	setup_timer(&pcmt->timer, dummy_timer_function, (unsigned long)pcmt);
+	runtime->private_data = pcmt;
+
+	snd_soc_set_runtime_hwparams(substream, &gb_plat_pcm_hardware);
+	return snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+}
+
+static int gb_pcm_close(struct snd_pcm_substream *substream)
+{
+	if (substream->runtime->private_data)
+		kfree(substream->runtime->private_data);
+	substream->runtime->private_data = NULL;
+	return 0;
+}
+
+static int gb_pcm_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *hw_params)
+{
+	return snd_pcm_lib_malloc_pages(substream,
+					params_buffer_bytes(hw_params));
+}
+
+static int gb_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+	return snd_pcm_lib_free_pages(substream);
+}
+
+static struct snd_pcm_ops gb_pcm_ops = {
+	.open           = gb_pcm_open,
+	.close		= gb_pcm_close,
+	.ioctl          = snd_pcm_lib_ioctl,
+	.hw_params      = gb_pcm_hw_params,
+	.hw_free        = gb_pcm_hw_free,
+	.prepare	= gb_pcm_prepare,
+	.pointer        = gb_pcm_pointer,
+};
+
+static void gb_pcm_free(struct snd_pcm *pcm)
+{
+	snd_pcm_lib_preallocate_free_for_all(pcm);
+}
+
+static int gb_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_pcm *pcm = rtd->pcm;
+
+	return snd_pcm_lib_preallocate_pages_for_all(
+			pcm,
+			SNDRV_DMA_TYPE_CONTINUOUS,
+			snd_dma_continuous_data(GFP_KERNEL),
+			PREALLOC_BUFFER, PREALLOC_BUFFER_MAX);
+}
+
+static struct snd_soc_platform_driver gb_soc_platform = {
+	.ops            = &gb_pcm_ops,
+	.pcm_new        = gb_pcm_new,
+	.pcm_free       = gb_pcm_free,
+};
+
+
+/************************************************************
+ * This is the aosc simple card junk which binds the platform
+ * codec, cpu and codec-dais etc togheter, also all the
+ * nested gross platfrom driver/device junk is here.
+ ************************************************************/
+static struct asoc_simple_card_info gb_card_info = {
+	.name           = "Greybus Audio Module",
+	.card           = "gb-card",
+	.codec          = "rt5639.0-001c", /* XXX this will need to be dynamic*/
+	.platform       = "gb-pcm-audio.0",
+	.daifmt         = GB_FMTS,
+	.cpu_dai = {
+		.name   = "gb-pcm-audio.0", /*XXX shouldn't this be gb-cpu-dai?*/
+		.fmt    = GB_FMTS,
+	},
+	.codec_dai = {
+		.name   = "rt5639-aif1",
+		.fmt    = SND_SOC_DAIFMT_CBM_CFM,
+		.sysclk = 11289600,
+	}
+};
+
+static struct platform_device gb_snd_plat_device = {
+	.name   = "asoc-simple-card",
+	.dev    = {
+		.platform_data  = &gb_card_info,
+	},
+};
+
+static struct platform_device gb_device = {
+	.name           = "gb-pcm-audio",
+};
+
+static struct platform_device *gb_devices[] = {
+	&gb_snd_plat_device,
+	&gb_device,
+};
+
+static const struct snd_soc_component_driver gb_soc_component = {
+	.name           = "gb-component",
+};
+
+static int gb_plat_probe(struct platform_device *pdev)
+{
+	int ret;
+
+	ret = snd_soc_register_platform(&pdev->dev, &gb_soc_platform);
+	ret = snd_soc_register_component(&pdev->dev, &gb_soc_component,
+							&gb_cpu_dai, 1);
+	return ret;
+}
+
+static struct platform_driver gb_plat_driver = {
+	.driver         = {
+		.name   = "gb-pcm-audio",
+	},
+	.probe          = gb_plat_probe,
+};
+
+
+/******************************************************************
+ * This is the basic hook to let me get things initialized
+ ******************************************************************/
+static int __init devices_setup(void)
+{
+	int err;
+	struct platform_device *device;
+
+	err = platform_driver_register(&gb_plat_driver);
+
+	platform_add_devices(gb_devices, ARRAY_SIZE(gb_devices));
+
+	return err;
+}
+device_initcall(devices_setup);
