in samsung/phy-exynos5-usbdrd.c [826:934]
static int exynos5_usbdrd_phy_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *node = dev->of_node;
struct exynos5_usbdrd_phy *phy_drd;
struct phy_provider *phy_provider;
const struct exynos5_usbdrd_phy_drvdata *drv_data;
struct regmap *reg_pmu;
u32 pmu_offset;
int i, ret;
int channel;
phy_drd = devm_kzalloc(dev, sizeof(*phy_drd), GFP_KERNEL);
if (!phy_drd)
return -ENOMEM;
dev_set_drvdata(dev, phy_drd);
phy_drd->dev = dev;
phy_drd->reg_phy = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(phy_drd->reg_phy))
return PTR_ERR(phy_drd->reg_phy);
drv_data = of_device_get_match_data(dev);
if (!drv_data)
return -EINVAL;
phy_drd->drv_data = drv_data;
ret = exynos5_usbdrd_phy_clk_handle(phy_drd);
if (ret) {
dev_err(dev, "Failed to initialize clocks\n");
return ret;
}
reg_pmu = syscon_regmap_lookup_by_phandle(dev->of_node,
"samsung,pmu-syscon");
if (IS_ERR(reg_pmu)) {
dev_err(dev, "Failed to lookup PMU regmap\n");
return PTR_ERR(reg_pmu);
}
/*
* Exynos5420 SoC has multiple channels for USB 3.0 PHY, with
* each having separate power control registers.
* 'channel' facilitates to set such registers.
*/
channel = of_alias_get_id(node, "usbdrdphy");
if (channel < 0)
dev_dbg(dev, "Not a multi-controller usbdrd phy\n");
switch (channel) {
case 1:
pmu_offset = phy_drd->drv_data->pmu_offset_usbdrd1_phy;
break;
case 0:
default:
pmu_offset = phy_drd->drv_data->pmu_offset_usbdrd0_phy;
break;
}
/* Get Vbus regulators */
phy_drd->vbus = devm_regulator_get(dev, "vbus");
if (IS_ERR(phy_drd->vbus)) {
ret = PTR_ERR(phy_drd->vbus);
if (ret == -EPROBE_DEFER)
return ret;
dev_warn(dev, "Failed to get VBUS supply regulator\n");
phy_drd->vbus = NULL;
}
phy_drd->vbus_boost = devm_regulator_get(dev, "vbus-boost");
if (IS_ERR(phy_drd->vbus_boost)) {
ret = PTR_ERR(phy_drd->vbus_boost);
if (ret == -EPROBE_DEFER)
return ret;
dev_warn(dev, "Failed to get VBUS boost supply regulator\n");
phy_drd->vbus_boost = NULL;
}
dev_vdbg(dev, "Creating usbdrd_phy phy\n");
for (i = 0; i < EXYNOS5_DRDPHYS_NUM; i++) {
struct phy *phy = devm_phy_create(dev, NULL,
&exynos5_usbdrd_phy_ops);
if (IS_ERR(phy)) {
dev_err(dev, "Failed to create usbdrd_phy phy\n");
return PTR_ERR(phy);
}
phy_drd->phys[i].phy = phy;
phy_drd->phys[i].index = i;
phy_drd->phys[i].reg_pmu = reg_pmu;
phy_drd->phys[i].pmu_offset = pmu_offset;
phy_drd->phys[i].phy_cfg = &drv_data->phy_cfg[i];
phy_set_drvdata(phy, &phy_drd->phys[i]);
}
phy_provider = devm_of_phy_provider_register(dev,
exynos5_usbdrd_phy_xlate);
if (IS_ERR(phy_provider)) {
dev_err(phy_drd->dev, "Failed to register phy provider\n");
return PTR_ERR(phy_provider);
}
return 0;
}