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

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

USB: pxa2xx_udc understands GPIO based VBUS sensing



This updates the PXA 25x UDC board-independent infrastructure for VBUS sensing
and the D+ pullup.  The original code evolved from rather bizarre support on
Intel's "Lubbock" reference hardware, so that on more sensible hardware it
doesn't work as well as it could/should.

The change is just to teach the UDC driver how to use built-in PXA GPIO pins
directly.  This reduces the amount of board-specfic object code needed, and
enables the use of a VBUS sensing IRQ on boards (like Gumstix) that have one.
With VBUS sensing, the UDC is unclocked until a host is actually connected.

Signed-off-by: default avatarDavid Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 3a16f7b4
Loading
Loading
Loading
Loading
+1 −14
Original line number Diff line number Diff line
@@ -284,21 +284,9 @@ static struct pxaficp_platform_data corgi_ficp_platform_data = {
/*
 * USB Device Controller
 */
static void corgi_udc_command(int cmd)
{
	switch(cmd)	{
	case PXA2XX_UDC_CMD_CONNECT:
		GPSR(CORGI_GPIO_USB_PULLUP) = GPIO_bit(CORGI_GPIO_USB_PULLUP);
		break;
	case PXA2XX_UDC_CMD_DISCONNECT:
		GPCR(CORGI_GPIO_USB_PULLUP) = GPIO_bit(CORGI_GPIO_USB_PULLUP);
		break;
	}
}

static struct pxa2xx_udc_mach_info udc_info __initdata = {
	/* no connect GPIO; corgi can't tell connection status */
	.udc_command		= corgi_udc_command,
	.gpio_pullup		= CORGI_GPIO_USB_PULLUP,
};


@@ -350,7 +338,6 @@ static void __init corgi_init(void)
	corgi_ssp_set_machinfo(&corgi_ssp_machinfo);

	pxa_gpio_mode(CORGI_GPIO_IR_ON | GPIO_OUT);
	pxa_gpio_mode(CORGI_GPIO_USB_PULLUP | GPIO_OUT);
	pxa_gpio_mode(CORGI_GPIO_HSYNC | GPIO_IN);

 	pxa_set_udc_info(&udc_info);
+68 −2
Original line number Diff line number Diff line
@@ -150,6 +150,39 @@ MODULE_PARM_DESC (fifo_mode, "pxa2xx udc fifo mode");
static void pxa2xx_ep_fifo_flush (struct usb_ep *ep);
static void nuke (struct pxa2xx_ep *, int status);

/* one GPIO should be used to detect VBUS from the host */
static int is_vbus_present(void)
{
	struct pxa2xx_udc_mach_info		*mach = the_controller->mach;

	if (mach->gpio_vbus)
		return pxa_gpio_get(mach->gpio_vbus);
	if (mach->udc_is_connected)
		return mach->udc_is_connected();
	return 1;
}

/* one GPIO should control a D+ pullup, so host sees this device (or not) */
static void pullup_off(void)
{
	struct pxa2xx_udc_mach_info		*mach = the_controller->mach;

	if (mach->gpio_pullup)
		pxa_gpio_set(mach->gpio_pullup, 0);
	else if (mach->udc_command)
		mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT);
}

static void pullup_on(void)
{
	struct pxa2xx_udc_mach_info		*mach = the_controller->mach;

	if (mach->gpio_pullup)
		pxa_gpio_set(mach->gpio_pullup, 1);
	else if (mach->udc_command)
		mach->udc_command(PXA2XX_UDC_CMD_CONNECT);
}

