diff options
Diffstat (limited to 'drivers/phy/qualcomm')
-rw-r--r-- | drivers/phy/qualcomm/phy-qcom-qmp.c | 113 |
1 files changed, 56 insertions, 57 deletions
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c b/drivers/phy/qualcomm/phy-qcom-qmp.c index 26623ddb0751..271cdf7aaffa 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp.c @@ -1801,6 +1801,8 @@ struct qmp_phy_cfg { * struct qmp_phy - per-lane phy descriptor * * @phy: generic phy + * @cfg: phy specific configuration + * @serdes: iomapped memory space for phy's serdes (i.e. PLL) * @tx: iomapped memory space for lane's tx * @rx: iomapped memory space for lane's rx * @pcs: iomapped memory space for lane's pcs @@ -1815,6 +1817,8 @@ struct qmp_phy_cfg { */ struct qmp_phy { struct phy *phy; + const struct qmp_phy_cfg *cfg; + void __iomem *serdes; void __iomem *tx; void __iomem *rx; void __iomem *pcs; @@ -1832,14 +1836,12 @@ struct qmp_phy { * struct qcom_qmp - structure holding QMP phy block attributes * * @dev: device - * @serdes: iomapped memory space for phy's serdes * @dp_com: iomapped memory space for phy's dp_com control block * * @clks: array of clocks required by phy * @resets: array of resets required by phy * @vregs: regulator supplies bulk data * - * @cfg: phy specific configuration * @phys: array of per-lane phy descriptors * @phy_mutex: mutex lock for PHY common block initialization * @init_count: phy common block initialization count @@ -1847,14 +1849,12 @@ struct qmp_phy { */ struct qcom_qmp { struct device *dev; - void __iomem *serdes; void __iomem *dp_com; struct clk_bulk_data *clks; struct reset_control **resets; struct regulator_bulk_data *vregs; - const struct qmp_phy_cfg *cfg; struct qmp_phy **phys; struct mutex phy_mutex; @@ -2480,8 +2480,8 @@ static void qcom_qmp_phy_configure(void __iomem *base, static int qcom_qmp_phy_com_init(struct qmp_phy *qphy) { struct qcom_qmp *qmp = qphy->qmp; - const struct qmp_phy_cfg *cfg = qmp->cfg; - void __iomem *serdes = qmp->serdes; + const struct qmp_phy_cfg *cfg = qphy->cfg; + void __iomem *serdes = qphy->serdes; void __iomem *pcs = qphy->pcs; void __iomem *dp_com = qmp->dp_com; int ret, i; @@ -2512,7 +2512,7 @@ static int qcom_qmp_phy_com_init(struct qmp_phy *qphy) ret = reset_control_deassert(qmp->resets[i]); if (ret) { dev_err(qmp->dev, "%s reset deassert failed\n", - qmp->cfg->reset_list[i]); + qphy->cfg->reset_list[i]); goto err_rst; } } @@ -2594,10 +2594,11 @@ err_reg_enable: return ret; } -static int qcom_qmp_phy_com_exit(struct qcom_qmp *qmp) +static int qcom_qmp_phy_com_exit(struct qmp_phy *qphy) { - const struct qmp_phy_cfg *cfg = qmp->cfg; - void __iomem *serdes = qmp->serdes; + struct qcom_qmp *qmp = qphy->qmp; + const struct qmp_phy_cfg *cfg = qphy->cfg; + void __iomem *serdes = qphy->serdes; int i = cfg->num_resets; mutex_lock(&qmp->phy_mutex); @@ -2632,7 +2633,7 @@ static int qcom_qmp_phy_enable(struct phy *phy) { struct qmp_phy *qphy = phy_get_drvdata(phy); struct qcom_qmp *qmp = qphy->qmp; - const struct qmp_phy_cfg *cfg = qmp->cfg; + const struct qmp_phy_cfg *cfg = qphy->cfg; void __iomem *tx = qphy->tx; void __iomem *rx = qphy->rx; void __iomem *pcs = qphy->pcs; @@ -2757,7 +2758,7 @@ err_clk_enable: if (cfg->has_lane_rst) reset_control_assert(qphy->lane_rst); err_lane_rst: - qcom_qmp_phy_com_exit(qmp); + qcom_qmp_phy_com_exit(qphy); return ret; } @@ -2765,8 +2766,7 @@ err_lane_rst: static int qcom_qmp_phy_disable(struct phy *phy) { struct qmp_phy *qphy = phy_get_drvdata(phy); - struct qcom_qmp *qmp = qphy->qmp; - const struct qmp_phy_cfg *cfg = qmp->cfg; + const struct qmp_phy_cfg *cfg = qphy->cfg; clk_disable_unprepare(qphy->pipe_clk); @@ -2789,7 +2789,7 @@ static int qcom_qmp_phy_disable(struct phy *phy) if (cfg->has_lane_rst) reset_control_assert(qphy->lane_rst); - qcom_qmp_phy_com_exit(qmp); + qcom_qmp_phy_com_exit(qphy); return 0; } @@ -2806,8 +2806,7 @@ static int qcom_qmp_phy_set_mode(struct phy *phy, static void qcom_qmp_phy_enable_autonomous_mode(struct qmp_phy *qphy) { - struct qcom_qmp *qmp = qphy->qmp; - const struct qmp_phy_cfg *cfg = qmp->cfg; + const struct qmp_phy_cfg *cfg = qphy->cfg; void __iomem *pcs = qphy->pcs; void __iomem *pcs_misc = qphy->pcs_misc; u32 intr_mask; @@ -2836,8 +2835,7 @@ static void qcom_qmp_phy_enable_autonomous_mode(struct qmp_phy *qphy) static void qcom_qmp_phy_disable_autonomous_mode(struct qmp_phy *qphy) { - struct qcom_qmp *qmp = qphy->qmp; - const struct qmp_phy_cfg *cfg = qmp->cfg; + const struct qmp_phy_cfg *cfg = qphy->cfg; void __iomem *pcs = qphy->pcs; void __iomem *pcs_misc = qphy->pcs_misc; @@ -2857,7 +2855,7 @@ static int __maybe_unused qcom_qmp_phy_runtime_suspend(struct device *dev) { struct qcom_qmp *qmp = dev_get_drvdata(dev); struct qmp_phy *qphy = qmp->phys[0]; - const struct qmp_phy_cfg *cfg = qmp->cfg; + const struct qmp_phy_cfg *cfg = qphy->cfg; dev_vdbg(dev, "Suspending QMP phy, mode:%d\n", qphy->mode); @@ -2882,7 +2880,7 @@ static int __maybe_unused qcom_qmp_phy_runtime_resume(struct device *dev) { struct qcom_qmp *qmp = dev_get_drvdata(dev); struct qmp_phy *qphy = qmp->phys[0]; - const struct qmp_phy_cfg *cfg = qmp->cfg; + const struct qmp_phy_cfg *cfg = qphy->cfg; int ret = 0; dev_vdbg(dev, "Resuming QMP phy, mode:%d\n", qphy->mode); @@ -2914,10 +2912,10 @@ static int __maybe_unused qcom_qmp_phy_runtime_resume(struct device *dev) return 0; } -static int qcom_qmp_phy_vreg_init(struct device *dev) +static int qcom_qmp_phy_vreg_init(struct device *dev, const struct qmp_phy_cfg *cfg) { struct qcom_qmp *qmp = dev_get_drvdata(dev); - int num = qmp->cfg->num_vregs; + int num = cfg->num_vregs; int i; qmp->vregs = devm_kcalloc(dev, num, sizeof(*qmp->vregs), GFP_KERNEL); @@ -2925,24 +2923,24 @@ static int qcom_qmp_phy_vreg_init(struct device *dev) return -ENOMEM; for (i = 0; i < num; i++) - qmp->vregs[i].supply = qmp->cfg->vreg_list[i]; + qmp->vregs[i].supply = cfg->vreg_list[i]; return devm_regulator_bulk_get(dev, num, qmp->vregs); } -static int qcom_qmp_phy_reset_init(struct device *dev) +static int qcom_qmp_phy_reset_init(struct device *dev, const struct qmp_phy_cfg *cfg) { struct qcom_qmp *qmp = dev_get_drvdata(dev); int i; - qmp->resets = devm_kcalloc(dev, qmp->cfg->num_resets, + qmp->resets = devm_kcalloc(dev, cfg->num_resets, sizeof(*qmp->resets), GFP_KERNEL); if (!qmp->resets) return -ENOMEM; - for (i = 0; i < qmp->cfg->num_resets; i++) { + for (i = 0; i < cfg->num_resets; i++) { struct reset_control *rst; - const char *name = qmp->cfg->reset_list[i]; + const char *name = cfg->reset_list[i]; rst = devm_reset_control_get(dev, name); if (IS_ERR(rst)) { @@ -2955,10 +2953,10 @@ static int qcom_qmp_phy_reset_init(struct device *dev) return 0; } -static int qcom_qmp_phy_clk_init(struct device *dev) +static int qcom_qmp_phy_clk_init(struct device *dev, const struct qmp_phy_cfg *cfg) { struct qcom_qmp *qmp = dev_get_drvdata(dev); - int num = qmp->cfg->num_clks; + int num = cfg->num_clks; int i; qmp->clks = devm_kcalloc(dev, num, sizeof(*qmp->clks), GFP_KERNEL); @@ -2966,7 +2964,7 @@ static int qcom_qmp_phy_clk_init(struct device *dev) return -ENOMEM; for (i = 0; i < num; i++) - qmp->clks[i].id = qmp->cfg->clk_list[i]; + qmp->clks[i].id = cfg->clk_list[i]; return devm_clk_bulk_get(dev, num, qmp->clks); } @@ -3000,12 +2998,6 @@ static int phy_pipe_clk_register(struct qcom_qmp *qmp, struct device_node *np) struct clk_init_data init = { }; int ret; - if ((qmp->cfg->type != PHY_TYPE_USB3) && - (qmp->cfg->type != PHY_TYPE_PCIE)) { - /* not all phys register pipe clocks, so return success */ - return 0; - } - ret = of_property_read_string(np, "clock-output-names", &init.name); if (ret) { dev_err(qmp->dev, "%pOFn: No clock-output-names\n", np); @@ -3056,7 +3048,8 @@ static const struct phy_ops qcom_qmp_pcie_ufs_ops = { }; static -int qcom_qmp_phy_create(struct device *dev, struct device_node *np, int id) +int qcom_qmp_phy_create(struct device *dev, struct device_node *np, int id, + void __iomem *serdes, const struct qmp_phy_cfg *cfg) { struct qcom_qmp *qmp = dev_get_drvdata(dev); struct phy *generic_phy; @@ -3069,6 +3062,8 @@ int qcom_qmp_phy_create(struct device *dev, struct device_node *np, int id) if (!qphy) return -ENOMEM; + qphy->cfg = cfg; + qphy->serdes = serdes; /* * Get memory resources for each phy lane: * Resources are indexed as: tx -> 0; rx -> 1; pcs -> 2. @@ -3093,7 +3088,7 @@ int qcom_qmp_phy_create(struct device *dev, struct device_node *np, int id) * back to old legacy behavior of assuming they can be reached at an * offset from the first lane. */ - if (qmp->cfg->is_dual_lane_phy) { + if (cfg->is_dual_lane_phy) { qphy->tx2 = of_iomap(np, 3); qphy->rx2 = of_iomap(np, 4); if (!qphy->tx2 || !qphy->rx2) { @@ -3126,8 +3121,8 @@ int qcom_qmp_phy_create(struct device *dev, struct device_node *np, int id) snprintf(prop_name, sizeof(prop_name), "pipe%d", id); qphy->pipe_clk = of_clk_get_by_name(np, prop_name); if (IS_ERR(qphy->pipe_clk)) { - if (qmp->cfg->type == PHY_TYPE_PCIE || - qmp->cfg->type == PHY_TYPE_USB3) { + if (cfg->type == PHY_TYPE_PCIE || + cfg->type == PHY_TYPE_USB3) { ret = PTR_ERR(qphy->pipe_clk); if (ret != -EPROBE_DEFER) dev_err(dev, @@ -3139,7 +3134,7 @@ int qcom_qmp_phy_create(struct device *dev, struct device_node *np, int id) } /* Get lane reset, if any */ - if (qmp->cfg->has_lane_rst) { + if (cfg->has_lane_rst) { snprintf(prop_name, sizeof(prop_name), "lane%d", id); qphy->lane_rst = of_reset_control_get(np, prop_name); if (IS_ERR(qphy->lane_rst)) { @@ -3148,7 +3143,7 @@ int qcom_qmp_phy_create(struct device *dev, struct device_node *np, int id) } } - if (qmp->cfg->type == PHY_TYPE_UFS || qmp->cfg->type == PHY_TYPE_PCIE) + if (cfg->type == PHY_TYPE_UFS || cfg->type == PHY_TYPE_PCIE) ops = &qcom_qmp_pcie_ufs_ops; generic_phy = devm_phy_create(dev, np, ops); @@ -3246,6 +3241,8 @@ static int qcom_qmp_phy_probe(struct platform_device *pdev) struct device_node *child; struct phy_provider *phy_provider; void __iomem *base; + void __iomem *serdes; + const struct qmp_phy_cfg *cfg; int num, id; int ret; @@ -3257,8 +3254,8 @@ static int qcom_qmp_phy_probe(struct platform_device *pdev) dev_set_drvdata(dev, qmp); /* Get the specific init parameters of QMP phy */ - qmp->cfg = of_device_get_match_data(dev); - if (!qmp->cfg) + cfg = of_device_get_match_data(dev); + if (!cfg) return -EINVAL; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -3267,10 +3264,10 @@ static int qcom_qmp_phy_probe(struct platform_device *pdev) return PTR_ERR(base); /* per PHY serdes; usually located at base address */ - qmp->serdes = base; + serdes = base; /* per PHY dp_com; if PHY has dp_com control block */ - if (qmp->cfg->has_phy_dp_com_ctrl) { + if (cfg->has_phy_dp_com_ctrl) { res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dp_com"); base = devm_ioremap_resource(dev, res); @@ -3282,15 +3279,15 @@ static int qcom_qmp_phy_probe(struct platform_device *pdev) mutex_init(&qmp->phy_mutex); - ret = qcom_qmp_phy_clk_init(dev); + ret = qcom_qmp_phy_clk_init(dev, cfg); if (ret) return ret; - ret = qcom_qmp_phy_reset_init(dev); + ret = qcom_qmp_phy_reset_init(dev, cfg); if (ret) return ret; - ret = qcom_qmp_phy_vreg_init(dev); + ret = qcom_qmp_phy_vreg_init(dev, cfg); if (ret) { if (ret != -EPROBE_DEFER) dev_err(dev, "failed to get regulator supplies: %d\n", @@ -3300,7 +3297,7 @@ static int qcom_qmp_phy_probe(struct platform_device *pdev) num = of_get_available_child_count(dev->of_node); /* do we have a rogue child node ? */ - if (num > qmp->cfg->nlanes) + if (num > cfg->nlanes) return -EINVAL; qmp->phys = devm_kcalloc(dev, num, sizeof(*qmp->phys), GFP_KERNEL); @@ -3318,7 +3315,7 @@ static int qcom_qmp_phy_probe(struct platform_device *pdev) for_each_available_child_of_node(dev->of_node, child) { /* Create per-lane phy */ - ret = qcom_qmp_phy_create(dev, child, id); + ret = qcom_qmp_phy_create(dev, child, id, serdes, cfg); if (ret) { dev_err(dev, "failed to create lane%d phy, %d\n", id, ret); @@ -3329,11 +3326,13 @@ static int qcom_qmp_phy_probe(struct platform_device *pdev) * Register the pipe clock provided by phy. * See function description to see details of this pipe clock. */ - ret = phy_pipe_clk_register(qmp, child); - if (ret) { - dev_err(qmp->dev, - "failed to register pipe clock source\n"); - goto err_node_put; + if (cfg->type == PHY_TYPE_USB3 || cfg->type == PHY_TYPE_PCIE) { + ret = phy_pipe_clk_register(qmp, child); + if (ret) { + dev_err(qmp->dev, + "failed to register pipe clock source\n"); + goto err_node_put; + } } id++; } |