diff --git a/arch/arm/mach-s3c6400/include/mach/dma.h b/arch/arm/mach-s3c6400/include/mach/dma.h
index 004edab23954d5c46c054c26e13af91a522d27a8..6723860748be252561be560cb78cde08f456a9a3 100644
--- a/arch/arm/mach-s3c6400/include/mach/dma.h
+++ b/arch/arm/mach-s3c6400/include/mach/dma.h
@@ -58,21 +58,13 @@ enum dma_ch {
 	DMACH_MAX		/* the end */
 };
 
-static __inline__ int s3c_dma_has_circular(void)
+static __inline__ bool s3c_dma_has_circular(void)
 {
-	/* we will be supporting ciruclar buffers as soon as we have DMA
-	 * engine support.
-	 */
-	return 1;
+	return true;
 }
 
 #define S3C2410_DMAF_CIRCULAR		(1 << 0)
 
-static inline bool s3c_dma_has_circular(void)
-{
-	return false;
-}
-
 #include <plat/dma.h>
 
 #endif /* __ASM_ARCH_IRQ_H */
diff --git a/arch/arm/mach-s3c6410/Kconfig b/arch/arm/mach-s3c6410/Kconfig
index 53fc3ff657f7b7855c0907d76f470af1ad8f0476..72d4b11b207783efec5633eccd926989052992bc 100644
--- a/arch/arm/mach-s3c6410/Kconfig
+++ b/arch/arm/mach-s3c6410/Kconfig
@@ -77,6 +77,7 @@ config SMDK6410_WM1190_EV1
 	depends on MACH_SMDK6410
 	select REGULATOR
 	select REGULATOR_WM8350
+	select S3C24XX_GPIO_EXTRA64
 	select MFD_WM8350_I2C
 	select MFD_WM8350_CONFIG_MODE_0
 	select MFD_WM8350_CONFIG_MODE_3
