USB: at91 udc, support at91sam926x addresses

This is an update to the AT91 USB Device (Gadget) driver.

The base I/O address provided in the platform_device resources is now
ioremap()'ed instead of using a statically mapped memory area.  This
helps portability to the newer AT91sam926x processors.

The major change is that we now have to pass a 'struct at91_udc'
parameter to at91_udp_read() and at91_udp_write().

Signed-off-by: Andrew Victor <andrew@sanpeople.com>
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
index 8165633..b53b937 100644
--- a/drivers/usb/gadget/at91_udc.c
+++ b/drivers/usb/gadget/at91_udc.c
@@ -43,12 +43,12 @@
 #include <linux/usb_gadget.h>
 
 #include <asm/byteorder.h>
+#include <asm/hardware.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/system.h>
 #include <asm/mach-types.h>
 
-#include <asm/arch/hardware.h>
 #include <asm/arch/gpio.h>
 #include <asm/arch/board.h>
 
@@ -78,27 +78,11 @@
 static const char driver_name [] = "at91_udc";
 static const char ep0name[] = "ep0";
 
-/*-------------------------------------------------------------------------*/
 
-/*
- * Read from a UDP register.
- */
-static inline unsigned long at91_udp_read(unsigned int reg)
-{
-	void __iomem *udp_base = (void __iomem *)AT91_VA_BASE_UDP;
-
-	return __raw_readl(udp_base + reg);
-}
-
-/*
- * Write to a UDP register.
- */
-static inline void at91_udp_write(unsigned int reg, unsigned long value)
-{
-	void __iomem *udp_base = (void __iomem *)AT91_VA_BASE_UDP;
-
-	__raw_writel(value, udp_base + reg);
-}
+#define at91_udp_read(dev, reg) \
+	__raw_readl((dev)->udp_baseaddr + (reg))
+#define at91_udp_write(dev, reg, val) \
+	__raw_writel((val), (dev)->udp_baseaddr + (reg))
 
 /*-------------------------------------------------------------------------*/
 
@@ -210,13 +194,13 @@
 		return 0;
 	}
 
-	tmp = at91_udp_read(AT91_UDP_FRM_NUM);
+	tmp = at91_udp_read(udc, AT91_UDP_FRM_NUM);
 	seq_printf(s, "frame %05x:%s%s frame=%d\n", tmp,
 		(tmp & AT91_UDP_FRM_OK) ? " ok" : "",
 		(tmp & AT91_UDP_FRM_ERR) ? " err" : "",
 		(tmp & AT91_UDP_NUM));
 
-	tmp = at91_udp_read(AT91_UDP_GLB_STAT);
+	tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT);
 	seq_printf(s, "glbstate %02x:%s" FOURBITS "\n", tmp,
 		(tmp & AT91_UDP_RMWUPE) ? " rmwupe" : "",
 		(tmp & AT91_UDP_RSMINPR) ? " rsminpr" : "",
@@ -224,13 +208,13 @@
 		(tmp & AT91_UDP_CONFG) ? " confg" : "",
 		(tmp & AT91_UDP_FADDEN) ? " fadden" : "");
 
-	tmp = at91_udp_read(AT91_UDP_FADDR);
+	tmp = at91_udp_read(udc, AT91_UDP_FADDR);
 	seq_printf(s, "faddr   %03x:%s fadd=%d\n", tmp,
 		(tmp & AT91_UDP_FEN) ? " fen" : "",
 		(tmp & AT91_UDP_FADD));
 
