static int tegra_ehci_remove(struct platform_device *pdev)
{
	struct tegra_ehci_hcd *tegra = platform_get_drvdata(pdev);
	struct usb_hcd *hcd = NULL;

	if (tegra == NULL)
		return -EINVAL;

	hcd = ehci_to_hcd(tegra->ehci);

	if (hcd == NULL)
		return -EINVAL;

#ifdef CONFIG_USB_OTG_UTILS
	if (tegra->transceiver) {
		otg_set_host(tegra->transceiver->otg, NULL);
		usb_put_transceiver(tegra->transceiver);
	}
#endif

	if (tegra->irq)
		disable_irq_wake(tegra->irq);

	/* Make sure phy is powered ON to access USB register */
	if(!tegra_usb_phy_hw_accessible(tegra->phy))
		tegra_usb_phy_power_on(tegra->phy);

	usb_remove_hcd(hcd);
	tegra_usb_phy_power_off(tegra->phy);
	usb_phy_shutdown(get_usb_phy(tegra->phy));
	iounmap(hcd->regs);
	usb_put_hcd(hcd);

	return 0;
}
Exemplo n.º 2
0
static int tegra_ehci_bus_suspend(struct usb_hcd *hcd)
{
	struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller);
	int err = 0;
	EHCI_DBG("%s() BEGIN\n", __func__);

#ifdef CONFIG_TEGRA_EHCI_BOOST_CPU_FREQ
	tegra->boost_requested = false;
	if (tegra->boost_enable
	    && pm_qos_request_active(&tegra->boost_cpu_freq_req))
		pm_qos_update_request(&tegra->boost_cpu_freq_req,
			PM_QOS_DEFAULT_VALUE);
	tegra->cpu_boost_in_work = false;
#endif

	mutex_lock(&tegra->sync_lock);
	tegra->bus_suspended_fail = false;
	err = ehci_bus_suspend(hcd);
	if (err)
		tegra->bus_suspended_fail = true;
	else
		usb_phy_set_suspend(get_usb_phy(tegra->phy), 1);
	mutex_unlock(&tegra->sync_lock);
	EHCI_DBG("%s() END\n", __func__);

	return err;
}
Exemplo n.º 3
0
static int tegra_ehci_remove(struct platform_device *pdev)
{
	struct tegra_ehci_hcd *tegra = platform_get_drvdata(pdev);
	struct usb_hcd *hcd = NULL;
	struct usb_device *rhdev = NULL;
	struct tegra_usb_platform_data *pdata;
	unsigned long timeout = 0;

	if (tegra == NULL)
		return -EINVAL;

	hcd = ehci_to_hcd(tegra->ehci);

	if (hcd == NULL)
		return -EINVAL;

#ifdef CONFIG_TEGRA_EHCI_BOOST_CPU_FREQ
	cancel_delayed_work(&tegra->boost_cpu_freq_work);
	pm_qos_update_request(&tegra->boost_cpu_freq_req,
				PM_QOS_DEFAULT_VALUE);
	tegra->cpu_boost_in_work = false;
#endif
	rhdev = hcd->self.root_hub;
	pdata = dev_get_platdata(&pdev->dev);

#ifdef CONFIG_USB_OTG_UTILS
	if (tegra->transceiver) {
		otg_set_host(tegra->transceiver->otg, NULL);
		usb_put_transceiver(tegra->transceiver);
	}
#endif

	if (tegra->irq)
		disable_irq_wake(tegra->irq);

	/* Make sure phy is powered ON to access USB register */
	if(!tegra_usb_phy_hw_accessible(tegra->phy))
		tegra_usb_phy_power_on(tegra->phy);

	if (pdata->port_otg) {

		timeout = jiffies + 5 * HZ;

		/* wait for devices connected to root hub to disconnect*/
		while (time_before(jiffies, timeout) &&
			rhdev && rhdev->children[0])
			;

		/* wait for any control packets sent to root hub to complete */
		mdelay(1000);
	}

	usb_remove_hcd(hcd);
	tegra_usb_phy_power_off(tegra->phy);
	usb_phy_shutdown(get_usb_phy(tegra->phy));
	iounmap(hcd->regs);
	usb_put_hcd(hcd);

	return 0;
}
Exemplo n.º 4
0
static int tegra_ehci_remove(struct platform_device *pdev)
{
	struct tegra_ehci_hcd *tegra = platform_get_drvdata(pdev);
	struct usb_hcd *hcd = ehci_to_hcd(tegra->ehci);
	struct usb_device *rhdev = NULL;
	struct tegra_usb_platform_data *pdata;
	unsigned long timeout = 0;

	wake_lock_destroy(&tegra->ehci_wake_lock);

#ifdef CONFIG_TEGRA_EHCI_BOOST_CPU_FREQ
	cancel_delayed_work_sync(&tegra->boost_cpu_freq_work);
	tegra->cpu_boost_in_work = false;
	pm_qos_remove_request(&tegra->boost_cpu_freq_req);
#endif
	rhdev = hcd->self.root_hub;
	pdata = dev_get_platdata(&pdev->dev);

	if (!IS_ERR_OR_NULL(tegra->transceiver))
		otg_set_host(tegra->transceiver->otg, NULL);

	/* Make sure phy is powered ON to access USB register */
	if(!tegra_usb_phy_hw_accessible(tegra->phy))
		tegra_usb_phy_power_on(tegra->phy);

	if (pdata->port_otg) {
		timeout = jiffies + 5 * HZ;
		/* wait for devices connected to root hub to disconnect*/
		while (rhdev && usb_hub_find_child(rhdev, 1)) {
			/* wait for any control packets
			sent to root hub to complete */
			if (time_after(jiffies, timeout))
				break;
			msleep(20);
			cpu_relax();
		}
	}

#ifdef CONFIG_TEGRA_EHCI_BOOST_CPU_FREQ
	device_remove_file(hcd->self.controller, &dev_attr_boost_enable);
#endif
	usb_remove_hcd(hcd);
	usb_put_hcd(hcd);
	tegra_usb_phy_power_off(tegra->phy);
	usb_phy_shutdown(get_usb_phy(tegra->phy));

	mutex_destroy(&tegra->sync_lock);
	tegra_pd_remove_device(&pdev->dev);

	return 0;
}
static int tegra_ehci_bus_resume(struct usb_hcd *hcd)
{
	struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller);
	int err = 0;
	EHCI_DBG("%s() BEGIN\n", __func__);

	mutex_lock(&tegra->sync_lock);
	usb_phy_set_suspend(get_usb_phy(tegra->phy), 0);
	err = ehci_bus_resume(hcd);
	mutex_unlock(&tegra->sync_lock);
	EHCI_DBG("%s() END\n", __func__);

	return err;
}
static int tegra_ehci_bus_suspend(struct usb_hcd *hcd)
{
	struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller);
	int err = 0;
	EHCI_DBG("%s() BEGIN\n", __func__);
	mutex_lock(&tegra->sync_lock);
	tegra->bus_suspended_fail = false;
	err = ehci_bus_suspend(hcd);
	if (err)
		tegra->bus_suspended_fail = true;
	else
		usb_phy_set_suspend(get_usb_phy(tegra->phy), 1);
	mutex_unlock(&tegra->sync_lock);
	EHCI_DBG("%s() END\n", __func__);

	return err;
}
Exemplo n.º 7
0
static int tegra_ehci_bus_resume(struct usb_hcd *hcd)
{
	struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller);
	int err = 0;
	EHCI_DBG("%s() BEGIN\n", __func__);

