static int exynos_change_usb_mode(struct exynos_usb_switch *usb_switch,
				enum usb_cable_status mode)
{
	struct s3c_udc *udc;
	unsigned long cur_mode = usb_switch->connect;
	int ret = 0;

	if (test_bit(USB_DEVICE_ATTACHED, &cur_mode) ||
	    test_bit(USB_HOST_ATTACHED, &cur_mode)) {
		if (mode == USB_DEVICE_ATTACHED ||
			mode == USB_HOST_ATTACHED) {
			printk(KERN_DEBUG "Skip request %d, current %lu\n",
				mode, cur_mode);
			return -EPERM;
		}
	}

	if (!test_bit(USB_DEVICE_ATTACHED, &cur_mode) &&
			mode == USB_DEVICE_DETACHED) {
		printk(KERN_DEBUG "Skip request %d, current %lu\n",
			mode, cur_mode);
		return -EPERM;
	} else if (!test_bit(USB_HOST_ATTACHED, &cur_mode) &&
			mode == USB_HOST_DETACHED) {
		printk(KERN_DEBUG "Skip request %d, current %lu\n",
			mode, cur_mode);
		return -EPERM;
	}

	switch (mode) {
	case USB_DEVICE_DETACHED:
		if (test_bit(USB_HOST_ATTACHED, &cur_mode)) {
			printk(KERN_ERR "Abnormal request %d, current %lu\n",
				mode, cur_mode);
			return -EPERM;
		}
		udc = dev_get_drvdata(usb_switch->s3c_udc_dev);
		if (udc && udc->gadget.ops && udc->gadget.ops->vbus_session)
			udc->gadget.ops->vbus_session(&udc->gadget, 0);
		clear_bit(USB_DEVICE_ATTACHED, &usb_switch->connect);
		break;
	case USB_DEVICE_ATTACHED:
		udc = dev_get_drvdata(usb_switch->s3c_udc_dev);
		if (udc && udc->gadget.ops && udc->gadget.ops->vbus_session)
			udc->gadget.ops->vbus_session(&udc->gadget, 1);
		set_bit(USB_DEVICE_ATTACHED, &usb_switch->connect);
		break;
	case USB_HOST_DETACHED:
		if (test_bit(USB_DEVICE_ATTACHED, &cur_mode)) {
			printk(KERN_ERR "Abnormal request %d, current %lu\n",
				mode, cur_mode);
			return -EPERM;
		}
		if (usb_switch->ohci_dev)
			pm_runtime_allow(usb_switch->ohci_dev);
		if (usb_switch->ehci_dev)
			pm_runtime_allow(usb_switch->ehci_dev);
		if (usb_switch->gpio_host_vbus)
			set_host_vbus(usb_switch, 0);

		wake_unlock(&usb_switch->wake_lock);

		clear_bit(USB_HOST_ATTACHED, &usb_switch->connect);
		break;
	case USB_HOST_ATTACHED:
		wake_lock(&usb_switch->wake_lock);

		if (usb_switch->gpio_host_vbus)
			set_host_vbus(usb_switch, 1);

		if (usb_switch->ehci_dev)
			pm_runtime_forbid(usb_switch->ehci_dev);
		if (usb_switch->ohci_dev)
			pm_runtime_forbid(usb_switch->ohci_dev);
		set_bit(USB_HOST_ATTACHED, &usb_switch->connect);
		break;
	default:
		printk(KERN_ERR "Does not changed\n");
	}
	printk(KERN_ERR "usb cable = %d\n", mode);

	return ret;
}
Beispiel #2
0
static int exynos_change_usb_mode(struct exynos_usb_switch *usb_switch,
				enum usb_cable_status mode)
{
	struct s3c_udc *udc;
	struct exynos_ss_udc *ss_udc;
	unsigned long cur_mode = usb_switch->connect;
	int ret = 0;

	if (test_bit(USB_DEVICE_ATTACHED, &cur_mode) ||
	    test_bit(USB_HOST_ATTACHED, &cur_mode)) {
		if (mode == USB_DEVICE_ATTACHED ||
			mode == USB_HOST_ATTACHED) {
			printk(KERN_DEBUG "Skip request %d, current %lu\n",
				mode, cur_mode);
			return -EPERM;
		}
	} else if (test_bit(USB_DRD_DEVICE_ATTACHED, &cur_mode) ||
		   test_bit(USB_DRD_HOST_ATTACHED, &cur_mode)) {
		if (mode == USB_DRD_DEVICE_ATTACHED ||
			mode == USB_DRD_HOST_ATTACHED) {
			printk(KERN_DEBUG "Skip request %d, current %lu\n",
				mode, cur_mode);
			return -EPERM;
		}
	}

