|
@@ -1481,7 +1481,9 @@ static int s3c2410_udc_set_pullup(struct s3c2410_udc *udc, int is_on)
|
|
|
{
|
|
|
dprintk(DEBUG_NORMAL, "%s()\n", __func__);
|
|
|
|
|
|
- if (udc_info && udc_info->udc_command) {
|
|
|
+ if (udc_info && (udc_info->udc_command ||
|
|
|
+ gpio_is_valid(udc_info->pullup_pin))) {
|
|
|
+
|
|
|
if (is_on)
|
|
|
s3c2410_udc_enable(udc);
|
|
|
else {
|
|
@@ -1558,6 +1560,32 @@ static const struct usb_gadget_ops s3c2410_ops = {
|
|
|
.vbus_draw = s3c2410_vbus_draw,
|
|
|
};
|
|
|
|
|
|
+static void s3c2410_udc_command(enum s3c2410_udc_cmd_e cmd)
|
|
|
+{
|
|
|
+ if (!udc_info)
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (udc_info->udc_command) {
|
|
|
+ udc_info->udc_command(S3C2410_UDC_P_DISABLE);
|
|
|
+ } else if (gpio_is_valid(udc_info->pullup_pin)) {
|
|
|
+ int value;
|
|
|
+
|
|
|
+ switch (cmd) {
|
|
|
+ case S3C2410_UDC_P_ENABLE:
|
|
|
+ value = 1;
|
|
|
+ break;
|
|
|
+ case S3C2410_UDC_P_DISABLE:
|
|
|
+ value = 0;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ value ^= udc_info->pullup_pin_inverted;
|
|
|
+
|
|
|
+ gpio_set_value(udc_info->pullup_pin, value);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/*------------------------- gadget driver handling---------------------------*/
|
|
|
/*
|
|
|
* s3c2410_udc_disable
|
|
@@ -1579,8 +1607,7 @@ static void s3c2410_udc_disable(struct s3c2410_udc *dev)
|
|
|
udc_write(0x1F, S3C2410_UDC_EP_INT_REG);
|
|
|
|
|
|
/* Good bye, cruel world */
|
|
|
- if (udc_info && udc_info->udc_command)
|
|
|
- udc_info->udc_command(S3C2410_UDC_P_DISABLE);
|
|
|
+ s3c2410_udc_command(S3C2410_UDC_P_DISABLE);
|
|
|
|
|
|
/* Set speed to unknown */
|
|
|
dev->gadget.speed = USB_SPEED_UNKNOWN;
|
|
@@ -1641,8 +1668,7 @@ static void s3c2410_udc_enable(struct s3c2410_udc *dev)
|
|
|
udc_write(S3C2410_UDC_INT_EP0, S3C2410_UDC_EP_INT_EN_REG);
|
|
|
|
|
|
/* time to say "hello, world" */
|
|
|
- if (udc_info && udc_info->udc_command)
|
|
|
- udc_info->udc_command(S3C2410_UDC_P_ENABLE);
|
|
|
+ s3c2410_udc_command(S3C2410_UDC_P_ENABLE);
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -1917,6 +1943,17 @@ static int s3c2410_udc_probe(struct platform_device *pdev)
|
|
|
udc->vbus = 1;
|
|
|
}
|
|
|
|
|
|
+ if (udc_info && !udc_info->udc_command &&
|
|
|
+ gpio_is_valid(udc_info->pullup_pin)) {
|
|
|
+
|
|
|
+ retval = gpio_request_one(udc_info->pullup_pin,
|
|
|
+ udc_info->vbus_pin_inverted ?
|
|
|
+ GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW,
|
|
|
+ "udc pullup");
|
|
|
+ if (retval)
|
|
|
+ goto err_vbus_irq;
|
|
|
+ }
|
|
|
+
|
|
|
if (s3c2410_udc_debugfs_root) {
|
|
|
udc->regs_info = debugfs_create_file("registers", S_IRUGO,
|
|
|
s3c2410_udc_debugfs_root,
|
|
@@ -1929,6 +1966,9 @@ static int s3c2410_udc_probe(struct platform_device *pdev)
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
+err_vbus_irq:
|
|
|
+ if (udc_info && udc_info->vbus_pin > 0)
|
|
|
+ free_irq(gpio_to_irq(udc_info->vbus_pin), udc);
|
|
|
err_gpio_claim:
|
|
|
if (udc_info && udc_info->vbus_pin > 0)
|
|
|
gpio_free(udc_info->vbus_pin);
|
|
@@ -1956,6 +1996,10 @@ static int s3c2410_udc_remove(struct platform_device *pdev)
|
|
|
|
|
|
debugfs_remove(udc->regs_info);
|
|
|
|
|
|
+ if (udc_info && !udc_info->udc_command &&
|
|
|
+ gpio_is_valid(udc_info->pullup_pin))
|
|
|
+ gpio_free(udc_info->pullup_pin);
|
|
|
+
|
|
|
if (udc_info && udc_info->vbus_pin > 0) {
|
|
|
irq = gpio_to_irq(udc_info->vbus_pin);
|
|
|
free_irq(irq, udc);
|
|
@@ -1987,16 +2031,14 @@ static int s3c2410_udc_remove(struct platform_device *pdev)
|
|
|
#ifdef CONFIG_PM
|
|
|
static int s3c2410_udc_suspend(struct platform_device *pdev, pm_message_t message)
|
|
|
{
|
|
|
- if (udc_info && udc_info->udc_command)
|
|
|
- udc_info->udc_command(S3C2410_UDC_P_DISABLE);
|
|
|
+ s3c2410_udc_command(S3C2410_UDC_P_DISABLE);
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
static int s3c2410_udc_resume(struct platform_device *pdev)
|
|
|
{
|
|
|
- if (udc_info && udc_info->udc_command)
|
|
|
- udc_info->udc_command(S3C2410_UDC_P_ENABLE);
|
|
|
+ s3c2410_udc_command(S3C2410_UDC_P_ENABLE);
|
|
|
|
|
|
return 0;
|
|
|
}
|