atmel_lcdfb: support native-mode display-timings
authorSam Ravnborg <sam@ravnborg.org>
Mon, 8 Oct 2018 10:57:35 +0000 (12:57 +0200)
committerBartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
Mon, 8 Oct 2018 10:57:35 +0000 (12:57 +0200)
When a device tree set a display-timing using native-mode
then according to the bindings doc this should:

    native-mode:
    The native mode for the display, in case multiple
    modes are provided.
    When omitted, assume the first node is the native.

The atmel_lcdfb used the last timing subnode and did not
respect the timing mode specified with native-mode.

Introduce use of of_get_videomode() which allowed
a nice simplification of the code while also
added support for native-mode.

As a nice side-effect this fixes a memory leak where the
data used for timings and the display_np was not freed.

Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
Cc: Nicolas Ferre <nicolas.ferre@microchip.com>
Cc: Alexandre Belloni <alexandre.belloni@bootlin.com>
Signed-off-by: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
drivers/video/fbdev/atmel_lcdfb.c

index 076d24afbd728bb3e8b4ffbc41f8a3be9642b51d..4ed55e6bbb84047927c0da3a314b419e9312dd02 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
+#include <video/of_videomode.h>
 #include <video/of_display_timing.h>
 #include <linux/regulator/consumer.h>
 #include <video/videomode.h>
@@ -1028,11 +1029,11 @@ static int atmel_lcdfb_of_init(struct atmel_lcdfb_info *sinfo)
        struct device *dev = &sinfo->pdev->dev;
        struct device_node *np =dev->of_node;
        struct device_node *display_np;
-       struct device_node *timings_np;
-       struct display_timings *timings;
        struct atmel_lcdfb_power_ctrl_gpio *og;
        bool is_gpio_power = false;
+       struct fb_videomode fb_vm;
        struct gpio_desc *gpiod;
+       struct videomode vm;
        int ret = -ENOENT;
        int i;
 
@@ -1105,44 +1106,18 @@ static int atmel_lcdfb_of_init(struct atmel_lcdfb_info *sinfo)
        pdata->lcdcon_is_backlight = of_property_read_bool(display_np, "atmel,lcdcon-backlight");
        pdata->lcdcon_pol_negative = of_property_read_bool(display_np, "atmel,lcdcon-backlight-inverted");
 
-       timings = of_get_display_timings(display_np);
-       if (!timings) {
-               dev_err(dev, "failed to get display timings\n");
-               ret = -EINVAL;
+       ret = of_get_videomode(display_np, &vm, OF_USE_NATIVE_MODE);
+       if (ret) {
+               dev_err(dev, "failed to get videomode from DT\n");
                goto put_display_node;
        }
 
-       timings_np = of_get_child_by_name(display_np, "display-timings");
-       if (!timings_np) {
-               dev_err(dev, "failed to find display-timings node\n");
-               ret = -ENODEV;
+       ret = fb_videomode_from_videomode(&vm, &fb_vm);
+       if (ret < 0)
                goto put_display_node;
-       }
 
-       for (i = 0; i < of_get_child_count(timings_np); i++) {
-               struct videomode vm;
-               struct fb_videomode fb_vm;
-
-               ret = videomode_from_timings(timings, &vm, i);
-               if (ret < 0)
-                       goto put_timings_node;
-               ret = fb_videomode_from_videomode(&vm, &fb_vm);
-               if (ret < 0)
-                       goto put_timings_node;
-
-               fb_add_videomode(&fb_vm, &info->modelist);
-       }
-
-       /*
-        * FIXME: Make sure we are not referencing any fields in display_np
-        * and timings_np and drop our references to them before returning to
-        * avoid leaking the nodes on probe deferral and driver unbind.
-        */
-
-       return 0;
+       fb_add_videomode(&fb_vm, &info->modelist);
 
-put_timings_node:
-       of_node_put(timings_np);
 put_display_node:
        of_node_put(display_np);
        return ret;