static void pio_irq_enable(int bEndpointAddress)
{
        bEndpointAddress &= 0xf;
@@ -1721,6 +1754,16 @@ lubbock_vbus_irq(int irq, void *_dev, struct pt_regs *r)

#endif

static irqreturn_t
udc_vbus_irq(int irq, void *_dev, struct pt_regs *r)
{
	struct pxa2xx_udc	*dev = _dev;
	int			vbus = pxa_gpio_get(dev->mach->gpio_vbus);

	pxa2xx_udc_vbus_session(&dev->gadget, vbus);
	return IRQ_HANDLED;
}


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

@@ -2438,7 +2481,7 @@ static struct pxa2xx_udc memory = {
static int __init pxa2xx_udc_probe(struct platform_device *pdev)
{
	struct pxa2xx_udc *dev = &memory;
	int retval, out_dma = 1;
	int retval, out_dma = 1, vbus_irq;
	u32 chiprev;

	/* insist on Intel/ARM/XScale */
@@ -2502,6 +2545,16 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
	/* other non-static parts of init */
	dev->dev = &pdev->dev;
	dev->mach = pdev->dev.platform_data;
	if (dev->mach->gpio_vbus) {
		vbus_irq = IRQ_GPIO(dev->mach->gpio_vbus & GPIO_MD_MASK_NR);
		pxa_gpio_mode((dev->mach->gpio_vbus & GPIO_MD_MASK_NR)
				| GPIO_IN);
		set_irq_type(vbus_irq, IRQT_BOTHEDGE);
	} else
		vbus_irq = 0;
	if (dev->mach->gpio_pullup)
		pxa_gpio_mode((dev->mach->gpio_pullup & GPIO_MD_MASK_NR)
				| GPIO_OUT | GPIO_DFLT_LOW);

	init_timer(&dev->timer);
	dev->timer.function = udc_watchdog;
@@ -2557,8 +2610,19 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
		HEX_DISPLAY(dev->stats.irqs);
		LUB_DISC_BLNK_LED &= 0xff;
#endif
	}
	} else
#endif
	if (vbus_irq) {
		retval = request_irq(vbus_irq, udc_vbus_irq,
				SA_INTERRUPT | SA_SAMPLE_RANDOM,
				driver_name, dev);
		if (retval != 0) {
			printk(KERN_ERR "%s: can't get irq %i, err %d\n",
				driver_name, vbus_irq, retval);
			free_irq(IRQ_USB, dev);
			return -EBUSY;
		}
	}
	create_proc_files();

	return 0;
@@ -2587,6 +2651,8 @@ static int __exit pxa2xx_udc_remove(struct platform_device *pdev)
		free_irq(LUBBOCK_USB_IRQ, dev);
	}
#endif
	if (dev->mach->gpio_vbus)
		free_irq(IRQ_GPIO(dev->mach->gpio_vbus), dev);
	platform_set_drvdata(pdev, NULL);
	the_controller = NULL;
	return 0;
+8 −16
Original line number Diff line number Diff line
@@ -177,27 +177,19 @@ struct pxa2xx_udc {

static struct pxa2xx_udc *the_controller;

/* one GPIO should be used to detect VBUS from the host */
static inline int is_vbus_present(void)
static inline int pxa_gpio_get(unsigned gpio)
{
	if (!the_controller->mach->udc_is_connected)
		return 1;
	return the_controller->mach->udc_is_connected();
	return (GPLR(gpio) & GPIO_bit(gpio)) != 0;
}

/* one GPIO should control a D+ pullup, so host sees this device (or not) */
static inline void pullup_off(void)
static inline void pxa_gpio_set(unsigned gpio, int is_on)
{
	if (!the_controller->mach->udc_command)
		return;
	the_controller->mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT);
}
	int mask = GPIO_bit(gpio);

static inline void pullup_on(void)
{
	if (!the_controller->mach->udc_command)
		return;
	the_controller->mach->udc_command(PXA2XX_UDC_CMD_CONNECT);
	if (is_on)
		GPSR(gpio) = mask;
	else
		GPCR(gpio) = mask;
}

/*-------------------------------------------------------------------------*/
+8 −0
Original line number Diff line number Diff line
@@ -12,6 +12,14 @@ struct pxa2xx_udc_mach_info {
        void (*udc_command)(int cmd);
#define	PXA2XX_UDC_CMD_CONNECT		0	/* let host see us */
#define	PXA2XX_UDC_CMD_DISCONNECT	1	/* so host won't see us */

	/* Boards following the design guidelines in the developer's manual,
	 * with on-chip GPIOs not Lubbock's wierd hardware, can have a sane
	 * VBUS IRQ and omit the methods above.  Store the GPIO number
	 * here; for GPIO 0, also mask in one of the pxa_gpio_mode() bits.
	 */
	u16	gpio_vbus;			/* high == vbus present */
	u16	gpio_pullup;			/* high == pullup activated */
};

extern void pxa_set_udc_info(struct pxa2xx_udc_mach_info *info);