-	proc_irq_show(s, "imr   ", at91_udp_read(AT91_UDP_IMR));
-	proc_irq_show(s, "isr   ", at91_udp_read(AT91_UDP_ISR));
+	proc_irq_show(s, "imr   ", at91_udp_read(udc, AT91_UDP_IMR));
+	proc_irq_show(s, "isr   ", at91_udp_read(udc, AT91_UDP_ISR));
 
 	if (udc->enabled && udc->vbus) {
 		proc_ep_show(s, &udc->ep[0]);
@@ -286,6 +270,7 @@
 static void done(struct at91_ep *ep, struct at91_request *req, int status)
 {
 	unsigned	stopped = ep->stopped;
+	struct at91_udc	*udc = ep->udc;
 
 	list_del_init(&req->queue);
 	if (req->req.status == -EINPROGRESS)
@@ -301,7 +286,7 @@
 
 	/* ep0 is always ready; other endpoints need a non-empty queue */
 	if (list_empty(&ep->queue) && ep->int_mask != (1 << 0))
-		at91_udp_write(AT91_UDP_IDR, ep->int_mask);
+		at91_udp_write(udc, AT91_UDP_IDR, ep->int_mask);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -554,8 +539,8 @@
 	 * reset/init endpoint fifo.  NOTE:  leaves fifo_bank alone,
 	 * since endpoint resets don't reset hw pingpong state.
 	 */
-	at91_udp_write(AT91_UDP_RST_EP, ep->int_mask);
-	at91_udp_write(AT91_UDP_RST_EP, 0);
+	at91_udp_write(dev, AT91_UDP_RST_EP, ep->int_mask);
+	at91_udp_write(dev, AT91_UDP_RST_EP, 0);
 
 	local_irq_restore(flags);
 	return 0;
@@ -564,6 +549,7 @@
 static int at91_ep_disable (struct usb_ep * _ep)
 {
 	struct at91_ep	*ep = container_of(_ep, struct at91_ep, ep);
+	struct at91_udc	*udc = ep->udc;
 	unsigned long	flags;
 
 	if (ep == &ep->udc->ep[0])
@@ -579,8 +565,8 @@
 
 	/* reset fifos and endpoint */
 	if (ep->udc->clocked) {
-		at91_udp_write(AT91_UDP_RST_EP, ep->int_mask);
-		at91_udp_write(AT91_UDP_RST_EP, 0);
+		at91_udp_write(udc, AT91_UDP_RST_EP, ep->int_mask);
+		at91_udp_write(udc, AT91_UDP_RST_EP, 0);
 		__raw_writel(0, ep->creg);
 	}
 
@@ -695,10 +681,10 @@
 			 * reconfigures the endpoints.
 			 */
 			if (dev->wait_for_config_ack) {
-				tmp = at91_udp_read(AT91_UDP_GLB_STAT);
+				tmp = at91_udp_read(dev, AT91_UDP_GLB_STAT);
 				tmp ^= AT91_UDP_CONFG;
 				VDBG("toggle config\n");
-				at91_udp_write(AT91_UDP_GLB_STAT, tmp);
+				at91_udp_write(dev, AT91_UDP_GLB_STAT, tmp);
 			}
 			if (req->req.length == 0) {
 ep0_in_status:
@@ -727,7 +713,7 @@
 
 	if (req && !status) {
 		list_add_tail (&req->queue, &ep->queue);
-		at91_udp_write(AT91_UDP_IER, ep->int_mask);
+		at91_udp_write(dev, AT91_UDP_IER, ep->int_mask);
 	}
 done:
 	local_irq_restore(flags);
@@ -758,6 +744,7 @@
 static int at91_ep_set_halt(struct usb_ep *_ep, int value)
 {
 	struct at91_ep	*ep = container_of(_ep, struct at91_ep, ep);
+	struct at91_udc	*udc = ep->udc;
 	u32 __iomem	*creg;
 	u32		csr;
 	unsigned long	flags;
@@ -785,8 +772,8 @@
 			csr |= AT91_UDP_FORCESTALL;
 			VDBG("halt %s\n", ep->ep.name);
 		} else {
-			at91_udp_write(AT91_UDP_RST_EP, ep->int_mask);
-			at91_udp_write(AT91_UDP_RST_EP, 0);
+			at91_udp_write(udc, AT91_UDP_RST_EP, ep->int_mask);
+			at91_udp_write(udc, AT91_UDP_RST_EP, 0);
 			csr &= ~AT91_UDP_FORCESTALL;
 		}
 		__raw_writel(csr, creg);
@@ -813,9 +800,11 @@
 
 static int at91_get_frame(struct usb_gadget *gadget)
 {
+	struct at91_udc *udc = to_udc(gadget);
+
 	if (!to_udc(gadget)->clocked)
 		return -EINVAL;
-	return at91_udp_read(AT91_UDP_FRM_NUM) & AT91_UDP_NUM;
+	return at91_udp_read(udc, AT91_UDP_FRM_NUM) & AT91_UDP_NUM;
 }
 
 static int at91_wakeup(struct usb_gadget *gadget)
@@ -833,11 +822,11 @@
 
 	/* NOTE:  some "early versions" handle ESR differently ... */
 
-	glbstate = at91_udp_read(AT91_UDP_GLB_STAT);
+	glbstate = at91_udp_read(udc, AT91_UDP_GLB_STAT);
 	if (!(glbstate & AT91_UDP_ESR))
 		goto done;
 	glbstate |= AT91_UDP_ESR;
-	at91_udp_write(AT91_UDP_GLB_STAT, glbstate);
+	at91_udp_write(udc, AT91_UDP_GLB_STAT, glbstate);
 
 done:
 	local_irq_restore(flags);
@@ -861,6 +850,7 @@
 		ep->stopped = 0;
 		ep->fifo_bank = 0;
 		ep->ep.maxpacket = ep->maxpacket;
+		ep->creg = (void __iomem *) udc->udp_baseaddr + AT91_UDP_CSR(i);
 		// initialiser une queue par endpoint
 		INIT_LIST_HEAD(&ep->queue);
 	}
@@ -915,13 +905,14 @@
 	if (!udc->enabled || !udc->vbus)
 		is_on = 0;
 	DBG("%sactive\n", is_on ? "" : "in");
+
 	if (is_on) {
 		clk_on(udc);
-		at91_udp_write(AT91_UDP_TXVC, 0);
+		at91_udp_write(udc, AT91_UDP_TXVC, 0);
 		at91_set_gpio_value(udc->board.pullup_pin, 1);
-	} else  {
+	} else {
 		stop_activity(udc);
-		at91_udp_write(AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS);
+		at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS);
 		at91_set_gpio_value(udc->board.pullup_pin, 0);
 		clk_off(udc);
 	}
@@ -1086,7 +1077,7 @@
 
 	case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
 			| USB_REQ_SET_CONFIGURATION:
-		tmp = at91_udp_read(AT91_UDP_GLB_STAT) & AT91_UDP_CONFG;
+		tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT) & AT91_UDP_CONFG;
 		if (pkt.r.wValue)
 			udc->wait_for_config_ack = (tmp == 0);
 		else
@@ -1103,7 +1094,7 @@
 	case ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
 			| USB_REQ_GET_STATUS:
 		tmp = (udc->selfpowered << USB_DEVICE_SELF_POWERED);
-		if (at91_udp_read(AT91_UDP_GLB_STAT) & AT91_UDP_ESR)
+		if (at91_udp_read(udc, AT91_UDP_GLB_STAT) & AT91_UDP_ESR)
 			tmp |= (1 << USB_DEVICE_REMOTE_WAKEUP);
 		PACKET("get device status\n");
 		__raw_writeb(tmp, dreg);
@@ -1114,17 +1105,17 @@
 			| USB_REQ_SET_FEATURE:
 		if (w_value != USB_DEVICE_REMOTE_WAKEUP)
 			goto stall;
-		tmp = at91_udp_read(AT91_UDP_GLB_STAT);
+		tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT);
 		tmp |= AT91_UDP_ESR;