	if (!test_bit(USB_DEVICE_ATTACHED, &cur_mode) &&
			mode == USB_DEVICE_DETACHED) {
		printk(KERN_DEBUG "Skip request %d, current %lu\n",
			mode, cur_mode);
		return -EPERM;
	} else if (!test_bit(USB_HOST_ATTACHED, &cur_mode) &&
			mode == USB_HOST_DETACHED) {
		printk(KERN_DEBUG "Skip request %d, current %lu\n",
			mode, cur_mode);
		return -EPERM;
	} else if (!test_bit(USB_DRD_DEVICE_ATTACHED, &cur_mode) &&
			mode == USB_DRD_DEVICE_DETACHED) {
		printk(KERN_DEBUG "Skip request %d, current %lu\n",
			mode, cur_mode);
		return -EPERM;
	} else if (!test_bit(USB_DRD_HOST_ATTACHED, &cur_mode) &&
			mode == USB_DRD_HOST_DETACHED) {
		printk(KERN_DEBUG "Skip request %d, current %lu\n",
			mode, cur_mode);
		return -EPERM;
	}

	switch (mode) {
	case USB_DEVICE_DETACHED:
		if (test_bit(USB_HOST_ATTACHED, &cur_mode)) {
			printk(KERN_ERR "Abnormal request %d, current %lu\n",
				mode, cur_mode);
			return -EPERM;
		}
		udc = dev_get_drvdata(usb_switch->s3c_udc_dev);
		if (udc && udc->gadget.ops && udc->gadget.ops->vbus_session)
			udc->gadget.ops->vbus_session(&udc->gadget, 0);
		clear_bit(USB_DEVICE_ATTACHED, &usb_switch->connect);
		break;
	case USB_DEVICE_ATTACHED:
		udc = dev_get_drvdata(usb_switch->s3c_udc_dev);
		if (udc && udc->gadget.ops && udc->gadget.ops->vbus_session)
			udc->gadget.ops->vbus_session(&udc->gadget, 1);
		set_bit(USB_DEVICE_ATTACHED, &usb_switch->connect);
		break;
	case USB_HOST_DETACHED:
		if (test_bit(USB_DEVICE_ATTACHED, &cur_mode)) {
			printk(KERN_ERR "Abnormal request %d, current %lu\n",
				mode, cur_mode);
			return -EPERM;
		}
		if (usb_switch->ohci_dev)
			pm_runtime_put(usb_switch->ohci_dev);
		if (usb_switch->ehci_dev)
			pm_runtime_put(usb_switch->ehci_dev);
		if (usb_switch->gpio_host_vbus)
			set_host_vbus(usb_switch, 0);

#if defined(CONFIG_BATTERY_SAMSUNG)
		exynos_usb_cable_disconnect();
#endif
		clear_bit(USB_HOST_ATTACHED, &usb_switch->connect);
		break;
	case USB_HOST_ATTACHED:
#if defined(CONFIG_BATTERY_SAMSUNG)
		exynos_usb_cable_connect();
#endif
		if (usb_switch->gpio_host_vbus)
			set_host_vbus(usb_switch, 1);

		if (usb_switch->ehci_dev)
			pm_runtime_get_sync(usb_switch->ehci_dev);
		if (usb_switch->ohci_dev)
			pm_runtime_get_sync(usb_switch->ohci_dev);
		set_bit(USB_HOST_ATTACHED, &usb_switch->connect);
		break;
	case USB_DRD_DEVICE_DETACHED:
		if (test_bit(USB_DRD_HOST_ATTACHED, &cur_mode)) {
			printk(KERN_ERR "Abnormal request %d, current %lu\n",
				mode, cur_mode);
			return -EPERM;
		}

		ss_udc = dev_get_drvdata(usb_switch->exynos_udc_dev);
		if (ss_udc && ss_udc->gadget.ops &&
			ss_udc->gadget.ops->vbus_session)
			ss_udc->gadget.ops->vbus_session(&ss_udc->gadget, 0);
		clear_bit(USB_DRD_DEVICE_ATTACHED, &usb_switch->connect);
		break;
	case USB_DRD_DEVICE_ATTACHED:
		ss_udc = dev_get_drvdata(usb_switch->exynos_udc_dev);
		if (ss_udc && ss_udc->gadget.ops &&
			ss_udc->gadget.ops->vbus_session)
			ss_udc->gadget.ops->vbus_session(&ss_udc->gadget, 1);
		set_bit(USB_DRD_DEVICE_ATTACHED, &usb_switch->connect);
		break;
	case USB_DRD_HOST_DETACHED:
		if (test_bit(USB_DRD_DEVICE_ATTACHED, &cur_mode)) {
			printk(KERN_ERR "Abnormal request %d, current %lu\n",
				mode, cur_mode);
			return -EPERM;
		}

		if (usb_switch->xhci_dev)
			pm_runtime_put_sync(usb_switch->xhci_dev);
#if defined(CONFIG_BATTERY_SAMSUNG)
		exynos_usb_cable_disconnect();
#endif
		clear_bit(USB_DRD_HOST_ATTACHED, &usb_switch->connect);
		break;
	case USB_DRD_HOST_ATTACHED:
#if defined(CONFIG_BATTERY_SAMSUNG)
		exynos_usb_cable_connect();
#endif
		if (usb_switch->xhci_dev)
			pm_runtime_get_sync(usb_switch->xhci_dev);
		set_bit(USB_DRD_HOST_ATTACHED, &usb_switch->connect);
		break;
	default:
		printk(KERN_ERR "Does not changed\n");
	}
	printk(KERN_INFO "usb cable = %d\n", mode);

