static int exynos_usb_status_init(struct exynos_usb_switch *usb_switch) { mutex_lock(&usb_switch->mutex); /* 2.0 USB */ if (!test_bit(USB_DRD_DEVICE_ATTACHED, &usb_switch->connect) || !test_bit(USB_DRD_HOST_ATTACHED, &usb_switch->connect)) { if (is_host_detect(usb_switch)) exynos_change_usb_mode(usb_switch, USB_HOST_ATTACHED); else if (is_device_detect(usb_switch)) { if (usb_switch->gpio_host_vbus) exynos_change_usb_mode(usb_switch, USB_DEVICE_ATTACHED); else queue_work(usb_switch->workqueue, &usb_switch->switch_work); } } /* 3.0 USB */ if (!test_bit(USB_DRD_DEVICE_ATTACHED, &usb_switch->connect) || !test_bit(USB_DRD_HOST_ATTACHED, &usb_switch->connect)) { if (is_drd_host_detect(usb_switch)) exynos_change_usb_mode(usb_switch, USB_DRD_HOST_ATTACHED); else if (is_drd_device_detect(usb_switch)) queue_work(usb_switch->workqueue, &usb_switch->switch_drd_work); } mutex_unlock(&usb_switch->mutex); return 0; }
static irqreturn_t exynos_device_detect_thread(int irq, void *data) { struct exynos_usb_switch *usb_switch = data; mutex_lock(&usb_switch->mutex); /* Debounce connect delay */ msleep(20); if (is_host_detect(usb_switch)) printk(KERN_DEBUG "Not expected situation\n"); else if (is_device_detect(usb_switch)) { if (usb_switch->gpio_host_vbus) exynos_change_usb_mode(usb_switch, USB_DEVICE_ATTACHED); else queue_work(usb_switch->workqueue, &usb_switch->switch_work); } else { /* VBUS PIN low */ exynos_change_usb_mode(usb_switch, USB_DEVICE_DETACHED); } mutex_unlock(&usb_switch->mutex); return IRQ_HANDLED; }
static irqreturn_t exynos_drd_host_detect_thread(int irq, void *data) { struct exynos_usb_switch *usb_switch = data; mutex_lock(&usb_switch->mutex); if (is_drd_host_detect(usb_switch)) exynos_change_usb_mode(usb_switch, USB_DRD_HOST_ATTACHED); else exynos_change_usb_mode(usb_switch, USB_DRD_HOST_DETACHED); mutex_unlock(&usb_switch->mutex); return IRQ_HANDLED; }
static int exynos_usbswitch_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct exynos_usb_switch *usb_switch = platform_get_drvdata(pdev); dev_dbg(dev, "%s\n", __func__); mutex_lock(&usb_switch->mutex); if (test_bit(USB_DEVICE_ATTACHED, &usb_switch->connect)) exynos_change_usb_mode(usb_switch, USB_DEVICE_DETACHED); if (test_bit(USB_DRD_DEVICE_ATTACHED, &usb_switch->connect)) exynos_change_usb_mode(usb_switch, USB_DRD_DEVICE_DETACHED); usb_switch->connect = 0; mutex_unlock(&usb_switch->mutex); return 0; }
static ssize_t exynos_usbswitch_store_id(struct device *dev, struct device_attribute *attr, const char *buf, size_t n) { struct exynos_usb_switch *usb_switch = dev_get_drvdata(dev); int id; if (sscanf(buf, "%d", &id) != 1) return -EINVAL; mutex_lock(&usb_switch->mutex); if (!id) exynos_change_usb_mode(usb_switch, USB_HOST_ATTACHED); else exynos_change_usb_mode(usb_switch, USB_HOST_DETACHED); mutex_unlock(&usb_switch->mutex); return n; }
static void exnos_usb_drd_switch_worker(struct work_struct *work) { struct exynos_usb_switch *usb_switch = container_of(work, struct exynos_usb_switch, switch_drd_work); int cnt = 0; mutex_lock(&usb_switch->mutex); /* If already device detached or host_detected, */ if (!is_drd_device_detect(usb_switch) || is_drd_host_detect(usb_switch)) goto done; if (!usb_switch->xhci_dev) goto detect; while (!pm_runtime_suspended(usb_switch->xhci_dev) || usb_switch->xhci_dev->power.is_suspended) { mutex_unlock(&usb_switch->mutex); msleep(SWITCH_WAIT_TIME); mutex_lock(&usb_switch->mutex); /* If already device detached or host_detected, */ if (!is_drd_device_detect(usb_switch) || is_drd_host_detect(usb_switch)) goto done; if (cnt++ > WAIT_TIMES) { printk(KERN_ERR "%s:device not attached by host\n", __func__); goto done; } } if (cnt > 1) printk(KERN_INFO "Device wait host power during %d\n", (cnt-1)); detect: /* Check Device, VBUS PIN high active */ exynos_change_usb_mode(usb_switch, USB_DRD_DEVICE_ATTACHED); done: mutex_unlock(&usb_switch->mutex); }
static int __devinit exynos_usbswitch_probe(struct platform_device *pdev) { struct s5p_usbswitch_platdata *pdata = dev_get_platdata(&pdev->dev); struct device *dev = &pdev->dev; struct exynos_usb_switch *usb_switch; int irq; int ret = 0; usb_switch = kzalloc(sizeof(struct exynos_usb_switch), GFP_KERNEL); if (!usb_switch) { ret = -ENOMEM; return ret; } our_switch = usb_switch; mutex_init(&usb_switch->mutex); usb_switch->workqueue = create_singlethread_workqueue("usb_switch"); INIT_WORK(&usb_switch->switch_work, exnos_usb_switch_worker); INIT_WORK(&usb_switch->switch_drd_work, exnos_usb_drd_switch_worker); usb_switch->gpio_host_detect = pdata->gpio_host_detect; usb_switch->gpio_device_detect = pdata->gpio_device_detect; usb_switch->gpio_host_vbus = pdata->gpio_host_vbus; usb_switch->gpio_drd_host_detect = pdata->gpio_drd_host_detect; usb_switch->gpio_drd_device_detect = pdata->gpio_drd_device_detect; usb_switch->ehci_dev = pdata->ehci_dev; usb_switch->ohci_dev = pdata->ohci_dev; usb_switch->xhci_dev = pdata->xhci_dev; usb_switch->s3c_udc_dev = pdata->s3c_udc_dev; usb_switch->exynos_udc_dev = pdata->exynos_udc_dev; /* USB Device detect IRQ */ irq = platform_get_irq(pdev, 1); if (irq > 0 && usb_switch->s3c_udc_dev) { ret = request_threaded_irq(irq, NULL, exynos_device_detect_thread, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "DEVICE_DETECT", usb_switch); if (ret) { dev_err(dev, "Failed to request device irq %d\n", irq); goto fail; } usb_switch->device_detect_irq = irq; } else if (usb_switch->s3c_udc_dev) exynos_change_usb_mode(usb_switch, USB_DEVICE_ATTACHED); else dev_info(dev, "Disable device detect IRQ\n"); /* USB Host detect IRQ */ irq = platform_get_irq(pdev, 0); if (irq > 0 && (usb_switch->ehci_dev || usb_switch->ohci_dev)) { ret = request_threaded_irq(irq, NULL, exynos_host_detect_thread, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "HOST_DETECT", usb_switch); if (ret) { dev_err(dev, "Failed to request host irq %d\n", irq); goto fail_gpio_device_detect; } usb_switch->host_detect_irq = irq; } else if (usb_switch->ehci_dev || usb_switch->ohci_dev) exynos_change_usb_mode(usb_switch, USB_HOST_ATTACHED); else dev_info(dev, "Disable host detect IRQ\n"); /* USB DRD Device detect IRQ */ irq = platform_get_irq(pdev, 3); if (irq > 0 && usb_switch->exynos_udc_dev) { ret = request_threaded_irq(irq, NULL, exynos_drd_device_detect_thread, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "DRD_DEVICE_DETECT", usb_switch); if (ret) { dev_err(dev, "Failed to request drd device irq %d\n", irq); goto fail_gpio_host_detect; } usb_switch->device_drd_detect_irq = irq; } else if (usb_switch->exynos_udc_dev) exynos_change_usb_mode(usb_switch, USB_DRD_DEVICE_ATTACHED); else dev_info(dev, "Disable drd device detect IRQ\n"); /* USB DRD Host detect IRQ */ irq = platform_get_irq(pdev, 2); if (irq > 0 && usb_switch->xhci_dev) { ret = request_threaded_irq(irq, NULL, exynos_drd_host_detect_thread, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "DRD_HOST_DETECT", usb_switch); if (ret) { dev_err(dev, "Failed to request drd host irq %d\n", irq); goto fail_gpio_drd_device_detect; } usb_switch->host_drd_detect_irq = irq; } else if (usb_switch->xhci_dev) exynos_change_usb_mode(usb_switch, USB_DRD_HOST_ATTACHED); else dev_info(dev, "Disable drd host detect IRQ\n"); exynos_usb_status_init(usb_switch); platform_set_drvdata(pdev, usb_switch); return ret; fail_gpio_drd_device_detect: free_irq(usb_switch->device_drd_detect_irq, usb_switch); fail_gpio_host_detect: free_irq(usb_switch->host_detect_irq, usb_switch); fail_gpio_device_detect: free_irq(usb_switch->device_detect_irq, usb_switch); fail: cancel_work_sync(&usb_switch->switch_work); destroy_workqueue(usb_switch->workqueue); mutex_destroy(&usb_switch->mutex); kfree(usb_switch); return ret; }
static int exynos_usbswitch_probe(struct platform_device *pdev) { struct s5p_usbswitch_platdata *pdata = dev_get_platdata(&pdev->dev); struct device *dev = &pdev->dev; struct exynos_usb_switch *usb_switch; int ret = 0; usb_switch = devm_kzalloc(dev, sizeof(struct exynos_usb_switch), GFP_KERNEL); if (!usb_switch) return -ENOMEM; our_switch = usb_switch; mutex_init(&usb_switch->mutex); wake_lock_init(&usb_switch->wake_lock, WAKE_LOCK_SUSPEND, "usb_switch_present"); usb_switch->workqueue = create_singlethread_workqueue("usb_switch"); INIT_WORK(&usb_switch->switch_work, exynos_usb_switch_worker); if (dev->of_node) { ret = exynos_usbswitch_parse_dt(usb_switch, dev); if (ret < 0) { dev_err(dev, "Failed to parse dt\n"); goto fail; } } else if (pdata) { usb_switch->gpio_host_detect = pdata->gpio_host_detect; usb_switch->gpio_device_detect = pdata->gpio_device_detect; usb_switch->gpio_host_vbus = pdata->gpio_host_vbus; usb_switch->ehci_dev = pdata->ehci_dev; usb_switch->ohci_dev = pdata->ohci_dev; usb_switch->s3c_udc_dev = pdata->s3c_udc_dev; usb_switch->host_detect_irq = platform_get_irq(pdev, 0); usb_switch->device_detect_irq = platform_get_irq(pdev, 1); } else { dev_err(dev, "Platform data is not available\n"); ret = -ENODEV; goto fail; } /* USB Device detect IRQ */ if (usb_switch->device_detect_irq > 0 && usb_switch->s3c_udc_dev) { ret = devm_request_threaded_irq(dev, usb_switch->device_detect_irq, NULL, exynos_device_detect_thread, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "DEVICE_DETECT", usb_switch); if (ret) { dev_err(dev, "Failed to request device irq %d\n", usb_switch->device_detect_irq); goto fail; } } else if (usb_switch->s3c_udc_dev) { exynos_change_usb_mode(usb_switch, USB_DEVICE_ATTACHED); } else { dev_info(dev, "Disable device detect IRQ\n"); } /* USB Host detect IRQ */ if (usb_switch->host_detect_irq > 0 && (usb_switch->ehci_dev || usb_switch->ohci_dev)) { ret = devm_request_threaded_irq(dev, usb_switch->host_detect_irq, NULL, exynos_host_detect_thread, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "HOST_DETECT", usb_switch); if (ret) { dev_err(dev, "Failed to request host irq %d\n", usb_switch->host_detect_irq); goto fail; } } else if (usb_switch->ehci_dev || usb_switch->ohci_dev) { exynos_change_usb_mode(usb_switch, USB_HOST_ATTACHED); } else { dev_info(dev, "Disable host detect IRQ\n"); } exynos_usb_status_init(usb_switch); ret = sysfs_create_group(&dev->kobj, &exynos_usbswitch_attr_group); if (ret) dev_warn(dev, "failed to create dwc3 otg attributes\n"); platform_set_drvdata(pdev, usb_switch); return 0; fail: wake_unlock(&usb_switch->wake_lock); cancel_work_sync(&usb_switch->switch_work); destroy_workqueue(usb_switch->workqueue); mutex_destroy(&usb_switch->mutex); return ret; }