From b91b067c531c9322f3719951b07303e790b13475 Mon Sep 17 00:00:00 2001
From: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
Date: Fri, 27 Mar 2009 12:59:46 -0700
Subject: [PATCH] musb: split out CPPI interrupt handler

As DaVinci DM646x has a dedicated CPPI DMA interrupt, replace
cppi_completion() (which has always been kind of layering
violation) by a complete CPPI interrupt handler.

[ dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org: only cppi_dma.c needs platform
device header, not cppi_dma.h ]

Signed-off-by: Dmitry Krivoschekov <dkrivoschekov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
Signed-off-by: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
---
 drivers/usb/musb/cppi_dma.c |   34 +++++++++++++++++++++++++++++++---
 drivers/usb/musb/cppi_dma.h |    6 ++++--
 drivers/usb/musb/davinci.c  |   14 ++++----------
 3 files changed, 39 insertions(+), 15 deletions(-)

diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c
index ac7227c..6ff3c67 100644
--- a/drivers/usb/musb/cppi_dma.c
+++ b/drivers/usb/musb/cppi_dma.c
@@ -6,6 +6,7 @@
  * The TUSB6020, using VLYNQ, has CPPI that looks much like DaVinci.
  */
 
+#include <linux/platform_device.h>
 #include <linux/usb.h>
 
 #include "musb_core.h"
@@ -1145,17 +1146,27 @@ static bool cppi_rx_scan(struct cppi *cppi, unsigned ch)
 	return completed;
 }
 
-void cppi_completion(struct musb *musb, u32 rx, u32 tx)
+irqreturn_t cppi_interrupt(int irq, void *dev_id)
 {
-	void __iomem		*tibase;
-	int			i, index;
+	struct musb		*musb = dev_id;
 	struct cppi		*cppi;
+	void __iomem		*tibase;
 	struct musb_hw_ep	*hw_ep = NULL;
+	u32			rx, tx;
+	int			i, index;
 
 	cppi = container_of(musb->dma_controller, struct cppi, controller);
 
 	tibase = musb->ctrl_base;
 
+	tx = musb_readl(tibase, DAVINCI_TXCPPI_MASKED_REG);
+	rx = musb_readl(tibase, DAVINCI_RXCPPI_MASKED_REG);
+
+	if (!tx && !rx)
+		return IRQ_NONE;
+
+	DBG(4, "CPPI IRQ Tx%x Rx%x\n", tx, rx);
+
 	/* process TX channels */
 	for (index = 0; tx; tx = tx >> 1, index++) {
 		struct cppi_channel		*tx_ch;
@@ -1293,6 +1304,8 @@ void cppi_completion(struct musb *musb, u32 rx, u32 tx)
 
 	/* write to CPPI EOI register to re-enable interrupts */
 	musb_writel(tibase, DAVINCI_CPPI_EOI_REG, 0);
+
+	return IRQ_HANDLED;
 }
 
 /* Instantiate a software object representing a DMA controller. */
@@ -1300,6 +1313,9 @@ struct dma_controller *__init
 dma_controller_create(struct musb *musb, void __iomem *mregs)
 {
 	struct cppi		*controller;
+	struct device		*dev = musb->controller;
+	struct platform_device	*pdev = to_platform_device(dev);
+	int			irq = platform_get_irq(pdev, 1);
 
 	controller = kzalloc(sizeof *controller, GFP_KERNEL);
 	if (!controller)
@@ -1330,6 +1346,15 @@ dma_controller_create(struct musb *musb, void __iomem *mregs)
 		return NULL;
 	}
 
+	if (irq > 0) {
+		if (request_irq(irq, cppi_interrupt, 0, "cppi-dma", musb)) {
+			dev_err(dev, "request_irq %d failed!\n", irq);
+			dma_controller_destroy(&controller->controller);
+			return NULL;
+		}
+		controller->irq = irq;
+	}
+
 	return &controller->controller;
 }
 
@@ -1342,6 +1367,9 @@ void dma_controller_destroy(struct dma_controller *c)
 
 	cppi = container_of(c, struct cppi, controller);
 
+	if (cppi->irq)
+		free_irq(cppi->irq, cppi->musb);
+
 	/* assert:  caller stopped the controller first */
 	dma_pool_destroy(cppi->pool);
 
diff --git a/drivers/usb/musb/cppi_dma.h b/drivers/usb/musb/cppi_dma.h
index 729b407..8a39de3 100644
--- a/drivers/usb/musb/cppi_dma.h
+++ b/drivers/usb/musb/cppi_dma.h
@@ -119,6 +119,8 @@ struct cppi {
 	void __iomem			*mregs;		/* Mentor regs */
 	void __iomem			*tibase;	/* TI/CPPI regs */
 
+	int				irq;
+
 	struct cppi_channel		tx[4];
 	struct cppi_channel		rx[4];
 
@@ -127,7 +129,7 @@ struct cppi {
 	struct list_head		tx_complete;
 };
 
-/* irq handling hook */
-extern void cppi_completion(struct musb *, u32 rx, u32 tx);
+/* CPPI IRQ handler */
+extern irqreturn_t cppi_interrupt(int, void *);
 
 #endif				/* end of ifndef _CPPI_DMA_H_ */
diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c
index 399c435..9fd74bf 100644
--- a/drivers/usb/musb/davinci.c
+++ b/drivers/usb/musb/davinci.c
@@ -250,6 +250,7 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci)
 	irqreturn_t	retval = IRQ_NONE;
 	struct musb	*musb = __hci;
 	void __iomem	*tibase = musb->ctrl_base;
+	struct cppi	*cppi;
 	u32		tmp;
 
 	spin_lock_irqsave(&musb->lock, flags);
@@ -266,16 +267,9 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci)
 	/* CPPI interrupts share the same IRQ line, but have their own
 	 * mask, state, "vector", and EOI registers.
 	 */
-	if (is_cppi_enabled()) {
-		u32 cppi_tx = musb_readl(tibase, DAVINCI_TXCPPI_MASKED_REG);
-		u32 cppi_rx = musb_readl(tibase, DAVINCI_RXCPPI_MASKED_REG);
-
-		if (cppi_tx || cppi_rx) {
-			DBG(4, "CPPI IRQ t%x r%x\n", cppi_tx, cppi_rx);
-			cppi_completion(musb, cppi_rx, cppi_tx);
-			retval = IRQ_HANDLED;
-		}
-	}
+	cppi = container_of(musb->dma_controller, struct cppi, controller);
+	if (is_cppi_enabled() && musb->dma_controller && !cppi->irq)
+		retval = cppi_interrupt(irq, __hci);
 
 	/* ack and handle non-CPPI interrupts */
 	tmp = musb_readl(tibase, DAVINCI_USB_INT_SRC_MASKED_REG);
-- 
1.6.0.4

