From: Sam Ravnborg <sam@xxxxxxxxxxxx> [ 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: Sam Ravnborg <sam@xxxxxxxxxxxx> Cc: Nicolas Ferre <nicolas.ferre@xxxxxxxxxxxxx> Cc: Alexandre Belloni <alexandre.belloni@xxxxxxxxxxx> Signed-off-by: Bartlomiej Zolnierkiewicz <b.zolnierkie@xxxxxxxxxxx> Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx> --- drivers/video/fbdev/atmel_lcdfb.c | 43 +++++++------------------------ 1 file changed, 9 insertions(+), 34 deletions(-) diff --git a/drivers/video/fbdev/atmel_lcdfb.c b/drivers/video/fbdev/atmel_lcdfb.c index 076d24afbd728..4ed55e6bbb840 100644 --- a/drivers/video/fbdev/atmel_lcdfb.c +++ b/drivers/video/fbdev/atmel_lcdfb.c @@ -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; -- 2.20.1