#ifdef CONFIG_TEGRA_EHCI_BOOST_CPU_FREQ
	pm_qos_update_request(&tegra->boost_cpu_freq_req,
			(s32)CONFIG_TEGRA_EHCI_BOOST_CPU_FREQ * 1000);
	tegra->cpu_boost_in_work = false;

#endif

	mutex_lock(&tegra->sync_lock);
	usb_phy_set_suspend(get_usb_phy(tegra->phy), 0);
	err = ehci_bus_resume(hcd);
	mutex_unlock(&tegra->sync_lock);
	EHCI_DBG("%s() END\n", __func__);

	return err;
}
Exemplo n.º 8
0
static int tegra_ehci_bus_resume(struct usb_hcd *hcd)
{
	struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller);
	int err = 0;
	EHCI_DBG("%s() BEGIN\n", __func__);

#ifdef CONFIG_TEGRA_EHCI_BOOST_CPU_FREQ
	tegra->boost_requested = true;
	if (pm_qos_request_active(&tegra->boost_cpu_freq_req)
		&& tegra->boost_enable) {
		schedule_delayed_work(&tegra->boost_cpu_freq_work, 4000);
		tegra->cpu_boost_in_work = true;
	}

#endif

	mutex_lock(&tegra->sync_lock);
	usb_phy_set_suspend(get_usb_phy(tegra->phy), 0);
	err = ehci_bus_resume(hcd);
	mutex_unlock(&tegra->sync_lock);
	EHCI_DBG("%s() END\n", __func__);

	return err;
}
static int tegra_ehci_probe(struct platform_device *pdev)
{
	struct resource *res;
	struct usb_hcd *hcd;
	struct tegra_ehci_hcd *tegra;
	struct tegra_usb_platform_data *pdata;
	int err = 0;
	int irq;
	int instance = pdev->id;

	/* Right now device-tree probed devices don't get dma_mask set.
	 * Since shared usb code relies on it, set it here for now.
	 * Once we have dma capability bindings this can go away.
	 */
	if (!pdev->dev.dma_mask)
		pdev->dev.dma_mask = &tegra_ehci_dma_mask;

	setup_vbus_gpio(pdev);

	tegra = devm_kzalloc(&pdev->dev, sizeof(struct tegra_ehci_hcd),
		GFP_KERNEL);
	if (!tegra) {
		dev_err(&pdev->dev, "memory alloc failed\n");
		return -ENOMEM;
	}

	mutex_init(&tegra->sync_lock);

	hcd = usb_create_hcd(&tegra_ehci_hc_driver, &pdev->dev,
					dev_name(&pdev->dev));
	if (!hcd) {
		dev_err(&pdev->dev, "unable to create HCD\n");
		return -ENOMEM;
	}

	platform_set_drvdata(pdev, tegra);

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res) {
		dev_err(&pdev->dev, "failed to get I/O memory\n");
		err = -ENXIO;
		goto fail_io;
	}
	hcd->rsrc_start = res->start;
	hcd->rsrc_len = resource_size(res);
	hcd->regs = ioremap(res->start, resource_size(res));
	if (!hcd->regs) {
		dev_err(&pdev->dev, "failed to remap I/O memory\n");
		err = -ENOMEM;
		goto fail_io;
	}

	/* This is pretty ugly and needs to be fixed when we do only
	 * device-tree probing. Old code relies on the platform_device
	 * numbering that we lack for device-tree-instantiated devices.
	 */
	if (instance < 0) {
		switch (res->start) {
		case TEGRA_USB_BASE:
			instance = 0;
			break;
		case TEGRA_USB2_BASE:
			instance = 1;
			break;
		case TEGRA_USB3_BASE:
			instance = 2;
			break;
		default:
			err = -ENODEV;
			dev_err(&pdev->dev, "unknown usb instance\n");
			goto fail_phy;
		}
	}

	irq = platform_get_irq(pdev, 0);
	if (irq < 0) {
		dev_err(&pdev->dev, "failed to get IRQ\n");
		err = -ENODEV;
		goto fail_irq;
	}
	tegra->irq = irq;

	pdata = dev_get_platdata(&pdev->dev);
	tegra->unaligned_dma_buf_supported = pdata->unaligned_dma_buf_supported;
	tegra->has_hostpc = pdata->has_hostpc;

	tegra->phy = tegra_usb_phy_open(pdev);
	if (IS_ERR(tegra->phy)) {
		dev_err(&pdev->dev, "failed to open USB phy\n");
		err = -ENXIO;
		goto fail_irq;
	}

	err = tegra_usb_phy_power_on(tegra->phy);
	if (err) {
		dev_err(&pdev->dev, "failed to power on the phy\n");
		goto fail_phy;
	}

	err = usb_phy_init(get_usb_phy(tegra->phy));
	if (err) {
		dev_err(&pdev->dev, "failed to init the phy\n");
		goto fail_phy;
	}

	err = usb_add_hcd(hcd, irq, IRQF_SHARED | IRQF_TRIGGER_HIGH);
	if (err) {
		dev_err(&pdev->dev, "Failed to add USB HCD, error=%d\n", err);
		goto fail_phy;
	}

	err = enable_irq_wake(tegra->irq);
	if (err < 0) {
		dev_warn(&pdev->dev,
				"Couldn't enable USB host mode wakeup, irq=%d, "
				"error=%d\n", irq, err);
		err = 0;
		tegra->irq = 0;
	}

	tegra->ehci = hcd_to_ehci(hcd);

