From 9d77db3c730780c8ef5ccd4b66403ff5675cfe4e Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Mon, 13 May 2024 10:30:14 +0000 Subject: [PATCH] modify sin led gpio --- kernel/drivers/usb/dwc2/platform.c | 291 ++++++++++++++++++++++++++++++++++++++++++++------------- 1 files changed, 224 insertions(+), 67 deletions(-) diff --git a/kernel/drivers/usb/dwc2/platform.c b/kernel/drivers/usb/dwc2/platform.c index 837b209..13f305b 100644 --- a/kernel/drivers/usb/dwc2/platform.c +++ b/kernel/drivers/usb/dwc2/platform.c @@ -131,9 +131,9 @@ } else if (hsotg->plat && hsotg->plat->phy_init) { ret = hsotg->plat->phy_init(pdev, hsotg->plat->phy_type); } else { - ret = phy_power_on(hsotg->phy); + ret = phy_init(hsotg->phy); if (ret == 0) - ret = phy_init(hsotg->phy); + ret = phy_power_on(hsotg->phy); } return ret; @@ -165,9 +165,9 @@ } else if (hsotg->plat && hsotg->plat->phy_exit) { ret = hsotg->plat->phy_exit(pdev, hsotg->plat->phy_type); } else { - ret = phy_exit(hsotg->phy); + ret = phy_power_off(hsotg->phy); if (ret == 0) - ret = phy_power_off(hsotg->phy); + ret = phy_exit(hsotg->phy); } return ret; @@ -191,21 +191,16 @@ static int __dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg) { - int clk, ret; + int ret; ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies), hsotg->supplies); if (ret) return ret; - for (clk = 0; clk < DWC2_MAX_CLKS && hsotg->clks[clk]; clk++) { - ret = clk_prepare_enable(hsotg->clks[clk]); - if (ret) { - while (--clk >= 0) - clk_disable_unprepare(hsotg->clks[clk]); - return ret; - } - } + ret = clk_bulk_prepare_enable(hsotg->num_clks, hsotg->clks); + if (ret) + return ret; if (!hsotg->ll_phy_enabled) ret = dwc2_lowlevel_phy_enable(hsotg); @@ -231,7 +226,7 @@ static int __dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg) { - int clk, ret = 0; + int ret = 0; if (hsotg->ll_phy_enabled) ret = dwc2_lowlevel_phy_disable(hsotg); @@ -239,14 +234,9 @@ if (ret) return ret; - for (clk = DWC2_MAX_CLKS - 1; clk >= 0; clk--) - if (hsotg->clks[clk]) - clk_disable_unprepare(hsotg->clks[clk]); + clk_bulk_disable_unprepare(hsotg->num_clks, hsotg->clks); - ret = regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), - hsotg->supplies); - - return ret; + return regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), hsotg->supplies); } /** @@ -265,17 +255,9 @@ return ret; } -/* Only used to reset usb phy at interrupter runtime */ -static void dwc2_reset_phy_work(struct work_struct *data) -{ - struct dwc2_hsotg *hsotg = container_of(data, struct dwc2_hsotg, - phy_rst_work); - phy_reset(hsotg->phy); -} - static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg) { - int i, clk, ret; + int i, ret; hsotg->reset = devm_reset_control_get_optional(hsotg->dev, "dwc2"); if (IS_ERR(hsotg->reset)) { @@ -294,9 +276,6 @@ } reset_control_deassert(hsotg->reset_ecc); - - /* Set default UTMI width */ - hsotg->phyif = GUSBCFG_PHYIF16; /* * Attempt to find a generic PHY, then look for an old style @@ -317,7 +296,6 @@ return ret; } } - INIT_WORK(&hsotg->phy_rst_work, dwc2_reset_phy_work); if (!hsotg->phy) { hsotg->uphy = devm_usb_get_phy(hsotg->dev, USB_PHY_TYPE_USB2); @@ -340,28 +318,19 @@ hsotg->plat = dev_get_platdata(hsotg->dev); - if (hsotg->phy) { + /* Clock */ + if (hsotg->dev->of_node) { + ret = devm_clk_bulk_get_all(hsotg->dev, &hsotg->clks); + if (ret == -EPROBE_DEFER) + return ret; /* - * If using the generic PHY framework, check if the PHY bus - * width is 8-bit and set the phyif appropriately. + * Clocks are optional, but new DT platforms should support all + * clocks as required by the DT-binding. */ - if (phy_get_bus_width(hsotg->phy) == 8) - hsotg->phyif = GUSBCFG_PHYIF8; - } - - for (clk = 0; clk < DWC2_MAX_CLKS; clk++) { - hsotg->clks[clk] = of_clk_get(hsotg->dev->of_node, clk); - if (IS_ERR(hsotg->clks[clk])) { - ret = PTR_ERR(hsotg->clks[clk]); - if (ret == -EPROBE_DEFER) { - while (--clk >= 0) - clk_put(hsotg->clks[clk]); - return ret; - } - - hsotg->clks[clk] = NULL; - break; - } + if (ret < 0) + hsotg->num_clks = 0; + else + hsotg->num_clks = ret; } /* Regulators */ @@ -371,7 +340,9 @@ ret = devm_regulator_bulk_get(hsotg->dev, ARRAY_SIZE(hsotg->supplies), hsotg->supplies); if (ret) { - dev_err(hsotg->dev, "failed to request supplies: %d\n", ret); + if (ret != -EPROBE_DEFER) + dev_err(hsotg->dev, "failed to request supplies: %d\n", + ret); return ret; } return 0; @@ -397,6 +368,11 @@ dwc2_hcd_remove(hsotg); if (hsotg->gadget_enabled) dwc2_hsotg_remove(hsotg); + + dwc2_drd_exit(hsotg); + + if (hsotg->params.activate_stm_id_vb_detection) + regulator_disable(hsotg->usb33d); pm_runtime_put_sync(hsotg->dev); pm_runtime_disable(hsotg->dev); @@ -448,6 +424,37 @@ } /** + * Check core version + * + * @hsotg: Programming view of the DWC_otg controller + * + */ +int dwc2_check_core_version(struct dwc2_hsotg *hsotg) +{ + struct dwc2_hw_params *hw = &hsotg->hw_params; + + /* + * Attempt to ensure this device is really a DWC_otg Controller. + * Read and verify the GSNPSID register contents. The value should be + * 0x45f4xxxx, 0x5531xxxx or 0x5532xxxx + */ + + hw->snpsid = dwc2_readl(hsotg, GSNPSID); + if ((hw->snpsid & GSNPSID_ID_MASK) != DWC2_OTG_ID && + (hw->snpsid & GSNPSID_ID_MASK) != DWC2_FS_IOT_ID && + (hw->snpsid & GSNPSID_ID_MASK) != DWC2_HS_IOT_ID) { + dev_err(hsotg->dev, "Bad value for GSNPSID: 0x%08x\n", + hw->snpsid); + return -ENODEV; + } + + dev_dbg(hsotg->dev, "Core Release: %1x.%1x%1x%1x (snpsid=%x)\n", + hw->snpsid >> 12 & 0xf, hw->snpsid >> 8 & 0xf, + hw->snpsid >> 4 & 0xf, hw->snpsid & 0xf, hw->snpsid); + return 0; +} + +/** * dwc2_driver_probe() - Called when the DWC_otg core is bound to the DWC_otg * driver * @@ -482,8 +489,7 @@ return retval; } - res = platform_get_resource(dev, IORESOURCE_MEM, 0); - hsotg->regs = devm_ioremap_resource(&dev->dev, res); + hsotg->regs = devm_platform_get_and_ioremap_resource(dev, 0, &res); if (IS_ERR(hsotg->regs)) return PTR_ERR(hsotg->regs); @@ -497,10 +503,8 @@ spin_lock_init(&hsotg->lock); hsotg->irq = platform_get_irq(dev, 0); - if (hsotg->irq < 0) { - dev_err(&dev->dev, "missing IRQ resource\n"); + if (hsotg->irq < 0) return hsotg->irq; - } dev_dbg(hsotg->dev, "registering common handler for irq%d\n", hsotg->irq); @@ -509,6 +513,14 @@ dev_name(hsotg->dev), hsotg); if (retval) return retval; + + hsotg->vbus_supply = devm_regulator_get_optional(hsotg->dev, "vbus"); + if (IS_ERR(hsotg->vbus_supply)) { + retval = PTR_ERR(hsotg->vbus_supply); + hsotg->vbus_supply = NULL; + if (retval != -ENODEV) + return retval; + } retval = dwc2_lowlevel_hw_enable(hsotg); if (retval) @@ -522,6 +534,18 @@ goto error; retval = dwc2_get_dr_mode(hsotg); + if (retval) + goto error; + + hsotg->need_phy_for_wake = + of_property_read_bool(dev->dev.of_node, + "snps,need-phy-for-wake"); + + /* + * Before performing any core related operations + * check core version. + */ + retval = dwc2_check_core_version(hsotg); if (retval) goto error; @@ -549,11 +573,63 @@ if (retval) goto error; + if (hsotg->params.activate_stm_id_vb_detection) { + u32 ggpio; + + hsotg->usb33d = devm_regulator_get(hsotg->dev, "usb33d"); + if (IS_ERR(hsotg->usb33d)) { + retval = PTR_ERR(hsotg->usb33d); + if (retval != -EPROBE_DEFER) + dev_err(hsotg->dev, + "failed to request usb33d supply: %d\n", + retval); + goto error; + } + retval = regulator_enable(hsotg->usb33d); + if (retval) { + dev_err(hsotg->dev, + "failed to enable usb33d supply: %d\n", retval); + goto error; + } + + ggpio = dwc2_readl(hsotg, GGPIO); + ggpio |= GGPIO_STM32_OTG_GCCFG_IDEN; + ggpio |= GGPIO_STM32_OTG_GCCFG_VBDEN; + dwc2_writel(hsotg, ggpio, GGPIO); + + /* ID/VBUS detection startup time */ + usleep_range(5000, 7000); + } + + retval = dwc2_drd_init(hsotg); + if (retval) { + if (retval != -EPROBE_DEFER) + dev_err(hsotg->dev, "failed to initialize dual-role\n"); + goto error_init; + } + if (hsotg->dr_mode != USB_DR_MODE_HOST) { retval = dwc2_gadget_init(hsotg); if (retval) - goto error; + goto error_drd; hsotg->gadget_enabled = 1; + } + + /* + * If we need PHY for wakeup we must be wakeup capable. + * When we have a device that can wake without the PHY we + * can adjust this condition. + */ + if (hsotg->need_phy_for_wake) + device_set_wakeup_capable(&dev->dev, true); + + hsotg->reset_phy_on_wake = + of_property_read_bool(dev->dev.of_node, + "snps,reset-phy-on-wake"); + if (hsotg->reset_phy_on_wake && !hsotg->phy) { + dev_warn(hsotg->dev, + "Quirk reset-phy-on-wake only supports generic PHYs\n"); + hsotg->reset_phy_on_wake = false; } if (hsotg->dr_mode != USB_DR_MODE_PERIPHERAL) { @@ -561,7 +637,7 @@ if (retval) { if (hsotg->gadget_enabled) dwc2_hsotg_remove(hsotg); - goto error; + goto error_drd; } hsotg->hcd_enabled = 1; } @@ -588,16 +664,29 @@ if (retval) { hsotg->gadget.udc = NULL; dwc2_hsotg_remove(hsotg); - goto error; + goto error_debugfs; } } #endif /* CONFIG_USB_DWC2_PERIPHERAL || CONFIG_USB_DWC2_DUAL_ROLE */ return 0; +#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || \ + IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE) +error_debugfs: + dwc2_debugfs_exit(hsotg); + if (hsotg->hcd_enabled) + dwc2_hcd_remove(hsotg); +#endif +error_drd: + dwc2_drd_exit(hsotg); + +error_init: + if (hsotg->params.activate_stm_id_vb_detection) + regulator_disable(hsotg->usb33d); error: pm_runtime_put_sync(hsotg->dev); pm_runtime_disable(hsotg->dev); - if (hsotg->dr_mode != USB_DR_MODE_PERIPHERAL) + if (hsotg->ll_hw_enabled) dwc2_lowlevel_hw_disable(hsotg); return retval; } @@ -605,13 +694,50 @@ static int __maybe_unused dwc2_suspend(struct device *dev) { struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev); + bool is_device_mode = dwc2_is_device_mode(dwc2); int ret = 0; - if (dwc2_is_device_mode(dwc2)) + if (is_device_mode) dwc2_hsotg_suspend(dwc2); - if (dwc2->ll_hw_enabled) + dwc2_drd_suspend(dwc2); + + if (dwc2->params.activate_stm_id_vb_detection) { + unsigned long flags; + u32 ggpio, gotgctl; + + /* + * Need to force the mode to the current mode to avoid Mode + * Mismatch Interrupt when ID detection will be disabled. + */ + dwc2_force_mode(dwc2, !is_device_mode); + + spin_lock_irqsave(&dwc2->lock, flags); + gotgctl = dwc2_readl(dwc2, GOTGCTL); + /* bypass debounce filter, enable overrides */ + gotgctl |= GOTGCTL_DBNCE_FLTR_BYPASS; + gotgctl |= GOTGCTL_BVALOEN | GOTGCTL_AVALOEN; + /* Force A / B session if needed */ + if (gotgctl & GOTGCTL_ASESVLD) + gotgctl |= GOTGCTL_AVALOVAL; + if (gotgctl & GOTGCTL_BSESVLD) + gotgctl |= GOTGCTL_BVALOVAL; + dwc2_writel(dwc2, gotgctl, GOTGCTL); + spin_unlock_irqrestore(&dwc2->lock, flags); + + ggpio = dwc2_readl(dwc2, GGPIO); + ggpio &= ~GGPIO_STM32_OTG_GCCFG_IDEN; + ggpio &= ~GGPIO_STM32_OTG_GCCFG_VBDEN; + dwc2_writel(dwc2, ggpio, GGPIO); + + regulator_disable(dwc2->usb33d); + } + + if (dwc2->ll_hw_enabled && + (is_device_mode || dwc2_host_can_poweroff_phy(dwc2))) { ret = __dwc2_lowlevel_hw_disable(dwc2); + dwc2->phy_off_for_suspend = true; + } return ret; } @@ -622,11 +748,42 @@ unsigned long flags; int ret = 0; - if (dwc2->ll_hw_enabled) { + if (dwc2->phy_off_for_suspend && dwc2->ll_hw_enabled) { ret = __dwc2_lowlevel_hw_enable(dwc2); if (ret) return ret; } + dwc2->phy_off_for_suspend = false; + + if (dwc2->params.activate_stm_id_vb_detection) { + unsigned long flags; + u32 ggpio, gotgctl; + + ret = regulator_enable(dwc2->usb33d); + if (ret) + return ret; + + ggpio = dwc2_readl(dwc2, GGPIO); + ggpio |= GGPIO_STM32_OTG_GCCFG_IDEN; + ggpio |= GGPIO_STM32_OTG_GCCFG_VBDEN; + dwc2_writel(dwc2, ggpio, GGPIO); + + /* ID/VBUS detection startup time */ + usleep_range(5000, 7000); + + spin_lock_irqsave(&dwc2->lock, flags); + gotgctl = dwc2_readl(dwc2, GOTGCTL); + gotgctl &= ~GOTGCTL_DBNCE_FLTR_BYPASS; + gotgctl &= ~(GOTGCTL_BVALOEN | GOTGCTL_AVALOEN | + GOTGCTL_BVALOVAL | GOTGCTL_AVALOVAL); + dwc2_writel(dwc2, gotgctl, GOTGCTL); + spin_unlock_irqrestore(&dwc2->lock, flags); + } + + /* Need to restore FORCEDEVMODE/FORCEHOSTMODE */ + dwc2_force_dr_mode(dwc2); + + dwc2_drd_resume(dwc2); if (dwc2->dr_mode == USB_DR_MODE_HOST && dwc2_is_device_mode(dwc2)) { /* Reinit for Host mode if lost power */ -- Gitblit v1.6.2