diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index 1e8f273f7c8b..40b71da5a214 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -26,6 +26,7 @@ #include "drm_fb_helper.h" static LIST_HEAD(module_list); +static bool slave_probing; void tilcdc_module_init(struct tilcdc_module *mod, const char *name, const struct tilcdc_module_ops *funcs) @@ -41,6 +42,11 @@ void tilcdc_module_cleanup(struct tilcdc_module *mod) list_del(&mod->list); } +void tilcdc_slave_probedefer(bool defered) +{ + slave_probing = defered; +} + static struct of_device_id tilcdc_of_match[]; static struct drm_framebuffer *tilcdc_fb_create(struct drm_device *dev, @@ -580,6 +586,10 @@ static int tilcdc_pdev_probe(struct platform_device *pdev) return -ENXIO; } + /* defer probing if slave is in deferred probing */ + if (slave_probing == true) + return -EPROBE_DEFER; + return drm_platform_init(&tilcdc_driver, pdev); } diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.h b/drivers/gpu/drm/tilcdc/tilcdc_drv.h index 66df316ca434..093803683b25 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.h +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.h @@ -117,7 +117,7 @@ struct tilcdc_module { void tilcdc_module_init(struct tilcdc_module *mod, const char *name, const struct tilcdc_module_ops *funcs); void tilcdc_module_cleanup(struct tilcdc_module *mod); - +void tilcdc_slave_probedefer(bool defered); /* Panel config that needs to be set in the crtc, but is not coming from * the mode timings. The display module is expected to call diff --git a/drivers/gpu/drm/tilcdc/tilcdc_slave.c b/drivers/gpu/drm/tilcdc/tilcdc_slave.c index 8bf4fd19181c..dfffaf014022 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_slave.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_slave.c @@ -298,6 +298,7 @@ static int slave_probe(struct platform_device *pdev) struct tilcdc_module *mod; struct pinctrl *pinctrl; uint32_t i2c_phandle; + struct i2c_adapter *slavei2c; int ret = -EINVAL; /* bail out early if no DT data: */ @@ -306,44 +307,48 @@ static int slave_probe(struct platform_device *pdev) return -ENXIO; } + /* Bail out early if i2c not specified */ + if (of_property_read_u32(node, "i2c", &i2c_phandle)) { + dev_err(&pdev->dev, "could not get i2c bus phandle\n"); + return ret; + } + + i2c_node = of_find_node_by_phandle(i2c_phandle); + if (!i2c_node) { + dev_err(&pdev->dev, "could not get i2c bus node\n"); + return ret; + } + + /* but defer the probe if it can't be initialized it might come later */ + slavei2c = of_find_i2c_adapter_by_node(i2c_node); + of_node_put(i2c_node); + + if (!slavei2c) { + ret = -EPROBE_DEFER; + tilcdc_slave_probedefer(true); + dev_err(&pdev->dev, "could not get i2c\n"); + return ret; + } + slave_mod = kzalloc(sizeof(*slave_mod), GFP_KERNEL); if (!slave_mod) return -ENOMEM; mod = &slave_mod->base; + mod->preferred_bpp = slave_info.bpp; + + slave_mod->i2c = slavei2c; + tilcdc_module_init(mod, "slave", &slave_module_ops); pinctrl = devm_pinctrl_get_select_default(&pdev->dev); if (IS_ERR(pinctrl)) dev_warn(&pdev->dev, "pins are not configured\n"); - if (of_property_read_u32(node, "i2c", &i2c_phandle)) { - dev_err(&pdev->dev, "could not get i2c bus phandle\n"); - goto fail; - } - - mod->preferred_bpp = slave_info.bpp; - - i2c_node = of_find_node_by_phandle(i2c_phandle); - if (!i2c_node) { - dev_err(&pdev->dev, "could not get i2c bus node\n"); - goto fail; - } - - slave_mod->i2c = of_find_i2c_adapter_by_node(i2c_node); - if (!slave_mod->i2c) { - dev_err(&pdev->dev, "could not get i2c\n"); - goto fail; - } - - of_node_put(i2c_node); + tilcdc_slave_probedefer(false); return 0; - -fail: - slave_destroy(mod); - return ret; } static int slave_remove(struct platform_device *pdev)