X-Git-Url: http://plrg.eecs.uci.edu/git/?p=firefly-linux-kernel-4.4.55.git;a=blobdiff_plain;f=drivers%2Fusb%2Fdwc_otg_310%2Fdwc_otg_driver.c;h=4463f1bb35d2e393f92dd24cdcb19d67559b0afb;hp=3afba4084333f0474c65466660b59ba0e8642a36;hb=ec42359f2660cfd0afa81c4e38b9e3695a1828a0;hpb=c7ec4ec5a3c4bd25c2d6cadc01062291679a4946 diff --git a/drivers/usb/dwc_otg_310/dwc_otg_driver.c b/drivers/usb/dwc_otg_310/dwc_otg_driver.c old mode 100755 new mode 100644 index 3afba4084333..4463f1bb35d2 --- a/drivers/usb/dwc_otg_310/dwc_otg_driver.c +++ b/drivers/usb/dwc_otg_310/dwc_otg_driver.c @@ -68,6 +68,7 @@ static const char dwc_host20_driver_name[] = "usb20_host"; static const char dwc_otg20_driver_name[] = "usb20_otg"; dwc_otg_device_t *g_otgdev; +void *dwc_otg_dev; extern int pcd_init(struct platform_device *_dev); extern int otg20_hcd_init(struct platform_device *_dev); @@ -76,33 +77,6 @@ extern int pcd_remove(struct platform_device *_dev); extern void hcd_remove(struct platform_device *_dev); extern void dwc_otg_adp_start(dwc_otg_core_if_t *core_if, uint8_t is_host); -#ifdef CONFIG_USB20_OTG -static struct usb20otg_pdata_id usb20otg_pdata[] = { - { - .name = "rk3188-usb20otg", - .pdata = &usb20otg_pdata_rk3188, - }, - { - .name = "rk3288-usb20otg", - .pdata = &usb20otg_pdata_rk3288, - }, - {}, -}; -#endif - -#ifdef CONFIG_USB20_HOST -static struct usb20host_pdata_id usb20host_pdata[] = { - { - .name = "rk3188-usb20host", - .pdata = &usb20host_pdata_rk3188, - }, - { - .name = "rk3288-usb20host", - .pdata = &usb20host_pdata_rk3288, - }, - {}, -}; -#endif #ifdef CONFIG_RK_USB_UART static u32 usb_to_uart_status; @@ -378,13 +352,21 @@ extern void dwc_otg_hub_disconnect_device(struct usb_hub *hub); void dwc_otg_force_host(dwc_otg_core_if_t *core_if) { dwc_otg_device_t *otg_dev = core_if->otg_dev; + struct dwc_otg_platform_data *pdata = otg_dev->pldata; dctl_data_t dctl = {.d32 = 0 }; unsigned long flags; if (core_if->op_state == A_HOST) { - printk("dwc_otg_force_host,already in A_HOST mode,everest\n"); + dev_info(pdata->dev, + "dwc_otg_force_host,already in A_HOST mode,everest\n"); + return; + } else if (pdata->get_status(USB_STATUS_BVABLID) && + core_if->pmic_vbus) { + dev_info(pdata->dev, + "Please disconnect the USB cable first, and try again!\n"); return; } + core_if->op_state = A_HOST; cancel_delayed_work(&otg_dev->pcd->check_vbus_work); @@ -412,6 +394,7 @@ void dwc_otg_force_device(dwc_otg_core_if_t *core_if) local_irq_save(flags); if (core_if->op_state == B_PERIPHERAL) { + local_irq_restore(flags); printk ("dwc_otg_force_device,already in B_PERIPHERAL,everest\n"); return; @@ -433,28 +416,6 @@ void dwc_otg_force_device(dwc_otg_core_if_t *core_if) local_irq_restore(flags); } -static void dwc_otg_set_force_mode(dwc_otg_core_if_t *core_if, int mode) -{ - gusbcfg_data_t usbcfg = {.d32 = 0 }; - printk("!!!dwc_otg_set_force_mode\n"); - usbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg); - switch (mode) { - case USB_MODE_FORCE_HOST: - usbcfg.b.force_host_mode = 1; - usbcfg.b.force_dev_mode = 0; - break; - case USB_MODE_FORCE_DEVICE: - usbcfg.b.force_host_mode = 0; - usbcfg.b.force_dev_mode = 1; - break; - case USB_MODE_NORMAL: - usbcfg.b.force_host_mode = 0; - usbcfg.b.force_dev_mode = 0; - break; - } - DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg, usbcfg.d32); -} - static ssize_t force_usb_mode_show(struct device_driver *drv, char *buf) { dwc_otg_device_t *otg_dev = g_otgdev; @@ -964,14 +925,24 @@ static int host20_driver_remove(struct platform_device *_dev) } static const struct of_device_id usb20_host_of_match[] = { +#ifdef CONFIG_ARM { .compatible = "rockchip,rk3188_usb20_host", - .data = &usb20host_pdata[RK3188_USB_CTLR], + .data = &usb20host_pdata_rk3188, }, { .compatible = "rockchip,rk3288_usb20_host", - .data = &usb20host_pdata[RK3288_USB_CTLR], + .data = &usb20host_pdata_rk3288, + }, + { + .compatible = "rockchip,rk3036_usb20_host", + .data = &usb20host_pdata_rk3036, + }, + { + .compatible = "rockchip,rk3126_usb20_host", + .data = &usb20host_pdata_rk3126, }, +#endif {}, }; @@ -997,21 +968,17 @@ static int host20_driver_probe(struct platform_device *_dev) struct device *dev = &_dev->dev; struct device_node *node = _dev->dev.of_node; struct dwc_otg_platform_data *pldata; - struct usb20host_pdata_id *p; const struct of_device_id *match = of_match_device(of_match_ptr(usb20_host_of_match), &_dev->dev); - if (match) { - p = (struct usb20host_pdata_id *)match->data; + if (match && match->data) { + pldata = (void *)match->data; + pldata->dev = dev; } else { - dev_err(dev, "usb20host match failed\n"); + dev_err(dev, "usb20otg match failed\n"); return -EINVAL; } - dev->platform_data = p->pdata; - pldata = dev->platform_data; - pldata->dev = dev; - if (!node) { dev_err(dev, "device node not found\n"); return -EINVAL; @@ -1056,8 +1023,14 @@ static int host20_driver_probe(struct platform_device *_dev) retval = -ENOMEM; goto clk_disable; } - dev_dbg(&_dev->dev, "base=0x%08x\n", - (unsigned)dwc_otg_device->os_dep.base); + dev_dbg(&_dev->dev, "base=0x%p\n", dwc_otg_device->os_dep.base); + + /* Set device flags indicating whether the HCD supports DMA. */ + if (!_dev->dev.dma_mask) + _dev->dev.dma_mask = &_dev->dev.coherent_dma_mask; + retval = dma_set_coherent_mask(&_dev->dev, DMA_BIT_MASK(32)); + if (retval) + goto clk_disable; /* * Initialize driver data to point to the global DWC_otg @@ -1195,14 +1168,18 @@ static void dwc_otg_driver_shutdown(struct platform_device *_dev) struct device *dev = &_dev->dev; dwc_otg_device_t *otg_dev = dev->platform_data; dwc_otg_core_if_t *core_if = otg_dev->core_if; + struct dwc_otg_platform_data *pldata = otg_dev->pldata; dctl_data_t dctl = {.d32 = 0 }; + dwc_otg_pcd_t *pcd = core_if->otg_dev->pcd; DWC_PRINTF("%s: disconnect USB %s mode\n", __func__, dwc_otg_is_host_mode(core_if) ? "host" : "device"); + if (dwc_otg_is_host_mode(core_if)) { if (core_if->hcd_cb && core_if->hcd_cb->stop) core_if->hcd_cb->stop(core_if->hcd_cb_p); } else { + cancel_delayed_work_sync(&pcd->check_vbus_work); /* soft disconnect */ dctl.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dctl); @@ -1213,6 +1190,11 @@ static void dwc_otg_driver_shutdown(struct platform_device *_dev) /* Clear any pending interrupts */ DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF); + if (pldata->dwc_otg_uart_mode != NULL) + pldata->dwc_otg_uart_mode(pldata, PHY_USB_MODE); + if (pldata->phy_suspend != NULL) + pldata->phy_suspend(pldata, USB_PHY_ENABLED); + } /** @@ -1318,16 +1300,31 @@ static int otg20_driver_remove(struct platform_device *_dev) } static const struct of_device_id usb20_otg_of_match[] = { +#ifdef CONFIG_ARM { .compatible = "rockchip,rk3188_usb20_otg", - .data = &usb20otg_pdata[RK3188_USB_CTLR], + .data = &usb20otg_pdata_rk3188, }, { .compatible = "rockchip,rk3288_usb20_otg", - .data = &usb20otg_pdata[RK3288_USB_CTLR], + .data = &usb20otg_pdata_rk3288, }, { + .compatible = "rockchip,rk3036_usb20_otg", + .data = &usb20otg_pdata_rk3036, + }, + { + .compatible = "rockchip,rk3126_usb20_otg", + .data = &usb20otg_pdata_rk3126, + }, +#endif +#ifdef CONFIG_ARM64 + { + .compatible = "rockchip,rk3368-usb", + .data = &usb20otg_pdata_rk3368, }, +#endif + { }, }; MODULE_DEVICE_TABLE(of, usb20_otg_of_match); @@ -1353,27 +1350,22 @@ static int otg20_driver_probe(struct platform_device *_dev) struct device *dev = &_dev->dev; struct device_node *node = _dev->dev.of_node; struct dwc_otg_platform_data *pldata; - struct usb20otg_pdata_id *p; const struct of_device_id *match = of_match_device(of_match_ptr(usb20_otg_of_match), &_dev->dev); - if (match) { - p = (struct usb20otg_pdata_id *)match->data; + if (match && match->data) { + pldata = (void *)match->data; + pldata->dev = dev; } else { dev_err(dev, "usb20otg match failed\n"); return -EINVAL; } - dev->platform_data = p->pdata; - /* dev->platform_data = &usb20otg_pdata; */ - pldata = dev->platform_data; - pldata->dev = dev; - if (!node) { dev_err(dev, "device node not found\n"); return -EINVAL; } - /*todo : move to usbdev_rk-XX.c */ + if (pldata->hw_init) pldata->hw_init(); @@ -1422,8 +1414,14 @@ static int otg20_driver_probe(struct platform_device *_dev) retval = -ENOMEM; goto clk_disable; } - dev_dbg(&_dev->dev, "base=0x%08x\n", - (unsigned)dwc_otg_device->os_dep.base); + dev_dbg(&_dev->dev, "base=0x%p\n", dwc_otg_device->os_dep.base); + + /* Set device flags indicating whether the HCD supports DMA. */ + if (!_dev->dev.dma_mask) + _dev->dev.dma_mask = &_dev->dev.coherent_dma_mask; + retval = dma_set_coherent_mask(&_dev->dev, DMA_BIT_MASK(32)); + if (retval) + goto clk_disable; /* * Initialize driver data to point to the global DWC_otg @@ -1431,6 +1429,7 @@ static int otg20_driver_probe(struct platform_device *_dev) */ g_otgdev = dwc_otg_device; + dwc_otg_dev = (struct device *)&_dev->dev; pldata->privdata = dwc_otg_device; dwc_otg_device->pldata = pldata; @@ -1513,6 +1512,10 @@ static int otg20_driver_probe(struct platform_device *_dev) of_property_read_u32(node, "rockchip,usb-mode", &val); dwc_otg_device->core_if->usb_mode = val; + /* Indicate usb vbus get from pmic (e.g. rk81x) */ + dwc_otg_device->core_if->pmic_vbus = of_property_read_bool(node, + "rockchip,usb-pmic-vbus"); + #ifndef DWC_HOST_ONLY /* * Initialize the PCD @@ -1541,7 +1544,8 @@ static int otg20_driver_probe(struct platform_device *_dev) * perform initial actions required for Internal ADP logic. */ if (!dwc_otg_get_param_adp_enable(dwc_otg_device->core_if)) { - if (pldata->phy_status == USB_PHY_ENABLED) { + if (dwc_otg_device->core_if->usb_mode == USB_MODE_NORMAL && + pldata->phy_status == USB_PHY_ENABLED) { pldata->phy_suspend(pldata, USB_PHY_SUSPEND); udelay(3); pldata->clock_enable(pldata, 0); @@ -1564,10 +1568,59 @@ clk_disable: return retval; } +#ifdef CONFIG_PM +static int dwc_otg_pm_suspend(struct device *dev) +{ + dwc_otg_device_t *dwc_otg_device; + struct dwc_otg_platform_data *pdata_otg; + + dwc_otg_device = dev_get_platdata(dev); + + dev_dbg(dev, "dwc_otg PM suspend\n"); + + if (dwc_otg_device->core_if->op_state == B_PERIPHERAL) + return 0; + + pdata_otg = dwc_otg_device->pldata; + pdata_otg->phy_suspend(pdata_otg, USB_PHY_SUSPEND); + + return 0; +} + +static int dwc_otg_pm_resume(struct device *dev) +{ + dwc_otg_device_t *dwc_otg_device; + struct dwc_otg_platform_data *pdata_otg; + + dwc_otg_device = dev_get_platdata(dev); + + dev_dbg(dev, "dwc_otg PM resume\n"); + + if (dwc_otg_device->core_if->op_state == B_PERIPHERAL) + return 0; + + pdata_otg = dwc_otg_device->pldata; + pdata_otg->phy_suspend(pdata_otg, USB_PHY_ENABLED); + + return 0; +} +#else +#define dwc_otg_pm_suspend NULL +#define dwc_otg_pm_resume NULL +#endif + +static const struct dev_pm_ops dwc_otg_dev_pm_ops = { + .suspend = dwc_otg_pm_suspend, + .resume = dwc_otg_pm_resume, +}; + static struct platform_driver dwc_otg_driver = { .driver = { .name = (char *)dwc_otg20_driver_name, .of_match_table = of_match_ptr(usb20_otg_of_match), +#ifdef CONFIG_PM + .pm = &dwc_otg_dev_pm_ops, +#endif }, .probe = otg20_driver_probe, .remove = otg20_driver_remove, @@ -1580,10 +1633,14 @@ static struct platform_driver dwc_otg_driver = { void rk_usb_power_up(void) { struct dwc_otg_platform_data *pldata_otg; +#ifdef CONFIG_USB20_HOST struct dwc_otg_platform_data *pldata_host; +#endif +#ifdef CONFIG_USB_EHCI_RK struct rkehci_platform_data *pldata_ehci; +#endif - if (cpu_is_rk3288()) { + if (is_rk3288_usb()) { #ifdef CONFIG_RK_USB_UART /* enable USB bypass UART function */ writel_relaxed(0x00c00000 | usb_to_uart_status, @@ -1619,16 +1676,29 @@ void rk_usb_power_up(void) } #endif + } else { + dwc_otg_device_t *otg_dev = g_otgdev; + + if (!otg_dev) + return; + + pldata_otg = otg_dev->pldata; + if (pldata_otg && pldata_otg->phy_power_down) + pldata_otg->phy_power_down(PHY_POWER_UP); } } void rk_usb_power_down(void) { struct dwc_otg_platform_data *pldata_otg; +#ifdef CONFIG_USB20_HOST struct dwc_otg_platform_data *pldata_host; +#endif +#ifdef CONFIG_USB_EHCI_RK struct rkehci_platform_data *pldata_ehci; +#endif - if (cpu_is_rk3288()) { + if (is_rk3288_usb()) { #ifdef CONFIG_RK_USB_UART /* disable USB bypass UART function */ usb_to_uart_status = @@ -1671,6 +1741,15 @@ void rk_usb_power_down(void) RK3288_GRF_UOC1_CON0); } #endif + } else { + dwc_otg_device_t *otg_dev = g_otgdev; + + if (!otg_dev) + return; + + pldata_otg = otg_dev->pldata; + if (pldata_otg && pldata_otg->phy_power_down) + pldata_otg->phy_power_down(PHY_POWER_DOWN); } }