-		at91_udp_write(AT91_UDP_GLB_STAT, tmp);
+		at91_udp_write(udc, AT91_UDP_GLB_STAT, tmp);
 		goto succeed;
 	case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
 			| USB_REQ_CLEAR_FEATURE:
 		if (w_value != USB_DEVICE_REMOTE_WAKEUP)
 			goto stall;
-		tmp = at91_udp_read(AT91_UDP_GLB_STAT);
+		tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT);
 		tmp &= ~AT91_UDP_ESR;
-		at91_udp_write(AT91_UDP_GLB_STAT, tmp);
+		at91_udp_write(udc, AT91_UDP_GLB_STAT, tmp);
 		goto succeed;
 
 	/*
@@ -1206,8 +1197,8 @@
 		} else if (ep->is_in)
 			goto stall;
 
-		at91_udp_write(AT91_UDP_RST_EP, ep->int_mask);
-		at91_udp_write(AT91_UDP_RST_EP, 0);
+		at91_udp_write(udc, AT91_UDP_RST_EP, ep->int_mask);
+		at91_udp_write(udc, AT91_UDP_RST_EP, 0);
 		tmp = __raw_readl(ep->creg);
 		tmp |= CLR_FX;
 		tmp &= ~(SET_FX | AT91_UDP_FORCESTALL);
@@ -1300,13 +1291,13 @@
 			if (udc->wait_for_addr_ack) {
 				u32	tmp;
 
-				at91_udp_write(AT91_UDP_FADDR,
+				at91_udp_write(udc, AT91_UDP_FADDR,
 						AT91_UDP_FEN | udc->addr);
-				tmp = at91_udp_read(AT91_UDP_GLB_STAT);
+				tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT);
 				tmp &= ~AT91_UDP_FADDEN;
 				if (udc->addr)
 					tmp |= AT91_UDP_FADDEN;
-				at91_udp_write(AT91_UDP_GLB_STAT, tmp);
+				at91_udp_write(udc, AT91_UDP_GLB_STAT, tmp);
 
 				udc->wait_for_addr_ack = 0;
 				VDBG("address %d\n", udc->addr);
@@ -1374,28 +1365,28 @@
 	while (rescans--) {
 		u32 status;
 
-		status = at91_udp_read(AT91_UDP_ISR)
-			& at91_udp_read(AT91_UDP_IMR);
+		status = at91_udp_read(udc, AT91_UDP_ISR)
+			& at91_udp_read(udc, AT91_UDP_IMR);
 		if (!status)
 			break;
 
 		/* USB reset irq:  not maskable */
 		if (status & AT91_UDP_ENDBUSRES) {
-			at91_udp_write(AT91_UDP_IDR, ~MINIMUS_INTERRUPTUS);
-			at91_udp_write(AT91_UDP_IER, MINIMUS_INTERRUPTUS);
+			at91_udp_write(udc, AT91_UDP_IDR, ~MINIMUS_INTERRUPTUS);
+			at91_udp_write(udc, AT91_UDP_IER, MINIMUS_INTERRUPTUS);
 			/* Atmel code clears this irq twice */
-			at91_udp_write(AT91_UDP_ICR, AT91_UDP_ENDBUSRES);
-			at91_udp_write(AT91_UDP_ICR, AT91_UDP_ENDBUSRES);
+			at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_ENDBUSRES);
+			at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_ENDBUSRES);
 			VDBG("end bus reset\n");
 			udc->addr = 0;
 			stop_activity(udc);
 
 			/* enable ep0 */
