static int msm_ssphy_qmp_reset(struct usb_phy *uphy) { struct msm_ssphy_qmp *phy = container_of(uphy, struct msm_ssphy_qmp, phy); int ret; dev_dbg(uphy->dev, "Resetting QMP phy\n"); if (!phy->clk_enabled) { ret = msm_ssphy_qmp_init_clocks(phy); if (ret) { dev_err(uphy->dev, "failed to init clocks %d\n", ret); return ret; } } /* Assert USB3 PHY reset */ ret = clk_reset(phy->phy_com_reset, CLK_RESET_ASSERT); if (ret && ret != -EINVAL) { dev_err(uphy->dev, "phy_com_reset clk assert failed\n"); return ret; } ret = clk_reset(phy->phy_reset, CLK_RESET_ASSERT); if (ret) { dev_err(uphy->dev, "phy_reset clk assert failed\n"); goto deassert_phy_com_reset; } ret = clk_reset(phy->pipe_clk, CLK_RESET_ASSERT); if (ret && ret != -ENOSYS) { dev_err(uphy->dev, "pipe_clk reset assert failed\n"); goto deassert_phy_reset; } /* Clear USB3 PHY reset */ ret = clk_reset(phy->pipe_clk, CLK_RESET_DEASSERT); if (ret && ret != -ENOSYS) { dev_err(uphy->dev, "pipe_clk reset assert failed\n"); goto deassert_phy_reset; } ret = clk_reset(phy->phy_reset, CLK_RESET_DEASSERT); if (ret) { dev_err(uphy->dev, "phy_reset clk deassert failed\n"); goto deassert_phy_com_reset; } ret = clk_reset(phy->phy_com_reset, CLK_RESET_DEASSERT); if (ret && ret != -EINVAL) { dev_err(uphy->dev, "phy_com_reset clk deassert failed\n"); return ret; } return 0; deassert_phy_reset: clk_reset(phy->phy_reset, CLK_RESET_DEASSERT); deassert_phy_com_reset: clk_reset(phy->phy_com_reset, CLK_RESET_DEASSERT); phy->in_suspend = false; return ret; }
/* SSPHY Initialization */ static int msm_ssphy_qmp_init(struct usb_phy *uphy) { struct msm_ssphy_qmp *phy = container_of(uphy, struct msm_ssphy_qmp, phy); int ret; unsigned init_timeout_usec = INIT_MAX_TIME_USEC; u32 revid; const struct qmp_reg_val *reg = NULL; dev_dbg(uphy->dev, "Initializing QMP phy\n"); if (!phy->clk_enabled) { ret = msm_ssphy_qmp_init_clocks(phy); if (ret) { dev_err(uphy->dev, "failed to init clocks %d\n", ret); return ret; } } /* Rev ID is made up each of the LSBs of REVISION_ID[0-3] */ revid = (readl_relaxed(phy->base + PCIE_USB3_PHY_REVISION_ID3) & 0xFF) << 24; revid |= (readl_relaxed(phy->base + PCIE_USB3_PHY_REVISION_ID2) & 0xFF) << 16; revid |= (readl_relaxed(phy->base + PCIE_USB3_PHY_REVISION_ID1) & 0xFF) << 8; revid |= readl_relaxed(phy->base + PCIE_USB3_PHY_REVISION_ID0) & 0xFF; switch (revid) { case 0x10000000: reg = qmp_settings_rev0; break; case 0x10000001: reg = qmp_settings_rev1; break; default: dev_err(uphy->dev, "Unknown revid 0x%x, cannot initialize PHY\n", revid); return -ENODEV; } /* Configure AHB2PHY for one wait state reads/writes */ if (phy->ahb2phy) writel_relaxed(0x11, phy->ahb2phy + PERIPH_SS_AHB2PHY_TOP_CFG); writel_relaxed(0x01, phy->base + PCIE_USB3_PHY_POWER_DOWN_CONTROL); while (reg && reg->offset != -1 && reg->val != -1) { writel_relaxed(reg->val, phy->base + reg->offset); reg++; } if (phy->override_pll_cal) { reg = qmp_override_pll; while (reg->offset != -1 && reg->val != -1) { writel_relaxed(reg->val, phy->base + reg->offset); reg++; } } writel_relaxed(0x00, phy->base + PCIE_USB3_PHY_SW_RESET); writel_relaxed(0x03, phy->base + PCIE_USB3_PHY_START); if (!phy->switch_pipe_clk_src) /* this clock wasn't enabled before, enable it now */ clk_prepare_enable(phy->pipe_clk); /* Wait for PHY initialization to be done */ do { if (readl_relaxed(phy->base + PCIE_USB3_PHY_PCS_STATUS) & PHYSTATUS) usleep(1); else break; } while (--init_timeout_usec); if (!init_timeout_usec) { dev_err(uphy->dev, "QMP PHY initialization timeout\n"); return -EBUSY; }; /* * After PHY initilization above, the PHY is generating * the usb3_pipe_clk in 125MHz. Therefore now we can (if needed) * switch the gcc_usb3_pipe_clk to 125MHz as well, so the * gcc_usb3_pipe_clk is sourced now from the usb3_pipe3_clk * instead of from the xo clock. */ if (phy->switch_pipe_clk_src) clk_set_rate(phy->pipe_clk, 125000000); return 0; }
static int msm_ssphy_qmp_reset(struct usb_phy *uphy) { struct msm_ssphy_qmp *phy = container_of(uphy, struct msm_ssphy_qmp, phy); int ret; dev_info(uphy->dev, "Resetting QMP phy\n"); if (!phy->clk_enabled) { ret = msm_ssphy_qmp_init_clocks(phy); if (ret) { dev_err(uphy->dev, "failed to init clocks %d\n", ret); return ret; } } if (phy->phy_com_reset) { ret = clk_reset(phy->phy_com_reset, CLK_RESET_ASSERT); if (ret) { dev_err(uphy->dev, "phy_com_reset clk assert failed\n"); return ret; } } if (phy->phy_phy_reset) { ret = clk_reset(phy->phy_phy_reset, CLK_RESET_ASSERT); if (ret) { dev_err(uphy->dev, "phy_phy reset assert failed\n"); goto deassert_phy_com_reset; } } else { ret = clk_reset(phy->pipe_clk, CLK_RESET_ASSERT); if (ret) { dev_err(uphy->dev, "pipe_clk reset assert failed\n"); goto deassert_phy_com_reset; } } ret = clk_reset(phy->phy_reset, CLK_RESET_ASSERT); if (ret) { dev_err(uphy->dev, "phy_reset clk assert failed\n"); goto deassert_phy_phy_reset; } ret = clk_reset(phy->phy_reset, CLK_RESET_DEASSERT); if (ret) { dev_err(uphy->dev, "phy_reset clk deassert failed\n"); goto deassert_phy_phy_reset; } if (phy->phy_phy_reset) { ret = clk_reset(phy->phy_phy_reset, CLK_RESET_DEASSERT); if (ret) { dev_err(uphy->dev, "phy_phy reset deassert failed\n"); goto deassert_phy_com_reset; } } else { ret = clk_reset(phy->pipe_clk, CLK_RESET_DEASSERT); if (ret) { dev_err(uphy->dev, "pipe_clk reset deassert failed\n"); goto deassert_phy_com_reset; } } if (phy->phy_com_reset) { ret = clk_reset(phy->phy_com_reset, CLK_RESET_DEASSERT); if (ret) { dev_err(uphy->dev, "phy_com_reset clk deassert failed\n"); return ret; } } return 0; deassert_phy_phy_reset: if (phy->phy_phy_reset) clk_reset(phy->phy_phy_reset, CLK_RESET_DEASSERT); else clk_reset(phy->pipe_clk, CLK_RESET_DEASSERT); deassert_phy_com_reset: if (phy->phy_com_reset) clk_reset(phy->phy_com_reset, CLK_RESET_DEASSERT); phy->in_suspend = false; return ret; }
static int msm_ssphy_qmp_probe(struct platform_device *pdev) { struct msm_ssphy_qmp *phy; struct device *dev = &pdev->dev; struct resource *res; int ret = 0; phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); if (!phy) return -ENOMEM; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(dev, "missing memory base resource\n"); return -ENODEV; } phy->base = devm_ioremap_nocache(dev, res->start, resource_size(res)); if (!phy->base) { dev_err(dev, "ioremap failed\n"); return -ENODEV; } ret = of_property_read_u32_array(dev->of_node, "qcom,vdd-voltage-level", (u32 *) phy->vdd_levels, ARRAY_SIZE(phy->vdd_levels)); if (ret) { dev_err(dev, "error reading qcom,vdd-voltage-level property\n"); return ret; } phy->vdd = devm_regulator_get(dev, "vdd"); if (IS_ERR(phy->vdd)) { dev_err(dev, "unable to get vdd supply\n"); return PTR_ERR(phy->vdd); } phy->vdda18 = devm_regulator_get(dev, "vdda18"); if (IS_ERR(phy->vdda18)) { dev_err(dev, "unable to get vdda18 supply\n"); return PTR_ERR(phy->vdda18); } ret = msm_ssusb_qmp_config_vdd(phy, 1); if (ret) { dev_err(dev, "ssusb vdd_dig configuration failed\n"); return ret; } ret = regulator_enable(phy->vdd); if (ret) { dev_err(dev, "unable to enable the ssusb vdd_dig\n"); goto unconfig_ss_vdd; } ret = msm_ssusb_qmp_ldo_enable(phy, 1); if (ret) { dev_err(dev, "ssusb vreg enable failed\n"); goto disable_ss_vdd; } platform_set_drvdata(pdev, phy); if (of_property_read_bool(dev->of_node, "qcom,vbus-valid-override")) phy->phy.flags |= PHY_VBUS_VALID_OVERRIDE; phy->phy.dev = dev; phy->phy.init = msm_ssphy_qmp_init; phy->phy.set_suspend = msm_ssphy_qmp_set_suspend; phy->phy.set_params = msm_ssphy_qmp_set_params; phy->phy.notify_connect = msm_ssphy_qmp_notify_connect; phy->phy.notify_disconnect = msm_ssphy_qmp_notify_disconnect; phy->phy.reset = msm_ssphy_qmp_reset; phy->phy.type = USB_PHY_TYPE_USB3; ret = msm_ssphy_qmp_init_clocks(phy); if (ret) { dev_err(dev, "Fail to init qmp phy clocks\n"); goto disable_ss_ldo; } ret = usb_add_phy_dev(&phy->phy); if (ret) goto disable_ss_ldo; return 0; disable_ss_ldo: msm_ssusb_qmp_ldo_enable(phy, 0); disable_ss_vdd: regulator_disable(phy->vdd); unconfig_ss_vdd: msm_ssusb_qmp_config_vdd(phy, 0); return ret; }
static int msm_ssphy_qmp_init(struct usb_phy *uphy) { struct msm_ssphy_qmp *phy = container_of(uphy, struct msm_ssphy_qmp, phy); int ret; unsigned init_timeout_usec = INIT_MAX_TIME_USEC; u32 revid; const struct qmp_reg_val *reg = NULL, *misc = NULL; dev_info(uphy->dev, "Initializing QMP phy\n"); if (phy->emulation) return 0; if (!phy->clk_enabled) { ret = msm_ssphy_qmp_init_clocks(phy); if (ret) { dev_err(uphy->dev, "failed to init clocks %d\n", ret); return ret; } } revid = (readl_relaxed(phy->base + PCIE_USB3_PHY_REVISION_ID3) & 0xFF) << 24; revid |= (readl_relaxed(phy->base + PCIE_USB3_PHY_REVISION_ID2) & 0xFF) << 16; revid |= (readl_relaxed(phy->base + PCIE_USB3_PHY_REVISION_ID1) & 0xFF) << 8; revid |= readl_relaxed(phy->base + PCIE_USB3_PHY_REVISION_ID0) & 0xFF; dev_info(uphy->dev, "QMP phy revid = %x\n", revid); switch (revid) { case 0x10000000: reg = qmp_settings_rev0; misc = qmp_settings_rev0_misc; break; case 0x10000001: reg = qmp_settings_rev1; misc = qmp_settings_rev1_misc; break; default: dev_err(uphy->dev, "Unknown revid 0x%x, cannot initialize PHY\n", revid); return -ENODEV; } if (phy->ahb2phy) writel_relaxed(0x11, phy->ahb2phy + PERIPH_SS_AHB2PHY_TOP_CFG); writel_relaxed(0x01, phy->base + PCIE_USB3_PHY_POWER_DOWN_CONTROL); ret = configure_phy_regs(uphy, reg); if (ret) { dev_err(uphy->dev, "Failed the main PHY configuration\n"); return ret; } if (phy->override_pll_cal) { reg = qmp_override_pll; ret = configure_phy_regs(uphy, reg); if (ret) { dev_err(uphy->dev, "Failed the PHY PLL override configuration\n"); return ret; } } if (phy->misc_config) { ret = configure_phy_regs(uphy, misc); if (ret) { dev_err(uphy->dev, "Failed the misc PHY configuration\n"); return ret; } } writel_relaxed(0x00, phy->base + PCIE_USB3_PHY_SW_RESET); writel_relaxed(0x03, phy->base + PCIE_USB3_PHY_START); if (!phy->switch_pipe_clk_src) clk_prepare_enable(phy->pipe_clk); do { if (readl_relaxed(phy->base + PCIE_USB3_PHY_PCS_STATUS) & PHYSTATUS) usleep(1); else break; } while (--init_timeout_usec); if (!init_timeout_usec) { dev_err(uphy->dev, "QMP PHY initialization timeout\n"); return -EBUSY; }; if (phy->switch_pipe_clk_src) clk_set_rate(phy->pipe_clk, 125000000); return 0; }