drm/tegra: Properly reference count the DDC I2C adapter
authorThierry Reding <treding@nvidia.com>
Wed, 8 Apr 2020 18:01:00 +0000 (20:01 +0200)
committerThierry Reding <treding@nvidia.com>
Thu, 17 Sep 2020 10:27:11 +0000 (12:27 +0200)
Use the of_get_i2c_adapter_by_node(), which is similar to the existing
call to of_find_i2c_adapter_by_node() except that it also takes a
reference to the owner module of the I2C adapter. In order to properly
balance this out, call i2c_put_adapter() to release the reference to the
I2C adapter and its owner module.

For the special case where the DDC comes from the DPAUX, care must be
taken to perform the same steps (i.e. get_device() and module_get()) so
that the reference counts are all balanced.

Signed-off-by: Thierry Reding <treding@nvidia.com>
drivers/gpu/drm/tegra/output.c
drivers/gpu/drm/tegra/sor.c

index e36e5e7c2f694dfe627b1c720d959509041735ce..03382550f7d963c51cd2ad65370bd3f48c597dd4 100644 (file)
@@ -112,7 +112,7 @@ int tegra_output_probe(struct tegra_output *output)
 
        ddc = of_parse_phandle(output->of_node, "nvidia,ddc-i2c-bus", 0);
        if (ddc) {
-               output->ddc = of_find_i2c_adapter_by_node(ddc);
+               output->ddc = of_get_i2c_adapter_by_node(ddc);
                if (!output->ddc) {
                        err = -EPROBE_DEFER;
                        of_node_put(ddc);
@@ -173,7 +173,7 @@ void tegra_output_remove(struct tegra_output *output)
                free_irq(output->hpd_irq, output);
 
        if (output->ddc)
-               put_device(&output->ddc->dev);
+               i2c_put_adapter(output->ddc);
 }
 
 int tegra_output_init(struct drm_device *drm, struct tegra_output *output)
index 45b5258c77a2914e01d3c3f5f8873f98e796e74c..e88a17c2937f26819f0ef1c774d2317f6bfcb1ac 100644 (file)
@@ -3728,7 +3728,12 @@ static int tegra_sor_probe(struct platform_device *pdev)
                if (!sor->aux)
                        return -EPROBE_DEFER;
 
-               sor->output.ddc = &sor->aux->ddc;
+               if (get_device(&sor->aux->ddc.dev)) {
+                       if (try_module_get(sor->aux->ddc.owner))
+                               sor->output.ddc = &sor->aux->ddc;
+                       else
+                               put_device(&sor->aux->ddc.dev);
+               }
        }
 
        if (!sor->aux) {