-			at91_udp_write(AT91_UDP_CSR(0),
+			at91_udp_write(udc, AT91_UDP_CSR(0),
 					AT91_UDP_EPEDS | AT91_UDP_EPTYPE_CTRL);
 			udc->gadget.speed = USB_SPEED_FULL;
 			udc->suspended = 0;
-			at91_udp_write(AT91_UDP_IER, AT91_UDP_EP(0));
+			at91_udp_write(udc, AT91_UDP_IER, AT91_UDP_EP(0));
 
 			/*
 			 * NOTE:  this driver keeps clocks off unless the
@@ -1406,9 +1397,9 @@
 
 		/* host initiated suspend (3+ms bus idle) */
 		} else if (status & AT91_UDP_RXSUSP) {
-			at91_udp_write(AT91_UDP_IDR, AT91_UDP_RXSUSP);
-			at91_udp_write(AT91_UDP_IER, AT91_UDP_RXRSM);
-			at91_udp_write(AT91_UDP_ICR, AT91_UDP_RXSUSP);
+			at91_udp_write(udc, AT91_UDP_IDR, AT91_UDP_RXSUSP);
+			at91_udp_write(udc, AT91_UDP_IER, AT91_UDP_RXRSM);
+			at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_RXSUSP);
 			// VDBG("bus suspend\n");
 			if (udc->suspended)
 				continue;
@@ -1425,9 +1416,9 @@
 
 		/* host initiated resume */
 		} else if (status & AT91_UDP_RXRSM) {
-			at91_udp_write(AT91_UDP_IDR, AT91_UDP_RXRSM);
-			at91_udp_write(AT91_UDP_IER, AT91_UDP_RXSUSP);
-			at91_udp_write(AT91_UDP_ICR, AT91_UDP_RXRSM);
+			at91_udp_write(udc, AT91_UDP_IDR, AT91_UDP_RXRSM);
+			at91_udp_write(udc, AT91_UDP_IER, AT91_UDP_RXSUSP);
+			at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_RXRSM);
 			// VDBG("bus resume\n");
 			if (!udc->suspended)
 				continue;
@@ -1485,8 +1476,6 @@
 		},
 		.udc		= &controller,
 		.maxpacket	= 8,
-		.creg		= (void __iomem *)(AT91_VA_BASE_UDP
-					+ AT91_UDP_CSR(0)),
 		.int_mask	= 1 << 0,
 	},
 	.ep[1] = {
@@ -1497,8 +1486,6 @@
 		.udc		= &controller,
 		.is_pingpong	= 1,
 		.maxpacket	= 64,
-		.creg		= (void __iomem *)(AT91_VA_BASE_UDP
-					+ AT91_UDP_CSR(1)),
 		.int_mask	= 1 << 1,
 	},
 	.ep[2] = {
@@ -1509,8 +1496,6 @@
 		.udc		= &controller,
 		.is_pingpong	= 1,
 		.maxpacket	= 64,
-		.creg		= (void __iomem *)(AT91_VA_BASE_UDP
-					+ AT91_UDP_CSR(2)),
 		.int_mask	= 1 << 2,
 	},
 	.ep[3] = {
@@ -1521,8 +1506,6 @@
 		},
 		.udc		= &controller,
 		.maxpacket	= 8,
