static int mdss_pll_resource_parse(struct platform_device *pdev,
				struct mdss_pll_resources *pll_res)
{
	int rc = 0;
	const char *compatible_stream;

	if (!pdev || !pll_res) {
		pr_err("Invalid input parameters\n");
		return -EINVAL;
	}

	rc = mdss_pll_util_resource_parse(pdev, pll_res);
	if (rc) {
		pr_err("Failed to parse the resources rc=%d\n", rc);
		goto end;
	}

	compatible_stream = of_get_property(pdev->dev.of_node,
				"compatible", NULL);
	if (!compatible_stream) {
		pr_err("Failed to parse the compatible stream\n");
		goto err;
	}

	if (!strcmp(compatible_stream, "qcom,mdss_dsi_pll_8916")) {
		pll_res->pll_interface_type = MDSS_DSI_PLL_LPM;
		pll_res->target_id = MDSS_PLL_TARGET_8916;
	} else if (!strcmp(compatible_stream, "qcom,mdss_dsi_pll_8939")) {
		pll_res->pll_interface_type = MDSS_DSI_PLL_LPM;
		pll_res->target_id = MDSS_PLL_TARGET_8939;
	} else if (!strcmp(compatible_stream, "qcom,mdss_dsi_pll_8909")) {
		pll_res->pll_interface_type = MDSS_DSI_PLL_LPM;
		pll_res->target_id = MDSS_PLL_TARGET_8909;
	} else if (!strcmp(compatible_stream, "qcom,mdss_dsi_pll_8974")) {
		pll_res->pll_interface_type = MDSS_DSI_PLL_HPM;
		pll_res->target_id = MDSS_PLL_TARGET_8974;
	} else if (!strcmp(compatible_stream, "qcom,mdss_dsi_pll_8994")) {
		pll_res->pll_interface_type = MDSS_DSI_PLL_20NM;
		pll_res->target_id = MDSS_PLL_TARGET_8994;
	} else if (!strcmp(compatible_stream, "qcom,mdss_edp_pll")) {
		pll_res->pll_interface_type = MDSS_EDP_PLL;
	} else if (!strcmp(compatible_stream, "qcom,mdss_hdmi_pll")) {
		pll_res->pll_interface_type = MDSS_HDMI_PLL;
	} else if (!strcmp(compatible_stream, "qcom,mdss_hdmi_pll_8994")) {
		pll_res->pll_interface_type = MDSS_HDMI_PLL_20NM;
	} else {
		goto err;
	}

