drm/tilcdc fixing i2c/slave initialization race
authorDarren Etheridge <detheridge@ti.com>
Fri, 21 Jun 2013 18:52:27 +0000 (13:52 -0500)
committerDave Airlie <airlied@redhat.com>
Thu, 27 Jun 2013 23:12:54 +0000 (09:12 +1000)
In certain senarios drm will initialize before i2c this means that i2c
slave devices like the nxp tda998x will fail to be probed.  This patch
detects this condition then defers the probe of the slave device and
the tilcdc main driver.

Signed-off-by: Darren Etheridge <detheridge@ti.com>
Acked-by: Rob Clark <robdclark@gmail.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
drivers/gpu/drm/tilcdc/tilcdc_drv.c
drivers/gpu/drm/tilcdc/tilcdc_drv.h
drivers/gpu/drm/tilcdc/tilcdc_slave.c

index 1e8f273f7c8bc505a45e146f3ef9bda474440653..40b71da5a2145815f7539a76c0c01791fbb94fbc 100644 (file)
@@ -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);
 }
 
index 66df316ca434b0fb3b92bd6b7a27acbeb87f4cd1..093803683b25241dc86ff9124fed081b7b54fd81 100644 (file)
@@ -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
index 8bf4fd19181c48df7f697db72cf7f5f1c608e853..dfffaf01402225b20bbbcefd97b264cad040ce28 100644 (file)
@@ -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;
        }
 
-       slave_mod = kzalloc(sizeof(*slave_mod), GFP_KERNEL);
-       if (!slave_mod)
-               return -ENOMEM;
-
-       mod = &slave_mod->base;
-
-       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");
-
+       /* 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");
-               goto fail;
+               return ret;
        }
 
-       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;
+               return ret;
        }
 
-       slave_mod->i2c = of_find_i2c_adapter_by_node(i2c_node);
-       if (!slave_mod->i2c) {
+       /* 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");
-               goto fail;
+               return ret;
        }
 
-       of_node_put(i2c_node);
+       slave_mod = kzalloc(sizeof(*slave_mod), GFP_KERNEL);
+       if (!slave_mod)
+               return -ENOMEM;
 
-       return 0;
+       mod = &slave_mod->base;
 
-fail:
-       slave_destroy(mod);
-       return ret;
+       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");
+
+       tilcdc_slave_probedefer(false);
+
+       return 0;
 }
 
 static int slave_remove(struct platform_device *pdev)