static int tegra_ehci_remove(struct platform_device *pdev) { struct tegra_hcd_platform_data *pdata = pdev->dev.platform_data; struct usb_hcd *hcd = platform_get_drvdata(pdev); if (pdata == NULL || hcd == NULL) return -EINVAL; usb_remove_hcd(hcd); usb_put_hcd(hcd); #ifdef CONFIG_DMABOUNCE dmabounce_unregister_dev(&pdev->dev); #endif NvDdkUsbPhyClose(pdata->hUsbPhy); iounmap(hcd->regs); if (pdata->gpio_nr) gpio_free(pdata->gpio_nr); return 0; }
static int __exit tegra_otg_remove(struct platform_device *pdev) { struct tegra_otg_data *tegra_otg = platform_get_drvdata(pdev); otg_set_transceiver(NULL); free_irq(tegra_otg->irq, &pdev->dev); iounmap(tegra_otg->regs); NvDdkUsbPhyClose(tegra_otg->usb_phy); platform_set_drvdata(pdev, NULL); kfree(tegra_otg); sg_tegra_otg = NULL; return 0; }
static int tegra_ehci_probe(struct platform_device *pdev) { struct resource *res; struct tegra_hcd_platform_data *pdata = pdev->dev.platform_data; struct usb_hcd *hcd; int e = 0; int irq; unsigned int temp; struct ehci_hcd *ehci; if (!pdata) { dev_err(&pdev->dev, "platform data must be specified\n"); return -EINVAL; } WARN_ON(!pdev->dev.coherent_dma_mask || !pdev->dev.dma_mask); hcd = usb_create_hcd(&tegra_ehci_hc_driver, &pdev->dev, dev_name(&pdev->dev)); if (IS_ERR_OR_NULL(hcd)) { dev_err(&pdev->dev, "Unable to create HCD\n"); return -ENOMEM; } if (pdata->id_detect == ID_PIN_GPIO) { e = gpio_request(pdata->gpio_nr, dev_name(&pdev->dev)); if (e < 0) { dev_err(&pdev->dev, "request ID pin GPIO failed\n"); goto fail_hcd; } e = gpio_direction_input(pdata->gpio_nr); if (e < 0) { dev_err(&pdev->dev, "failed to set ID pin as input\n"); goto fail_gpio; } } INIT_WORK(&pdata->work, tegra_ehci_busy_hint_work); /* Init the tegra USB phy */ if (NvDdkUsbPhyOpen(s_hRmGlobal, pdata->instance, &pdata->hUsbPhy) != NvSuccess) { dev_err(&pdev->dev, "failed to open USB phy DDK\n"); e = -ENODEV; goto fail_gpio; } tegra_ehci_power_up(hcd); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(&pdev->dev, "failed to get I/O memory\n"); e = -ENXIO; goto fail_phy; } if (!pdata->otg_mode) { res = request_mem_region(res->start, resource_size(res), dev_name(&pdev->dev)); if (!res) { dev_err(&pdev->dev, "resource in use\n"); e = -EBUSY; goto fail_phy; } } hcd->rsrc_start = res->start; hcd->rsrc_len = resource_size(res); hcd->regs = ioremap(res->start, resource_size(res)); if (!hcd->regs) { e = -ENOMEM; goto fail_mem; } /* 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)); irq = platform_get_irq(pdev, 0); if (!irq) { e = -ENODEV; goto fail_iomap; } set_irq_flags(irq, IRQF_VALID); ehci = hcd_to_ehci(hcd); INIT_WORK(&ehci->irq_work, tegra_ehci_irq_work); e = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED); if (e != 0) { dev_err(&pdev->dev, "failed to add HCD\n"); goto fail_iomap; } platform_set_drvdata(pdev, hcd); #ifdef CONFIG_DMABOUNCE e = dmabounce_register_dev(&pdev->dev, 1024, 32768); if (e != 0) { dev_err(&pdev->dev, "failed to register DMA bounce\n"); goto fail_add; } #endif #ifdef CONFIG_USB_OTG_UTILS if (pdata->otg_mode) { ehci->transceiver = otg_get_transceiver(); if (!ehci->transceiver) { dev_err(&pdev->dev, "Failed to get OTG transceiver\n"); e = -ENODEV; goto fail_dmabounce; } otg_set_host(ehci->transceiver, (struct usb_bus *)hcd); /* Stop the controller and power down the phy, OTG will * start the host driver based on the ID pin * detection */ ehci_halt(ehci); /* reset the host and put the controller in idle mode */ temp = ehci_readl(ehci, &ehci->regs->command); temp |= CMD_RESET; ehci_writel(ehci, temp, &ehci->regs->command); temp = readl(hcd->regs + TEGRA_USB_USBMODE_REG_OFFSET); writel((temp & ~TEGRA_USB_USBMODE_HOST), (hcd->regs + TEGRA_USB_USBMODE_REG_OFFSET)); /* indicate hcd flags, that hardware is not accessable now * in host mode*/ clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); tegra_ehci_power_down(hcd); ehci->host_reinited = 0; } else #endif { if (pdata->id_detect == ID_PIN_CABLE_ID) { /* enable the cable ID interrupt */ temp = readl(hcd->regs + TEGRA_USB_PHY_WAKEUP_REG_OFFSET); temp |= TEGRA_USB_ID_INT_ENABLE; temp |= TEGRA_USB_ID_PIN_WAKEUP_ENABLE; writel(temp, (hcd->regs + TEGRA_USB_PHY_WAKEUP_REG_OFFSET)); /* Check if we detect any device connected */ if (temp & TEGRA_USB_ID_PIN_STATUS) { tegra_ehci_power_down(hcd); } else { tegra_ehci_power_up(hcd); } } } return 0; fail_dmabounce: #ifdef CONFIG_DMABOUNCE dmabounce_unregister_dev(&pdev->dev); #endif fail_add: usb_remove_hcd(hcd); fail_iomap: iounmap(hcd->regs); fail_mem: res = platform_get_resource(pdev, IORESOURCE_MEM, 0); release_mem_region(res->start, resource_size(res)); fail_phy: NvDdkUsbPhyClose(pdata->hUsbPhy); fail_gpio: if (pdata->gpio_nr) gpio_free(pdata->gpio_nr); fail_hcd: usb_put_hcd(hcd); return e; }
/* platform driver interface */ static int __devinit tegra_otg_probe(struct platform_device *pdev) { int err = 0; struct resource *res; int instance = pdev->id; NvError e; struct tegra_otg_platform_data *pdata; sg_tegra_otg = kzalloc(sizeof(struct tegra_otg_data), GFP_KERNEL); if (!sg_tegra_otg) return -ENOMEM; spin_lock_init(&sg_tegra_otg->lock); platform_set_drvdata(pdev, sg_tegra_otg); NV_CHECK_ERROR_CLEANUP( NvDdkUsbPhyOpen(s_hRmGlobal, instance, &sg_tegra_otg->usb_phy) ); NV_CHECK_ERROR_CLEANUP( NvDdkUsbPhyPowerUp(sg_tegra_otg->usb_phy, NV_FALSE, 0) ); sg_tegra_otg->instance = pdev->id; sg_tegra_otg->dev = &pdev->dev; sg_tegra_otg->otg.label = driver_name; sg_tegra_otg->otg.state = OTG_STATE_UNDEFINED; sg_tegra_otg->otg.set_peripheral = tegra_otg_set_peripheral; sg_tegra_otg->otg.set_host = tegra_otg_set_host; sg_tegra_otg->otg.set_power = tegra_otg_set_power; sg_tegra_otg->otg.set_suspend = tegra_otg_set_suspend; pdata = sg_tegra_otg->dev->platform_data; if(pdata->usb_property->IdPinDetectionType == NvOdmUsbIdPinType_CableId) sg_tegra_otg->id_connected = 1; if(pdata->usb_property->UseInternalPhyWakeup) sg_tegra_otg->vbus_connected = 1; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { err = -ENXIO; goto err_irq; } sg_tegra_otg->regs = ioremap(res->start, resource_size(res)); if (!sg_tegra_otg->regs) { err = -ENOMEM; goto err_irq; } sg_tegra_otg->irq = platform_get_irq(pdev, 0); if (!sg_tegra_otg->irq) { err = -ENODEV; goto err_irq; } err = request_irq(sg_tegra_otg->irq, tegra_otg_irq, IRQF_SHARED, driver_name, pdev); if (err) { printk("cannot request irq %d err %d\n", sg_tegra_otg->irq, err); goto err_mem_map; } /* only active when a gadget is registered */ err = otg_set_transceiver(&sg_tegra_otg->otg); if (err) { dev_err(&pdev->dev, "can't register transceiver, err: %d\n", err); goto err_otg; } NvDdkUsbPhyPowerDown(sg_tegra_otg->usb_phy, NV_FALSE, 0); return 0; err_otg: free_irq(sg_tegra_otg->irq, &pdev->dev); err_mem_map: iounmap(sg_tegra_otg->regs); err_irq: NvDdkUsbPhyClose(sg_tegra_otg->usb_phy); fail: platform_set_drvdata(pdev, NULL); kfree(sg_tegra_otg); return err; }
NvError NvDdkUsbPhyOpen( NvRmDeviceHandle hRm, NvU32 Instance, NvDdkUsbPhyHandle *hUsbPhy) { NvError e; NvU32 MaxInstances = 0; NvDdkUsbPhy *pUsbPhy = NULL; NvOsMutexHandle UsbPhyMutex = NULL; NvRmModuleInfo info[MAX_USB_INSTANCES]; NvU32 j; NV_ASSERT(hRm); NV_ASSERT(hUsbPhy); NV_ASSERT(Instance < MAX_USB_INSTANCES); NV_CHECK_ERROR(NvRmModuleGetModuleInfo( hRm, NvRmModuleID_Usb2Otg, &MaxInstances, NULL )); if (MaxInstances > MAX_USB_INSTANCES) { // Ceil "instances" to MAX_USB_INSTANCES MaxInstances = MAX_USB_INSTANCES; } NV_CHECK_ERROR(NvRmModuleGetModuleInfo( hRm, NvRmModuleID_Usb2Otg, &MaxInstances, info )); for (j = 0; j < MaxInstances; j++) { // Check whether the requested instance is present if(info[j].Instance == Instance) break; } // No match found return if (j == MaxInstances) { return NvError_ModuleNotPresent; } if (!s_UsbPhyMutex) { e = NvOsMutexCreate(&UsbPhyMutex); if (e!=NvSuccess) return e; if (NvOsAtomicCompareExchange32( (NvS32*)&s_UsbPhyMutex, 0, (NvS32)UsbPhyMutex)!=0) { NvOsMutexDestroy(UsbPhyMutex); } } NvOsMutexLock(s_UsbPhyMutex); if (!s_pUsbPhy) { s_pUsbPhy = NvOsAlloc(MaxInstances * sizeof(NvDdkUsbPhy)); if (s_pUsbPhy) NvOsMemset(s_pUsbPhy, 0, MaxInstances * sizeof(NvDdkUsbPhy)); } NvOsMutexUnlock(s_UsbPhyMutex); if (!s_pUsbPhy) return NvError_InsufficientMemory; NvOsMutexLock(s_UsbPhyMutex); if (!s_pUtmiPadConfig) { s_pUtmiPadConfig = NvOsAlloc(sizeof(NvDdkUsbPhyUtmiPadConfig)); if (s_pUtmiPadConfig) { NvRmPhysAddr PhyAddr; NvOsMemset(s_pUtmiPadConfig, 0, sizeof(NvDdkUsbPhyUtmiPadConfig)); NvRmModuleGetBaseAddress( hRm, NVRM_MODULE_ID(NvRmModuleID_Usb2Otg, 0), &PhyAddr, &s_pUtmiPadConfig->BankSize); NV_CHECK_ERROR_CLEANUP( NvRmPhysicalMemMap( PhyAddr, s_pUtmiPadConfig->BankSize, NVOS_MEM_READ_WRITE, NvOsMemAttribute_Uncached, (void **)&s_pUtmiPadConfig->pVirAdr)); } } NvOsMutexUnlock(s_UsbPhyMutex); if (!s_pUtmiPadConfig) return NvError_InsufficientMemory; pUsbPhy = &s_pUsbPhy[Instance]; NvOsMutexLock(s_UsbPhyMutex); if (!pUsbPhy->RefCount) { NvRmPhysAddr PhysAddr; NvOsMutexHandle ThreadSafetyMutex = NULL; NvOsMemset(pUsbPhy, 0, sizeof(NvDdkUsbPhy)); pUsbPhy->Instance = Instance; pUsbPhy->hRmDevice = hRm; pUsbPhy->RefCount = 1; pUsbPhy->IsPhyPoweredUp = NV_FALSE; pUsbPhy->pUtmiPadConfig = s_pUtmiPadConfig; pUsbPhy->pProperty = NvOdmQueryGetUsbProperty( NvOdmIoModule_Usb, pUsbPhy->Instance); pUsbPhy->TurnOffPowerRail = UsbPhyTurnOffPowerRail(MaxInstances); NV_CHECK_ERROR_CLEANUP(NvOsMutexCreate(&ThreadSafetyMutex)); if (NvOsAtomicCompareExchange32( (NvS32*)&pUsbPhy->ThreadSafetyMutex, 0, (NvS32)ThreadSafetyMutex)!=0) { NvOsMutexDestroy(ThreadSafetyMutex); } NvRmModuleGetBaseAddress( pUsbPhy->hRmDevice, NVRM_MODULE_ID(NvRmModuleID_Usb2Otg, pUsbPhy->Instance), &PhysAddr, &pUsbPhy->UsbBankSize); NV_CHECK_ERROR_CLEANUP( NvRmPhysicalMemMap( PhysAddr, pUsbPhy->UsbBankSize, NVOS_MEM_READ_WRITE, NvOsMemAttribute_Uncached, (void **)&pUsbPhy->UsbVirAdr)); NvRmModuleGetBaseAddress( pUsbPhy->hRmDevice, NVRM_MODULE_ID(NvRmModuleID_Misc, 0), &PhysAddr, &pUsbPhy->MiscBankSize); NV_CHECK_ERROR_CLEANUP( NvRmPhysicalMemMap( PhysAddr, pUsbPhy->MiscBankSize, NVOS_MEM_READ_WRITE, NvOsMemAttribute_Uncached, (void **)&pUsbPhy->MiscVirAdr)); if ( ( pUsbPhy->pProperty->UsbInterfaceType == NvOdmUsbInterfaceType_UlpiNullPhy) || ( pUsbPhy->pProperty->UsbInterfaceType == NvOdmUsbInterfaceType_UlpiExternalPhy)) { if (NvRmSetModuleTristate( pUsbPhy->hRmDevice, NVRM_MODULE_ID(NvRmModuleID_Usb2Otg, pUsbPhy->Instance), NV_FALSE) != NvSuccess ) return NvError_NotSupported; } // Register with Power Manager NV_CHECK_ERROR_CLEANUP( NvOsSemaphoreCreate(&pUsbPhy->hPwrEventSem, 0)); pUsbPhy->RmPowerClientId = NVRM_POWER_CLIENT_TAG('U','S','B','p'); NV_CHECK_ERROR_CLEANUP( NvRmPowerRegister(pUsbPhy->hRmDevice, pUsbPhy->hPwrEventSem, &pUsbPhy->RmPowerClientId)); // Open the H/W interface UsbPhyOpenHwInterface(pUsbPhy); // Initialize the USB Phy NV_CHECK_ERROR_CLEANUP(UsbPhyInitialize(pUsbPhy)); } else { pUsbPhy->RefCount++; } *hUsbPhy = pUsbPhy; NvOsMutexUnlock(s_UsbPhyMutex); return NvSuccess; fail: NvDdkUsbPhyClose(pUsbPhy); NvOsMutexUnlock(s_UsbPhyMutex); return e; }