Files
android_kernel_samsung_sm86…/msm/dp/dp_pll.c
Sudarsan Ramesh e66a2089f4 disp: msm: dp: update pll driver to fix clock names per target
With the change in the clock names for newer targets, this fix
updates the driver to support different clock names per target.

Change-Id: I58c35fce34356f8c79adb0ac8a907e2fb60813ae
Signed-off-by: Sudarsan Ramesh <sudarame@codeaurora.org>
2021-03-01 11:09:15 -05:00

173 行
3.5 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
*/
#include <linux/err.h>
#include <linux/of_device.h>
#include "dp_debug.h"
#include "dp_pll.h"
static int dp_pll_fill_io(struct dp_pll *pll)
{
struct dp_parser *parser = pll->parser;
pll->io.dp_phy = parser->get_io(parser, "dp_phy");
if (!pll->io.dp_phy) {
DP_ERR("Invalid dp_phy resource\n");
return -ENOMEM;
}
pll->io.dp_pll = parser->get_io(parser, "dp_pll");
if (!pll->io.dp_pll) {
DP_ERR("Invalid dp_pll resource\n");
return -ENOMEM;
}
pll->io.dp_ln_tx0 = parser->get_io(parser, "dp_ln_tx0");
if (!pll->io.dp_ln_tx0) {
DP_ERR("Invalid dp_ln_tx1 resource\n");
return -ENOMEM;
}
pll->io.dp_ln_tx1 = parser->get_io(parser, "dp_ln_tx1");
if (!pll->io.dp_ln_tx1) {
DP_ERR("Invalid dp_ln_tx1 resource\n");
return -ENOMEM;
}
pll->io.gdsc = parser->get_io(parser, "gdsc");
if (!pll->io.gdsc) {
DP_ERR("Invalid gdsc resource\n");
return -ENOMEM;
}
return 0;
}
static int dp_pll_clock_register(struct dp_pll *pll)
{
int rc;
switch (pll->revision) {
case DP_PLL_5NM_V1:
case DP_PLL_5NM_V2:
rc = dp_pll_clock_register_5nm(pll);
break;
default:
rc = -ENOTSUPP;
break;
}
return rc;
}
static void dp_pll_clock_unregister(struct dp_pll *pll)
{
switch (pll->revision) {
case DP_PLL_5NM_V1:
case DP_PLL_5NM_V2:
dp_pll_clock_unregister_5nm(pll);
break;
default:
break;
}
}
int dp_pll_clock_register_helper(struct dp_pll *pll, struct dp_pll_vco_clk *clks, int num_clks)
{
int rc = 0, i = 0;
struct platform_device *pdev;
struct clk *clk;
if (!pll || !clks) {
DP_ERR("input not initialized\n");
return -EINVAL;
}
pdev = pll->pdev;
for (i = 0; i < num_clks; i++) {
clks[i].priv = pll;
clk = clk_register(&pdev->dev, &clks[i].hw);
if (IS_ERR(clk)) {
DP_ERR("%s registration failed for DP: %d\n",
clk_hw_get_name(&clks[i].hw), pll->index);
return -EINVAL;
}
pll->clk_data->clks[i] = clk;
}
return rc;
}
struct dp_pll *dp_pll_get(struct dp_pll_in *in)
{
int rc = 0;
struct dp_pll *pll;
struct dp_parser *parser;
const char *label = NULL;
struct platform_device *pdev;
if (!in || !in->pdev || !in->pdev->dev.of_node || !in->parser) {
DP_ERR("Invalid resource pointers\n");
return ERR_PTR(-EINVAL);
}
pll = kzalloc(sizeof(*pll), GFP_KERNEL);
if (!pll)
return ERR_PTR(-ENOMEM);
pll->pdev = in->pdev;
pll->parser = in->parser;
pll->aux = in->aux;
pll->dp_core_revision = in->dp_core_revision;
parser = pll->parser;
pdev = pll->pdev;
label = of_get_property(pdev->dev.of_node, "qcom,pll-revision", NULL);
if (label) {
if (!strcmp(label, "5nm-v1")) {
pll->revision = DP_PLL_5NM_V1;
} else if (!strcmp(label, "5nm-v2")) {
pll->revision = DP_PLL_5NM_V2;
} else {
DP_ERR("Unsupported pll revision\n");
rc = -ENOTSUPP;
goto error;
}
} else {
DP_ERR("pll revision not specified\n");
rc = -EINVAL;
goto error;
}
pll->ssc_en = of_property_read_bool(pdev->dev.of_node,
"qcom,ssc-feature-enable");
pll->bonding_en = of_property_read_bool(pdev->dev.of_node,
"qcom,bonding-feature-enable");
rc = dp_pll_fill_io(pll);
if (rc)
goto error;
rc = dp_pll_clock_register(pll);
if (rc)
goto error;
DP_INFO("revision=%s, ssc_en=%d, bonding_en=%d\n",
dp_pll_get_revision(pll->revision), pll->ssc_en,
pll->bonding_en);
return pll;
error:
kfree(pll);
return ERR_PTR(rc);
}
void dp_pll_put(struct dp_pll *pll)
{
dp_pll_clock_unregister(pll);
kfree(pll);
}