static int sun4i_usb_phy_probe()

in allwinner/phy-sun4i-usb.c [683:858]


static int sun4i_usb_phy_probe(struct platform_device *pdev)
{
	struct sun4i_usb_phy_data *data;
	struct device *dev = &pdev->dev;
	struct device_node *np = dev->of_node;
	struct phy_provider *phy_provider;
	int i, ret;

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

	spin_lock_init(&data->reg_lock);
	INIT_DELAYED_WORK(&data->detect, sun4i_usb_phy0_id_vbus_det_scan);
	dev_set_drvdata(dev, data);
	data->cfg = of_device_get_match_data(dev);
	if (!data->cfg)
		return -EINVAL;

	data->base = devm_platform_ioremap_resource_byname(pdev, "phy_ctrl");
	if (IS_ERR(data->base))
		return PTR_ERR(data->base);

	data->id_det_gpio = devm_gpiod_get_optional(dev, "usb0_id_det",
						    GPIOD_IN);
	if (IS_ERR(data->id_det_gpio)) {
		dev_err(dev, "Couldn't request ID GPIO\n");
		return PTR_ERR(data->id_det_gpio);
	}

	data->vbus_det_gpio = devm_gpiod_get_optional(dev, "usb0_vbus_det",
						      GPIOD_IN);
	if (IS_ERR(data->vbus_det_gpio)) {
		dev_err(dev, "Couldn't request VBUS detect GPIO\n");
		return PTR_ERR(data->vbus_det_gpio);
	}

	if (of_find_property(np, "usb0_vbus_power-supply", NULL)) {
		data->vbus_power_supply = devm_power_supply_get_by_phandle(dev,
						     "usb0_vbus_power-supply");
		if (IS_ERR(data->vbus_power_supply)) {
			dev_err(dev, "Couldn't get the VBUS power supply\n");
			return PTR_ERR(data->vbus_power_supply);
		}

		if (!data->vbus_power_supply)
			return -EPROBE_DEFER;
	}

	data->dr_mode = of_usb_get_dr_mode_by_phy(np, 0);

	data->extcon = devm_extcon_dev_allocate(dev, sun4i_usb_phy0_cable);
	if (IS_ERR(data->extcon)) {
		dev_err(dev, "Couldn't allocate our extcon device\n");
		return PTR_ERR(data->extcon);
	}

	ret = devm_extcon_dev_register(dev, data->extcon);
	if (ret) {
		dev_err(dev, "failed to register extcon: %d\n", ret);
		return ret;
	}

	for (i = 0; i < data->cfg->num_phys; i++) {
		struct sun4i_usb_phy *phy = data->phys + i;
		char name[16];

		if (data->cfg->missing_phys & BIT(i))
			continue;

		snprintf(name, sizeof(name), "usb%d_vbus", i);
		phy->vbus = devm_regulator_get_optional(dev, name);
		if (IS_ERR(phy->vbus)) {
			if (PTR_ERR(phy->vbus) == -EPROBE_DEFER) {
				dev_err(dev,
					"Couldn't get regulator %s... Deferring probe\n",
					name);
				return -EPROBE_DEFER;
			}

			phy->vbus = NULL;
		}

		if (data->cfg->dedicated_clocks)
			snprintf(name, sizeof(name), "usb%d_phy", i);
		else
			strlcpy(name, "usb_phy", sizeof(name));

		phy->clk = devm_clk_get(dev, name);
		if (IS_ERR(phy->clk)) {
			dev_err(dev, "failed to get clock %s\n", name);
			return PTR_ERR(phy->clk);
		}

		/* The first PHY is always tied to OTG, and never HSIC */
		if (data->cfg->hsic_index && i == data->cfg->hsic_index) {
			/* HSIC needs secondary clock */
			snprintf(name, sizeof(name), "usb%d_hsic_12M", i);
			phy->clk2 = devm_clk_get(dev, name);
			if (IS_ERR(phy->clk2)) {
				dev_err(dev, "failed to get clock %s\n", name);
				return PTR_ERR(phy->clk2);
			}
		}

		snprintf(name, sizeof(name), "usb%d_reset", i);
		phy->reset = devm_reset_control_get(dev, name);
		if (IS_ERR(phy->reset)) {
			dev_err(dev, "failed to get reset %s\n", name);
			return PTR_ERR(phy->reset);
		}

		if (i || data->cfg->phy0_dual_route) { /* No pmu for musb */
			snprintf(name, sizeof(name), "pmu%d", i);
			phy->pmu = devm_platform_ioremap_resource_byname(pdev, name);
			if (IS_ERR(phy->pmu))
				return PTR_ERR(phy->pmu);
		}

		phy->phy = devm_phy_create(dev, NULL, &sun4i_usb_phy_ops);
		if (IS_ERR(phy->phy)) {
			dev_err(dev, "failed to create PHY %d\n", i);
			return PTR_ERR(phy->phy);
		}

		phy->index = i;
		phy_set_drvdata(phy->phy, &data->phys[i]);
	}

	data->id_det_irq = gpiod_to_irq(data->id_det_gpio);
	if (data->id_det_irq > 0) {
		ret = devm_request_irq(dev, data->id_det_irq,
				sun4i_usb_phy0_id_vbus_det_irq,
				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
				"usb0-id-det", data);
		if (ret) {
			dev_err(dev, "Err requesting id-det-irq: %d\n", ret);
			return ret;
		}
	}

	data->vbus_det_irq = gpiod_to_irq(data->vbus_det_gpio);
	if (data->vbus_det_irq > 0) {
		ret = devm_request_irq(dev, data->vbus_det_irq,
				sun4i_usb_phy0_id_vbus_det_irq,
				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
				"usb0-vbus-det", data);
		if (ret) {
			dev_err(dev, "Err requesting vbus-det-irq: %d\n", ret);
			data->vbus_det_irq = -1;
			sun4i_usb_phy_remove(pdev); /* Stop detect work */
			return ret;
		}
	}

	if (data->vbus_power_supply) {
		data->vbus_power_nb.notifier_call = sun4i_usb_phy0_vbus_notify;
		data->vbus_power_nb.priority = 0;
		ret = power_supply_reg_notifier(&data->vbus_power_nb);
		if (ret) {
			sun4i_usb_phy_remove(pdev); /* Stop detect work */
			return ret;
		}
		data->vbus_power_nb_registered = true;
	}

	phy_provider = devm_of_phy_provider_register(dev, sun4i_usb_phy_xlate);
	if (IS_ERR(phy_provider)) {
		sun4i_usb_phy_remove(pdev); /* Stop detect work */
		return PTR_ERR(phy_provider);
	}

	dev_dbg(dev, "successfully loaded\n");

	return 0;
}