MLK-17275-1: drm/bridge: adv7511: Add support for OF_DYNAMIC
authorRobert Chiras <robert.chiras@nxp.com>
Thu, 21 Dec 2017 08:59:20 +0000 (10:59 +0200)
committerLeonard Crestez <leonard.crestez@nxp.com>
Wed, 17 Apr 2019 23:51:34 +0000 (02:51 +0300)
When CONFIG_OF_DYNAMIC is used, and this driver is enabled in
devicetree, but fails to probe a physical i2c client, it should disable
it's remote endpoint, so that the DRM master device won't fail to bind
the other available devices.
Usually, the remote endpoint of this device is a DRM encoder. If a DRM
encoder fails to bind, the DRM master device will also fail to bind.
This is why, we should disable the encoder node dynamically in
devicetree.

Signed-off-by: Robert Chiras <robert.chiras@nxp.com>
Reviewed-by: Laurentiu Palcu <laurentiu.palcu@nxp.com>
drivers/gpu/drm/bridge/adv7511/adv7511_drv.c

index 620434e..82d3f78 100644 (file)
@@ -9,7 +9,9 @@
 #include <linux/device.h>
 #include <linux/gpio/consumer.h>
 #include <linux/module.h>
+#include <linux/of.h>
 #include <linux/of_device.h>
+#include <linux/of_graph.h>
 #include <linux/slab.h>
 #include <linux/clk.h>
 
@@ -1109,6 +1111,11 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
        struct adv7511_link_config link_config;
        struct adv7511 *adv7511;
        struct device *dev = &i2c->dev;
+#if IS_ENABLED(CONFIG_OF_DYNAMIC)
+       struct device_node *remote_node = NULL, *endpoint = NULL;
+       struct of_changeset ocs;
+       struct property *prop;
+#endif
        unsigned int val;
        int ret;
 
@@ -1249,6 +1256,44 @@ err_i2c_unregister_edid:
        i2c_unregister_device(adv7511->i2c_edid);
 uninit_regulators:
        adv7511_uninit_regulators(adv7511);
+#if IS_ENABLED(CONFIG_OF_DYNAMIC)
+       endpoint = of_graph_get_next_endpoint(dev->of_node, NULL);
+       if (endpoint)
+               remote_node = of_graph_get_remote_port_parent(endpoint);
+
+       if (remote_node) {
+               int num_endpoints = 0;
+
+               /*
+                * Remote node should have two endpoints (input and output: us)
+                * If remote node has more than two endpoints, probably that it
+                * has more outputs, so there is no need to disable it.
+                */
+               endpoint = NULL;
+               while ((endpoint = of_graph_get_next_endpoint(remote_node,
+                                                             endpoint)))
+                       num_endpoints++;
+
+               if (num_endpoints > 2) {
+                       of_node_put(remote_node);
+                       return ret;
+               }
+
+               prop = devm_kzalloc(dev, sizeof(*prop), GFP_KERNEL);
+               prop->name = devm_kstrdup(dev, "status", GFP_KERNEL);
+               prop->value = devm_kstrdup(dev, "disabled", GFP_KERNEL);
+               prop->length = 9;
+               of_changeset_init(&ocs);
+               of_changeset_update_property(&ocs, remote_node, prop);
+               ret = of_changeset_apply(&ocs);
+               if (!ret)
+                       dev_warn(dev,
+                               "Probe failed. Remote port '%s' disabled\n",
+                               remote_node->full_name);
+
+               of_node_put(remote_node);
+       };
+#endif
 
        return ret;
 }