diff --git a/arch/arm/mach-s3c6410/mach-smdk6410.c b/arch/arm/mach-s3c6410/mach-smdk6410.c
index ea51dbe76e3ec55a903a872d3e2544ef5a8b4bea..9f1a214626201bf2a969eefe60081b24dfa521be 100644
--- a/arch/arm/mach-s3c6410/mach-smdk6410.c
+++ b/arch/arm/mach-s3c6410/mach-smdk6410.c
@@ -320,6 +320,9 @@ static int __init smdk6410_wm8350_init(struct wm8350 *wm8350)
 {
 	int i;
 
+	/* Configure the IRQ line */
+	s3c_gpio_setpull(S3C64XX_GPN(12), S3C_GPIO_PULL_UP);
+
 	/* Instantiate the regulators */
 	for (i = 0; i < ARRAY_SIZE(wm1190_regulators); i++)
 		wm8350_register_regulator(wm8350,
diff --git a/arch/arm/plat-s3c64xx/dma.c b/arch/arm/plat-s3c64xx/dma.c
index 266a10745a85988c36f74671ab216bf60dd3cd96..d554b936fcfb38fb4aca764cbcc6e33049976610 100644
--- a/arch/arm/plat-s3c64xx/dma.c
+++ b/arch/arm/plat-s3c64xx/dma.c
@@ -151,8 +151,6 @@ static void s3c64xx_dma_fill_lli(struct s3c2410_dma_chan *chan,
 		src = chan->dev_addr;
 		dst = data;
 		control0 = PL080_CONTROL_SRC_AHB2;
-		control0 |= (u32)chan->hw_width << PL080_CONTROL_SWIDTH_SHIFT;
-		control0 |= 2 << PL080_CONTROL_DWIDTH_SHIFT;
 		control0 |= PL080_CONTROL_DST_INCR;
 		break;
 
@@ -160,8 +158,6 @@ static void s3c64xx_dma_fill_lli(struct s3c2410_dma_chan *chan,
 		src = data;
 		dst = chan->dev_addr;
 		control0 = PL080_CONTROL_DST_AHB2;
-		control0 |= (u32)chan->hw_width << PL080_CONTROL_DWIDTH_SHIFT;
-		control0 |= 2 << PL080_CONTROL_SWIDTH_SHIFT;
 		control0 |= PL080_CONTROL_SRC_INCR;
 		break;
 	default:
@@ -173,6 +169,8 @@ static void s3c64xx_dma_fill_lli(struct s3c2410_dma_chan *chan,
 	control1 = size >> chan->hw_width;	/* size in no of xfers */
 	control0 |= PL080_CONTROL_PROT_SYS;	/* always in priv. mode */
 	control0 |= PL080_CONTROL_TC_IRQ_EN;	/* always fire IRQ */
+	control0 |= (u32)chan->hw_width << PL080_CONTROL_DWIDTH_SHIFT;
+	control0 |= (u32)chan->hw_width << PL080_CONTROL_SWIDTH_SHIFT;
 
 	lli->src_addr = src;
 	lli->dst_addr = dst;
@@ -339,6 +337,7 @@ int s3c2410_dma_enqueue(unsigned int channel, void *id,
 	struct s3c64xx_dma_buff *next;
 	struct s3c64xx_dma_buff *buff;
 	struct pl080s_lli *lli;
+	unsigned long flags;
 	int ret;
 
 	WARN_ON(!chan);
@@ -366,6 +365,8 @@ int s3c2410_dma_enqueue(unsigned int channel, void *id,
 
 	s3c64xx_dma_fill_lli(chan, lli, data, size);
 
+	local_irq_save(flags);
+
 	if ((next = chan->next) != NULL) {
 		struct s3c64xx_dma_buff *end = chan->end;
 		struct pl080s_lli *endlli = end->lli;
@@ -397,6 +398,8 @@ int s3c2410_dma_enqueue(unsigned int channel, void *id,
 		s3c64xx_lli_to_regs(chan, lli);
 	}
 
+	local_irq_restore(flags);
+
 	show_lli(lli);
 
 	dbg_showchan(chan);
@@ -560,26 +563,11 @@ int s3c2410_dma_free(unsigned int channel, struct s3c2410_dma_client *client)
 
 EXPORT_SYMBOL(s3c2410_dma_free);
 
-
-static void s3c64xx_dma_tcirq(struct s3c64xx_dmac *dmac, int offs)
-{
-	struct s3c2410_dma_chan *chan = dmac->channels + offs;
-
-	/* note, we currently do not bother to work out which buffer
-	 * or buffers have been completed since the last tc-irq. */
-
-	if (chan->callback_fn)
-		(chan->callback_fn)(chan, chan->curr->pw, 0, S3C2410_RES_OK);
-}
-
-static void s3c64xx_dma_errirq(struct s3c64xx_dmac *dmac, int offs)
-{
-	printk(KERN_DEBUG "%s: offs %d\n", __func__, offs);
-}
-
 static irqreturn_t s3c64xx_dma_irq(int irq, void *pw)
 {
 	struct s3c64xx_dmac *dmac = pw;
+	struct s3c2410_dma_chan *chan;
+	enum s3c2410_dma_buffresult res;
 	u32 tcstat, errstat;
 	u32 bit;
 	int offs;
@@ -588,14 +576,54 @@ static irqreturn_t s3c64xx_dma_irq(int irq, void *pw)
 	errstat = readl(dmac->regs + PL080_ERR_STATUS);
 
 	for (offs = 0, bit = 1; offs < 8; offs++, bit <<= 1) {
+		struct s3c64xx_dma_buff *buff;
+
+		if (!(errstat & bit) && !(tcstat & bit))
+			continue;
+
+		chan = dmac->channels + offs;
+		res = S3C2410_RES_ERR;
+
 		if (tcstat & bit) {
 			writel(bit, dmac->regs + PL080_TC_CLEAR);
-			s3c64xx_dma_tcirq(dmac, offs);
+			res = S3C2410_RES_OK;
 		}
 
-		if (errstat & bit) {
-			s3c64xx_dma_errirq(dmac, offs);
+		if (errstat & bit)
 			writel(bit, dmac->regs + PL080_ERR_CLEAR);
+
+		/* 'next' points to the buffer that is next to the
+		 * currently active buffer.
+		 * For CIRCULAR queues, 'next' will be same as 'curr'
+		 * when 'end' is the active buffer.
+		 */
+		buff = chan->curr;
+		while (buff && buff != chan->next
+				&& buff->next != chan->next)
+			buff = buff->next;
+
+		if (!buff)
+			BUG();
+
+		if (buff == chan->next)
+			buff = chan->end;
+
+		s3c64xx_dma_bufffdone(chan, buff, res);
+
+		/* Free the node and update curr, if non-circular queue */
+		if (!(chan->flags & S3C2410_DMAF_CIRCULAR)) {
+			chan->curr = buff->next;
+			s3c64xx_dma_freebuff(buff);
+		}
+
+		/* Update 'next' */
+		buff = chan->next;
+		if (chan->next == chan->end) {
+			chan->next = chan->curr;
+			if (!(chan->flags & S3C2410_DMAF_CIRCULAR))
+				chan->end = NULL;
+		} else {
+			chan->next = buff->next;
 		}
 	}