static int ehci_oxnas_reset(struct usb_hcd *hcd) { #define txttfill_tuning reserved2[0] struct ehci_hcd *ehci; u32 tmp; int retval = ehci_setup(hcd); if (retval) return retval; ehci = hcd_to_ehci(hcd); tmp = ehci_readl(ehci, &ehci->regs->txfill_tuning); tmp &= ~0x00ff0000; tmp |= 0x003f0000; /* set burst pre load count to 0x40 (63 * 4 bytes) */ tmp |= 0x16; /* set sheduler overhead to 22 * 1.267us (HS) or 22 * 6.33us (FS/LS)*/ ehci_writel(ehci, tmp, &ehci->regs->txfill_tuning); tmp = ehci_readl(ehci, &ehci->regs->txttfill_tuning); tmp |= 0x2; /* set sheduler overhead to 2 * 6.333us */ ehci_writel(ehci, tmp, &ehci->regs->txttfill_tuning); return retval; }
/* * Root HUB Status Data */ static int _emxx_hub_status_data(struct usb_hcd *hcd, char *buf) { int status; status = ehci_hub_status_data(hcd, buf); if (status) { u32 temp; struct ehci_hcd *ehci = hcd_to_ehci(hcd); temp = ehci_readl(ehci, &ehci->regs->port_status[0]); if (temp & PORT_CONNECT) { temp = readl(SMU_CKRQMODE_MASK1); writel(temp & ~0x04000000, SMU_CKRQMODE_MASK1); } else { temp = readl(SMU_CKRQMODE_MASK1); writel(temp | 0x04000000, SMU_CKRQMODE_MASK1); } } return status; }
static int ehci_orion_setup(struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); int retval; ehci_reset(ehci); retval = ehci_halt(ehci); if (retval) return retval; /* * data structure init */ retval = ehci_init(hcd); if (retval) return retval; hcd->has_tt = 1; ehci_port_power(ehci, 0); return retval; }
static int ehci_sead3_setup(struct usb_hcd *hcd) { int ret; struct ehci_hcd *ehci = hcd_to_ehci(hcd); ehci->caps = hcd->regs + 0x100; #ifdef __BIG_ENDIAN ehci->big_endian_mmio = 1; ehci->big_endian_desc = 1; #endif ret = ehci_setup(hcd); if (ret) return ret; ehci->need_io_watchdog = 0; /* Set burst length to 16 words. */ ehci_writel(ehci, 0x1010, &ehci->regs->reserved1[1]); return ret; }
static int host_start(struct ci13xxx *ci) { struct usb_hcd *hcd; struct ehci_hcd *ehci; int ret; if (usb_disabled()) return -ENODEV; hcd = usb_create_hcd(&ci_ehci_hc_driver, ci->dev, dev_name(ci->dev)); if (!hcd) return -ENOMEM; dev_set_drvdata(ci->dev, ci); hcd->rsrc_start = ci->hw_bank.phys; hcd->rsrc_len = ci->hw_bank.size; hcd->regs = ci->hw_bank.abs; hcd->has_tt = 1; hcd->power_budget = ci->platdata->power_budget; hcd->phy = ci->transceiver; ehci = hcd_to_ehci(hcd); ehci->caps = ci->hw_bank.cap; ehci->has_hostpc = ci->hw_bank.lpm; ret = usb_add_hcd(hcd, 0, 0); if (ret) usb_put_hcd(hcd); else ci->hcd = hcd; if (ci->platdata->flags & CI13XXX_DISABLE_STREAMING) hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS); return ret; }
static void tegra_ehci_restart (struct usb_hcd *hcd) { unsigned int temp; struct ehci_hcd *ehci = hcd_to_ehci(hcd); /* Set to Host mode by setting bit 0-1 of USB device mode register */ temp = readl(hcd->regs + TEGRA_USB_USBMODE_REG_OFFSET); writel((temp | TEGRA_USB_USBMODE_HOST), (hcd->regs + TEGRA_USB_USBMODE_REG_OFFSET)); /* reset the ehci controller */ ehci->controller_resets_phy = 0; ehci_reset(ehci); ehci->controller_resets_phy = 1; /* setup the frame list and Async q heads */ ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list); ehci_writel(ehci, (u32)ehci->async->qh_dma, &ehci->regs->async_next); /* setup the command register and set the controller in RUN mode */ ehci->command &= ~(CMD_LRESET|CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET); ehci->command |= CMD_RUN; ehci_writel(ehci, ehci->command, &ehci->regs->command); /* Enable the root Port Power */ if (HCS_PPC (ehci->hcs_params)) { temp = ehci_readl(ehci, &ehci->regs->port_status[0]); ehci_writel(ehci, temp | PORT_POWER, &ehci->regs->port_status[0]); } down_write(&ehci_cf_port_reset_rwsem); hcd->state = HC_STATE_RUNNING; /* unblock posted writes */ ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag); ehci_readl(ehci, &ehci->regs->command); up_write(&ehci_cf_port_reset_rwsem); /* Turn On Interrupts */ ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable); }
/* called during probe() after chip reset completes */ static int ehci_fsl_setup(struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); int retval; /* EHCI registers start at offset 0x00 */ ehci->caps = hcd->regs + 0x100; ehci->regs = hcd->regs + 0x100 + HC_LENGTH(readl(&ehci->caps->hc_capbase)); vdbg("%s(): ehci->caps=0x%p ehci->regs=0x%p\n", __FUNCTION__, ehci->caps, ehci->regs); dbg_hcs_params(ehci, "reset"); dbg_hcc_params(ehci, "reset"); /* cache this readonly data; minimize chip reads */ ehci->hcs_params = readl(&ehci->caps->hcs_params); retval = ehci_halt(ehci); if (retval) return retval; /* data structure init */ retval = ehci_init(hcd); if (retval) return retval; ehci->is_tdi_rh_tt = 1; ehci->sbrn = 0x20; ehci_reset(ehci); retval = ehci_fsl_reinit(ehci); return retval; }
static int ehci_hcd_ppc_of_remove(struct platform_device *op) { struct usb_hcd *hcd = dev_get_drvdata(&op->dev); struct ehci_hcd *ehci = hcd_to_ehci(hcd); struct device_node *np; struct resource res; dev_set_drvdata(&op->dev, NULL); dev_dbg(&op->dev, "stopping PPC-OF USB Controller\n"); usb_remove_hcd(hcd); irq_dispose_mapping(hcd->irq); /* use request_mem_region to test if the ohci driver is loaded. if so * ensure the ohci core is operational. */ if (ehci->has_amcc_usb23) { np = of_find_compatible_node(NULL, NULL, "ibm,usb-ohci-440epx"); if (np != NULL) { if (!of_address_to_resource(np, 0, &res)) if (!request_mem_region(res.start, 0x4, hcd_name)) set_ohci_hcfs(ehci, 1); else release_mem_region(res.start, 0x4); else pr_debug("%s: no ohci offset in fdt\n", __FILE__); of_node_put(np); } } usb_put_hcd(hcd); return 0; }
static int cns3xxx_ehci_init(struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); int retval; /* * EHCI and OHCI share the same clock and power, * resetting twice would cause the 1st controller been reset. * Therefore only do power up at the first up device, and * power down at the last down device. * * Set USB AHB INCR length to 16 */ if (atomic_inc_return(&usb_pwr_ref) == 1) { cns3xxx_pwr_power_up(1 << PM_PLL_HM_PD_CTRL_REG_OFFSET_PLL_USB); cns3xxx_pwr_clk_en(1 << PM_CLK_GATE_REG_OFFSET_USB_HOST); cns3xxx_pwr_soft_rst(1 << PM_SOFT_RST_REG_OFFST_USB_HOST); __raw_writel((__raw_readl(MISC_CHIP_CONFIG_REG) | (0X2 << 24)), MISC_CHIP_CONFIG_REG); } ehci->caps = hcd->regs; ehci->regs = hcd->regs + HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase)); ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); hcd->has_tt = 0; ehci_reset(ehci); retval = ehci_init(hcd); if (retval) return retval; ehci_port_power(ehci, 0); return retval; }
static void tegra_ehci_restart(struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); unsigned int temp; ehci->controller_resets_phy = 0; ehci_reset(ehci); tegra_ehci_post_reset(tegra->phy, false); if (tegra->phy->usb_phy_type == TEGRA_USB_PHY_TYPE_NULL_ULPI) ehci->controller_resets_phy = 1; /* setup the frame list and Async q heads */ ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list); ehci_writel(ehci, (u32)ehci->async->qh_dma, &ehci->regs->async_next); /* setup the command register and set the controller in RUN mode */ ehci->command &= ~(CMD_LRESET|CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET); ehci->command |= CMD_RUN; ehci_writel(ehci, ehci->command, &ehci->regs->command); /* Enable the root Port Power */ if (HCS_PPC(ehci->hcs_params)) { temp = ehci_readl(ehci, &ehci->regs->port_status[0]); ehci_writel(ehci, temp | PORT_POWER, &ehci->regs->port_status[0]); } down_write(&ehci_cf_port_reset_rwsem); hcd->state = HC_STATE_RUNNING; ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag); /* flush posted writes */ ehci_readl(ehci, &ehci->regs->command); up_write(&ehci_cf_port_reset_rwsem); /* Turn On Interrupts */ ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable); }
static int ehci_fsl_bus_suspend(struct usb_hcd *hcd) { int ret = 0; struct fsl_usb2_platform_data *pdata; u32 tmp, portsc; struct ehci_hcd *ehci = hcd_to_ehci(hcd); pdata = hcd->self.controller->platform_data; printk(KERN_DEBUG "%s, %s\n", __func__, pdata->name); /* the host is already at low power mode */ if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { return 0; } portsc = ehci_readl(ehci, &ehci->regs->port_status[0]); ret = ehci_bus_suspend(hcd); if (ret != 0) return ret; if (portsc & PORT_CCS) { printk(KERN_DEBUG "there is a device on the port\n"); tmp = ehci_readl(ehci, &ehci->regs->command); tmp |= CMD_RUN; ehci_writel(ehci, tmp, &ehci->regs->command); } if (pdata->platform_suspend) pdata->platform_suspend(pdata); usb_host_set_wakeup(hcd->self.controller, true); fsl_usb_lowpower_mode(pdata, true); fsl_usb_clk_gate(hcd->self.controller->platform_data, false); clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); return ret; }
static int ehci_ci_portpower(struct usb_hcd *hcd, int portnum, bool enable) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); struct ehci_ci_priv *priv = (struct ehci_ci_priv *)ehci->priv; struct device *dev = hcd->self.controller; struct ci_hdrc *ci = dev_get_drvdata(dev); int ret = 0; int port = HCS_N_PORTS(ehci->hcs_params); if (priv->reg_vbus) { if (port > 1) { dev_warn(dev, "Not support multi-port regulator control\n"); return 0; } if (enable) ret = regulator_enable(priv->reg_vbus); else ret = regulator_disable(priv->reg_vbus); if (ret) { dev_err(dev, "Failed to %s vbus regulator, ret=%d\n", enable ? "enable" : "disable", ret); return ret; } } if (enable && (ci->platdata->phy_mode == USBPHY_INTERFACE_MODE_HSIC)) { /* * Marvell 28nm HSIC PHY requires forcing the port to HS mode. * As HSIC is always HS, this should be safe for others. */ hw_port_test_set(ci, 5); hw_port_test_set(ci, 0); } return 0; };
/* called during probe() after chip reset completes */ static int ehci_fsl_setup(struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); int retval; struct fsl_usb2_platform_data *pdata; pdata = hcd->self.controller->platform_data; ehci->big_endian_desc = pdata->big_endian_desc; ehci->big_endian_mmio = pdata->big_endian_mmio; /* EHCI registers start at offset 0x100 */ ehci->caps = hcd->regs + 0x100; ehci->regs = hcd->regs + 0x100 + HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase)); dbg_hcs_params(ehci, "reset"); dbg_hcc_params(ehci, "reset"); /* cache this readonly data; minimize chip reads */ ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); retval = ehci_halt(ehci); /* data structure init */ retval = ehci_init(hcd); if (retval) return retval; ehci->is_tdi_rh_tt = 1; ehci->sbrn = 0x20; ehci_reset(ehci); retval = ehci_fsl_reinit(ehci); return retval; }
static int ehci_platform_reset(struct usb_hcd *hcd) { struct platform_device *pdev = to_platform_device(hcd->self.controller); struct usb_ehci_pdata *pdata = dev_get_platdata(&pdev->dev); struct ehci_hcd *ehci = hcd_to_ehci(hcd); int retval; ehci->has_synopsys_hc_bug = pdata->has_synopsys_hc_bug; if (pdata->pre_setup) { retval = pdata->pre_setup(hcd); if (retval < 0) return retval; } ehci->caps = hcd->regs + pdata->caps_offset; retval = ehci_setup(hcd); if (retval) return retval; if (pdata->no_io_watchdog) ehci->need_io_watchdog = 0; return 0; }
static int ehci_platform_reset(struct usb_hcd *hcd) { struct platform_device *pdev = to_platform_device(hcd->self.controller); struct usb_ehci_pdata *pdata = pdev->dev.platform_data; struct ehci_hcd *ehci = hcd_to_ehci(hcd); int retval; hcd->has_tt = pdata->has_tt; ehci->has_synopsys_hc_bug = pdata->has_synopsys_hc_bug; ehci->big_endian_desc = pdata->big_endian_desc; ehci->big_endian_mmio = pdata->big_endian_mmio; ehci->caps = hcd->regs + pdata->caps_offset; retval = ehci_setup(hcd); if (retval) return retval; if (pdata->port_power_on) ehci_port_power(ehci, 1); if (pdata->port_power_off) ehci_port_power(ehci, 0); return 0; }
/* * non-error returns are a promise to giveback() the urb later * we drop ownership so next owner (or urb unlink) can get it * * urb + dev is in hcd.self.controller.urb_list * we're queueing TDs onto software and hardware lists * * hcd-specific init for hcpriv hasn't been done yet * * NOTE: control, bulk, and interrupt share the same code to append TDs * to a (possibly active) QH, and the same QH scanning code. */ static int ehci_urb_enqueue ( struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags ) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); struct list_head qtd_list; INIT_LIST_HEAD (&qtd_list); switch (usb_pipetype (urb->pipe)) { case PIPE_CONTROL: /* qh_completions() code doesn't handle all the fault cases * in multi-TD control transfers. Even 1KB is rare anyway. */ if (urb->transfer_buffer_length > (16 * 1024)) return -EMSGSIZE; /* FALLTHROUGH */ /* case PIPE_BULK: */ default: if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags)) return -ENOMEM; return submit_async(ehci, urb, &qtd_list, mem_flags); case PIPE_INTERRUPT: if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags)) return -ENOMEM; return intr_submit(ehci, urb, &qtd_list, mem_flags); case PIPE_ISOCHRONOUS: if (urb->dev->speed == USB_SPEED_HIGH) return itd_submit (ehci, urb, mem_flags); else return sitd_submit (ehci, urb, mem_flags); } }
static void s5p_wait_for_cp_resume(struct platform_device *pdev, struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); struct s5p_ehci_platdata *pdata = pdev->dev.platform_data; u32 __iomem *portsc ; u32 val32, retry_cnt = 0; #if !defined(CONFIG_MDM_HSIC_PM) /* when use usb3503 hub, need not wait cp resume */ if (modem_using_hub()) return; #endif portsc = &ehci->regs->port_status[CP_PORT-1]; #if !defined(CONFIG_MDM_HSIC_PM) if (pdata && pdata->noti_host_states) pdata->noti_host_states(pdev, S5P_HOST_ON); #endif do { msleep(10); val32 = ehci_readl(ehci, portsc); } while (++retry_cnt < RETRY_CNT_LIMIT && !(val32 & PORT_CONNECT)); if (retry_cnt >= RETRY_CNT_LIMIT) dev_info(&pdev->dev, "%s: retry_cnt = %d, portsc = 0x%x\n", __func__, retry_cnt, val32); #if defined(CONFIG_UMTS_MODEM_XMM6262) if (pdata && pdata->get_cp_active_state && !pdata->get_cp_active_state()) { s5p_ehci_port_control(pdev, CP_PORT, 0); pr_err("mif: force port%d off by cp reset\n", CP_PORT); } #endif }
static int ehci_spear_setup(struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); int retval = 0; /* registers start at offset 0x0 */ ehci->caps = hcd->regs; ehci->regs = hcd->regs + HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase)); /* cache this readonly data; minimize chip reads */ ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); retval = ehci_halt(ehci); if (retval) return retval; retval = ehci_init(hcd); if (retval) return retval; ehci_reset(ehci); ehci_port_power(ehci, 0); return retval; }
void usb_register_dump(void) { struct usb_hcd *hcd; struct ehci_hcd *ehci; int i = 0; if(s_hsic_hcd) { hcd = s_hsic_hcd; ehci = hcd_to_ehci(hcd); for( i = 0; i < 0x200; i = i+16) { pr_info("ADDRESS:%d 0x%08x 0x%08x 0x%08x 0x%08x\n", (int)(hcd->regs + i), readl(hcd->regs + i), readl(hcd->regs + i + 4), readl(hcd->regs + i + 8), readl(hcd->regs + i + 12)); } pr_info("USB2_IF_USB_SUSP_CTRL_0: 0x%08x\n", readl(hcd->regs + 0x400)); pr_info("HSIC Registers\n"); for( i = 0xc00; i < 0xc40; i = i+16) { pr_info("ADDRESS:%d 0x%08x 0x%08x 0x%08x 0x%08x\n", (int)(hcd->regs + i), readl(hcd->regs + i), readl(hcd->regs + i + 4), readl(hcd->regs + i + 8), readl(hcd->regs + i + 12)); } } }
static int ixp4xx_ehci_init(struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); int retval = 0; ehci->big_endian_desc = 1; ehci->big_endian_mmio = 1; ehci->caps = hcd->regs + 0x100; ehci->regs = hcd->regs + 0x100 + HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase)); ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); hcd->has_tt = 1; ehci_reset(ehci); retval = ehci_init(hcd); if (retval) return retval; ehci_port_power(ehci, 0); return retval; }
static int tegra_ehci_bus_suspend(struct usb_hcd *hcd) { struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); struct ehci_hcd *ehci = hcd_to_ehci(hcd); int err = 0; EHCI_DBG("%s() BEGIN\n", __func__); pr_info("%s::resetdone = %ld:tegra->port_resuming =%d\n", __func__, ehci->reset_done[0], tegra->port_resuming); mutex_lock(&tegra->sync_lock); tegra->bus_suspended_fail = false; err = ehci_bus_suspend(hcd); if (err) { if(tegra->port_resuming) pr_info("%s: bus_suspended aborted because of resume. err=(%d):resetdone = %ld:tegra->port_resuming =%d\n", __func__, err, ehci->reset_done[0], tegra->port_resuming); else pr_info("%s: bus_suspended_fail err=(%d):resetdone = %ld\n", __func__, err, ehci->reset_done[0]); tegra->bus_suspended_fail = true; } else tegra_usb_phy_suspend(tegra->phy); mutex_unlock(&tegra->sync_lock); EHCI_DBG("%s() END\n", __func__); return err; }
static int sram_restore(struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); void __iomem *base; int offset; if (!ehci->sram_swap) return -EFAULT; base = ioremap_nocache(ehci->sram_addr, ehci->sram_size); if (!base) { ehci_warn(ehci, "SRAM_restore ioremap fails\n"); return -EFAULT; } for (offset = 0; offset < ehci->sram_size; offset += 4) writel(*(u32 *)(ehci->sram_swap + offset), base + offset); iounmap(base); vfree(ehci->sram_swap); ehci->sram_swap = NULL; return 0; }
static int sw_ehci_hcd_resume(struct device *dev) { struct sw_hci_hcd *sw_ehci = NULL; struct usb_hcd *hcd = NULL; struct ehci_hcd *ehci = NULL; if (dev == NULL) return 0; hcd = dev_get_drvdata(dev); if (hcd == NULL) return 0; sw_ehci = dev->platform_data; if (sw_ehci == NULL) return 0; if (sw_ehci->probe == 0) return 0; ehci = hcd_to_ehci(hcd); if (ehci == NULL) return 0; pr_info("[%s]: resume\n", sw_ehci->hci_name); sw_start_ehci(sw_ehci); /* Mark hardware accessible again as we are out of D3 state by now */ set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) { int mask = INTR_MASK; ehci_prepare_ports_for_controller_resume(ehci); if (!hcd->self.root_hub->do_remote_wakeup) mask &= ~STS_PCD; ehci_writel(ehci, mask, &ehci->regs->intr_enable); ehci_readl(ehci, &ehci->regs->intr_enable); return 0; } pr_info("[%s]: hci lost power, restarting\n", sw_ehci->hci_name); usb_root_hub_lost_power(hcd->self.root_hub); /* Else reset, to cope with power loss or flush-to-storage * style "resume" having let BIOS kick in during reboot. */ (void) ehci_halt(ehci); (void) ehci_reset(ehci); /* emptying the schedule aborts any urbs */ spin_lock_irq(&ehci->lock); if (ehci->reclaim) end_unlink_async(ehci); ehci_work(ehci); spin_unlock_irq(&ehci->lock); ehci_writel(ehci, ehci->command, &ehci->regs->command); ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag); ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */ /* here we "know" root ports should always stay powered */ ehci_port_power(ehci, 1); hcd->state = HC_STATE_SUSPENDED; return 0; }
int bcm_ehci_probe(struct platform_device *pdev) { struct ehci_bcm_usb_cfg *usb; struct usb_hcd *hcd; struct ehci_hcd *ehci; struct resource *iomem, *ioarea; int ret, irq; if (usb_disabled()) return -ENODEV; iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!iomem) { EHCI_ERR(pdev, "no mem resource\n"); ret = -ENOMEM; goto err_exit; } /* get the irq info */ irq = platform_get_irq(pdev, 0); if (!irq) { EHCI_ERR(pdev, "no irq resource\n"); ret = -ENODEV; goto err_exit; } ioarea = request_mem_region(iomem->start, resource_size(iomem), pdev->name); if (!ioarea) { EHCI_ERR(pdev, "memory region already claimed\n"); ret = -EBUSY; goto err_exit; } usb = kzalloc(sizeof(*usb), GFP_KERNEL); if (!usb) { EHCI_ERR(pdev, "unable to allocate memory for private data\n"); ret = -ENOMEM; goto err_free_iomem; } usb->virt_reg_base = ioremap(iomem->start, resource_size(iomem)); if (!usb->virt_reg_base) { EHCI_ERR(pdev, "ioremap failed\n"); ret = -ENOMEM; goto err_free_private_mem; } hcd = usb_create_hcd(&ehci_bcm_hcd_driver, &pdev->dev, (char *)pdev->name); if (!hcd) { EHCI_ERR(pdev, "usb_create_hcd failed\n"); ret = -ENOMEM; goto err_usb_term; } /* struct ehci_regs def'd in Linux ehci.h * which is included by Linux ehci-hcd.c */ usb->hcd = hcd; hcd->rsrc_start = (unsigned int)usb->virt_reg_base; hcd->rsrc_len = sizeof(struct ehci_regs); hcd->regs = usb->virt_reg_base; ehci = hcd_to_ehci(hcd); ehci->caps = hcd->regs; ehci->regs = hcd->regs + HC_LENGTH(ehci, readl(&ehci->caps->hc_capbase)); /* cache this readonly data; minimize chip reads */ ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); ret = usb_add_hcd(hcd, irq, BCM_USBEHCI_IRQF_FLAGS); if (ret) { EHCI_ERR(pdev, "usb_add_hcd failed\n"); goto err_remove_hcd; } platform_set_drvdata(pdev, usb); EHCI_INFO(pdev, "probe done\n"); return 0; err_remove_hcd: usb_remove_hcd(hcd); usb_put_hcd(hcd); err_usb_term: iounmap(usb->virt_reg_base); err_free_private_mem: kfree(usb); err_free_iomem: release_mem_region(iomem->start, resource_size(iomem)); err_exit: EHCI_ERR(pdev, "probe failed: %d\n", ret); return ret; }
static int sw_ehci_hcd_probe(struct platform_device *pdev) { struct usb_hcd *hcd = NULL; struct ehci_hcd *ehci = NULL; struct sw_hci_hcd *sw_ehci = NULL; int ret = 0; if (pdev == NULL) return -EINVAL; /* if usb is disabled, can not probe */ if (usb_disabled()) return -ENODEV; sw_ehci = pdev->dev.platform_data; if (!sw_ehci) return -ENODATA; sw_ehci->pdev = pdev; g_sw_ehci[sw_ehci->usbc_no] = sw_ehci; pr_debug("[%s%d]: probe, pdev->name: %s, pdev->id: %d," " sw_ehci: 0x%p\n", SW_EHCI_NAME, sw_ehci->usbc_no, pdev->name, pdev->id, sw_ehci); /* get io resource */ sw_get_io_resource(pdev, sw_ehci); sw_ehci->ehci_base = sw_ehci->usb_vbase + SW_USB_EHCI_BASE_OFFSET; sw_ehci->ehci_reg_length = SW_USB_EHCI_LEN; /* creat a usb_hcd for the ehci controller */ hcd = usb_create_hcd(&sw_ehci_hc_driver, &pdev->dev, SW_EHCI_NAME); if (!hcd) { pr_err("%s: failed to create hcd\n", __func__); ret = -ENOMEM; goto err_create_hcd; } hcd->rsrc_start = (u32) sw_ehci->ehci_base; hcd->rsrc_len = sw_ehci->ehci_reg_length; hcd->regs = sw_ehci->ehci_base; sw_ehci->hcd = hcd; /* echi start to work */ sw_start_ehci(sw_ehci); ehci = hcd_to_ehci(hcd); ehci->caps = hcd->regs; ehci->regs = hcd->regs + HC_LENGTH(ehci, readl(&ehci->caps->hc_capbase)); /* cache this readonly data, minimize chip reads */ ehci->hcs_params = readl(&ehci->caps->hcs_params); ret = usb_add_hcd(hcd, sw_ehci->irq_no, IRQF_DISABLED | IRQF_SHARED); if (ret != 0) { pr_err("%s: failed to add hcd, rc=%d\n", __func__, ret); goto err_add_hcd; } platform_set_drvdata(pdev, hcd); pr_debug("[%s]: probe, clock: 0x60(0x%x), 0xcc(0x%x);" " usb: 0x800(0x%x), dram:(0x%x, 0x%x)\n", sw_ehci->hci_name, (u32) USBC_Readl(sw_ehci->clock_vbase + 0x60), (u32) USBC_Readl(sw_ehci->clock_vbase + 0xcc), (u32) USBC_Readl(sw_ehci->usb_vbase + 0x800), (u32) USBC_Readl(sw_ehci->sdram_vbase + SW_SDRAM_REG_HPCR_USB1), (u32) USBC_Readl(sw_ehci->sdram_vbase + SW_SDRAM_REG_HPCR_USB2)); sw_ehci->probe = 1; /* Disable ehci, when driver probe */ if (sw_ehci->host_init_state == 0) { if (ehci_first_probe[sw_ehci->usbc_no]) { sw_usb_disable_ehci(sw_ehci->usbc_no); ehci_first_probe[sw_ehci->usbc_no]--; } } return 0; err_add_hcd: usb_put_hcd(hcd); err_create_hcd: sw_ehci->hcd = NULL; g_sw_ehci[sw_ehci->usbc_no] = NULL; return ret; }
static void ehci_hsic_remove(struct pci_dev *pdev) { struct usb_hcd *hcd = pci_get_drvdata(pdev); struct ehci_hcd *ehci = hcd_to_ehci(hcd); if (!hcd) return; hsic.hsic_stopped = 1; hsic_enable = 0; if (pci_dev_run_wake(pdev)) pm_runtime_get_noresume(&pdev->dev); if (!enabling_disabling) { if (!pci_dev_run_wake(pdev)) pm_runtime_get_noresume(&pdev->dev); pm_runtime_forbid(&pdev->dev); } /* Free the aux irq */ hsic_aux_irq_free(); hsic_wakeup_irq_free(); /* Fake an interrupt request in order to give the driver a chance * to test whether the controller hardware has been removed (e.g., * cardbus physical eject). */ local_irq_disable(); usb_hcd_irq(0, hcd); local_irq_enable(); usb_remove_hcd(hcd); #if 0 ehci_hsic_port_power(ehci, 0); #endif /* Set phy low power mode, disable phy clock */ ehci_hsic_phy_power(ehci, 1); if (hcd->driver->flags & HCD_MEMORY) { iounmap(hcd->regs); release_mem_region(hcd->rsrc_start, hcd->rsrc_len); } else { release_region(hcd->rsrc_start, hcd->rsrc_len); } usb_put_hcd(hcd); gpio_free(hsic.aux_gpio); gpio_free(hsic.wakeup_gpio); pci_disable_device(pdev); cancel_delayed_work_sync(&hsic.wakeup_work); destroy_workqueue(hsic.work_queue); wake_lock_destroy(&(hsic.resume_wake_lock)); wake_lock_destroy(&hsic.s3_wake_lock); usb_unregister_notify(&hsic.hsic_pm_nb); unregister_pm_notifier(&hsic.hsic_s3_entry_nb); hsic_debugfs_cleanup(); }
static int ehci_hsic_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct hc_driver *driver; struct usb_hcd *hcd; struct ehci_hcd *ehci; int irq, retval; pr_debug("initializing Intel EHCI HSIC Host Controller\n"); if (usb_disabled()) return -ENODEV; if (!id) return -EINVAL; pci_dev = pdev; if (pci_enable_device(pdev) < 0) return -ENODEV; pdev->current_state = PCI_D0; wake_lock_init(&hsic.resume_wake_lock, WAKE_LOCK_SUSPEND, "hsic_aux2_wlock"); wake_lock_init(&hsic.s3_wake_lock, WAKE_LOCK_SUSPEND, "hsic_s3_wlock"); hsic.hsic_pm_nb.notifier_call = hsic_pm_notify; usb_register_notify(&hsic.hsic_pm_nb); hsic.hsic_s3_entry_nb.notifier_call = hsic_s3_entry_notify; register_pm_notifier(&hsic.hsic_s3_entry_nb); /* we need not call pci_enable_dev since otg transceiver already take * the control of this device and this probe actaully gets called by * otg transceiver driver with HNP protocol. */ irq = pdev->irq; if (!pdev->irq) { dev_dbg(&pdev->dev, "No IRQ.\n"); retval = -ENODEV; goto disable_pci; } driver = (struct hc_driver *)id->driver_data; if (!driver) return -EINVAL; /* AUX GPIO init */ retval = hsic_aux_gpio_init(); if (retval < 0) { dev_err(&pdev->dev, "AUX GPIO init fail\n"); retval = -ENODEV; goto disable_pci; } /* AUX GPIO init */ retval = hsic_wakeup_gpio_init(); if (retval < 0) { dev_err(&pdev->dev, "Wakeup GPIO init fail\n"); retval = -ENODEV; goto disable_pci; } hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev)); if (!hcd) { retval = -ENOMEM; goto disable_pci; } ehci = hcd_to_ehci(hcd); hcd->rsrc_start = pci_resource_start(pdev, 0); hcd->rsrc_len = pci_resource_len(pdev, 0); if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, driver->description)) { dev_dbg(&pdev->dev, "controller already in use\n"); retval = -EBUSY; goto clear_companion; } hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); if (hcd->regs == NULL) { dev_dbg(&pdev->dev, "error mapping memory\n"); retval = -EFAULT; goto release_mem_region; } pci_set_master(pdev); if (hsic.hsic_enable_created == 0) { retval = create_device_files(); if (retval < 0) { dev_dbg(&pdev->dev, "error create device files\n"); goto release_mem_region; } hsic.hsic_enable_created = 1; } if (hsic.hsic_mutex_init == 0) { mutex_init(&hsic.hsic_mutex); mutex_init(&hsic.wlock_mutex); hsic.hsic_mutex_init = 1; } if (hsic.aux_wq_init == 0) { init_waitqueue_head(&hsic.aux_wq); hsic.aux_wq_init = 1; } hsic.work_queue = create_singlethread_workqueue("hsic"); INIT_DELAYED_WORK(&hsic.wakeup_work, wakeup_work); INIT_DELAYED_WORK(&(hsic.hsic_aux), hsic_aux_work); hcd->hsic_notify = hsic_notify; retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED | IRQF_NO_SUSPEND); if (retval != 0) goto unmap_registers; dev_set_drvdata(&pdev->dev, hcd); /* Clear phy low power mode, enable phy clock */ ehci_hsic_phy_power(ehci, 0); if (pci_dev_run_wake(pdev)) pm_runtime_put_noidle(&pdev->dev); if (!enabling_disabling) { /* Check here to avoid to call pm_runtime_put_noidle() twice */ if (!pci_dev_run_wake(pdev)) pm_runtime_put_noidle(&pdev->dev); pm_runtime_allow(&pdev->dev); } hsic.hsic_stopped = 0; hsic_enable = 1; hsic.s3_rt_state = RESUMED; s3_wake_lock(); hsic_debugfs_init(hcd); return retval; unmap_registers: destroy_workqueue(hsic.work_queue); if (driver->flags & HCD_MEMORY) { iounmap(hcd->regs); release_mem_region: release_mem_region(hcd->rsrc_start, hcd->rsrc_len); } else release_region(hcd->rsrc_start, hcd->rsrc_len); clear_companion: dev_set_drvdata(&pdev->dev, NULL); usb_put_hcd(hcd); disable_pci: pci_disable_device(pdev); dev_err(&pdev->dev, "init %s fail, %d\n", dev_name(&pdev->dev), retval); wake_lock_destroy(&(hsic.resume_wake_lock)); wake_lock_destroy(&hsic.s3_wake_lock); return retval; }
static int tegra_ehci_hub_control( struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength ) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); int ports = HCS_N_PORTS(ehci->hcs_params); u32 temp, status; u32 __iomem *status_reg; u32 usbsts_reg; unsigned long flags; int retval = 0; unsigned selector; struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); bool hsic = false; if (!tegra->host_resumed) { if (buf) memset (buf, 0, wLength); return retval; } if (tegra->phy->instance == 1) { struct tegra_ulpi_config *config = tegra->phy->config; hsic = (config->inf_type == TEGRA_USB_UHSIC); } status_reg = &ehci->regs->port_status[(wIndex & 0xff) - 1]; spin_lock_irqsave(&ehci->lock, flags); /* * In ehci_hub_control() for USB_PORT_FEAT_ENABLE clears the other bits * that are write on clear, by writing back the register read value, so * USB_PORT_FEAT_ENABLE is handled by masking the set on clear bits */ if (typeReq == ClearPortFeature && wValue == USB_PORT_FEAT_ENABLE) { temp = ehci_readl(ehci, status_reg) & ~PORT_RWC_BITS; ehci_writel(ehci, temp & ~PORT_PE, status_reg); goto done; } else if (typeReq == GetPortStatus) { temp = ehci_readl(ehci, status_reg); if (tegra->port_resuming && !(temp & PORT_SUSPEND) && time_after_eq(jiffies, ehci->reset_done[wIndex-1])) { /* Resume completed, re-enable disconnect detection */ tegra->port_resuming = 0; clear_bit((wIndex & 0xff) - 1, &ehci->suspended_ports); ehci->reset_done[wIndex-1] = 0; tegra_usb_phy_postresume(tegra->phy, false); } } else if (typeReq == SetPortFeature && wValue == USB_PORT_FEAT_SUSPEND) { temp = ehci_readl(ehci, status_reg); if ((temp & PORT_PE) == 0 || (temp & PORT_RESET) != 0) { retval = -EPIPE; goto done; } temp &= ~PORT_WKCONN_E; temp |= PORT_WKDISC_E | PORT_WKOC_E; ehci_writel(ehci, temp | PORT_SUSPEND, status_reg); /* Need a 4ms delay before the controller goes to suspend */ mdelay(4); /* * If a transaction is in progress, there may be a delay in * suspending the port. Poll until the port is suspended. */ if (handshake(ehci, status_reg, PORT_SUSPEND, PORT_SUSPEND, 5000)) pr_err("%s: timeout waiting for SUSPEND\n", __func__); set_bit((wIndex & 0xff) - 1, &ehci->suspended_ports); goto done; } /* * Tegra host controller will time the resume operation to clear the bit * when the port control state switches to HS or FS Idle. This behavior * is different from EHCI where the host controller driver is required * to set this bit to a zero after the resume duration is timed in the * driver. */ else if (typeReq == ClearPortFeature && wValue == USB_PORT_FEAT_SUSPEND) { temp = ehci_readl(ehci, status_reg); if ((temp & PORT_RESET) || !(temp & PORT_PE)) { retval = -EPIPE; goto done; } if (!(temp & PORT_SUSPEND)) goto done; tegra->port_resuming = 1; /* Disable disconnect detection during port resume */ tegra_usb_phy_preresume(tegra->phy, false); ehci_dbg(ehci, "%s:USBSTS = 0x%x", __func__, ehci_readl(ehci, &ehci->regs->status)); usbsts_reg = ehci_readl(ehci, &ehci->regs->status); ehci_writel(ehci, usbsts_reg, &ehci->regs->status); usbsts_reg = ehci_readl(ehci, &ehci->regs->status); udelay(20); if (handshake(ehci, &ehci->regs->status, STS_SRI, STS_SRI, 2000)) pr_err("%s: timeout set for STS_SRI\n", __func__); usbsts_reg = ehci_readl(ehci, &ehci->regs->status); ehci_writel(ehci, usbsts_reg, &ehci->regs->status); if (handshake(ehci, &ehci->regs->status, STS_SRI, 0, 2000)) pr_err("%s: timeout clear STS_SRI\n", __func__); if (handshake(ehci, &ehci->regs->status, STS_SRI, STS_SRI, 2000)) pr_err("%s: timeout set STS_SRI\n", __func__); udelay(20); temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS); /* start resume signaling */ ehci_writel(ehci, temp | PORT_RESUME, status_reg); ehci->reset_done[wIndex-1] = jiffies + msecs_to_jiffies(25); /* whoever resumes must GetPortStatus to complete it!! */ goto done; } /* Handle port reset here */ if ((hsic) && (typeReq == SetPortFeature) && ((wValue == USB_PORT_FEAT_RESET) || (wValue == USB_PORT_FEAT_POWER))) { selector = wIndex >> 8; wIndex &= 0xff; if (!wIndex || wIndex > ports) { retval = -EPIPE; goto done; } wIndex--; status = 0; temp = ehci_readl(ehci, status_reg); if (temp & PORT_OWNER) goto done; temp &= ~PORT_RWC_BITS; switch (wValue) { case USB_PORT_FEAT_RESET: { if (temp & PORT_RESUME) { retval = -EPIPE; goto done; } /* line status bits may report this as low speed, * which can be fine if this root hub has a * transaction translator built in. */ if ((temp & (PORT_PE|PORT_CONNECT)) == PORT_CONNECT && !ehci_is_TDI(ehci) && PORT_USB11 (temp)) { ehci_dbg (ehci, "port %d low speed --> companion\n", wIndex + 1); temp |= PORT_OWNER; ehci_writel(ehci, temp, status_reg); } else { ehci_vdbg(ehci, "port %d reset\n", wIndex + 1); temp &= ~PORT_PE; /* * caller must wait, then call GetPortStatus * usb 2.0 spec says 50 ms resets on root */ ehci->reset_done[wIndex] = jiffies + msecs_to_jiffies(50); ehci_writel(ehci, temp, status_reg); if (hsic && (wIndex == 0)) tegra_usb_phy_bus_reset(tegra->phy); } break; } case USB_PORT_FEAT_POWER: { if (HCS_PPC(ehci->hcs_params)) ehci_writel(ehci, temp | PORT_POWER, status_reg); if (hsic && (wIndex == 0)) tegra_usb_phy_bus_connect(tegra->phy); break; } } goto done; }
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_hub_control( struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength ) { struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); struct ehci_hcd *ehci = hcd_to_ehci(hcd); int retval = 0; u32 __iomem *status_reg; if (!tegra_usb_phy_hw_accessible(tegra->phy)) { if (buf) memset(buf, 0, wLength); return retval; } /* Do tegra phy specific actions based on the type request */ switch (typeReq) { case GetPortStatus: if (tegra->port_resuming) { u32 cmd; int delay = ehci->reset_done[wIndex-1] - jiffies; /* Sometimes it seems we get called too soon... In that case, wait.*/ if (delay > 0) { ehci_dbg(ehci, "GetPortStatus called too soon, waiting %dms...\n", delay); mdelay(jiffies_to_msecs(delay)); } status_reg = &ehci->regs->port_status[(wIndex & 0xff) - 1]; /* Ensure the port PORT_SUSPEND and PORT_RESUME has cleared */ if (handshake(ehci, status_reg, (PORT_SUSPEND | PORT_RESUME), 0, 25000)) { EHCI_DBG("%s: timeout waiting for SUSPEND to clear\n", __func__); } tegra_usb_phy_post_resume(tegra->phy); tegra->port_resuming = 0; /* If run bit is not set by now enable it */ cmd = ehci_readl(ehci, &ehci->regs->command); if (!(cmd & CMD_RUN)) { cmd |= CMD_RUN; ehci->command |= CMD_RUN; ehci_writel(ehci, cmd, &ehci->regs->command); } /* Now we can safely re-enable irqs */ ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable); } break; case ClearPortFeature: if (wValue == USB_PORT_FEAT_SUSPEND) { tegra_usb_phy_pre_resume(tegra->phy, false); tegra->port_resuming = 1; } else if (wValue == USB_PORT_FEAT_ENABLE) { u32 temp; temp = ehci_readl(ehci, &ehci->regs->port_status[0]) & ~PORT_RWC_BITS; ehci_writel(ehci, temp & ~PORT_PE, &ehci->regs->port_status[0]); return retval; } break; case SetPortFeature: if (wValue == USB_PORT_FEAT_SUSPEND) tegra_usb_phy_pre_suspend(tegra->phy); break; } /* handle ehci hub control request */ retval = ehci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength); /* do tegra phy specific actions based on the type request */ if (!retval) { switch (typeReq) { case SetPortFeature: if (wValue == USB_PORT_FEAT_SUSPEND) { tegra_usb_phy_post_suspend(tegra->phy); } else if (wValue == USB_PORT_FEAT_RESET) { if (wIndex == 1) tegra_usb_phy_bus_reset(tegra->phy); } else if (wValue == USB_PORT_FEAT_POWER) { if (wIndex == 1) tegra_usb_phy_port_power(tegra->phy); } break; case ClearPortFeature: if (wValue == USB_PORT_FEAT_SUSPEND) { /* tegra USB controller needs 25 ms to resume the port */ ehci->reset_done[wIndex-1] = jiffies + msecs_to_jiffies(25); } break; } } return retval; }