diff options
Diffstat (limited to 'drivers/usb/gadget/s3c2410_udc.c')
-rw-r--r-- | drivers/usb/gadget/s3c2410_udc.c | 76 |
1 files changed, 66 insertions, 10 deletions
diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c index c2448950a8d8..6d8b04061d5d 100644 --- a/drivers/usb/gadget/s3c2410_udc.c +++ b/drivers/usb/gadget/s3c2410_udc.c | |||
@@ -902,7 +902,7 @@ static irqreturn_t s3c2410_udc_irq(int dummy, void *_dev) | |||
902 | int pwr_reg; | 902 | int pwr_reg; |
903 | int ep0csr; | 903 | int ep0csr; |
904 | int i; | 904 | int i; |
905 | u32 idx; | 905 | u32 idx, idx2; |
906 | unsigned long flags; | 906 | unsigned long flags; |
907 | 907 | ||
908 | spin_lock_irqsave(&dev->lock, flags); | 908 | spin_lock_irqsave(&dev->lock, flags); |
@@ -1017,6 +1017,20 @@ static irqreturn_t s3c2410_udc_irq(int dummy, void *_dev) | |||
1017 | } | 1017 | } |
1018 | } | 1018 | } |
1019 | 1019 | ||
1020 | /* what else causes this interrupt? a receive! who is it? */ | ||
1021 | if (!usb_status && !usbd_status && !pwr_reg && !ep0csr) { | ||
1022 | for (i = 1; i < S3C2410_ENDPOINTS; i++) { | ||
1023 | idx2 = udc_read(S3C2410_UDC_INDEX_REG); | ||
1024 | udc_write(i, S3C2410_UDC_INDEX_REG); | ||
1025 | |||
1026 | if (udc_read(S3C2410_UDC_OUT_CSR1_REG) & 0x1) | ||
1027 | s3c2410_udc_handle_ep(&dev->ep[i]); | ||
1028 | |||
1029 | /* restore index */ | ||
1030 | udc_write(idx2, S3C2410_UDC_INDEX_REG); | ||
1031 | } | ||
1032 | } | ||
1033 | |||
1020 | dprintk(DEBUG_VERBOSE, "irq: %d s3c2410_udc_done.\n", IRQ_USBD); | 1034 | dprintk(DEBUG_VERBOSE, "irq: %d s3c2410_udc_done.\n", IRQ_USBD); |
1021 | 1035 | ||
1022 | /* Restore old index */ | 1036 | /* Restore old index */ |
@@ -1467,7 +1481,9 @@ static int s3c2410_udc_set_pullup(struct s3c2410_udc *udc, int is_on) | |||
1467 | { | 1481 | { |
1468 | dprintk(DEBUG_NORMAL, "%s()\n", __func__); | 1482 | dprintk(DEBUG_NORMAL, "%s()\n", __func__); |
1469 | 1483 | ||
1470 | if (udc_info && udc_info->udc_command) { | 1484 | if (udc_info && (udc_info->udc_command || |
1485 | gpio_is_valid(udc_info->pullup_pin))) { | ||
1486 | |||
1471 | if (is_on) | 1487 | if (is_on) |
1472 | s3c2410_udc_enable(udc); | 1488 | s3c2410_udc_enable(udc); |
1473 | else { | 1489 | else { |
@@ -1544,6 +1560,32 @@ static const struct usb_gadget_ops s3c2410_ops = { | |||
1544 | .vbus_draw = s3c2410_vbus_draw, | 1560 | .vbus_draw = s3c2410_vbus_draw, |
1545 | }; | 1561 | }; |
1546 | 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 | |||
1547 | /*------------------------- gadget driver handling---------------------------*/ | 1589 | /*------------------------- gadget driver handling---------------------------*/ |
1548 | /* | 1590 | /* |
1549 | * s3c2410_udc_disable | 1591 | * s3c2410_udc_disable |
@@ -1565,8 +1607,7 @@ static void s3c2410_udc_disable(struct s3c2410_udc *dev) | |||
1565 | udc_write(0x1F, S3C2410_UDC_EP_INT_REG); | 1607 | udc_write(0x1F, S3C2410_UDC_EP_INT_REG); |
1566 | 1608 | ||
1567 | /* Good bye, cruel world */ | 1609 | /* Good bye, cruel world */ |
1568 | if (udc_info && udc_info->udc_command) | 1610 | s3c2410_udc_command(S3C2410_UDC_P_DISABLE); |
1569 | udc_info->udc_command(S3C2410_UDC_P_DISABLE); | ||
1570 | 1611 | ||
1571 | /* Set speed to unknown */ | 1612 | /* Set speed to unknown */ |
1572 | dev->gadget.speed = USB_SPEED_UNKNOWN; | 1613 | dev->gadget.speed = USB_SPEED_UNKNOWN; |
@@ -1627,8 +1668,7 @@ static void s3c2410_udc_enable(struct s3c2410_udc *dev) | |||
1627 | 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); |
1628 | 1669 | ||
1629 | /* time to say "hello, world" */ | 1670 | /* time to say "hello, world" */ |
1630 | if (udc_info && udc_info->udc_command) | 1671 | s3c2410_udc_command(S3C2410_UDC_P_ENABLE); |
1631 | udc_info->udc_command(S3C2410_UDC_P_ENABLE); | ||
1632 | } | 1672 | } |
1633 | 1673 | ||
1634 | /* | 1674 | /* |
@@ -1903,6 +1943,17 @@ static int s3c2410_udc_probe(struct platform_device *pdev) | |||
1903 | udc->vbus = 1; | 1943 | udc->vbus = 1; |
1904 | } | 1944 | } |
1905 | 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 | |||
1906 | if (s3c2410_udc_debugfs_root) { | 1957 | if (s3c2410_udc_debugfs_root) { |
1907 | udc->regs_info = debugfs_create_file("registers", S_IRUGO, | 1958 | udc->regs_info = debugfs_create_file("registers", S_IRUGO, |
1908 | s3c2410_udc_debugfs_root, | 1959 | s3c2410_udc_debugfs_root, |
@@ -1915,6 +1966,9 @@ static int s3c2410_udc_probe(struct platform_device *pdev) | |||
1915 | 1966 | ||
1916 | return 0; | 1967 | return 0; |
1917 | 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); | ||
1918 | err_gpio_claim: | 1972 | err_gpio_claim: |
1919 | if (udc_info && udc_info->vbus_pin > 0) | 1973 | if (udc_info && udc_info->vbus_pin > 0) |
1920 | gpio_free(udc_info->vbus_pin); | 1974 | gpio_free(udc_info->vbus_pin); |
@@ -1942,6 +1996,10 @@ static int s3c2410_udc_remove(struct platform_device *pdev) | |||
1942 | 1996 | ||
1943 | debugfs_remove(udc->regs_info); | 1997 | debugfs_remove(udc->regs_info); |
1944 | 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 | |||
1945 | if (udc_info && udc_info->vbus_pin > 0) { | 2003 | if (udc_info && udc_info->vbus_pin > 0) { |
1946 | irq = gpio_to_irq(udc_info->vbus_pin); | 2004 | irq = gpio_to_irq(udc_info->vbus_pin); |
1947 | free_irq(irq, udc); | 2005 | free_irq(irq, udc); |
@@ -1973,16 +2031,14 @@ static int s3c2410_udc_remove(struct platform_device *pdev) | |||
1973 | #ifdef CONFIG_PM | 2031 | #ifdef CONFIG_PM |
1974 | 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) |
1975 | { | 2033 | { |
1976 | if (udc_info && udc_info->udc_command) | 2034 | s3c2410_udc_command(S3C2410_UDC_P_DISABLE); |
1977 | udc_info->udc_command(S3C2410_UDC_P_DISABLE); | ||
1978 | 2035 | ||
1979 | return 0; | 2036 | return 0; |
1980 | } | 2037 | } |
1981 | 2038 | ||
1982 | static int s3c2410_udc_resume(struct platform_device *pdev) | 2039 | static int s3c2410_udc_resume(struct platform_device *pdev) |
1983 | { | 2040 | { |
1984 | if (udc_info && udc_info->udc_command) | 2041 | s3c2410_udc_command(S3C2410_UDC_P_ENABLE); |
1985 | udc_info->udc_command(S3C2410_UDC_P_ENABLE); | ||
1986 | 2042 | ||
1987 | return 0; | 2043 | return 0; |
1988 | } | 2044 | } |