static int qusb2_phy_probe()

in qualcomm/phy-qcom-qusb2.c [952:1097]


static int qusb2_phy_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct qusb2_phy *qphy;
	struct phy_provider *phy_provider;
	struct phy *generic_phy;
	int ret, i;
	int num;
	u32 value;
	struct override_params *or;

	qphy = devm_kzalloc(dev, sizeof(*qphy), GFP_KERNEL);
	if (!qphy)
		return -ENOMEM;
	or = &qphy->overrides;

	qphy->base = devm_platform_ioremap_resource(pdev, 0);
	if (IS_ERR(qphy->base))
		return PTR_ERR(qphy->base);

	qphy->cfg_ahb_clk = devm_clk_get(dev, "cfg_ahb");
	if (IS_ERR(qphy->cfg_ahb_clk)) {
		ret = PTR_ERR(qphy->cfg_ahb_clk);
		if (ret != -EPROBE_DEFER)
			dev_err(dev, "failed to get cfg ahb clk, %d\n", ret);
		return ret;
	}

	qphy->ref_clk = devm_clk_get(dev, "ref");
	if (IS_ERR(qphy->ref_clk)) {
		ret = PTR_ERR(qphy->ref_clk);
		if (ret != -EPROBE_DEFER)
			dev_err(dev, "failed to get ref clk, %d\n", ret);
		return ret;
	}

	qphy->iface_clk = devm_clk_get_optional(dev, "iface");
	if (IS_ERR(qphy->iface_clk))
		return PTR_ERR(qphy->iface_clk);

	qphy->phy_reset = devm_reset_control_get_by_index(&pdev->dev, 0);
	if (IS_ERR(qphy->phy_reset)) {
		dev_err(dev, "failed to get phy core reset\n");
		return PTR_ERR(qphy->phy_reset);
	}

	num = ARRAY_SIZE(qphy->vregs);
	for (i = 0; i < num; i++)
		qphy->vregs[i].supply = qusb2_phy_vreg_names[i];

	ret = devm_regulator_bulk_get(dev, num, qphy->vregs);
	if (ret) {
		if (ret != -EPROBE_DEFER)
			dev_err(dev, "failed to get regulator supplies: %d\n",
				ret);
		return ret;
	}

	/* Get the specific init parameters of QMP phy */
	qphy->cfg = of_device_get_match_data(dev);

	qphy->tcsr = syscon_regmap_lookup_by_phandle(dev->of_node,
							"qcom,tcsr-syscon");
	if (IS_ERR(qphy->tcsr)) {
		dev_dbg(dev, "failed to lookup TCSR regmap\n");
		qphy->tcsr = NULL;
	}

	qphy->cell = devm_nvmem_cell_get(dev, NULL);
	if (IS_ERR(qphy->cell)) {
		if (PTR_ERR(qphy->cell) == -EPROBE_DEFER)
			return -EPROBE_DEFER;
		qphy->cell = NULL;
		dev_dbg(dev, "failed to lookup tune2 hstx trim value\n");
	}

	if (!of_property_read_u32(dev->of_node, "qcom,imp-res-offset-value",
				  &value)) {
		or->imp_res_offset.value = (u8)value;
		or->imp_res_offset.override = true;
	}

	if (!of_property_read_u32(dev->of_node, "qcom,bias-ctrl-value",
				  &value)) {
		or->bias_ctrl.value = (u8)value;
		or->bias_ctrl.override = true;
	}

	if (!of_property_read_u32(dev->of_node, "qcom,charge-ctrl-value",
				  &value)) {
		or->charge_ctrl.value = (u8)value;
		or->charge_ctrl.override = true;
	}

	if (!of_property_read_u32(dev->of_node, "qcom,hstx-trim-value",
				  &value)) {
		or->hstx_trim.value = (u8)value;
		or->hstx_trim.override = true;
	}

	if (!of_property_read_u32(dev->of_node, "qcom,preemphasis-level",
				     &value)) {
		or->preemphasis.value = (u8)value;
		or->preemphasis.override = true;
	}

	if (!of_property_read_u32(dev->of_node, "qcom,preemphasis-width",
				     &value)) {
		or->preemphasis_width.value = (u8)value;
		or->preemphasis_width.override = true;
	}

	if (!of_property_read_u32(dev->of_node, "qcom,hsdisc-trim-value",
				  &value)) {
		or->hsdisc_trim.value = (u8)value;
		or->hsdisc_trim.override = true;
	}

	pm_runtime_set_active(dev);
	pm_runtime_enable(dev);
	/*
	 * Prevent runtime pm from being ON by default. Users can enable
	 * it using power/control in sysfs.
	 */
	pm_runtime_forbid(dev);

	generic_phy = devm_phy_create(dev, NULL, &qusb2_phy_gen_ops);
	if (IS_ERR(generic_phy)) {
		ret = PTR_ERR(generic_phy);
		dev_err(dev, "failed to create phy, %d\n", ret);
		pm_runtime_disable(dev);
		return ret;
	}
	qphy->phy = generic_phy;

	dev_set_drvdata(dev, qphy);
	phy_set_drvdata(generic_phy, qphy);

	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
	if (!IS_ERR(phy_provider))
		dev_info(dev, "Registered Qcom-QUSB2 phy\n");
	else
		pm_runtime_disable(dev);

	return PTR_ERR_OR_ZERO(phy_provider);
}