diff options
author | Lars-Peter Clausen <lars@metafoo.de> | 2011-03-07 02:41:59 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-03-07 15:23:22 -0500 |
commit | a74022a55e44fe2044ac3660452cafecb300aece (patch) | |
tree | ebff5a97a61c4e5762a042a515459469993ed7e1 | |
parent | 09173b589d547c002b6a2b560e150c4d7bb56c99 (diff) |
USB: s3c2410_udc: Add common implementation for GPIO controlled pullups
Currently all boards using the s3c2410_udc driver use a GPIO to control the
state of the pullup, as a result the same code is reimplemented in each board
file.
This patch adds support for using a GPIO to control the pullup state to the udc
driver, so the boards can use a common implementation.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | arch/arm/plat-s3c24xx/include/plat/udc.h | 4 | ||||
-rw-r--r-- | drivers/usb/gadget/s3c2410_udc.c | 60 |
2 files changed, 55 insertions, 9 deletions
diff --git a/arch/arm/plat-s3c24xx/include/plat/udc.h b/arch/arm/plat-s3c24xx/include/plat/udc.h index 546bb4008f49..80457c6414aa 100644 --- a/arch/arm/plat-s3c24xx/include/plat/udc.h +++ b/arch/arm/plat-s3c24xx/include/plat/udc.h | |||
@@ -27,6 +27,10 @@ enum s3c2410_udc_cmd_e { | |||
27 | struct s3c2410_udc_mach_info { | 27 | struct s3c2410_udc_mach_info { |
28 | void (*udc_command)(enum s3c2410_udc_cmd_e); | 28 | void (*udc_command)(enum s3c2410_udc_cmd_e); |
29 | void (*vbus_draw)(unsigned int ma); | 29 | void (*vbus_draw)(unsigned int ma); |
30 | |||
31 | unsigned int pullup_pin; | ||
32 | unsigned int pullup_pin_inverted; | ||
33 | |||
30 | unsigned int vbus_pin; | 34 | unsigned int vbus_pin; |
31 | unsigned char vbus_pin_inverted; | 35 | unsigned char vbus_pin_inverted; |
32 | }; | 36 | }; |
diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c index 2b025200a69a..6d8b04061d5d 100644 --- a/drivers/usb/gadget/s3c2410_udc.c +++ b/drivers/usb/gadget/s3c2410_udc.c | |||
@@ -1481,7 +1481,9 @@ static int s3c2410_udc_set_pullup(struct s3c2410_udc *udc, int is_on) | |||
1481 | { | 1481 | { |
1482 | dprintk(DEBUG_NORMAL, "%s()\n", __func__); | 1482 | dprintk(DEBUG_NORMAL, "%s()\n", __func__); |
1483 | 1483 | ||
1484 | if (udc_info && udc_info->udc_command) { | 1484 | if (udc_info && (udc_info->udc_command || |
1485 | gpio_is_valid(udc_info->pullup_pin))) { | ||
1486 | |||
1485 | if (is_on) | 1487 | if (is_on) |
1486 | s3c2410_udc_enable(udc); | 1488 | s3c2410_udc_enable(udc); |
1487 | else { | 1489 | else { |
@@ -1558,6 +1560,32 @@ static const struct usb_gadget_ops s3c2410_ops = { | |||
1558 | .vbus_draw = s3c2410_vbus_draw, | 1560 | .vbus_draw = s3c2410_vbus_draw, |
1559 | }; | 1561 | }; |
1560 | 1562 | ||
1563 | static void s3c2410_udc_command(enum s3c2410_udc_cmd_e cmd) | ||
1564 | { | ||
1565 | if (!udc_info) | ||
1566 | return; | ||
1567 | |||
1568 | if (udc_info->udc_command) { | ||
1569 | udc_info->udc_command(S3C2410_UDC_P_DISABLE); | ||
1570 | } else if (gpio_is_valid(udc_info->pullup_pin)) { | ||
1571 | int value; | ||
1572 | |||
1573 | switch (cmd) { | ||
1574 | case S3C2410_UDC_P_ENABLE: | ||
1575 | value = 1; | ||
1576 | break; | ||
1577 | case S3C2410_UDC_P_DISABLE: | ||
1578 | value = 0; | ||
1579 | break; | ||
1580 | default: | ||
1581 | return; | ||
1582 | } | ||
1583 | value ^= udc_info->pullup_pin_inverted; | ||
1584 | |||
1585 | gpio_set_value(udc_info->pullup_pin, value); | ||
1586 | } | ||
1587 | } | ||
1588 | |||
1561 | /*------------------------- gadget driver handling---------------------------*/ | 1589 | /*------------------------- gadget driver handling---------------------------*/ |
1562 | /* | 1590 | /* |
1563 | * s3c2410_udc_disable | 1591 | * s3c2410_udc_disable |
@@ -1579,8 +1607,7 @@ static void s3c2410_udc_disable(struct s3c2410_udc *dev) | |||
1579 | udc_write(0x1F, S3C2410_UDC_EP_INT_REG); | 1607 | udc_write(0x1F, S3C2410_UDC_EP_INT_REG); |
1580 | 1608 | ||
1581 | /* Good bye, cruel world */ | 1609 | /* Good bye, cruel world */ |
1582 | if (udc_info && udc_info->udc_command) | 1610 | s3c2410_udc_command(S3C2410_UDC_P_DISABLE); |
1583 | udc_info->udc_command(S3C2410_UDC_P_DISABLE); | ||
1584 | 1611 | ||
1585 | /* Set speed to unknown */ | 1612 | /* Set speed to unknown */ |
1586 | dev->gadget.speed = USB_SPEED_UNKNOWN; | 1613 | dev->gadget.speed = USB_SPEED_UNKNOWN; |
@@ -1641,8 +1668,7 @@ static void s3c2410_udc_enable(struct s3c2410_udc *dev) | |||
1641 | udc_write(S3C2410_UDC_INT_EP0, S3C2410_UDC_EP_INT_EN_REG); | 1668 | udc_write(S3C2410_UDC_INT_EP0, S3C2410_UDC_EP_INT_EN_REG); |
1642 | 1669 | ||
1643 | /* time to say "hello, world" */ | 1670 | /* time to say "hello, world" */ |
1644 | if (udc_info && udc_info->udc_command) | 1671 | s3c2410_udc_command(S3C2410_UDC_P_ENABLE); |
1645 | udc_info->udc_command(S3C2410_UDC_P_ENABLE); | ||
1646 | } | 1672 | } |
1647 | 1673 | ||
1648 | /* | 1674 | /* |
@@ -1917,6 +1943,17 @@ static int s3c2410_udc_probe(struct platform_device *pdev) | |||
1917 | udc->vbus = 1; | 1943 | udc->vbus = 1; |
1918 | } | 1944 | } |
1919 | 1945 | ||
1946 | if (udc_info && !udc_info->udc_command && | ||
1947 | gpio_is_valid(udc_info->pullup_pin)) { | ||
1948 | |||
1949 | retval = gpio_request_one(udc_info->pullup_pin, | ||
1950 | udc_info->vbus_pin_inverted ? | ||
1951 | GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW, | ||
1952 | "udc pullup"); | ||
1953 | if (retval) | ||
1954 | goto err_vbus_irq; | ||
1955 | } | ||
1956 | |||
1920 | if (s3c2410_udc_debugfs_root) { | 1957 | if (s3c2410_udc_debugfs_root) { |
1921 | udc->regs_info = debugfs_create_file("registers", S_IRUGO, | 1958 | udc->regs_info = debugfs_create_file("registers", S_IRUGO, |
1922 | s3c2410_udc_debugfs_root, | 1959 | s3c2410_udc_debugfs_root, |
@@ -1929,6 +1966,9 @@ static int s3c2410_udc_probe(struct platform_device *pdev) | |||
1929 | 1966 | ||
1930 | return 0; | 1967 | return 0; |
1931 | 1968 | ||
1969 | err_vbus_irq: | ||
1970 | if (udc_info && udc_info->vbus_pin > 0) | ||
1971 | free_irq(gpio_to_irq(udc_info->vbus_pin), udc); | ||
1932 | err_gpio_claim: | 1972 | err_gpio_claim: |
1933 | if (udc_info && udc_info->vbus_pin > 0) | 1973 | if (udc_info && udc_info->vbus_pin > 0) |
1934 | gpio_free(udc_info->vbus_pin); | 1974 | gpio_free(udc_info->vbus_pin); |
@@ -1956,6 +1996,10 @@ static int s3c2410_udc_remove(struct platform_device *pdev) | |||
1956 | 1996 | ||
1957 | debugfs_remove(udc->regs_info); | 1997 | debugfs_remove(udc->regs_info); |
1958 | 1998 | ||
1999 | if (udc_info && !udc_info->udc_command && | ||
2000 | gpio_is_valid(udc_info->pullup_pin)) | ||
2001 | gpio_free(udc_info->pullup_pin); | ||
2002 | |||
1959 | if (udc_info && udc_info->vbus_pin > 0) { | 2003 | if (udc_info && udc_info->vbus_pin > 0) { |
1960 | irq = gpio_to_irq(udc_info->vbus_pin); | 2004 | irq = gpio_to_irq(udc_info->vbus_pin); |
1961 | free_irq(irq, udc); | 2005 | free_irq(irq, udc); |
@@ -1987,16 +2031,14 @@ static int s3c2410_udc_remove(struct platform_device *pdev) | |||
1987 | #ifdef CONFIG_PM | 2031 | #ifdef CONFIG_PM |
1988 | static int s3c2410_udc_suspend(struct platform_device *pdev, pm_message_t message) | 2032 | static int s3c2410_udc_suspend(struct platform_device *pdev, pm_message_t message) |
1989 | { | 2033 | { |
1990 | if (udc_info && udc_info->udc_command) | 2034 | s3c2410_udc_command(S3C2410_UDC_P_DISABLE); |
1991 | udc_info->udc_command(S3C2410_UDC_P_DISABLE); | ||
1992 | 2035 | ||
1993 | return 0; | 2036 | return 0; |
1994 | } | 2037 | } |
1995 | 2038 | ||
1996 | static int s3c2410_udc_resume(struct platform_device *pdev) | 2039 | static int s3c2410_udc_resume(struct platform_device *pdev) |
1997 | { | 2040 | { |
1998 | if (udc_info && udc_info->udc_command) | 2041 | s3c2410_udc_command(S3C2410_UDC_P_ENABLE); |
1999 | udc_info->udc_command(S3C2410_UDC_P_ENABLE); | ||
2000 | 2042 | ||
2001 | return 0; | 2043 | return 0; |
2002 | } | 2044 | } |