diff options
Diffstat (limited to 'drivers/phy/samsung/phy-samsung-ufs.c')
-rw-r--r-- | drivers/phy/samsung/phy-samsung-ufs.c | 138 |
1 files changed, 49 insertions, 89 deletions
diff --git a/drivers/phy/samsung/phy-samsung-ufs.c b/drivers/phy/samsung/phy-samsung-ufs.c index 602ddef259eb..183c88e3d1ec 100644 --- a/drivers/phy/samsung/phy-samsung-ufs.c +++ b/drivers/phy/samsung/phy-samsung-ufs.c @@ -63,7 +63,8 @@ static int samsung_ufs_phy_wait_for_lock_acq(struct phy *phy) } err = readl_poll_timeout( - ufs_phy->reg_pma + PHY_APB_ADDR(PHY_CDR_LOCK_STATUS), + ufs_phy->reg_pma + + PHY_APB_ADDR(ufs_phy->drvdata->cdr_lock_status_offset), val, (val & PHY_CDR_LOCK_BIT), sleep_us, timeout_us); if (err) dev_err(ufs_phy->dev, @@ -75,7 +76,7 @@ out: static int samsung_ufs_phy_calibrate(struct phy *phy) { struct samsung_ufs_phy *ufs_phy = get_samsung_ufs_phy(phy); - struct samsung_ufs_phy_cfg **cfgs = ufs_phy->cfg; + const struct samsung_ufs_phy_cfg * const *cfgs = ufs_phy->cfgs; const struct samsung_ufs_phy_cfg *cfg; int err = 0; int i; @@ -130,113 +131,63 @@ out: return err; } -static int samsung_ufs_phy_symbol_clk_init(struct samsung_ufs_phy *phy) +static int samsung_ufs_phy_clks_init(struct samsung_ufs_phy *phy) { - int ret; - - phy->tx0_symbol_clk = devm_clk_get(phy->dev, "tx0_symbol_clk"); - if (IS_ERR(phy->tx0_symbol_clk)) { - dev_err(phy->dev, "failed to get tx0_symbol_clk clock\n"); - return PTR_ERR(phy->tx0_symbol_clk); - } + int i; + const struct samsung_ufs_phy_drvdata *drvdata = phy->drvdata; + int num_clks = drvdata->num_clks; - phy->rx0_symbol_clk = devm_clk_get(phy->dev, "rx0_symbol_clk"); - if (IS_ERR(phy->rx0_symbol_clk)) { - dev_err(phy->dev, "failed to get rx0_symbol_clk clock\n"); - return PTR_ERR(phy->rx0_symbol_clk); - } + phy->clks = devm_kcalloc(phy->dev, num_clks, sizeof(*phy->clks), + GFP_KERNEL); + if (!phy->clks) + return -ENOMEM; - phy->rx1_symbol_clk = devm_clk_get(phy->dev, "rx1_symbol_clk"); - if (IS_ERR(phy->rx1_symbol_clk)) { - dev_err(phy->dev, "failed to get rx1_symbol_clk clock\n"); - return PTR_ERR(phy->rx1_symbol_clk); - } + for (i = 0; i < num_clks; i++) + phy->clks[i].id = drvdata->clk_list[i]; - ret = clk_prepare_enable(phy->tx0_symbol_clk); - if (ret) { - dev_err(phy->dev, "%s: tx0_symbol_clk enable failed %d\n", __func__, ret); - goto out; - } + return devm_clk_bulk_get(phy->dev, num_clks, phy->clks); +} - ret = clk_prepare_enable(phy->rx0_symbol_clk); - if (ret) { - dev_err(phy->dev, "%s: rx0_symbol_clk enable failed %d\n", __func__, ret); - goto out_disable_tx0_clk; - } +static int samsung_ufs_phy_init(struct phy *phy) +{ + struct samsung_ufs_phy *ss_phy = get_samsung_ufs_phy(phy); - ret = clk_prepare_enable(phy->rx1_symbol_clk); - if (ret) { - dev_err(phy->dev, "%s: rx1_symbol_clk enable failed %d\n", __func__, ret); - goto out_disable_rx0_clk; - } + ss_phy->lane_cnt = phy->attrs.bus_width; + ss_phy->ufs_phy_state = CFG_PRE_INIT; return 0; - -out_disable_rx0_clk: - clk_disable_unprepare(phy->rx0_symbol_clk); -out_disable_tx0_clk: - clk_disable_unprepare(phy->tx0_symbol_clk); -out: - return ret; } -static int samsung_ufs_phy_clks_init(struct samsung_ufs_phy *phy) +static int samsung_ufs_phy_power_on(struct phy *phy) { + struct samsung_ufs_phy *ss_phy = get_samsung_ufs_phy(phy); int ret; - phy->ref_clk = devm_clk_get(phy->dev, "ref_clk"); - if (IS_ERR(phy->ref_clk)) - dev_err(phy->dev, "failed to get ref_clk clock\n"); + samsung_ufs_phy_ctrl_isol(ss_phy, false); - ret = clk_prepare_enable(phy->ref_clk); + ret = clk_bulk_prepare_enable(ss_phy->drvdata->num_clks, ss_phy->clks); if (ret) { - dev_err(phy->dev, "%s: ref_clk enable failed %d\n", __func__, ret); + dev_err(ss_phy->dev, "failed to enable ufs phy clocks\n"); return ret; } - dev_dbg(phy->dev, "UFS MPHY ref_clk_rate = %ld\n", clk_get_rate(phy->ref_clk)); - - return 0; -} - -static int samsung_ufs_phy_init(struct phy *phy) -{ - struct samsung_ufs_phy *ss_phy = get_samsung_ufs_phy(phy); - int ret; - - ss_phy->lane_cnt = phy->attrs.bus_width; - ss_phy->ufs_phy_state = CFG_PRE_INIT; - - if (ss_phy->drvdata->has_symbol_clk) { - ret = samsung_ufs_phy_symbol_clk_init(ss_phy); + if (ss_phy->ufs_phy_state == CFG_PRE_INIT) { + ret = samsung_ufs_phy_calibrate(phy); if (ret) - dev_err(ss_phy->dev, "failed to set ufs phy symbol clocks\n"); + dev_err(ss_phy->dev, "ufs phy calibration failed\n"); } - ret = samsung_ufs_phy_clks_init(ss_phy); - if (ret) - dev_err(ss_phy->dev, "failed to set ufs phy clocks\n"); - - ret = samsung_ufs_phy_calibrate(phy); - if (ret) - dev_err(ss_phy->dev, "ufs phy calibration failed\n"); - return ret; } -static int samsung_ufs_phy_power_on(struct phy *phy) -{ - struct samsung_ufs_phy *ss_phy = get_samsung_ufs_phy(phy); - - samsung_ufs_phy_ctrl_isol(ss_phy, false); - return 0; -} - static int samsung_ufs_phy_power_off(struct phy *phy) { struct samsung_ufs_phy *ss_phy = get_samsung_ufs_phy(phy); + clk_bulk_disable_unprepare(ss_phy->drvdata->num_clks, ss_phy->clks); + samsung_ufs_phy_ctrl_isol(ss_phy, true); + return 0; } @@ -257,13 +208,7 @@ static int samsung_ufs_phy_exit(struct phy *phy) { struct samsung_ufs_phy *ss_phy = get_samsung_ufs_phy(phy); - clk_disable_unprepare(ss_phy->ref_clk); - - if (ss_phy->drvdata->has_symbol_clk) { - clk_disable_unprepare(ss_phy->tx0_symbol_clk); - clk_disable_unprepare(ss_phy->rx0_symbol_clk); - clk_disable_unprepare(ss_phy->rx1_symbol_clk); - } + ss_phy->ufs_phy_state = CFG_TAG_MAX; return 0; } @@ -288,6 +233,7 @@ static int samsung_ufs_phy_probe(struct platform_device *pdev) struct phy *gen_phy; struct phy_provider *phy_provider; const struct samsung_ufs_phy_drvdata *drvdata; + u32 isol_offset; int err = 0; match = of_match_node(samsung_ufs_phy_match, dev->of_node); @@ -327,10 +273,21 @@ static int samsung_ufs_phy_probe(struct platform_device *pdev) drvdata = match->data; phy->dev = dev; phy->drvdata = drvdata; - phy->cfg = (struct samsung_ufs_phy_cfg **)drvdata->cfg; - phy->isol = &drvdata->isol; + phy->cfgs = drvdata->cfgs; + memcpy(&phy->isol, &drvdata->isol, sizeof(phy->isol)); + + if (!of_property_read_u32_index(dev->of_node, "samsung,pmu-syscon", 1, + &isol_offset)) + phy->isol.offset = isol_offset; + phy->lane_cnt = PHY_DEF_LANE_CNT; + err = samsung_ufs_phy_clks_init(phy); + if (err) { + dev_err(dev, "failed to get phy clocks\n"); + goto out; + } + phy_set_drvdata(gen_phy, phy); phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); @@ -350,6 +307,9 @@ static const struct of_device_id samsung_ufs_phy_match[] = { }, { .compatible = "samsung,exynosautov9-ufs-phy", .data = &exynosautov9_ufs_phy, + }, { + .compatible = "tesla,fsd-ufs-phy", + .data = &fsd_ufs_phy, }, {}, }; |