From faff8cbf871b5e23d260675a8ff98eeebda37461 Mon Sep 17 00:00:00 2001 From: Yaniv Gardi Date: Wed, 16 Jul 2014 23:46:05 +0300 Subject: [PATCH] scsi: ufs: remove code duplication from ufs specific phy In this change, code that is duplicated in specific ufs msm PHYs modules is removed, and helper functions that contain the common code are added to ufs-msm-phy.c. Change-Id: I30ca8b4d4b452450a155671da94f03d7b965160a Signed-off-by: Yaniv Gardi --- drivers/scsi/ufs/ufs-msm-phy-qmp-20nm.c | 71 +++++++------------- drivers/scsi/ufs/ufs-msm-phy-qmp-28nm.c | 76 ++++++++------------- drivers/scsi/ufs/ufs-msm-phy.c | 87 ++++++++++++++++++++++++- drivers/scsi/ufs/ufs-msm-phy.h | 10 ++- 4 files changed, 143 insertions(+), 101 deletions(-) diff --git a/drivers/scsi/ufs/ufs-msm-phy-qmp-20nm.c b/drivers/scsi/ufs/ufs-msm-phy-qmp-20nm.c index 1cacf2354e87..1e72dcc61ac9 100644 --- a/drivers/scsi/ufs/ufs-msm-phy-qmp-20nm.c +++ b/drivers/scsi/ufs/ufs-msm-phy-qmp-20nm.c @@ -30,36 +30,27 @@ #define UFS_PHY_NAME "ufs_msm_phy_qmp_20nm" -static void ufs_msm_phy_qmp_20nm_phy_calibrate(struct ufs_msm_phy *phy) +static int ufs_msm_phy_qmp_20nm_phy_calibrate(struct ufs_msm_phy *ufs_msm_phy) { - struct ufs_msm_phy_calibration *tbl; - int tbl_size; - int i; + struct ufs_msm_phy_calibration *tbl_A, *tbl_B; + int tbl_size_A, tbl_size_B; + int rate = UFS_MSM_LIMIT_HS_RATE; + int err; - tbl_size = ARRAY_SIZE(phy_cal_table_rate_A); - tbl = phy_cal_table_rate_A; + tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A); + tbl_A = phy_cal_table_rate_A; - /* - * calibration according phy_cal_table_rate_A happens - * regardless of the rate we intend to work with. - * Only in case we would like to work in rate B, we need - * to override a subset of registers of phy_cal_table_rate_A - * table, with phy_cal_table_rate_B table. - */ - for (i = 0; i < tbl_size; i++) - writel_relaxed(tbl[i].cfg_value, phy->mmio + tbl[i].reg_offset); + tbl_size_B = ARRAY_SIZE(phy_cal_table_rate_B); + tbl_B = phy_cal_table_rate_B; - if (UFS_MSM_LIMIT_HS_RATE == PA_HS_MODE_B) { - tbl = phy_cal_table_rate_B; - tbl_size = ARRAY_SIZE(phy_cal_table_rate_B); + err = ufs_msm_phy_calibrate(ufs_msm_phy, tbl_A, tbl_size_A, + tbl_B, tbl_size_B, rate); - for (i = 0; i < tbl_size; i++) - writel_relaxed(tbl[i].cfg_value, - phy->mmio + tbl[i].reg_offset); - } + if (err) + dev_err(ufs_msm_phy->dev, "%s: ufs_msm_phy_calibrate() failed %d\n", + __func__, err); - /* flush buffered writes */ - mb(); + return err; } static int ufs_msm_phy_qmp_20nm_init(struct phy *generic_phy) @@ -192,7 +183,6 @@ static int ufs_msm_phy_qmp_20nm_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct phy *generic_phy; struct ufs_msm_phy_qmp_20nm *phy; - struct phy_provider *phy_provider; int err = 0; phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); @@ -202,35 +192,20 @@ static int ufs_msm_phy_qmp_20nm_probe(struct platform_device *pdev) goto out; } - err = ufs_msm_phy_base_init(pdev, &phy->common_cfg); - if (err) { - dev_err(dev, "%s: phy base init failed %d\n", __func__, err); + generic_phy = ufs_msm_phy_generic_probe(pdev, &phy->common_cfg, + &ufs_msm_phy_qmp_20nm_phy_ops, &phy_20nm_ops); + + if (!generic_phy) { + dev_err(dev, "%s: ufs_msm_phy_generic_probe() failed\n", + __func__); + err = -EIO; goto out; } - phy->common_cfg.phy_spec_ops = &phy_20nm_ops; - phy->common_cfg.cached_regs = NULL; - - phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); - if (IS_ERR(phy_provider)) { - err = PTR_ERR(phy_provider); - dev_err(dev, "%s: failed to register phy %d\n", __func__, err); - goto out; - } - - generic_phy = devm_phy_create(dev, &ufs_msm_phy_qmp_20nm_phy_ops, NULL); - if (IS_ERR(generic_phy)) { - devm_of_phy_provider_unregister(dev, phy_provider); - err = PTR_ERR(generic_phy); - dev_err(dev, "%s: failed to create phy %d\n", __func__, err); - goto out; - } - - phy->common_cfg.dev = dev; phy_set_drvdata(generic_phy, phy); strlcpy(phy->common_cfg.name, UFS_PHY_NAME, - sizeof(phy->common_cfg.name)); + sizeof(phy->common_cfg.name)); out: return err; diff --git a/drivers/scsi/ufs/ufs-msm-phy-qmp-28nm.c b/drivers/scsi/ufs/ufs-msm-phy-qmp-28nm.c index f01bafe32b0d..a75a6ca8fc2a 100644 --- a/drivers/scsi/ufs/ufs-msm-phy-qmp-28nm.c +++ b/drivers/scsi/ufs/ufs-msm-phy-qmp-28nm.c @@ -97,46 +97,34 @@ out: return err; } -static void ufs_msm_phy_qmp_28nm_calibrate(struct ufs_msm_phy *ufs_msm_phy) +static int ufs_msm_phy_qmp_28nm_calibrate(struct ufs_msm_phy *ufs_msm_phy) { - struct ufs_msm_phy_calibration *tbl; - int tbl_size; - int i; + struct ufs_msm_phy_calibration *tbl_A, *tbl_B; + int tbl_size_A, tbl_size_B; + int rate = UFS_MSM_LIMIT_HS_RATE; u8 major = ufs_msm_phy->host_ctrl_rev_major; u16 minor = ufs_msm_phy->host_ctrl_rev_minor; u16 step = ufs_msm_phy->host_ctrl_rev_step; + int err; if ((major == 0x1) && (minor == 0x001) && (step == 0x0000)) { - tbl_size = ARRAY_SIZE(phy_cal_table_ctrl_1_1_0_rate_A); - tbl = phy_cal_table_ctrl_1_1_0_rate_A; + tbl_size_A = ARRAY_SIZE(phy_cal_table_ctrl_1_1_0_rate_A); + tbl_A = phy_cal_table_ctrl_1_1_0_rate_A; } else if ((major == 0x1) && (minor == 0x001) && (step == 0x0001)) { - tbl_size = ARRAY_SIZE(phy_cal_table_ctrl_1_1_1_rate_A); - tbl = phy_cal_table_ctrl_1_1_1_rate_A; + tbl_size_A = ARRAY_SIZE(phy_cal_table_ctrl_1_1_1_rate_A); + tbl_A = phy_cal_table_ctrl_1_1_1_rate_A; } - /* - * calibration according phy_cal_table_ctrl_x_x_x_rate_A - * happens regardless of the rate we intend to work with. - * Only in case we would like to work in rate B, we need - * to override a subset of registers of - * phy_cal_table_ctrl_x_x_x_rate_A table, with phy_cal_table_rate_B - * table. - */ - for (i = 0; i < tbl_size; i++) - writel_relaxed(tbl[i].cfg_value, - ufs_msm_phy->mmio + tbl[i].reg_offset); + tbl_B = phy_cal_table_rate_B; + tbl_size_B = ARRAY_SIZE(phy_cal_table_rate_B); - if (UFS_MSM_LIMIT_HS_RATE == PA_HS_MODE_B) { - tbl = phy_cal_table_rate_B; - tbl_size = ARRAY_SIZE(phy_cal_table_rate_B); + err = ufs_msm_phy_calibrate(ufs_msm_phy, tbl_A, tbl_size_A, + tbl_B, tbl_size_B, rate); + if (err) + dev_err(ufs_msm_phy->dev, "%s: ufs_msm_phy_calibrate() failed %d\n", + __func__, err); - for (i = 0; i < tbl_size; i++) - writel_relaxed(tbl[i].cfg_value, - ufs_msm_phy->mmio + tbl[i].reg_offset); - } - - /* flush buffered writes */ - mb(); + return err; } static @@ -286,7 +274,7 @@ static int ufs_msm_phy_qmp_28nm_resume(struct phy *generic_phy) return err; } -struct phy_ops ufs_msm_phy_ops = { +struct phy_ops ufs_msm_phy_qmp_28nm_phy_ops = { .init = ufs_msm_phy_qmp_28nm_init, .exit = ufs_msm_phy_exit, .power_on = ufs_msm_phy_power_on, @@ -312,7 +300,6 @@ static int ufs_msm_phy_qmp_28nm_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; int err = 0; struct phy *generic_phy; - struct phy_provider *phy_provider; phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); if (!phy) { @@ -321,37 +308,26 @@ static int ufs_msm_phy_qmp_28nm_probe(struct platform_device *pdev) goto out; } - err = ufs_msm_phy_base_init(pdev, &phy->common_cfg); - if (err) { - dev_err(dev, "%s: phy base init failed %d\n", __func__, err); - goto out; - } - - phy->common_cfg.phy_spec_ops = &phy_28nm_ops; phy->common_cfg.cached_regs = (struct ufs_msm_phy_calibration *)cached_phy_regs; phy->common_cfg.cached_regs_table_size = ARRAY_SIZE(cached_phy_regs); - phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); - if (IS_ERR(phy_provider)) { - err = PTR_ERR(phy_provider); - dev_err(dev, "%s: failed to register phy %d\n", __func__, err); + generic_phy = ufs_msm_phy_generic_probe(pdev, &phy->common_cfg, + &ufs_msm_phy_qmp_28nm_phy_ops, &phy_28nm_ops); + + if (!generic_phy) { + dev_err(dev, "%s: ufs_msm_phy_generic_probe() failed\n", + __func__); + err = -EIO; goto out; } - generic_phy = devm_phy_create(dev, &ufs_msm_phy_ops, NULL); - if (IS_ERR(generic_phy)) { - err = PTR_ERR(generic_phy); - dev_err(dev, "%s: failed to create phy %d\n", __func__, err); - goto out; - } - - phy->common_cfg.dev = dev; phy_set_drvdata(generic_phy, phy); strlcpy(phy->common_cfg.name, UFS_PHY_NAME, sizeof(phy->common_cfg.name)); + out: return err; } diff --git a/drivers/scsi/ufs/ufs-msm-phy.c b/drivers/scsi/ufs/ufs-msm-phy.c index f04b2621e68f..45b355efe10e 100644 --- a/drivers/scsi/ufs/ufs-msm-phy.c +++ b/drivers/scsi/ufs/ufs-msm-phy.c @@ -27,6 +27,87 @@ #include "ufs-msm.h" #include "ufs-msm-phy.h" +int ufs_msm_phy_calibrate(struct ufs_msm_phy *ufs_msm_phy, + struct ufs_msm_phy_calibration *tbl_A, int tbl_size_A, + struct ufs_msm_phy_calibration *tbl_B, int tbl_size_B, + int rate) +{ + int i; + int ret = 0; + + if (!tbl_A) { + dev_err(ufs_msm_phy->dev, "%s: tbl_A is NULL", __func__); + ret = EINVAL; + goto out; + } + + for (i = 0; i < tbl_size_A; i++) + writel_relaxed(tbl_A[i].cfg_value, + ufs_msm_phy->mmio + tbl_A[i].reg_offset); + + /* + * In case we would like to work in rate B, we need + * to override a registers that were configured in rate A table + * with registers of rate B table. + * table. + */ + if (rate == PA_HS_MODE_B) { + if (!tbl_B) { + dev_err(ufs_msm_phy->dev, "%s: tbl_B is NULL", + __func__); + ret = EINVAL; + goto out; + } + + for (i = 0; i < tbl_size_B; i++) + writel_relaxed(tbl_B[i].cfg_value, + ufs_msm_phy->mmio + tbl_B[i].reg_offset); + } + + /* flush buffered writes */ + mb(); + +out: + return ret; +} + +struct phy *ufs_msm_phy_generic_probe(struct platform_device *pdev, + struct ufs_msm_phy *common_cfg, + struct phy_ops *ufs_msm_phy_gen_ops, + struct ufs_msm_phy_specific_ops *phy_spec_ops) +{ + int err; + struct device *dev = &pdev->dev; + struct phy *generic_phy = NULL; + struct phy_provider *phy_provider; + + err = ufs_msm_phy_base_init(pdev, common_cfg); + if (err) { + dev_err(dev, "%s: phy base init failed %d\n", __func__, err); + goto out; + } + + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + if (IS_ERR(phy_provider)) { + err = PTR_ERR(phy_provider); + dev_err(dev, "%s: failed to register phy %d\n", __func__, err); + goto out; + } + + generic_phy = devm_phy_create(dev, ufs_msm_phy_gen_ops, NULL); + if (IS_ERR(generic_phy)) { + err = PTR_ERR(generic_phy); + dev_err(dev, "%s: failed to create phy %d\n", __func__, err); + goto out; + } + + common_cfg->phy_spec_ops = phy_spec_ops; + common_cfg->dev = dev; + +out: + return generic_phy; +} + /* * This assumes the embedded phy structure inside generic_phy is of type * struct ufs_msm_phy. In order to function properly it's crucial @@ -447,8 +528,10 @@ int ufs_msm_phy_calibrate_phy(struct phy *generic_phy) __func__); ret = -ENOTSUPP; } else { - ufs_msm_phy->phy_spec_ops-> - calibrate_phy(ufs_msm_phy); + ret = ufs_msm_phy->phy_spec_ops-> + calibrate_phy(ufs_msm_phy); + dev_err(ufs_msm_phy->dev, "%s: calibrate_phy() failed %d\n", + __func__, ret); } return ret; diff --git a/drivers/scsi/ufs/ufs-msm-phy.h b/drivers/scsi/ufs/ufs-msm-phy.h index 5edd9d2260a3..90eac935c161 100644 --- a/drivers/scsi/ufs/ufs-msm-phy.h +++ b/drivers/scsi/ufs/ufs-msm-phy.h @@ -130,7 +130,7 @@ struct ufs_msm_phy { * and writes to QSERDES_RX_SIGDET_CNTRL attribute */ struct ufs_msm_phy_specific_ops { - void (*calibrate_phy) (struct ufs_msm_phy *phy); + int (*calibrate_phy) (struct ufs_msm_phy *phy); void (*start_serdes) (struct ufs_msm_phy *phy); void (*save_configuration)(struct ufs_msm_phy *phy); int (*is_physical_coding_sublayer_ready) (struct ufs_msm_phy *phy); @@ -173,4 +173,12 @@ int ufs_msm_phy_init_vregulators(struct phy *generic_phy, struct ufs_msm_phy *phy_common); int ufs_msm_phy_remove(struct phy *generic_phy, struct ufs_msm_phy *ufs_msm_phy); +struct phy *ufs_msm_phy_generic_probe(struct platform_device *pdev, + struct ufs_msm_phy *common_cfg, + struct phy_ops *ufs_msm_phy_gen_ops, + struct ufs_msm_phy_specific_ops *phy_spec_ops); +int ufs_msm_phy_calibrate(struct ufs_msm_phy *ufs_msm_phy, + struct ufs_msm_phy_calibration *tbl_A, int tbl_size_A, + struct ufs_msm_phy_calibration *tbl_B, int tbl_size_B, + int rate); #endif