Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f3db6e82 authored by David Brownell's avatar David Brownell Committed by Greg Kroah-Hartman
Browse files

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: default avatarDavid Brownell <dbrownell@users.sourceforge.net>
Cc: Steve Birtles <arm_kernel_development@micromark.net.cn>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 4bde4a4c
Loading
Loading
Loading
Loading
+60 −19
Original line number Diff line number Diff line
@@ -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);

+1 −1
Original line number Diff line number Diff line
@@ -158,7 +158,7 @@ struct at91_request {

/*-------------------------------------------------------------------------*/

#ifdef VERBOSE
#ifdef VERBOSE_DEBUG
#    define VDBG		DBG
#else
#    define VDBG(stuff...)	do{}while(0)
+2 −1
Original line number Diff line number Diff line
@@ -40,7 +40,8 @@
 /* USB Device */
struct at91_udc_data {
	u8	vbus_pin;		/* high == host powering us */
	u8	pullup_pin;		/* high == D+ pulled up */
	u8	pullup_pin;		/* active == D+ pulled up */
	u8	pullup_active_low;	/* true == pullup_pin is active low */
};
extern void __init at91_add_device_udc(struct at91_udc_data *data);