Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 964cd867 authored by Sam Ravnborg's avatar Sam Ravnborg Committed by Greg Kroah-Hartman
Browse files

atmel_lcdfb: support native-mode display-timings



[ Upstream commit 60e5e48dba72c6b59a7a9c7686ba320766913368 ]

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: default avatarSam Ravnborg <sam@ravnborg.org>
Cc: Nicolas Ferre <nicolas.ferre@microchip.com>
Cc: Alexandre Belloni <alexandre.belloni@bootlin.com>
Signed-off-by: default avatarBartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent a3a76b5d
Loading
Loading
Loading
Loading
+9 −34
Original line number Original line Diff line number Diff line
@@ -22,6 +22,7 @@
#include <linux/module.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_device.h>
#include <video/of_videomode.h>
#include <video/of_display_timing.h>
#include <video/of_display_timing.h>
#include <linux/regulator/consumer.h>
#include <linux/regulator/consumer.h>
#include <video/videomode.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 *dev = &sinfo->pdev->dev;
	struct device_node *np =dev->of_node;
	struct device_node *np =dev->of_node;
	struct device_node *display_np;
	struct device_node *display_np;
	struct device_node *timings_np;
	struct display_timings *timings;
	struct atmel_lcdfb_power_ctrl_gpio *og;
	struct atmel_lcdfb_power_ctrl_gpio *og;
	bool is_gpio_power = false;
	bool is_gpio_power = false;
	struct fb_videomode fb_vm;
	struct gpio_desc *gpiod;
	struct gpio_desc *gpiod;
	struct videomode vm;
	int ret = -ENOENT;
	int ret = -ENOENT;
	int i;
	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_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");
	pdata->lcdcon_pol_negative = of_property_read_bool(display_np, "atmel,lcdcon-backlight-inverted");


	timings = of_get_display_timings(display_np);
	ret = of_get_videomode(display_np, &vm, OF_USE_NATIVE_MODE);
	if (!timings) {
	if (ret) {
		dev_err(dev, "failed to get display timings\n");
		dev_err(dev, "failed to get videomode from DT\n");
		ret = -EINVAL;
		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;
		goto put_display_node;
		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);
	ret = fb_videomode_from_videomode(&vm, &fb_vm);
	if (ret < 0)
	if (ret < 0)
			goto put_timings_node;
		goto put_display_node;


	fb_add_videomode(&fb_vm, &info->modelist);
	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;


put_timings_node:
	of_node_put(timings_np);
put_display_node:
put_display_node:
	of_node_put(display_np);
	of_node_put(display_np);
	return ret;
	return ret;