summary refs log tree commit diff
path: root/drivers/usb/gadget
diff options
context:
space:
mode:
authorDavid Brownell <dbrownell@users.sourceforge.net>2008-01-05 13:21:43 -0800
committerGreg Kroah-Hartman <gregkh@suse.de>2008-02-01 14:35:01 -0800
commitf3db6e82034a6ea89191fdcc6b9a984dc0d5d533 (patch)
tree5ae328679bef284fc5fad4dd74137c1a52abcd61 /drivers/usb/gadget
parent4bde4a4c4ff53e67cde4b0fe630d6fc28106bff8 (diff)
downloadlinux-f3db6e82034a6ea89191fdcc6b9a984dc0d5d533.tar.gz
USB: at91_udc uses generic GPIO calls; minor cleanup
Various small at91_udc cleanups:

 - Use generic GPIO calls, not older platform-specific ones
 - Use gpio_request()/gpio_free()
 - Use VERBOSE_DEBUG convention, not older VERBOSE
 - Fix sparse complaint about parameter type (changed to gfp_t)
 - Add missing newline to some rarely-seen debug messages
 - Fix some old cleanup bugs on probe() fault paths

Also add a mechanism whereby rm9200 gpios can drive the D+ pullup
through an inverting transistor, based on a patch from Steve Birtles.
Most UDC drivers supporting a GPIO based pullup should probably have
such an option, but testing it requries such a board in hand!

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Cc: Steve Birtles <arm_kernel_development@micromark.net.cn>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

Diffstat (limited to 'drivers/usb/gadget')
-rw-r--r--drivers/usb/gadget/at91_udc.c79
-rw-r--r--drivers/usb/gadget/at91_udc.h2
2 files changed, 61 insertions, 20 deletions
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
index 305db36a3b1c..a83e8b798ec9 100644
--- a/drivers/usb/gadget/at91_udc.c
+++ b/drivers/usb/gadget/at91_udc.c
@@ -21,8 +21,7 @@
  * Boston, MA  02111-1307, USA.
  */
 
-#undef	DEBUG
-#undef	VERBOSE
+#undef	VERBOSE_DEBUG
 #undef	PACKET_TRACE
 
 #include <linux/kernel.h>
@@ -46,8 +45,8 @@
 #include <asm/irq.h>
 #include <asm/system.h>
 #include <asm/mach-types.h>
+#include <asm/gpio.h>
 
-#include <asm/arch/gpio.h>
 #include <asm/arch/board.h>
 #include <asm/arch/cpu.h>
 #include <asm/arch/at91sam9261_matrix.h>
@@ -580,7 +579,7 @@ static int at91_ep_disable (struct usb_ep * _ep)
  */
 
 static struct usb_request *
-at91_ep_alloc_request(struct usb_ep *_ep, unsigned int gfp_flags)
+at91_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
 {
 	struct at91_request *req;
 
@@ -881,6 +880,8 @@ static void clk_off(struct at91_udc *udc)
  */
 static void pullup(struct at91_udc *udc, int is_on)
 {
+	int	active = !udc->board.pullup_active_low;
+
 	if (!udc->enabled || !udc->vbus)
 		is_on = 0;
 	DBG("%sactive\n", is_on ? "" : "in");
@@ -890,7 +891,7 @@ static void pullup(struct at91_udc *udc, int is_on)
 		at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_RXRSM);
 		at91_udp_write(udc, AT91_UDP_TXVC, 0);
 		if (cpu_is_at91rm9200())
-			at91_set_gpio_value(udc->board.pullup_pin, 1);
+			gpio_set_value(udc->board.pullup_pin, active);
 		else if (cpu_is_at91sam9260() || cpu_is_at91sam9263()) {
 			u32	txvc = at91_udp_read(udc, AT91_UDP_TXVC);
 
@@ -908,7 +909,7 @@ static void pullup(struct at91_udc *udc, int is_on)
 		at91_udp_write(udc, AT91_UDP_IDR, AT91_UDP_RXRSM);
 		at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS);
 		if (cpu_is_at91rm9200())
-			at91_set_gpio_value(udc->board.pullup_pin, 0);
+			gpio_set_value(udc->board.pullup_pin, !active);
 		else if (cpu_is_at91sam9260() || cpu_is_at91sam9263()) {
 			u32	txvc = at91_udp_read(udc, AT91_UDP_TXVC);
 
@@ -1551,7 +1552,7 @@ static irqreturn_t at91_vbus_irq(int irq, void *_udc)
 
 	/* vbus needs at least brief debouncing */
 	udelay(10);
-	value = at91_get_gpio_value(udc->board.vbus_pin);
+	value = gpio_get_value(udc->board.vbus_pin);
 	if (value != udc->vbus)
 		at91_vbus_session(&udc->gadget, value);
 
@@ -1647,12 +1648,12 @@ static int __init at91udc_probe(struct platform_device *pdev)
 	}
 
 	if (pdev->num_resources != 2) {
-		DBG("invalid num_resources");
+		DBG("invalid num_resources\n");
 		return -ENODEV;
 	}
 	if ((pdev->resource[0].flags != IORESOURCE_MEM)
 			|| (pdev->resource[1].flags != IORESOURCE_IRQ)) {
-		DBG("invalid resource type");
+		DBG("invalid resource type\n");
 		return -ENODEV;
 	}
 
@@ -1674,10 +1675,26 @@ static int __init at91udc_probe(struct platform_device *pdev)
 	udc->pdev = pdev;
 	udc->enabled = 0;
 
+	/* rm9200 needs manual D+ pullup; off by default */
+	if (cpu_is_at91rm9200()) {
+		if (udc->board.pullup_pin <= 0) {
+			DBG("no D+ pullup?\n");
+			retval = -ENODEV;
+			goto fail0;
+		}
+		retval = gpio_request(udc->board.pullup_pin, "udc_pullup");
+		if (retval) {
+			DBG("D+ pullup is busy\n");
+			goto fail0;
+		}
+		gpio_direction_output(udc->board.pullup_pin,
+				udc->board.pullup_active_low);
+	}
+
 	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;
+		retval = -ENOMEM;
+		goto fail0a;
 	}
 
 	udc_reinit(udc);