-		.creg		= (void __iomem *)(AT91_VA_BASE_UDP
-					+ AT91_UDP_CSR(3)),
 		.int_mask	= 1 << 3,
 	},
 	.ep[4] = {
@@ -1533,8 +1516,6 @@
 		.udc		= &controller,
 		.is_pingpong	= 1,
 		.maxpacket	= 256,
-		.creg		= (void __iomem *)(AT91_VA_BASE_UDP
-					+ AT91_UDP_CSR(4)),
 		.int_mask	= 1 << 4,
 	},
 	.ep[5] = {
@@ -1545,8 +1526,6 @@
 		.udc		= &controller,
 		.is_pingpong	= 1,
 		.maxpacket	= 256,
-		.creg		= (void __iomem *)(AT91_VA_BASE_UDP
-					+ AT91_UDP_CSR(5)),
 		.int_mask	= 1 << 5,
 	},
 	/* ep6 and ep7 are also reserved (custom silicon might use them) */
@@ -1615,7 +1594,7 @@
 
 	local_irq_disable();
 	udc->enabled = 0;
-	at91_udp_write(AT91_UDP_IDR, ~0);
+	at91_udp_write(udc, AT91_UDP_IDR, ~0);
 	pullup(udc, 0);
 	local_irq_enable();
 
@@ -1640,6 +1619,7 @@
 	struct device	*dev = &pdev->dev;
 	struct at91_udc	*udc;
 	int		retval;
+	struct resource	*res;
 
 	if (!dev->platform_data) {
 		/* small (so we copy it) but critical! */
@@ -1657,7 +1637,13 @@
 		return -ENODEV;
 	}
 
-	if (!request_mem_region(AT91RM9200_BASE_UDP, SZ_16K, driver_name)) {
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENXIO;
+
+	if (!request_mem_region(res->start,
+			res->end - res->start + 1,
+			driver_name)) {
 		DBG("someone's using UDC memory\n");
 		return -EBUSY;
 	}
@@ -1667,9 +1653,16 @@
 	udc->gadget.dev.parent = dev;
 	udc->board = *(struct at91_udc_data *) dev->platform_data;
 	udc->pdev = pdev;
-	udc_reinit(udc);
 	udc->enabled = 0;
 
+	udc->udp_baseaddr = ioremap(res->start, res->end - res->start + 1);
+	if (!udc->udp_baseaddr) {
+		release_mem_region(res->start, res->end - res->start + 1);
+		return -ENOMEM;
+	}
+
+	udc_reinit(udc);
+
 	/* get interface and function clocks */
 	udc->iclk = clk_get(dev, "udc_clk");
 	udc->fclk = clk_get(dev, "udpck");
@@ -1684,8 +1677,8 @@
 
 	/* don't do anything until we have both gadget driver and VBUS */
 	clk_enable(udc->iclk);
-	at91_udp_write(AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS);
-	at91_udp_write(AT91_UDP_IDR, 0xffffffff);
+	at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS);
+	at91_udp_write(udc, AT91_UDP_IDR, 0xffffffff);
 	clk_disable(udc->iclk);
 
 	/* request UDC and maybe VBUS irqs */
@@ -1719,7 +1712,7 @@
 fail1:
 	device_unregister(&udc->gadget.dev);
 fail0:
-	release_mem_region(AT91RM9200_BASE_UDP, SZ_16K);
+	release_mem_region(res->start, res->end - res->start + 1);
 	DBG("%s probe failed, %d\n", driver_name, retval);
 	return retval;
 }
@@ -1727,6 +1720,7 @@
 static int __devexit at91udc_remove(struct platform_device *pdev)
 {
 	struct at91_udc *udc = platform_get_drvdata(pdev);
+	struct resource *res;
 
 	DBG("remove\n");
 
@@ -1741,7 +1735,10 @@
 		free_irq(udc->board.vbus_pin, udc);
 	free_irq(udc->udp_irq, udc);
 	device_unregister(&udc->gadget.dev);
-	release_mem_region(AT91RM9200_BASE_UDP, SZ_16K);
+
+	iounmap(udc->udp_baseaddr);
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	release_mem_region(res->start, res->end - res->start + 1);
 
 	clk_put(udc->iclk);
 	clk_put(udc->fclk);
diff --git a/drivers/usb/gadget/at91_udc.h b/drivers/usb/gadget/at91_udc.h
index 882af42..a35f3b6 100644
--- a/drivers/usb/gadget/at91_udc.h
+++ b/drivers/usb/gadget/at91_udc.h
@@ -141,6 +141,7 @@
 	struct clk			*iclk, *fclk;
 	struct platform_device		*pdev;
 	struct proc_dir_entry		*pde;
+	void __iomem			*udp_baseaddr;
 	int				udp_irq;
 };