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 <ygardi@codeaurora.org>
This commit is contained in:
Yaniv Gardi 2014-07-16 23:46:05 +03:00 committed by Gerrit - the friendly Code Review server
parent a819856e9a
commit faff8cbf87
4 changed files with 143 additions and 101 deletions

View file

@ -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;

View file

@ -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;
}

View file

@ -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;

View file

@ -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