Some resources might differ based on platforms and we need platform specific functions to initialize or alter them. For better code re-usability, making a separate res_ops which will hold all such function pointers or other resource specific data. Also move common operations for host init into the probe sequence. Suggested-by: Pankaj Dubey <pankaj.dubey@xxxxxxxxxxx> Signed-off-by: Shradha Todi <shradha.t@xxxxxxxxxxx> --- drivers/pci/controller/dwc/pci-exynos.c | 103 ++++++++++++++++++------ 1 file changed, 78 insertions(+), 25 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-exynos.c b/drivers/pci/controller/dwc/pci-exynos.c index c830b20d54f0..dff23cf648f5 100644 --- a/drivers/pci/controller/dwc/pci-exynos.c +++ b/drivers/pci/controller/dwc/pci-exynos.c @@ -53,6 +53,7 @@ struct samsung_pcie_pdata { struct pci_ops *pci_ops; const struct dw_pcie_ops *dwc_ops; const struct dw_pcie_host_ops *host_ops; + const struct samsung_res_ops *res_ops; }; struct exynos_pcie { @@ -61,7 +62,13 @@ struct exynos_pcie { const struct samsung_pcie_pdata *pdata; struct clk_bulk_data *clks; struct phy *phy; - struct regulator_bulk_data supplies[2]; + struct regulator_bulk_data *supplies; + int supplies_cnt; +}; + +struct samsung_res_ops { + int (*init_regulator)(struct exynos_pcie *ep); + irqreturn_t (*pcie_irq_handler)(int irq, void *arg); }; static void exynos_pcie_writel(void __iomem *base, u32 val, u32 reg) @@ -74,6 +81,31 @@ static u32 exynos_pcie_readl(void __iomem *base, u32 reg) return readl(base + reg); } +static int samsung_regulator_enable(struct exynos_pcie *ep) +{ + int ret; + + if (ep->supplies_cnt == 0) + return 0; + + ret = regulator_bulk_enable(ep->supplies_cnt, ep->supplies); + + return ret; +} + +static void samsung_regulator_disable(struct exynos_pcie *ep) +{ + struct device *dev = ep->pci.dev; + int ret; + + if (ep->supplies_cnt == 0) + return; + + ret = regulator_bulk_disable(ep->supplies_cnt, ep->supplies); + if (ret) + dev_warn(dev, "failed to disable regulators: %d\n", ret); +} + static void exynos_pcie_sideband_dbi_w_mode(struct exynos_pcie *ep, bool on) { u32 val; @@ -244,7 +276,26 @@ static const struct dw_pcie_host_ops exynos_pcie_host_ops = { .init = exynos_pcie_host_init, }; -static int exynos_add_pcie_port(struct exynos_pcie *ep, +static int exynos_init_regulator(struct exynos_pcie *ep) +{ + struct device *dev = ep->pci.dev; + int ret = 0; + + ep->supplies_cnt = 2; + + ep->supplies = devm_kcalloc(dev, ep->supplies_cnt, sizeof(*ep->supplies), GFP_KERNEL); + if (!ep->supplies) + return -ENOMEM; + + ep->supplies[0].supply = "vdd18"; + ep->supplies[1].supply = "vdd10"; + + ret = devm_regulator_bulk_get(dev, ep->supplies_cnt, ep->supplies); + + return ret; +} + +static int samsung_irq_init(struct exynos_pcie *ep, struct platform_device *pdev) { struct dw_pcie *pci = &ep->pci; @@ -256,22 +307,15 @@ static int exynos_add_pcie_port(struct exynos_pcie *ep, if (pp->irq < 0) return pp->irq; - ret = devm_request_irq(dev, pp->irq, exynos_pcie_irq_handler, + ret = devm_request_irq(dev, pp->irq, ep->pdata->res_ops->pcie_irq_handler, IRQF_SHARED, "exynos-pcie", ep); if (ret) { dev_err(dev, "failed to request irq\n"); return ret; } - pp->ops = &exynos_pcie_host_ops; pp->msi_irq[0] = -ENODEV; - ret = dw_pcie_host_init(pp); - if (ret) { - dev_err(dev, "failed to initialize host\n"); - return ret; - } - return 0; } @@ -282,6 +326,11 @@ static const struct dw_pcie_ops exynos_dw_pcie_ops = { .start_link = exynos_pcie_start_link, }; +static const struct samsung_res_ops exynos_res_ops_data = { + .init_regulator = exynos_init_regulator, + .pcie_irq_handler = exynos_pcie_irq_handler, +}; + static int exynos_pcie_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -313,28 +362,31 @@ static int exynos_pcie_probe(struct platform_device *pdev) if (ret < 0) return ret; - ep->supplies[0].supply = "vdd18"; - ep->supplies[1].supply = "vdd10"; - ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ep->supplies), - ep->supplies); - if (ret) - return ret; + if (pdata->res_ops && pdata->res_ops->init_regulator) { + ret = ep->pdata->res_ops->init_regulator(ep); + if (ret) + return ret; + } - ret = regulator_bulk_enable(ARRAY_SIZE(ep->supplies), ep->supplies); + ret = samsung_regulator_enable(ep); if (ret) return ret; platform_set_drvdata(pdev, ep); - - ret = exynos_add_pcie_port(ep, pdev); + ret = samsung_irq_init(ep, pdev); + if (ret) + goto fail_regulator; + ep->pci.pp.ops = pdata->host_ops; + ret = dw_pcie_host_init(&ep->pci.pp); if (ret < 0) - goto fail_probe; + goto fail_phy_init; return 0; -fail_probe: +fail_phy_init: phy_exit(ep->phy); - regulator_bulk_disable(ARRAY_SIZE(ep->supplies), ep->supplies); +fail_regulator: + samsung_regulator_disable(ep); return ret; } @@ -347,7 +399,7 @@ static void exynos_pcie_remove(struct platform_device *pdev) exynos_pcie_assert_core_reset(ep); phy_power_off(ep->phy); phy_exit(ep->phy); - regulator_bulk_disable(ARRAY_SIZE(ep->supplies), ep->supplies); + samsung_regulator_disable(ep); } static int exynos_pcie_suspend_noirq(struct device *dev) @@ -357,7 +409,7 @@ static int exynos_pcie_suspend_noirq(struct device *dev) exynos_pcie_assert_core_reset(ep); phy_power_off(ep->phy); phy_exit(ep->phy); - regulator_bulk_disable(ARRAY_SIZE(ep->supplies), ep->supplies); + samsung_regulator_disable(ep); return 0; } @@ -369,7 +421,7 @@ static int exynos_pcie_resume_noirq(struct device *dev) struct dw_pcie_rp *pp = &pci->pp; int ret; - ret = regulator_bulk_enable(ARRAY_SIZE(ep->supplies), ep->supplies); + ret = samsung_regulator_enable(ep); if (ret) return ret; @@ -389,6 +441,7 @@ static const struct samsung_pcie_pdata exynos_5433_pcie_rc_pdata = { .dwc_ops = &exynos_dw_pcie_ops, .pci_ops = &exynos_pci_ops, .host_ops = &exynos_pcie_host_ops, + .res_ops = &exynos_res_ops_data, }; static const struct of_device_id exynos_pcie_of_match[] = { -- 2.49.0