aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Brownell <david-b@pacbell.net>2006-06-29 15:25:39 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2006-09-27 14:58:48 -0400
commitb2bbb20b37d734443d1c279d0033a64f6095db54 (patch)
tree067510f143dcb0e4f938f932994e5ac34f5da6b9
parent3a16f7b4a75d68364c3278523f51ac141a12758a (diff)
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: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--arch/arm/mach-pxa/corgi.c15
-rw-r--r--drivers/usb/gadget/pxa2xx_udc.c70
-rw-r--r--drivers/usb/gadget/pxa2xx_udc.h24
-rw-r--r--include/asm-arm/arch-pxa/udc.h8
4 files changed, 85 insertions, 32 deletions
diff --git a/arch/arm/mach-pxa/corgi.c b/arch/arm/mach-pxa/corgi.c
index cce26576999e..337c01c4ac37 100644
--- a/arch/arm/mach-pxa/corgi.c
+++ b/arch/arm/mach-pxa/corgi.c
@@ -284,21 +284,9 @@ static struct pxaficp_platform_data corgi_ficp_platform_data = {
284/* 284/*
285 * USB Device Controller 285 * USB Device Controller
286 */ 286 */
287static void corgi_udc_command(int cmd)
288{
289 switch(cmd) {
290 case PXA2XX_UDC_CMD_CONNECT:
291 GPSR(CORGI_GPIO_USB_PULLUP) = GPIO_bit(CORGI_GPIO_USB_PULLUP);
292 break;
293 case PXA2XX_UDC_CMD_DISCONNECT:
294 GPCR(CORGI_GPIO_USB_PULLUP) = GPIO_bit(CORGI_GPIO_USB_PULLUP);
295 break;
296 }
297}
298
299static struct pxa2xx_udc_mach_info udc_info __initdata = { 287static struct pxa2xx_udc_mach_info udc_info __initdata = {
300 /* no connect GPIO; corgi can't tell connection status */ 288 /* no connect GPIO; corgi can't tell connection status */
301 .udc_command = corgi_udc_command, 289 .gpio_pullup = CORGI_GPIO_USB_PULLUP,
302}; 290};
303 291
304 292
@@ -350,7 +338,6 @@ static void __init corgi_init(void)
350 corgi_ssp_set_machinfo(&corgi_ssp_machinfo); 338 corgi_ssp_set_machinfo(&corgi_ssp_machinfo);
351 339
352 pxa_gpio_mode(CORGI_GPIO_IR_ON | GPIO_OUT); 340 pxa_gpio_mode(CORGI_GPIO_IR_ON | GPIO_OUT);
353 pxa_gpio_mode(CORGI_GPIO_USB_PULLUP | GPIO_OUT);
354 pxa_gpio_mode(CORGI_GPIO_HSYNC | GPIO_IN); 341 pxa_gpio_mode(CORGI_GPIO_HSYNC | GPIO_IN);
355 342
356 pxa_set_udc_info(&udc_info); 343 pxa_set_udc_info(&udc_info);
diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c
index fff027d30a09..f1adcf8b2023 100644
--- a/drivers/usb/gadget/pxa2xx_udc.c
+++ b/drivers/usb/gadget/pxa2xx_udc.c
@@ -150,6 +150,39 @@ MODULE_PARM_DESC (fifo_mode, "pxa2xx udc fifo mode");
150static void pxa2xx_ep_fifo_flush (struct usb_ep *ep); 150static void pxa2xx_ep_fifo_flush (struct usb_ep *ep);
151static void nuke (struct pxa2xx_ep *, int status); 151static void nuke (struct pxa2xx_ep *, int status);
152 152
153/* one GPIO should be used to detect VBUS from the host */
154static int is_vbus_present(void)
155{
156 struct pxa2xx_udc_mach_info *mach = the_controller->mach;
157
158 if (mach->gpio_vbus)
159 return pxa_gpio_get(mach->gpio_vbus);
160 if (mach->udc_is_connected)
161 return mach->udc_is_connected();
162 return 1;
163}
164
165/* one GPIO should control a D+ pullup, so host sees this device (or not) */
166static void pullup_off(void)
167{
168 struct pxa2xx_udc_mach_info *mach = the_controller->mach;
169
170 if (mach->gpio_pullup)
171 pxa_gpio_set(mach->gpio_pullup, 0);
172 else if (mach->udc_command)
173 mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT);
174}
175
176static void pullup_on(void)
177{
178 struct pxa2xx_udc_mach_info *mach = the_controller->mach;
179
180 if (mach->gpio_pullup)
181 pxa_gpio_set(mach->gpio_pullup, 1);
182 else if (mach->udc_command)
183 mach->udc_command(PXA2XX_UDC_CMD_CONNECT);
184}
185
153static void pio_irq_enable(int bEndpointAddress) 186static void pio_irq_enable(int bEndpointAddress)
154{ 187{
155 bEndpointAddress &= 0xf; 188 bEndpointAddress &= 0xf;
@@ -1721,6 +1754,16 @@ lubbock_vbus_irq(int irq, void *_dev, struct pt_regs *r)
1721 1754
1722#endif 1755#endif
1723 1756
1757static irqreturn_t
1758udc_vbus_irq(int irq, void *_dev, struct pt_regs *r)
1759{
1760 struct pxa2xx_udc *dev = _dev;
1761 int vbus = pxa_gpio_get(dev->mach->gpio_vbus);
1762
1763 pxa2xx_udc_vbus_session(&dev->gadget, vbus);
1764 return IRQ_HANDLED;
1765}
1766
1724 1767
1725/*-------------------------------------------------------------------------*/ 1768/*-------------------------------------------------------------------------*/
1726 1769
@@ -2438,7 +2481,7 @@ static struct pxa2xx_udc memory = {
2438static int __init pxa2xx_udc_probe(struct platform_device *pdev) 2481static int __init pxa2xx_udc_probe(struct platform_device *pdev)
2439{ 2482{
2440 struct pxa2xx_udc *dev = &memory; 2483 struct pxa2xx_udc *dev = &memory;
2441 int retval, out_dma = 1; 2484 int retval, out_dma = 1, vbus_irq;
2442 u32 chiprev; 2485 u32 chiprev;
2443 2486
2444 /* insist on Intel/ARM/XScale */ 2487 /* insist on Intel/ARM/XScale */
@@ -2502,6 +2545,16 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
2502 /* other non-static parts of init */ 2545 /* other non-static parts of init */
2503 dev->dev = &pdev->dev; 2546 dev->dev = &pdev->dev;
2504 dev->mach = pdev->dev.platform_data; 2547 dev->mach = pdev->dev.platform_data;
2548 if (dev->mach->gpio_vbus) {
2549 vbus_irq = IRQ_GPIO(dev->mach->gpio_vbus & GPIO_MD_MASK_NR);
2550 pxa_gpio_mode((dev->mach->gpio_vbus & GPIO_MD_MASK_NR)
2551 | GPIO_IN);
2552 set_irq_type(vbus_irq, IRQT_BOTHEDGE);
2553 } else
2554 vbus_irq = 0;
2555 if (dev->mach->gpio_pullup)
2556 pxa_gpio_mode((dev->mach->gpio_pullup & GPIO_MD_MASK_NR)
2557 | GPIO_OUT | GPIO_DFLT_LOW);
2505 2558
2506 init_timer(&dev->timer); 2559 init_timer(&dev->timer);
2507 dev->timer.function = udc_watchdog; 2560 dev->timer.function = udc_watchdog;
@@ -2557,8 +2610,19 @@ lubbock_fail0:
2557 HEX_DISPLAY(dev->stats.irqs); 2610 HEX_DISPLAY(dev->stats.irqs);
2558 LUB_DISC_BLNK_LED &= 0xff; 2611 LUB_DISC_BLNK_LED &= 0xff;
2559#endif 2612#endif
2560 } 2613 } else
2561#endif 2614#endif
2615 if (vbus_irq) {
2616 retval = request_irq(vbus_irq, udc_vbus_irq,
2617 SA_INTERRUPT | SA_SAMPLE_RANDOM,
2618 driver_name, dev);
2619 if (retval != 0) {
2620 printk(KERN_ERR "%s: can't get irq %i, err %d\n",
2621 driver_name, vbus_irq, retval);
2622 free_irq(IRQ_USB, dev);
2623 return -EBUSY;
2624 }
2625 }
2562 create_proc_files(); 2626 create_proc_files();
2563 2627
2564 return 0; 2628 return 0;
@@ -2587,6 +2651,8 @@ static int __exit pxa2xx_udc_remove(struct platform_device *pdev)
2587 free_irq(LUBBOCK_USB_IRQ, dev); 2651 free_irq(LUBBOCK_USB_IRQ, dev);
2588 } 2652 }
2589#endif 2653#endif
2654 if (dev->mach->gpio_vbus)
2655 free_irq(IRQ_GPIO(dev->mach->gpio_vbus), dev);
2590 platform_set_drvdata(pdev, NULL); 2656 platform_set_drvdata(pdev, NULL);
2591 the_controller = NULL; 2657 the_controller = NULL;
2592 return 0; 2658 return 0;
diff --git a/drivers/usb/gadget/pxa2xx_udc.h b/drivers/usb/gadget/pxa2xx_udc.h
index 19a883f7d1b8..8e598c8bf4e3 100644
--- a/drivers/usb/gadget/pxa2xx_udc.h
+++ b/drivers/usb/gadget/pxa2xx_udc.h
@@ -177,27 +177,19 @@ struct pxa2xx_udc {
177 177
178static struct pxa2xx_udc *the_controller; 178static struct pxa2xx_udc *the_controller;
179 179
180/* one GPIO should be used to detect VBUS from the host */ 180static inline int pxa_gpio_get(unsigned gpio)
181static inline int is_vbus_present(void)
182{ 181{
183 if (!the_controller->mach->udc_is_connected) 182 return (GPLR(gpio) & GPIO_bit(gpio)) != 0;
184 return 1;
185 return the_controller->mach->udc_is_connected();
186} 183}
187 184
188/* one GPIO should control a D+ pullup, so host sees this device (or not) */ 185static inline void pxa_gpio_set(unsigned gpio, int is_on)
189static inline void pullup_off(void)
190{ 186{
191 if (!the_controller->mach->udc_command) 187 int mask = GPIO_bit(gpio);
192 return;
193 the_controller->mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT);
194}
195 188
196static inline void pullup_on(void) 189 if (is_on)
197{ 190 GPSR(gpio) = mask;
198 if (!the_controller->mach->udc_command) 191 else
199 return; 192 GPCR(gpio) = mask;
200 the_controller->mach->udc_command(PXA2XX_UDC_CMD_CONNECT);
201} 193}
202 194
203/*-------------------------------------------------------------------------*/ 195/*-------------------------------------------------------------------------*/
diff --git a/include/asm-arm/arch-pxa/udc.h b/include/asm-arm/arch-pxa/udc.h
index 30548a30c773..121cd241115d 100644
--- a/include/asm-arm/arch-pxa/udc.h
+++ b/include/asm-arm/arch-pxa/udc.h
@@ -12,6 +12,14 @@ struct pxa2xx_udc_mach_info {
12 void (*udc_command)(int cmd); 12 void (*udc_command)(int cmd);
13#define PXA2XX_UDC_CMD_CONNECT 0 /* let host see us */ 13#define PXA2XX_UDC_CMD_CONNECT 0 /* let host see us */
14#define PXA2XX_UDC_CMD_DISCONNECT 1 /* so host won't see us */ 14#define PXA2XX_UDC_CMD_DISCONNECT 1 /* so host won't see us */
15
16 /* Boards following the design guidelines in the developer's manual,
17 * with on-chip GPIOs not Lubbock's wierd hardware, can have a sane
18 * VBUS IRQ and omit the methods above. Store the GPIO number
19 * here; for GPIO 0, also mask in one of the pxa_gpio_mode() bits.
20 */
21 u16 gpio_vbus; /* high == vbus present */
22 u16 gpio_pullup; /* high == pullup activated */
15}; 23};
16 24
17extern void pxa_set_udc_info(struct pxa2xx_udc_mach_info *info); 25extern void pxa_set_udc_info(struct pxa2xx_udc_mach_info *info);