	return rc;

err:
	mdss_pll_resource_release(pdev, pll_res);
end:
	return rc;
}
static int mdss_pll_remove(struct platform_device *pdev)
{
	struct mdss_pll_resources *pll_res;

	pll_res = platform_get_drvdata(pdev);
	if (!pll_res) {
		pr_err("Invalid PLL resource data");
		return 0;
	}

	mdss_pll_resource_deinit(pdev, pll_res);
	if (pll_res->phy_base)
		iounmap(pll_res->phy_base);
	mdss_pll_resource_release(pdev, pll_res);
	iounmap(pll_res->pll_base);
	devm_kfree(&pdev->dev, pll_res);
	return 0;
}
static int mdss_pll_probe(struct platform_device *pdev)
{
	int rc = 0;
	const char *label;
	struct resource *pll_base_reg;
	struct resource *phy_base_reg;
	struct resource *dynamic_pll_base_reg;
	struct resource *gdsc_base_reg;
	struct mdss_pll_resources *pll_res;
#if defined(CONFIG_FB_MSM_MDSS_SAMSUNG)
	struct samsung_display_driver_data *vdd = samsung_get_vdd();
#endif

	if (!pdev->dev.of_node) {
		pr_err("MDSS pll driver only supports device tree probe\n");
		rc = -ENOTSUPP;
		goto error;
	}

	label = of_get_property(pdev->dev.of_node, "label", NULL);
	if (!label)
		pr_info("%d: MDSS pll label not specified\n", __LINE__);
	else
		pr_info("MDSS pll label = %s\n", label);

	pll_res = devm_kzalloc(&pdev->dev, sizeof(struct mdss_pll_resources),
								GFP_KERNEL);
	if (!pll_res) {
		pr_err("Failed to allocate the clock pll\n");
		rc = -ENOMEM;
		goto error;
	}
	platform_set_drvdata(pdev, pll_res);

	rc = of_property_read_u32(pdev->dev.of_node, "cell-index",
			&pll_res->index);
	if (rc) {
		pr_err("Unable to get the cell-index rc=%d\n", rc);
		pll_res->index = 0;
	}

	pll_base_reg = platform_get_resource_byname(pdev,
						IORESOURCE_MEM, "pll_base");
	if (!pll_base_reg) {
		pr_err("Unable to get the pll base resources\n");
		rc = -ENOMEM;
		goto io_error;
	}

	pll_res->pll_base = ioremap(pll_base_reg->start,
						resource_size(pll_base_reg));
	if (!pll_res->pll_base) {
		pr_err("Unable to remap pll base resources\n");
		rc = -ENOMEM;
		goto io_error;
	}

#if defined(CONFIG_FB_MSM_MDSS_SAMSUNG)
	if (!strcmp(label, "MDSS DSI 0 PLL") || !strcmp(label, "MDSS DSI 1 PLL"))
		vdd->dump_info[pll_res->index].dsi_pll.virtual_addr = (size_t)pll_res->pll_base;
#endif

	rc = mdss_pll_resource_parse(pdev, pll_res);
	if (rc) {
		pr_err("Pll resource parsing from dt failed rc=%d\n", rc);
		goto res_parse_error;
	}

	/*
	 * DSI PLL 1 is leaking current whenever MDSS GDSC is toggled. Need to
	 * map PLL1 registers along with the PLl0 so that we can manually turn
	 * off PLL1.
	 */
	if (pll_res->pll_interface_type == MDSS_DSI_PLL_20NM) {
		struct resource *pll_1_base_reg;
		pll_1_base_reg = platform_get_resource_byname(pdev,
				IORESOURCE_MEM, "pll_1_base");
		if (pll_1_base_reg) {
			pll_res->pll_1_base = ioremap(pll_1_base_reg->start,
					resource_size(pll_1_base_reg));
			if (!pll_res->pll_1_base)
				pr_err("Unable to remap pll 1 base resources\n");
		} else {
			pr_err("Unable to get the pll 1 base resource\n");
		}
	}

	phy_base_reg = platform_get_resource_byname(pdev,
						IORESOURCE_MEM, "phy_base");
	if (!phy_base_reg) {
		/* This resource is mandatory for HDMI pll */
		if (pll_res->pll_interface_type == MDSS_HDMI_PLL) {
			pr_err("Unable to get the phy base resources\n");
			rc = -ENOMEM;
			goto phy_io_error;
		}
	} else {
		pll_res->phy_base = ioremap(phy_base_reg->start,
						resource_size(phy_base_reg));
		if (!pll_res->phy_base) {
			pr_err("Unable to remap pll phy base resources\n");
			rc = -ENOMEM;
			goto phy_io_error;
		}
	}

	dynamic_pll_base_reg = platform_get_resource_byname(pdev,
					IORESOURCE_MEM, "dynamic_pll_base");
	if (dynamic_pll_base_reg) {
		pll_res->dyn_pll_base = ioremap(dynamic_pll_base_reg->start,
				resource_size(dynamic_pll_base_reg));
		if (!pll_res->dyn_pll_base) {
			pr_err("Unable to remap dynamic pll base resources\n");
			rc = -ENOMEM;
			goto dyn_pll_io_error;
		}
	}

	gdsc_base_reg = platform_get_resource_byname(pdev,
					IORESOURCE_MEM, "gdsc_base");
	if (!gdsc_base_reg) {
		pr_err("Unable to get the gdsc base resource\n");
		rc = -ENOMEM;
		goto gdsc_io_error;
	}
	pll_res->gdsc_base = ioremap(gdsc_base_reg->start,
			resource_size(gdsc_base_reg));
	if (!pll_res->gdsc_base) {
		pr_err("Unable to remap gdsc base resources\n");
		rc = -ENOMEM;
		goto gdsc_io_error;
	}

	rc = mdss_pll_resource_init(pdev, pll_res);
	if (rc) {
		pr_err("Pll resource init failed rc=%d\n", rc);
		goto res_init_error;
	}

	rc = mdss_pll_clock_register(pdev, pll_res);
	if (rc) {
		pr_err("Pll clock register failed rc=%d\n", rc);
		goto clock_register_error;
	}

	return rc;

clock_register_error:
	mdss_pll_resource_deinit(pdev, pll_res);
res_init_error:
	if (pll_res->gdsc_base)
		iounmap(pll_res->gdsc_base);
gdsc_io_error:
	if (pll_res->dyn_pll_base)
		iounmap(pll_res->dyn_pll_base);
dyn_pll_io_error:
	if (pll_res->phy_base)
		iounmap(pll_res->phy_base);
phy_io_error:
	if (pll_res->pll_1_base)
		iounmap(pll_res->pll_1_base);
	mdss_pll_resource_release(pdev, pll_res);
res_parse_error:
	iounmap(pll_res->pll_base);
io_error:
	devm_kfree(&pdev->dev, pll_res);
error:
	return rc;
}
static int mdss_pll_probe(struct platform_device *pdev)
{
	int rc = 0;
	const char *label;
	struct resource *pll_base_reg;
	struct resource *phy_base_reg;
	struct mdss_pll_resources *pll_res;

	if (!pdev->dev.of_node) {
		pr_err("MDSS pll driver only supports device tree probe\n");
		rc = -ENOTSUPP;
		goto error;
	}

	label = of_get_property(pdev->dev.of_node, "label", NULL);
	if (!label)
		pr_info("%d: MDSS pll label not specified\n", __LINE__);
	else
		pr_info("MDSS pll label = %s\n", label);

	pll_res = devm_kzalloc(&pdev->dev, sizeof(struct mdss_pll_resources),
								GFP_KERNEL);
	if (!pll_res) {
		pr_err("Failed to allocate the clock pll\n");
		rc = -ENOMEM;
		goto error;
	}
	platform_set_drvdata(pdev, pll_res);

	pll_base_reg = platform_get_resource_byname(pdev,
						IORESOURCE_MEM, "pll_base");
	if (!pll_base_reg) {
		pr_err("Unable to get the pll base resources\n");
		rc = -ENOMEM;
		goto io_error;
	}

	pll_res->pll_base = ioremap(pll_base_reg->start,
						resource_size(pll_base_reg));
	if (!pll_res->pll_base) {
		pr_err("Unable to remap pll base resources\n");
		rc = -ENOMEM;
		goto io_error;
	}

	rc = mdss_pll_resource_parse(pdev, pll_res);
	if (rc) {
		pr_err("Pll resource parsing from dt failed rc=%d\n", rc);
		goto res_parse_error;
	}

	phy_base_reg = platform_get_resource_byname(pdev,
						IORESOURCE_MEM, "phy_base");
	if (!phy_base_reg) {
		/* This resource is mandatory for HDMI pll */
		if (pll_res->pll_interface_type == MDSS_HDMI_PLL) {
			pr_err("Unable to get the phy base resources\n");
			rc = -ENOMEM;
			goto phy_io_error;
		}
	} else {
		pll_res->phy_base = ioremap(phy_base_reg->start,
						resource_size(phy_base_reg));
		if (!pll_res->phy_base) {
			pr_err("Unable to remap pll phy base resources\n");
			rc = -ENOMEM;
			goto phy_io_error;
		}
	}

	rc = mdss_pll_resource_init(pdev, pll_res);
	if (rc) {
		pr_err("Pll resource init failed rc=%d\n", rc);
		goto res_init_error;
	}

	rc = mdss_pll_clock_register(pdev, pll_res);
	if (rc) {
		pr_err("Pll clock register failed rc=%d\n", rc);
		goto clock_register_error;
	}

	return rc;

clock_register_error:
	mdss_pll_resource_deinit(pdev, pll_res);
res_init_error:
	if (pll_res->phy_base)
		iounmap(pll_res->phy_base);
phy_io_error:
	mdss_pll_resource_release(pdev, pll_res);
res_parse_error:
	iounmap(pll_res->pll_base);
io_error:
	devm_kfree(&pdev->dev, pll_res);
error:
	return rc;
}