static int inno_hdmi_phy_probe()

in rockchip/phy-rockchip-inno-hdmi.c [1143:1247]


static int inno_hdmi_phy_probe(struct platform_device *pdev)
{
	struct inno_hdmi_phy *inno;
	struct phy_provider *phy_provider;
	void __iomem *regs;
	int ret;

	inno = devm_kzalloc(&pdev->dev, sizeof(*inno), GFP_KERNEL);
	if (!inno)
		return -ENOMEM;

	inno->dev = &pdev->dev;

	inno->plat_data = of_device_get_match_data(inno->dev);
	if (!inno->plat_data || !inno->plat_data->ops)
		return -EINVAL;

	regs = devm_platform_ioremap_resource(pdev, 0);
	if (IS_ERR(regs))
		return PTR_ERR(regs);

	inno->sysclk = devm_clk_get(inno->dev, "sysclk");
	if (IS_ERR(inno->sysclk)) {
		ret = PTR_ERR(inno->sysclk);
		dev_err(inno->dev, "failed to get sysclk: %d\n", ret);
		return ret;
	}

	inno->refpclk = devm_clk_get(inno->dev, "refpclk");
	if (IS_ERR(inno->refpclk)) {
		ret = PTR_ERR(inno->refpclk);
		dev_err(inno->dev, "failed to get ref clock: %d\n", ret);
		return ret;
	}

	inno->refoclk = devm_clk_get(inno->dev, "refoclk");
	if (IS_ERR(inno->refoclk)) {
		ret = PTR_ERR(inno->refoclk);
		dev_err(inno->dev, "failed to get oscillator-ref clock: %d\n",
			ret);
		return ret;
	}

	ret = clk_prepare_enable(inno->sysclk);
	if (ret) {
		dev_err(inno->dev, "Cannot enable inno phy sysclk: %d\n", ret);
		return ret;
	}

	/*
	 * Refpclk needs to be on, on at least the rk3328 for still
	 * unknown reasons.
	 */
	ret = clk_prepare_enable(inno->refpclk);
	if (ret) {
		dev_err(inno->dev, "failed to enable refpclk\n");
		clk_disable_unprepare(inno->sysclk);
		return ret;
	}

	ret = devm_add_action_or_reset(inno->dev, inno_hdmi_phy_action,
				       inno);
	if (ret)
		return ret;

	inno->regmap = devm_regmap_init_mmio(inno->dev, regs,
					     &inno_hdmi_phy_regmap_config);
	if (IS_ERR(inno->regmap))
		return PTR_ERR(inno->regmap);

	/* only the newer rk3328 hdmiphy has an interrupt */
	inno->irq = platform_get_irq(pdev, 0);
	if (inno->irq > 0) {
		ret = devm_request_threaded_irq(inno->dev, inno->irq,
						inno_hdmi_phy_rk3328_hardirq,
						inno_hdmi_phy_rk3328_irq,
						IRQF_SHARED,
						dev_name(inno->dev), inno);
		if (ret)
			return ret;
	}

	inno->phy = devm_phy_create(inno->dev, NULL, &inno_hdmi_phy_ops);
	if (IS_ERR(inno->phy)) {
		dev_err(inno->dev, "failed to create HDMI PHY\n");
		return PTR_ERR(inno->phy);
	}

	phy_set_drvdata(inno->phy, inno);
	phy_set_bus_width(inno->phy, 8);

	if (inno->plat_data->ops->init) {
		ret = inno->plat_data->ops->init(inno);
		if (ret)
			return ret;
	}

	ret = inno_hdmi_phy_clk_register(inno);
	if (ret)
		return ret;

	phy_provider = devm_of_phy_provider_register(inno->dev,
						     of_phy_simple_xlate);
	return PTR_ERR_OR_ZERO(phy_provider);
}