in ti/phy-j721e-wiz.c [1133:1313]
static int wiz_probe(struct platform_device *pdev)
{
struct reset_controller_dev *phy_reset_dev;
struct device *dev = &pdev->dev;
struct device_node *node = dev->of_node;
struct platform_device *serdes_pdev;
bool already_configured = false;
struct device_node *child_node;
struct regmap *regmap;
struct resource res;
void __iomem *base;
struct wiz *wiz;
int ret, val, i;
u32 num_lanes;
wiz = devm_kzalloc(dev, sizeof(*wiz), GFP_KERNEL);
if (!wiz)
return -ENOMEM;
wiz->type = (enum wiz_type)of_device_get_match_data(dev);
child_node = of_get_child_by_name(node, "serdes");
if (!child_node) {
dev_err(dev, "Failed to get SERDES child DT node\n");
return -ENODEV;
}
ret = of_address_to_resource(child_node, 0, &res);
if (ret) {
dev_err(dev, "Failed to get memory resource\n");
goto err_addr_to_resource;
}
base = devm_ioremap(dev, res.start, resource_size(&res));
if (!base) {
ret = -ENOMEM;
goto err_addr_to_resource;
}
regmap = devm_regmap_init_mmio(dev, base, &wiz_regmap_config);
if (IS_ERR(regmap)) {
dev_err(dev, "Failed to initialize regmap\n");
ret = PTR_ERR(regmap);
goto err_addr_to_resource;
}
ret = of_property_read_u32(node, "num-lanes", &num_lanes);
if (ret) {
dev_err(dev, "Failed to read num-lanes property\n");
goto err_addr_to_resource;
}
if (num_lanes > WIZ_MAX_LANES) {
dev_err(dev, "Cannot support %d lanes\n", num_lanes);
ret = -ENODEV;
goto err_addr_to_resource;
}
wiz->gpio_typec_dir = devm_gpiod_get_optional(dev, "typec-dir",
GPIOD_IN);
if (IS_ERR(wiz->gpio_typec_dir)) {
ret = PTR_ERR(wiz->gpio_typec_dir);
if (ret != -EPROBE_DEFER)
dev_err(dev, "Failed to request typec-dir gpio: %d\n",
ret);
goto err_addr_to_resource;
}
if (wiz->gpio_typec_dir) {
ret = of_property_read_u32(node, "typec-dir-debounce-ms",
&wiz->typec_dir_delay);
if (ret && ret != -EINVAL) {
dev_err(dev, "Invalid typec-dir-debounce property\n");
goto err_addr_to_resource;
}
/* use min. debounce from Type-C spec if not provided in DT */
if (ret == -EINVAL)
wiz->typec_dir_delay = WIZ_TYPEC_DIR_DEBOUNCE_MIN;
if (wiz->typec_dir_delay < WIZ_TYPEC_DIR_DEBOUNCE_MIN ||
wiz->typec_dir_delay > WIZ_TYPEC_DIR_DEBOUNCE_MAX) {
ret = -EINVAL;
dev_err(dev, "Invalid typec-dir-debounce property\n");
goto err_addr_to_resource;
}
}
ret = wiz_get_lane_phy_types(dev, wiz);
if (ret)
return ret;
wiz->dev = dev;
wiz->regmap = regmap;
wiz->num_lanes = num_lanes;
if (wiz->type == J721E_WIZ_10G || wiz->type == AM64_WIZ_10G)
wiz->clk_mux_sel = clk_mux_sel_10g;
else
wiz->clk_mux_sel = clk_mux_sel_16g;
wiz->clk_div_sel = clk_div_sel;
if (wiz->type == J721E_WIZ_10G || wiz->type == AM64_WIZ_10G)
wiz->clk_div_sel_num = WIZ_DIV_NUM_CLOCKS_10G;
else
wiz->clk_div_sel_num = WIZ_DIV_NUM_CLOCKS_16G;
platform_set_drvdata(pdev, wiz);
ret = wiz_regfield_init(wiz);
if (ret) {
dev_err(dev, "Failed to initialize regfields\n");
goto err_addr_to_resource;
}
phy_reset_dev = &wiz->wiz_phy_reset_dev;
phy_reset_dev->dev = dev;
phy_reset_dev->ops = &wiz_phy_reset_ops,
phy_reset_dev->owner = THIS_MODULE,
phy_reset_dev->of_node = node;
/* Reset for each of the lane and one for the entire SERDES */
phy_reset_dev->nr_resets = num_lanes + 1;
ret = devm_reset_controller_register(dev, phy_reset_dev);
if (ret < 0) {
dev_warn(dev, "Failed to register reset controller\n");
goto err_addr_to_resource;
}
pm_runtime_enable(dev);
ret = pm_runtime_get_sync(dev);
if (ret < 0) {
dev_err(dev, "pm_runtime_get_sync failed\n");
goto err_get_sync;
}
ret = wiz_clock_init(wiz, node);
if (ret < 0) {
dev_warn(dev, "Failed to initialize clocks\n");
goto err_get_sync;
}
for (i = 0; i < wiz->num_lanes; i++) {
regmap_field_read(wiz->p_enable[i], &val);
if (val & (P_ENABLE | P_ENABLE_FORCE)) {
already_configured = true;
break;
}
}
if (!already_configured) {
ret = wiz_init(wiz);
if (ret) {
dev_err(dev, "WIZ initialization failed\n");
goto err_wiz_init;
}
}
serdes_pdev = of_platform_device_create(child_node, NULL, dev);
if (!serdes_pdev) {
dev_WARN(dev, "Unable to create SERDES platform device\n");
ret = -ENOMEM;
goto err_wiz_init;
}
wiz->serdes_pdev = serdes_pdev;
of_node_put(child_node);
return 0;
err_wiz_init:
wiz_clock_cleanup(wiz, node);
err_get_sync:
pm_runtime_put(dev);
pm_runtime_disable(dev);
err_addr_to_resource:
of_node_put(child_node);
return ret;
}