	return ret;
}
static int exynos_change_usb_mode(struct exynos_usb_switch *usb_switch,
				enum usb_cable_status mode)
{
	struct usb_gadget *gadget;
	unsigned long cur_mode = usb_switch->connect;
	int ret = 0;

	if (test_bit(USB_DEVICE_ATTACHED, &cur_mode) ||
	    test_bit(USB_HOST_ATTACHED, &cur_mode)) {
		if (mode == USB_DEVICE_ATTACHED ||
			mode == USB_HOST_ATTACHED) {
			printk(KERN_DEBUG "Skip request %d, current %lu\n",
				mode, cur_mode);
			return -EPERM;
		}
	}

	if (!test_bit(USB_DEVICE_ATTACHED, &cur_mode) &&
			mode == USB_DEVICE_DETACHED) {
		printk(KERN_DEBUG "Skip request %d, current %lu\n",
			mode, cur_mode);
		return -EPERM;
	} else if (!test_bit(USB_HOST_ATTACHED, &cur_mode) &&
			mode == USB_HOST_DETACHED) {
		printk(KERN_DEBUG "Skip request %d, current %lu\n",
			mode, cur_mode);
		return -EPERM;
	}

	/*
	 * FIXME: Currently we get gadget every time usb mode is going
	 * to change. This prevents from problems related to UDC module
	 * removing and wrong probe order. S3C UDC driver should provide
	 * corresponding helper function. If S3C UDC is not available weak
	 * analog is used instead.
	 *
	 * Correct solution would be to implement binding similar to OTG's
	 * set_host() and set_peripheral().
	 */
	gadget = s3c_udc_get_gadget(usb_switch->s3c_udc_dev);

	switch (mode) {
	case USB_DEVICE_DETACHED:
		if (test_bit(USB_HOST_ATTACHED, &cur_mode)) {
			printk(KERN_ERR "Abnormal request %d, current %lu\n",
				mode, cur_mode);
			return -EPERM;
		}
		if (gadget && gadget->ops)
			usb_gadget_vbus_disconnect(gadget);
		clear_bit(USB_DEVICE_ATTACHED, &usb_switch->connect);
		break;
	case USB_DEVICE_ATTACHED:
		if (gadget && gadget->ops)
			usb_gadget_vbus_connect(gadget);
		set_bit(USB_DEVICE_ATTACHED, &usb_switch->connect);
		break;
	case USB_HOST_DETACHED:
		if (test_bit(USB_DEVICE_ATTACHED, &cur_mode)) {
			printk(KERN_ERR "Abnormal request %d, current %lu\n",
				mode, cur_mode);
			return -EPERM;
		}
		if (usb_switch->ohci_dev)
			pm_runtime_allow(usb_switch->ohci_dev);
		if (usb_switch->ehci_dev)
			pm_runtime_allow(usb_switch->ehci_dev);
		if (usb_switch->gpio_host_vbus)
			set_host_vbus(usb_switch, 0);

		wake_unlock(&usb_switch->wake_lock);

		clear_bit(USB_HOST_ATTACHED, &usb_switch->connect);
		break;
	case USB_HOST_ATTACHED:
		wake_lock(&usb_switch->wake_lock);

		if (usb_switch->gpio_host_vbus)
			set_host_vbus(usb_switch, 1);

		if (usb_switch->ehci_dev)
			pm_runtime_forbid(usb_switch->ehci_dev);
		if (usb_switch->ohci_dev)
			pm_runtime_forbid(usb_switch->ohci_dev);
		set_bit(USB_HOST_ATTACHED, &usb_switch->connect);
		break;
	default:
		printk(KERN_ERR "Does not changed\n");
	}
	printk(KERN_ERR "usb cable = %d\n", mode);

	return ret;
}