#ifdef CONFIG_USB_OTG_UTILS
	if (pdata->port_otg) {
		tegra->transceiver = usb_get_transceiver();
		if (tegra->transceiver)
			otg_set_host(tegra->transceiver->otg, &hcd->self);
	}
#endif
	return err;

fail_phy:
	usb_phy_shutdown(get_usb_phy(tegra->phy));
fail_irq:
	iounmap(hcd->regs);
fail_io:
	usb_put_hcd(hcd);

	return err;
}
Exemplo n.º 10
0
static int tegra_ehci_probe(struct platform_device *pdev)
{
	struct resource *res;
	struct usb_hcd *hcd;
	struct tegra_ehci_hcd *tegra;
	struct tegra_usb_platform_data *pdata;
	int err = 0;
	int irq;
	int instance = pdev->id;

	/* Right now device-tree probed devices don't get dma_mask set.
	 * Since shared usb code relies on it, set it here for now.
	 * Once we have dma capability bindings this can go away.
	 */
	if (!pdev->dev.dma_mask)
		pdev->dev.dma_mask = &tegra_ehci_dma_mask;

	pdata = dev_get_platdata(&pdev->dev);

	tegra = devm_kzalloc(&pdev->dev, sizeof(struct tegra_ehci_hcd),
			     GFP_KERNEL);
	if (!tegra) {
		dev_err(&pdev->dev, "memory alloc failed\n");
		return -ENOMEM;
	}

	mutex_init(&tegra->sync_lock);

	hcd = usb_create_hcd(&tegra_ehci_hc_driver, &pdev->dev,
					dev_name(&pdev->dev));
	if (!hcd) {
		dev_err(&pdev->dev, "unable to create HCD\n");
		return -ENOMEM;
	}

	platform_set_drvdata(pdev, tegra);

#ifdef CONFIG_TEGRA_EHCI_BOOST_CPU_FREQ
	tegra->boost_requested = false;
	/* Add boost enable/disable knob */
	tegra->boost_enable = true;
	err = device_create_file(hcd->self.controller, &dev_attr_boost_enable);
	if (err < 0)
		goto fail_sysfs;
#endif

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res) {
		dev_err(&pdev->dev, "failed to get I/O memory\n");
		err = -ENXIO;
		goto fail_io;
	}
	hcd->rsrc_start = res->start;
	hcd->rsrc_len = resource_size(res);
	hcd->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
	if (!hcd->regs) {
		dev_err(&pdev->dev, "failed to remap I/O memory\n");
		err = -ENOMEM;
		goto fail_io;
	}

	/* This is pretty ugly and needs to be fixed when we do only
	 * device-tree probing. Old code relies on the platform_device
	 * numbering that we lack for device-tree-instantiated devices.
	 */
	if (instance < 0) {
		switch (res->start) {
		case TEGRA_USB_BASE:
			instance = 0;
			break;
		case TEGRA_USB2_BASE:
			instance = 1;
			break;
		case TEGRA_USB3_BASE:
			instance = 2;
			break;
		default:
			err = -ENODEV;
			dev_err(&pdev->dev, "unknown usb instance\n");
			goto fail_io;
		}
	}

	irq = platform_get_irq(pdev, 0);
	if (irq < 0) {
		dev_err(&pdev->dev, "failed to get IRQ\n");
		err = -ENODEV;
		goto fail_io;
	}
	tegra->irq = irq;

	tegra->unaligned_dma_buf_supported = pdata->unaligned_dma_buf_supported;
	tegra->has_hostpc = pdata->has_hostpc;

	tegra->phy = tegra_usb_phy_open(pdev);
	hcd->phy = get_usb_phy(tegra->phy);
	if (IS_ERR(tegra->phy)) {
		dev_err(&pdev->dev, "failed to open USB phy\n");
		err = -ENXIO;
		goto fail_io;
	}

	err = tegra_usb_phy_power_on(tegra->phy);
	if (err) {
		dev_err(&pdev->dev, "failed to power on the phy\n");
		goto fail_phy;
	}

	err = usb_phy_init(get_usb_phy(tegra->phy));
	if (err) {
		dev_err(&pdev->dev, "failed to init the phy\n");
		goto fail_phy;
	}

	err = usb_add_hcd(hcd, irq, IRQF_SHARED | IRQF_TRIGGER_HIGH);
	if (err) {
		dev_err(&pdev->dev, "Failed to add USB HCD, error=%d\n", err);
		goto fail_phy;
	}

	tegra->ehci = hcd_to_ehci(hcd);

	if (pdata->port_otg) {
		tegra->transceiver =
			devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
		if (!IS_ERR_OR_NULL(tegra->transceiver))
			otg_set_host(tegra->transceiver->otg, &hcd->self);
	}

	tegra_pd_add_device(&pdev->dev);
	pm_runtime_enable(&pdev->dev);

#ifdef CONFIG_TEGRA_EHCI_BOOST_CPU_FREQ
	INIT_DELAYED_WORK(&tegra->boost_cpu_freq_work,
					tegra_ehci_boost_cpu_frequency_work);
	pm_qos_add_request(&tegra->boost_cpu_freq_req, PM_QOS_CPU_FREQ_MIN,
					PM_QOS_DEFAULT_VALUE);
	schedule_delayed_work(&tegra->boost_cpu_freq_work, 12000);
	tegra->cpu_boost_in_work = true;
#endif

	wake_lock_init(&tegra->ehci_wake_lock,
		       WAKE_LOCK_SUSPEND, dev_name(&pdev->dev));

	return err;

fail_phy:
	usb_phy_shutdown(get_usb_phy(tegra->phy));
fail_io:
#ifdef CONFIG_TEGRA_EHCI_BOOST_CPU_FREQ
	device_remove_file(hcd->self.controller, &dev_attr_boost_enable);
fail_sysfs:
#endif
	usb_put_hcd(hcd);

	return err;
}