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>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
4bde4a4c4f
commit
f3db6e8203
@@ -21,8 +21,7 @@
|
|||||||
* Boston, MA 02111-1307, USA.
|
* Boston, MA 02111-1307, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#undef DEBUG
|
#undef VERBOSE_DEBUG
|
||||||
#undef VERBOSE
|
|
||||||
#undef PACKET_TRACE
|
#undef PACKET_TRACE
|
||||||
|
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
@@ -46,8 +45,8 @@
|
|||||||
#include <asm/irq.h>
|
#include <asm/irq.h>
|
||||||
#include <asm/system.h>
|
#include <asm/system.h>
|
||||||
#include <asm/mach-types.h>
|
#include <asm/mach-types.h>
|
||||||
|
#include <asm/gpio.h>
|
||||||
|
|
||||||
#include <asm/arch/gpio.h>
|
|
||||||
#include <asm/arch/board.h>
|
#include <asm/arch/board.h>
|
||||||
#include <asm/arch/cpu.h>
|
#include <asm/arch/cpu.h>
|
||||||
#include <asm/arch/at91sam9261_matrix.h>
|
#include <asm/arch/at91sam9261_matrix.h>
|
||||||
@@ -580,7 +579,7 @@ static int at91_ep_disable (struct usb_ep * _ep)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
static struct usb_request *
|
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;
|
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)
|
static void pullup(struct at91_udc *udc, int is_on)
|
||||||
{
|
{
|
||||||
|
int active = !udc->board.pullup_active_low;
|
||||||
|
|
||||||
if (!udc->enabled || !udc->vbus)
|
if (!udc->enabled || !udc->vbus)
|
||||||
is_on = 0;
|
is_on = 0;
|
||||||
DBG("%sactive\n", is_on ? "" : "in");
|
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_ICR, AT91_UDP_RXRSM);
|
||||||
at91_udp_write(udc, AT91_UDP_TXVC, 0);
|
at91_udp_write(udc, AT91_UDP_TXVC, 0);
|
||||||
if (cpu_is_at91rm9200())
|
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()) {
|
else if (cpu_is_at91sam9260() || cpu_is_at91sam9263()) {
|
||||||
u32 txvc = at91_udp_read(udc, AT91_UDP_TXVC);
|
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_IDR, AT91_UDP_RXRSM);
|
||||||
at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS);
|
at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS);
|
||||||
if (cpu_is_at91rm9200())
|
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()) {
|
else if (cpu_is_at91sam9260() || cpu_is_at91sam9263()) {
|
||||||
u32 txvc = at91_udp_read(udc, AT91_UDP_TXVC);
|
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 */
|
/* vbus needs at least brief debouncing */
|
||||||
udelay(10);
|
udelay(10);
|
||||||
value = at91_get_gpio_value(udc->board.vbus_pin);
|
value = gpio_get_value(udc->board.vbus_pin);
|
||||||
if (value != udc->vbus)
|
if (value != udc->vbus)
|
||||||
at91_vbus_session(&udc->gadget, value);
|
at91_vbus_session(&udc->gadget, value);
|
||||||
|
|
||||||
@@ -1647,12 +1648,12 @@ static int __init at91udc_probe(struct platform_device *pdev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (pdev->num_resources != 2) {
|
if (pdev->num_resources != 2) {
|
||||||
DBG("invalid num_resources");
|
DBG("invalid num_resources\n");
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
if ((pdev->resource[0].flags != IORESOURCE_MEM)
|
if ((pdev->resource[0].flags != IORESOURCE_MEM)
|
||||||
|| (pdev->resource[1].flags != IORESOURCE_IRQ)) {
|
|| (pdev->resource[1].flags != IORESOURCE_IRQ)) {
|
||||||
DBG("invalid resource type");
|
DBG("invalid resource type\n");
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1674,10 +1675,26 @@ static int __init at91udc_probe(struct platform_device *pdev)
|
|||||||
udc->pdev = pdev;
|
udc->pdev = pdev;
|
||||||
udc->enabled = 0;
|
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);
|
udc->udp_baseaddr = ioremap(res->start, res->end - res->start + 1);
|
||||||
if (!udc->udp_baseaddr) {
|
if (!udc->udp_baseaddr) {
|
||||||
release_mem_region(res->start, res->end - res->start + 1);
|
retval = -ENOMEM;
|
||||||
return -ENOMEM;
|
goto fail0a;
|
||||||
}
|
}
|
||||||
|
|
||||||
udc_reinit(udc);
|
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)) {
|
if (IS_ERR(udc->iclk) || IS_ERR(udc->fclk)) {
|
||||||
DBG("clocks missing\n");
|
DBG("clocks missing\n");
|
||||||
retval = -ENODEV;
|
retval = -ENODEV;
|
||||||
goto fail0;
|
/* NOTE: we "know" here that refcounts on these are NOPs */
|
||||||
|
goto fail0b;
|
||||||
}
|
}
|
||||||
|
|
||||||
retval = device_register(&udc->gadget.dev);
|
retval = device_register(&udc->gadget.dev);
|
||||||
if (retval < 0)
|
if (retval < 0)
|
||||||
goto fail0;
|
goto fail0b;
|
||||||
|
|
||||||
/* don't do anything until we have both gadget driver and VBUS */
|
/* don't do anything until we have both gadget driver and VBUS */
|
||||||
clk_enable(udc->iclk);
|
clk_enable(udc->iclk);
|
||||||
@@ -1705,25 +1723,32 @@ static int __init at91udc_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
/* request UDC and maybe VBUS irqs */
|
/* request UDC and maybe VBUS irqs */
|
||||||
udc->udp_irq = platform_get_irq(pdev, 0);
|
udc->udp_irq = platform_get_irq(pdev, 0);
|
||||||
if (request_irq(udc->udp_irq, at91_udc_irq,
|
retval = request_irq(udc->udp_irq, at91_udc_irq,
|
||||||
IRQF_DISABLED, driver_name, udc)) {
|
IRQF_DISABLED, driver_name, udc);
|
||||||
|
if (retval < 0) {
|
||||||
DBG("request irq %d failed\n", udc->udp_irq);
|
DBG("request irq %d failed\n", udc->udp_irq);
|
||||||
retval = -EBUSY;
|
|
||||||
goto fail1;
|
goto fail1;
|
||||||
}
|
}
|
||||||
if (udc->board.vbus_pin > 0) {
|
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
|
* Get the initial state of VBUS - we cannot expect
|
||||||
* a pending interrupt.
|
* 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,
|
if (request_irq(udc->board.vbus_pin, at91_vbus_irq,
|
||||||
IRQF_DISABLED, driver_name, udc)) {
|
IRQF_DISABLED, driver_name, udc)) {
|
||||||
DBG("request vbus irq %d failed\n",
|
DBG("request vbus irq %d failed\n",
|
||||||
udc->board.vbus_pin);
|
udc->board.vbus_pin);
|
||||||
free_irq(udc->udp_irq, udc);
|
free_irq(udc->udp_irq, udc);
|
||||||
retval = -EBUSY;
|
retval = -EBUSY;
|
||||||
goto fail1;
|
goto fail3;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
DBG("no VBUS detection, assuming always-on\n");
|
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);
|
INFO("%s version %s\n", driver_name, DRIVER_VERSION);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
fail3:
|
||||||
|
if (udc->board.vbus_pin > 0)
|
||||||
|
gpio_free(udc->board.vbus_pin);
|
||||||
|
fail2:
|
||||||
|
free_irq(udc->udp_irq, udc);
|
||||||
fail1:
|
fail1:
|
||||||
device_unregister(&udc->gadget.dev);
|
device_unregister(&udc->gadget.dev);
|
||||||
|
fail0b:
|
||||||
|
iounmap(udc->udp_baseaddr);
|
||||||
|
fail0a:
|
||||||
|
if (cpu_is_at91rm9200())
|
||||||
|
gpio_free(udc->board.pullup_pin);
|
||||||
fail0:
|
fail0:
|
||||||
release_mem_region(res->start, res->end - res->start + 1);
|
release_mem_region(res->start, res->end - res->start + 1);
|
||||||
DBG("%s probe failed, %d\n", driver_name, retval);
|
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);
|
device_init_wakeup(&pdev->dev, 0);
|
||||||
remove_debug_file(udc);
|
remove_debug_file(udc);
|
||||||
if (udc->board.vbus_pin > 0)
|
if (udc->board.vbus_pin > 0) {
|
||||||
free_irq(udc->board.vbus_pin, udc);
|
free_irq(udc->board.vbus_pin, udc);
|
||||||
|
gpio_free(udc->board.vbus_pin);
|
||||||
|
}
|
||||||
free_irq(udc->udp_irq, udc);
|
free_irq(udc->udp_irq, udc);
|
||||||
device_unregister(&udc->gadget.dev);
|
device_unregister(&udc->gadget.dev);
|
||||||
|
|
||||||
iounmap(udc->udp_baseaddr);
|
iounmap(udc->udp_baseaddr);
|
||||||
|
|
||||||
|
if (cpu_is_at91rm9200())
|
||||||
|
gpio_free(udc->board.pullup_pin);
|
||||||
|
|
||||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
release_mem_region(res->start, res->end - res->start + 1);
|
release_mem_region(res->start, res->end - res->start + 1);
|
||||||
|
|
||||||
|
@@ -158,7 +158,7 @@ struct at91_request {
|
|||||||
|
|
||||||
/*-------------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
#ifdef VERBOSE
|
#ifdef VERBOSE_DEBUG
|
||||||
# define VDBG DBG
|
# define VDBG DBG
|
||||||
#else
|
#else
|
||||||
# define VDBG(stuff...) do{}while(0)
|
# define VDBG(stuff...) do{}while(0)
|
||||||
|
@@ -40,7 +40,8 @@
|
|||||||
/* USB Device */
|
/* USB Device */
|
||||||
struct at91_udc_data {
|
struct at91_udc_data {
|
||||||
u8 vbus_pin; /* high == host powering us */
|
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);
|
extern void __init at91_add_device_udc(struct at91_udc_data *data);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user