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; }
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; }
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; }
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; }
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; }
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; }
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; }