|
|
|
@@ -110,11 +110,13 @@ struct phy_override_seq {
|
|
|
|
|
/**
|
|
|
|
|
* struct qcom_snps_hsphy - snps hs phy attributes
|
|
|
|
|
*
|
|
|
|
|
* @dev: device structure
|
|
|
|
|
*
|
|
|
|
|
* @phy: generic phy
|
|
|
|
|
* @base: iomapped memory space for snps hs phy
|
|
|
|
|
*
|
|
|
|
|
* @cfg_ahb_clk: AHB2PHY interface clock
|
|
|
|
|
* @ref_clk: phy reference clock
|
|
|
|
|
* @num_clks: number of clocks
|
|
|
|
|
* @clks: array of clocks
|
|
|
|
|
* @phy_reset: phy reset control
|
|
|
|
|
* @vregs: regulator supplies bulk data
|
|
|
|
|
* @phy_initialized: if PHY has been initialized correctly
|
|
|
|
@@ -122,11 +124,13 @@ struct phy_override_seq {
|
|
|
|
|
* @update_seq_cfg: tuning parameters for phy init
|
|
|
|
|
*/
|
|
|
|
|
struct qcom_snps_hsphy {
|
|
|
|
|
struct device *dev;
|
|
|
|
|
|
|
|
|
|
struct phy *phy;
|
|
|
|
|
void __iomem *base;
|
|
|
|
|
|
|
|
|
|
struct clk *cfg_ahb_clk;
|
|
|
|
|
struct clk *ref_clk;
|
|
|
|
|
int num_clks;
|
|
|
|
|
struct clk_bulk_data *clks;
|
|
|
|
|
struct reset_control *phy_reset;
|
|
|
|
|
struct regulator_bulk_data vregs[SNPS_HS_NUM_VREGS];
|
|
|
|
|
|
|
|
|
@@ -135,6 +139,34 @@ struct qcom_snps_hsphy {
|
|
|
|
|
struct phy_override_seq update_seq_cfg[NUM_HSPHY_TUNING_PARAMS];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static int qcom_snps_hsphy_clk_init(struct qcom_snps_hsphy *hsphy)
|
|
|
|
|
{
|
|
|
|
|
struct device *dev = hsphy->dev;
|
|
|
|
|
|
|
|
|
|
hsphy->num_clks = 2;
|
|
|
|
|
hsphy->clks = devm_kcalloc(dev, hsphy->num_clks, sizeof(*hsphy->clks), GFP_KERNEL);
|
|
|
|
|
if (!hsphy->clks)
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* TODO: Currently no device tree instantiation of the PHY is using the clock.
|
|
|
|
|
* This needs to be fixed in order for this code to be able to use devm_clk_bulk_get().
|
|
|
|
|
*/
|
|
|
|
|
hsphy->clks[0].id = "cfg_ahb";
|
|
|
|
|
hsphy->clks[0].clk = devm_clk_get_optional(dev, "cfg_ahb");
|
|
|
|
|
if (IS_ERR(hsphy->clks[0].clk))
|
|
|
|
|
return dev_err_probe(dev, PTR_ERR(hsphy->clks[0].clk),
|
|
|
|
|
"failed to get cfg_ahb clk\n");
|
|
|
|
|
|
|
|
|
|
hsphy->clks[1].id = "ref";
|
|
|
|
|
hsphy->clks[1].clk = devm_clk_get(dev, "ref");
|
|
|
|
|
if (IS_ERR(hsphy->clks[1].clk))
|
|
|
|
|
return dev_err_probe(dev, PTR_ERR(hsphy->clks[1].clk),
|
|
|
|
|
"failed to get ref clk\n");
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void qcom_snps_hsphy_write_mask(void __iomem *base, u32 offset,
|
|
|
|
|
u32 mask, u32 val)
|
|
|
|
|
{
|
|
|
|
@@ -165,22 +197,13 @@ static int qcom_snps_hsphy_suspend(struct qcom_snps_hsphy *hsphy)
|
|
|
|
|
0, USB2_AUTO_RESUME);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
clk_disable_unprepare(hsphy->cfg_ahb_clk);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int qcom_snps_hsphy_resume(struct qcom_snps_hsphy *hsphy)
|
|
|
|
|
{
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
dev_dbg(&hsphy->phy->dev, "Resume QCOM SNPS PHY, mode\n");
|
|
|
|
|
|
|
|
|
|
ret = clk_prepare_enable(hsphy->cfg_ahb_clk);
|
|
|
|
|
if (ret) {
|
|
|
|
|
dev_err(&hsphy->phy->dev, "failed to enable cfg ahb clock\n");
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -191,8 +214,7 @@ static int __maybe_unused qcom_snps_hsphy_runtime_suspend(struct device *dev)
|
|
|
|
|
if (!hsphy->phy_initialized)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
qcom_snps_hsphy_suspend(hsphy);
|
|
|
|
|
return 0;
|
|
|
|
|
return qcom_snps_hsphy_suspend(hsphy);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int __maybe_unused qcom_snps_hsphy_runtime_resume(struct device *dev)
|
|
|
|
@@ -202,8 +224,7 @@ static int __maybe_unused qcom_snps_hsphy_runtime_resume(struct device *dev)
|
|
|
|
|
if (!hsphy->phy_initialized)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
qcom_snps_hsphy_resume(hsphy);
|
|
|
|
|
return 0;
|
|
|
|
|
return qcom_snps_hsphy_resume(hsphy);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int qcom_snps_hsphy_set_mode(struct phy *phy, enum phy_mode mode,
|
|
|
|
@@ -374,16 +395,16 @@ static int qcom_snps_hsphy_init(struct phy *phy)
|
|
|
|
|
if (ret)
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
|
|
ret = clk_prepare_enable(hsphy->cfg_ahb_clk);
|
|
|
|
|
ret = clk_bulk_prepare_enable(hsphy->num_clks, hsphy->clks);
|
|
|
|
|
if (ret) {
|
|
|
|
|
dev_err(&phy->dev, "failed to enable cfg ahb clock, %d\n", ret);
|
|
|
|
|
dev_err(&phy->dev, "failed to enable clocks, %d\n", ret);
|
|
|
|
|
goto poweroff_phy;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret = reset_control_assert(hsphy->phy_reset);
|
|
|
|
|
if (ret) {
|
|
|
|
|
dev_err(&phy->dev, "failed to assert phy_reset, %d\n", ret);
|
|
|
|
|
goto disable_ahb_clk;
|
|
|
|
|
goto disable_clks;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
usleep_range(100, 150);
|
|
|
|
@@ -391,7 +412,7 @@ static int qcom_snps_hsphy_init(struct phy *phy)
|
|
|
|
|
ret = reset_control_deassert(hsphy->phy_reset);
|
|
|
|
|
if (ret) {
|
|
|
|
|
dev_err(&phy->dev, "failed to de-assert phy_reset, %d\n", ret);
|
|
|
|
|
goto disable_ahb_clk;
|
|
|
|
|
goto disable_clks;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_CFG0,
|
|
|
|
@@ -448,8 +469,8 @@ static int qcom_snps_hsphy_init(struct phy *phy)
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
disable_ahb_clk:
|
|
|
|
|
clk_disable_unprepare(hsphy->cfg_ahb_clk);
|
|
|
|
|
disable_clks:
|
|
|
|
|
clk_bulk_disable_unprepare(hsphy->num_clks, hsphy->clks);
|
|
|
|
|
poweroff_phy:
|
|
|
|
|
regulator_bulk_disable(ARRAY_SIZE(hsphy->vregs), hsphy->vregs);
|
|
|
|
|
|
|
|
|
@@ -461,7 +482,7 @@ static int qcom_snps_hsphy_exit(struct phy *phy)
|
|
|
|
|
struct qcom_snps_hsphy *hsphy = phy_get_drvdata(phy);
|
|
|
|
|
|
|
|
|
|
reset_control_assert(hsphy->phy_reset);
|
|
|
|
|
clk_disable_unprepare(hsphy->cfg_ahb_clk);
|
|
|
|
|
clk_bulk_disable_unprepare(hsphy->num_clks, hsphy->clks);
|
|
|
|
|
regulator_bulk_disable(ARRAY_SIZE(hsphy->vregs), hsphy->vregs);
|
|
|
|
|
hsphy->phy_initialized = false;
|
|
|
|
|
|
|
|
|
@@ -554,14 +575,15 @@ static int qcom_snps_hsphy_probe(struct platform_device *pdev)
|
|
|
|
|
if (!hsphy)
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
|
|
hsphy->dev = dev;
|
|
|
|
|
|
|
|
|
|
hsphy->base = devm_platform_ioremap_resource(pdev, 0);
|
|
|
|
|
if (IS_ERR(hsphy->base))
|
|
|
|
|
return PTR_ERR(hsphy->base);
|
|
|
|
|
|
|
|
|
|
hsphy->ref_clk = devm_clk_get(dev, "ref");
|
|
|
|
|
if (IS_ERR(hsphy->ref_clk))
|
|
|
|
|
return dev_err_probe(dev, PTR_ERR(hsphy->ref_clk),
|
|
|
|
|
"failed to get ref clk\n");
|
|
|
|
|
ret = qcom_snps_hsphy_clk_init(hsphy);
|
|
|
|
|
if (ret)
|
|
|
|
|
return dev_err_probe(dev, ret, "failed to initialize clocks\n");
|
|
|
|
|
|
|
|
|
|
hsphy->phy_reset = devm_reset_control_get_exclusive(&pdev->dev, NULL);
|
|
|
|
|
if (IS_ERR(hsphy->phy_reset)) {
|
|
|
|
|