Ejemplo n.º 1
0
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;
}
Ejemplo n.º 2
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;
}
Ejemplo n.º 3
0
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;
}
Ejemplo n.º 4
0
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;
}
Ejemplo n.º 6
0
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);
}
Ejemplo n.º 7
0
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;
}