atmel_lcdfb: support native-mode display-timings
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>
This commit is contained in:
parent
811ab8db89
commit
60e5e48dba
|
@ -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;
|
||||
fb_add_videomode(&fb_vm, &info->modelist);
|
||||
|
||||
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;
|
||||
|
||||
put_timings_node:
|
||||
of_node_put(timings_np);
|
||||
put_display_node:
|
||||
of_node_put(display_np);
|
||||
return ret;
|
||||
|
|
Loading…
Reference in New Issue