@@ -1688,12 +1705,13 @@ static int __init at91udc_probe(struct platform_device *pdev)
 	if (IS_ERR(udc->iclk) || IS_ERR(udc->fclk)) {
 		DBG("clocks missing\n");
 		retval = -ENODEV;
-		goto fail0;
+		/* NOTE: we "know" here that refcounts on these are NOPs */
+		goto fail0b;
 	}
 
 	retval = device_register(&udc->gadget.dev);
 	if (retval < 0)
-		goto fail0;
+		goto fail0b;
 
 	/* don't do anything until we have both gadget driver and VBUS */
 	clk_enable(udc->iclk);
@@ -1705,25 +1723,32 @@ static int __init at91udc_probe(struct platform_device *pdev)
 
 	/* request UDC and maybe VBUS irqs */
 	udc->udp_irq = platform_get_irq(pdev, 0);
-	if (request_irq(udc->udp_irq, at91_udc_irq,
-			IRQF_DISABLED, driver_name, udc)) {
+	retval = request_irq(udc->udp_irq, at91_udc_irq,
+			IRQF_DISABLED, driver_name, udc);
+	if (retval < 0) {
 		DBG("request irq %d failed\n", udc->udp_irq);
-		retval = -EBUSY;
 		goto fail1;
 	}
 	if (udc->board.vbus_pin > 0) {
+		retval = gpio_request(udc->board.vbus_pin, "udc_vbus");
+		if (retval < 0) {
+			DBG("request vbus pin failed\n");
+			goto fail2;
+		}
+		gpio_direction_input(udc->board.vbus_pin);
+
 		/*
 		 * Get the initial state of VBUS - we cannot expect
 		 * a pending interrupt.
 		 */
-		udc->vbus = at91_get_gpio_value(udc->board.vbus_pin);
+		udc->vbus = gpio_get_value(udc->board.vbus_pin);
 		if (request_irq(udc->board.vbus_pin, at91_vbus_irq,
 				IRQF_DISABLED, driver_name, udc)) {
 			DBG("request vbus irq %d failed\n",
 					udc->board.vbus_pin);
 			free_irq(udc->udp_irq, udc);
 			retval = -EBUSY;
-			goto fail1;
+			goto fail3;
 		}
 	} else {
 		DBG("no VBUS detection, assuming always-on\n");
@@ -1736,8 +1761,18 @@ static int __init at91udc_probe(struct platform_device *pdev)
 	INFO("%s version %s\n", driver_name, DRIVER_VERSION);
 	return 0;
 
+fail3:
+	if (udc->board.vbus_pin > 0)
+		gpio_free(udc->board.vbus_pin);
+fail2:
+	free_irq(udc->udp_irq, udc);
 fail1:
 	device_unregister(&udc->gadget.dev);
+fail0b:
+	iounmap(udc->udp_baseaddr);
+fail0a:
+	if (cpu_is_at91rm9200())
+		gpio_free(udc->board.pullup_pin);
 fail0:
 	release_mem_region(res->start, res->end - res->start + 1);
 	DBG("%s probe failed, %d\n", driver_name, retval);
@@ -1758,12 +1793,18 @@ static int __exit at91udc_remove(struct platform_device *pdev)
 
 	device_init_wakeup(&pdev->dev, 0);
 	remove_debug_file(udc);
-	if (udc->board.vbus_pin > 0)
+	if (udc->board.vbus_pin > 0) {
 		free_irq(udc->board.vbus_pin, udc);
+		gpio_free(udc->board.vbus_pin);
+	}
 	free_irq(udc->udp_irq, udc);
 	device_unregister(&udc->gadget.dev);
 
 	iounmap(udc->udp_baseaddr);
+
+	if (cpu_is_at91rm9200())
+		gpio_free(udc->board.pullup_pin);
+
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	release_mem_region(res->start, res->end - res->start + 1);
 
diff --git a/drivers/usb/gadget/at91_udc.h b/drivers/usb/gadget/at91_udc.h
index f3095a90a0ee..a973f2a50fb9 100644
--- a/drivers/usb/gadget/at91_udc.h
+++ b/drivers/usb/gadget/at91_udc.h
@@ -158,7 +158,7 @@ struct at91_request {
 
 /*-------------------------------------------------------------------------*/
 
-#ifdef VERBOSE
+#ifdef VERBOSE_DEBUG
 #    define VDBG		DBG
 #else
 #    define VDBG(stuff...)	do{}while(0)