summaryrefslogtreecommitdiff
path: root/drivers/phy/samsung/phy-samsung-ufs.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/phy/samsung/phy-samsung-ufs.c')
-rw-r--r--drivers/phy/samsung/phy-samsung-ufs.c75
1 files changed, 67 insertions, 8 deletions
diff --git a/drivers/phy/samsung/phy-samsung-ufs.c b/drivers/phy/samsung/phy-samsung-ufs.c
index 183c88e3d1ec..ee665f26c236 100644
--- a/drivers/phy/samsung/phy-samsung-ufs.c
+++ b/drivers/phy/samsung/phy-samsung-ufs.c
@@ -28,9 +28,9 @@
#define PHY_DEF_LANE_CNT 1
-static void samsung_ufs_phy_config(struct samsung_ufs_phy *phy,
- const struct samsung_ufs_phy_cfg *cfg,
- u8 lane)
+void samsung_ufs_phy_config(struct samsung_ufs_phy *phy,
+ const struct samsung_ufs_phy_cfg *cfg,
+ u8 lane)
{
enum {LANE_0, LANE_1}; /* lane index */
@@ -45,7 +45,7 @@ static void samsung_ufs_phy_config(struct samsung_ufs_phy *phy,
}
}
-static int samsung_ufs_phy_wait_for_lock_acq(struct phy *phy)
+int samsung_ufs_phy_wait_for_lock_acq(struct phy *phy, u8 lane)
{
struct samsung_ufs_phy *ufs_phy = get_samsung_ufs_phy(phy);
const unsigned int timeout_us = 100000;
@@ -97,8 +97,21 @@ static int samsung_ufs_phy_calibrate(struct phy *phy)
}
}
- if (ufs_phy->ufs_phy_state == CFG_POST_PWR_HS)
- err = samsung_ufs_phy_wait_for_lock_acq(phy);
+ for_each_phy_lane(ufs_phy, i) {
+ if (ufs_phy->ufs_phy_state == CFG_PRE_INIT &&
+ ufs_phy->drvdata->wait_for_cal) {
+ err = ufs_phy->drvdata->wait_for_cal(phy, i);
+ if (err)
+ goto out;
+ }
+
+ if (ufs_phy->ufs_phy_state == CFG_POST_PWR_HS &&
+ ufs_phy->drvdata->wait_for_cdr) {
+ err = ufs_phy->drvdata->wait_for_cdr(phy, i);
+ if (err)
+ goto out;
+ }
+ }
/**
* In Samsung ufshci, PHY need to be calibrated at different
@@ -204,6 +217,44 @@ static int samsung_ufs_phy_set_mode(struct phy *generic_phy,
return 0;
}
+static int samsung_ufs_phy_notify_state(struct phy *phy,
+ union phy_notify state)
+{
+ struct samsung_ufs_phy *ufs_phy = get_samsung_ufs_phy(phy);
+ const struct samsung_ufs_phy_cfg *cfg;
+ int i, err = -EINVAL;
+
+ if (!ufs_phy->cfgs_hibern8)
+ return 0;
+
+ if (state.ufs_state == PHY_UFS_HIBERN8_ENTER)
+ cfg = ufs_phy->cfgs_hibern8[CFG_POST_HIBERN8_ENTER];
+ else if (state.ufs_state == PHY_UFS_HIBERN8_EXIT)
+ cfg = ufs_phy->cfgs_hibern8[CFG_PRE_HIBERN8_EXIT];
+ else
+ goto err_out;
+
+ for_each_phy_cfg(cfg) {
+ for_each_phy_lane(ufs_phy, i) {
+ samsung_ufs_phy_config(ufs_phy, cfg, i);
+ }
+ }
+
+ if (state.ufs_state == PHY_UFS_HIBERN8_EXIT) {
+ for_each_phy_lane(ufs_phy, i) {
+ if (ufs_phy->drvdata->wait_for_cdr) {
+ err = ufs_phy->drvdata->wait_for_cdr(phy, i);
+ if (err)
+ goto err_out;
+ }
+ }
+ }
+
+ return 0;
+err_out:
+ return err;
+}
+
static int samsung_ufs_phy_exit(struct phy *phy)
{
struct samsung_ufs_phy *ss_phy = get_samsung_ufs_phy(phy);
@@ -220,6 +271,7 @@ static const struct phy_ops samsung_ufs_phy_ops = {
.power_off = samsung_ufs_phy_power_off,
.calibrate = samsung_ufs_phy_calibrate,
.set_mode = samsung_ufs_phy_set_mode,
+ .notify_phystate = samsung_ufs_phy_notify_state,
.owner = THIS_MODULE,
};
@@ -255,8 +307,8 @@ static int samsung_ufs_phy_probe(struct platform_device *pdev)
goto out;
}
- phy->reg_pmu = syscon_regmap_lookup_by_phandle(
- dev->of_node, "samsung,pmu-syscon");
+ phy->reg_pmu = syscon_regmap_lookup_by_phandle(dev->of_node,
+ "samsung,pmu-syscon");
if (IS_ERR(phy->reg_pmu)) {
err = PTR_ERR(phy->reg_pmu);
dev_err(dev, "failed syscon remap for pmu\n");
@@ -274,6 +326,7 @@ static int samsung_ufs_phy_probe(struct platform_device *pdev)
phy->dev = dev;
phy->drvdata = drvdata;
phy->cfgs = drvdata->cfgs;
+ phy->cfgs_hibern8 = drvdata->cfgs_hibern8;
memcpy(&phy->isol, &drvdata->isol, sizeof(phy->isol));
if (!of_property_read_u32_index(dev->of_node, "samsung,pmu-syscon", 1,
@@ -302,12 +355,18 @@ out:
static const struct of_device_id samsung_ufs_phy_match[] = {
{
+ .compatible = "google,gs101-ufs-phy",
+ .data = &tensor_gs101_ufs_phy,
+ }, {
.compatible = "samsung,exynos7-ufs-phy",
.data = &exynos7_ufs_phy,
}, {
.compatible = "samsung,exynosautov9-ufs-phy",
.data = &exynosautov9_ufs_phy,
}, {
+ .compatible = "samsung,exynosautov920-ufs-phy",
+ .data = &exynosautov920_ufs_phy,
+ }, {
.compatible = "tesla,fsd-ufs-phy",
.data = &fsd_ufs_phy,
},