static int mtk_tphy_probe()

in mediatek/phy-mtk-tphy.c [1244:1352]


static int mtk_tphy_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct device_node *np = dev->of_node;
	struct device_node *child_np;
	struct phy_provider *provider;
	struct resource *sif_res;
	struct mtk_tphy *tphy;
	struct resource res;
	int port, retval;

	tphy = devm_kzalloc(dev, sizeof(*tphy), GFP_KERNEL);
	if (!tphy)
		return -ENOMEM;

	tphy->pdata = of_device_get_match_data(dev);
	if (!tphy->pdata)
		return -EINVAL;

	tphy->nphys = of_get_child_count(np);
	tphy->phys = devm_kcalloc(dev, tphy->nphys,
				       sizeof(*tphy->phys), GFP_KERNEL);
	if (!tphy->phys)
		return -ENOMEM;

	tphy->dev = dev;
	platform_set_drvdata(pdev, tphy);

	sif_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	/* SATA phy of V1 needn't it if not shared with PCIe or USB */
	if (sif_res && tphy->pdata->version == MTK_PHY_V1) {
		/* get banks shared by multiple phys */
		tphy->sif_base = devm_ioremap_resource(dev, sif_res);
		if (IS_ERR(tphy->sif_base)) {
			dev_err(dev, "failed to remap sif regs\n");
			return PTR_ERR(tphy->sif_base);
		}
	}

	if (tphy->pdata->version < MTK_PHY_V3) {
		tphy->src_ref_clk = U3P_REF_CLK;
		tphy->src_coef = U3P_SLEW_RATE_COEF;
		/* update parameters of slew rate calibrate if exist */
		device_property_read_u32(dev, "mediatek,src-ref-clk-mhz",
					 &tphy->src_ref_clk);
		device_property_read_u32(dev, "mediatek,src-coef",
					 &tphy->src_coef);
	}

	port = 0;
	for_each_child_of_node(np, child_np) {
		struct mtk_phy_instance *instance;
		struct clk_bulk_data *clks;
		struct device *subdev;
		struct phy *phy;

		instance = devm_kzalloc(dev, sizeof(*instance), GFP_KERNEL);
		if (!instance) {
			retval = -ENOMEM;
			goto put_child;
		}

		tphy->phys[port] = instance;

		phy = devm_phy_create(dev, child_np, &mtk_tphy_ops);
		if (IS_ERR(phy)) {
			dev_err(dev, "failed to create phy\n");
			retval = PTR_ERR(phy);
			goto put_child;
		}

		subdev = &phy->dev;
		retval = of_address_to_resource(child_np, 0, &res);
		if (retval) {
			dev_err(subdev, "failed to get address resource(id-%d)\n",
				port);
			goto put_child;
		}

		instance->port_base = devm_ioremap_resource(subdev, &res);
		if (IS_ERR(instance->port_base)) {
			retval = PTR_ERR(instance->port_base);
			goto put_child;
		}

		instance->phy = phy;
		instance->index = port;
		phy_set_drvdata(phy, instance);
		port++;

		clks = instance->clks;
		clks[0].id = "ref";     /* digital (& analog) clock */
		clks[1].id = "da_ref";  /* analog clock */
		retval = devm_clk_bulk_get_optional(subdev, TPHY_CLKS_CNT, clks);
		if (retval)
			goto put_child;

		retval = phy_type_syscon_get(instance, child_np);
		if (retval)
			goto put_child;
	}

	provider = devm_of_phy_provider_register(dev, mtk_phy_xlate);

	return PTR_ERR_OR_ZERO(provider);
put_child:
	of_node_put(child_np);
	return retval;
}