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;
}