Merge tag 'backlight-next-4.18' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/backlight

Pull backlight updates from Lee Jones:
 "Core Frameworks
   - Provide helpers to enable/disable backlight
   - Provide standard and devres versions OF find helpers

  New Drivers:
   - Add support for the Zodiac Inflight Innovations RAVE Supervisory
     Processor

  New Functionality:
   - Allow pwm-on/pwm-off delay to be specified via DT

  Bug Fixes:
   - Fix ordering of the power {en,dis}able and PWM {en,dis}able
     signals
   - Fix Device Tree node look-up"

* tag 'backlight-next-4.18' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/backlight:
  backlight: as3711_bl: Fix Device Tree node leaks
  backlight: tps65217_bl: Fix Device Tree node lookup
  backlight: max8925_bl: Fix Device Tree node lookup
  backlight: as3711_bl: Fix Device Tree node lookup
  MAINTAINERS: Add dri-devel for backlight subsystem patches
  backlight: Nuke BL_CORE_DRIVER1
  staging: fbtft: Stop using BL_CORE_DRIVER1
  backlight: pandora: Stop using BL_CORE_DRIVER1
  backlight: generic-bl: Remove DRIVER1 state
  backlight: Nuke unused backlight.props.state states
  backlight: otm3225a: Add support for ORISE OTM3225A LCD SoC
  backlight: pwm_bl: Don't use GPIOF_* with gpiod_get_direction
  pwm-backlight: Add support for PWM delays proprieties.
  dt-bindings: pwm-backlight: Add PWM delay proprieties.
  pwm-backlight: Enable/disable the PWM before/after LCD enable toggle.
  dt-bindings: backlight: Add binding for RAVE SP backlight driver
  backlight: Add RAVE SP backlight driver
diff --git a/Documentation/devicetree/bindings/leds/backlight/pwm-backlight.txt b/Documentation/devicetree/bindings/leds/backlight/pwm-backlight.txt
index 764db86..3108109 100644
--- a/Documentation/devicetree/bindings/leds/backlight/pwm-backlight.txt
+++ b/Documentation/devicetree/bindings/leds/backlight/pwm-backlight.txt
@@ -17,6 +17,10 @@
                "pwms" property (see PWM binding[0])
   - enable-gpios: contains a single GPIO specifier for the GPIO which enables
                   and disables the backlight (see GPIO binding[1])
+  - post-pwm-on-delay-ms: Delay in ms between setting an initial (non-zero) PWM
+                          and enabling the backlight using GPIO.
+  - pwm-off-delay-ms: Delay in ms between disabling the backlight using GPIO
+                      and setting PWM value to 0.
 
 [0]: Documentation/devicetree/bindings/pwm/pwm.txt
 [1]: Documentation/devicetree/bindings/gpio/gpio.txt
@@ -32,4 +36,6 @@
 
 		power-supply = <&vdd_bl_reg>;
 		enable-gpios = <&gpio 58 0>;
+		post-pwm-on-delay-ms = <10>;
+		pwm-off-delay-ms = <10>;
 	};
diff --git a/Documentation/devicetree/bindings/leds/backlight/zii,rave-sp-backlight.txt b/Documentation/devicetree/bindings/leds/backlight/zii,rave-sp-backlight.txt
new file mode 100644
index 0000000..ff5c921
--- /dev/null
+++ b/Documentation/devicetree/bindings/leds/backlight/zii,rave-sp-backlight.txt
@@ -0,0 +1,23 @@
+Zodiac Inflight Innovations RAVE Supervisory Processor Backlight Bindings
+
+RAVE SP backlight device is a "MFD cell" device corresponding to
+backlight functionality of RAVE Supervisory Processor. It is expected
+that its Device Tree node is specified as a child of the node
+corresponding to the parent RAVE SP device (as documented in
+Documentation/devicetree/bindings/mfd/zii,rave-sp.txt)
+
+Required properties:
+
+- compatible: Should be "zii,rave-sp-backlight"
+
+Example:
+
+	rave-sp {
+		compatible = "zii,rave-sp-rdu1";
+		current-speed = <38400>;
+
+		backlight {
+			compatible = "zii,rave-sp-backlight";
+		};
+	}
+
diff --git a/MAINTAINERS b/MAINTAINERS
index 8fcfc9a..868be4a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2606,6 +2606,7 @@
 M:	Lee Jones <lee.jones@linaro.org>
 M:	Daniel Thompson <daniel.thompson@linaro.org>
 M:	Jingoo Han <jingoohan1@gmail.com>
+L:	dri-devel@lists.freedesktop.org
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/lee/backlight.git
 S:	Maintained
 F:	drivers/video/backlight/
diff --git a/drivers/staging/fbtft/fbtft-core.c b/drivers/staging/fbtft/fbtft-core.c
index 0e36b66..731e471 100644
--- a/drivers/staging/fbtft/fbtft-core.c
+++ b/drivers/staging/fbtft/fbtft-core.c
@@ -246,7 +246,7 @@
 static int fbtft_backlight_update_status(struct backlight_device *bd)
 {
 	struct fbtft_par *par = bl_get_data(bd);
-	bool polarity = !!(bd->props.state & BL_CORE_DRIVER1);
+	bool polarity = par->polarity;
 
 	fbtft_par_dbg(DEBUG_BACKLIGHT, par,
 		"%s: polarity=%d, power=%d, fb_blank=%d\n",
@@ -296,7 +296,7 @@
 	/* Assume backlight is off, get polarity from current state of pin */
 	bl_props.power = FB_BLANK_POWERDOWN;
 	if (!gpio_get_value(par->gpio.led[0]))
-		bl_props.state |= BL_CORE_DRIVER1;
+		par->polarity = true;
 
 	bd = backlight_device_register(dev_driver_string(par->info->device),
 				       par->info->device, par,
diff --git a/drivers/staging/fbtft/fbtft.h b/drivers/staging/fbtft/fbtft.h
index e19e64e..c7cb4a7 100644
--- a/drivers/staging/fbtft/fbtft.h
+++ b/drivers/staging/fbtft/fbtft.h
@@ -229,6 +229,7 @@
 	ktime_t update_time;
 	bool bgr;
 	void *extra;
+	bool polarity;
 };
 
 #define NUMARGS(...)  (sizeof((int[]){__VA_ARGS__})/sizeof(int))
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index 4e1d2ad..2919e23 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -150,6 +150,13 @@
 	  If you have a HX-8357 LCD panel, say Y to enable its LCD control
 	  driver.
 
+  config LCD_OTM3225A
+  	tristate "ORISE Technology OTM3225A support"
+  	depends on SPI
+  	help
+  	  If you have a panel based on the OTM3225A controller
+  	  chip then say y to include a driver for it.
+
 endif # LCD_CLASS_DEVICE
 
 #
@@ -467,6 +474,12 @@
 	  If you have an ARCxCnnnn family backlight say Y to enable
 	  the backlight driver.
 
+config BACKLIGHT_RAVE_SP
+	tristate "RAVE SP Backlight driver"
+	depends on RAVE_SP_CORE
+	help
+	  Support for backlight control on RAVE SP device.
+
 endif # BACKLIGHT_CLASS_DEVICE
 
 endif # BACKLIGHT_LCD_SUPPORT
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index 5e28f01..0dcc2c7 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -13,6 +13,7 @@
 obj-$(CONFIG_LCD_LMS283GF05)		+= lms283gf05.o
 obj-$(CONFIG_LCD_LMS501KF03)		+= lms501kf03.o
 obj-$(CONFIG_LCD_LTV350QV)		+= ltv350qv.o
+obj-$(CONFIG_LCD_OTM3225A)		+= otm3225a.o
 obj-$(CONFIG_LCD_PLATFORM)		+= platform_lcd.o
 obj-$(CONFIG_LCD_S6E63M0)		+= s6e63m0.o
 obj-$(CONFIG_LCD_TDO24M)		+= tdo24m.o
@@ -57,3 +58,4 @@
 obj-$(CONFIG_BACKLIGHT_TPS65217)	+= tps65217_bl.o
 obj-$(CONFIG_BACKLIGHT_WM831X)		+= wm831x_bl.o
 obj-$(CONFIG_BACKLIGHT_ARCXCNN) 	+= arcxcnn_bl.o
+obj-$(CONFIG_BACKLIGHT_RAVE_SP)		+= rave-sp-backlight.o
diff --git a/drivers/video/backlight/as3711_bl.c b/drivers/video/backlight/as3711_bl.c
index 734a915..ca544aa 100644
--- a/drivers/video/backlight/as3711_bl.c
+++ b/drivers/video/backlight/as3711_bl.c
@@ -28,8 +28,6 @@
 
 struct as3711_bl_data {
 	bool powered;
-	const char *fb_name;
-	struct device *fb_dev;
 	enum as3711_bl_type type;
 	int brightness;
 	struct backlight_device *bl;
@@ -262,10 +260,10 @@
 static int as3711_backlight_parse_dt(struct device *dev)
 {
 	struct as3711_bl_pdata *pdata = dev_get_platdata(dev);
-	struct device_node *bl =
-		of_find_node_by_name(dev->parent->of_node, "backlight"), *fb;
+	struct device_node *bl, *fb;
 	int ret;
 
+	bl = of_get_child_by_name(dev->parent->of_node, "backlight");
 	if (!bl) {
 		dev_dbg(dev, "backlight node not found\n");
 		return -ENODEV;
@@ -273,26 +271,30 @@
 
 	fb = of_parse_phandle(bl, "su1-dev", 0);
 	if (fb) {
-		pdata->su1_fb = fb->full_name;
+		of_node_put(fb);
+
+		pdata->su1_fb = true;
 
 		ret = of_property_read_u32(bl, "su1-max-uA", &pdata->su1_max_uA);
 		if (pdata->su1_max_uA <= 0)
 			ret = -EINVAL;
 		if (ret < 0)
-			return ret;
+			goto err_put_bl;
 	}
 
 	fb = of_parse_phandle(bl, "su2-dev", 0);
 	if (fb) {
 		int count = 0;
 
-		pdata->su2_fb = fb->full_name;
+		of_node_put(fb);
+
+		pdata->su2_fb = true;
 
 		ret = of_property_read_u32(bl, "su2-max-uA", &pdata->su2_max_uA);
 		if (pdata->su2_max_uA <= 0)
 			ret = -EINVAL;
 		if (ret < 0)
-			return ret;
+			goto err_put_bl;
 
 		if (of_find_property(bl, "su2-feedback-voltage", NULL)) {
 			pdata->su2_feedback = AS3711_SU2_VOLTAGE;
@@ -314,8 +316,10 @@
 			pdata->su2_feedback = AS3711_SU2_CURR_AUTO;
 			count++;
 		}
-		if (count != 1)
-			return -EINVAL;
+		if (count != 1) {
+			ret = -EINVAL;
+			goto err_put_bl;
+		}
 
 		count = 0;
 		if (of_find_property(bl, "su2-fbprot-lx-sd4", NULL)) {
@@ -334,8 +338,10 @@
 			pdata->su2_fbprot = AS3711_SU2_GPIO4;
 			count++;
 		}
-		if (count != 1)
-			return -EINVAL;
+		if (count != 1) {
+			ret = -EINVAL;
+			goto err_put_bl;
+		}
 
 		count = 0;
 		if (of_find_property(bl, "su2-auto-curr1", NULL)) {
@@ -355,11 +361,20 @@
 		 * At least one su2-auto-curr* must be specified iff
 		 * AS3711_SU2_CURR_AUTO is used
 		 */
-		if (!count ^ (pdata->su2_feedback != AS3711_SU2_CURR_AUTO))
-			return -EINVAL;
+		if (!count ^ (pdata->su2_feedback != AS3711_SU2_CURR_AUTO)) {
+			ret = -EINVAL;
+			goto err_put_bl;
+		}
 	}
 
+	of_node_put(bl);
+
 	return 0;
+
+err_put_bl:
+	of_node_put(bl);
+
+	return ret;
 }
 
 static int as3711_backlight_probe(struct platform_device *pdev)
@@ -412,7 +427,6 @@
 
 	if (pdata->su1_fb) {
 		su = &supply->su1;
-		su->fb_name = pdata->su1_fb;
 		su->type = AS3711_BL_SU1;
 
 		max_brightness = min(pdata->su1_max_uA, 31);
@@ -423,7 +437,6 @@
 
 	if (pdata->su2_fb) {
 		su = &supply->su2;
-		su->fb_name = pdata->su2_fb;
 		su->type = AS3711_BL_SU2;
 
 		switch (pdata->su2_fbprot) {
diff --git a/drivers/video/backlight/generic_bl.c b/drivers/video/backlight/generic_bl.c
index 67dfb93..4dea91a 100644
--- a/drivers/video/backlight/generic_bl.c
+++ b/drivers/video/backlight/generic_bl.c
@@ -21,9 +21,6 @@
 static struct backlight_device *generic_backlight_device;
 static struct generic_bl_info *bl_machinfo;
 
-/* Flag to signal when the battery is low */
-#define GENERICBL_BATTLOW       BL_CORE_DRIVER1
-
 static int genericbl_send_intensity(struct backlight_device *bd)
 {
 	int intensity = bd->props.brightness;
@@ -34,8 +31,6 @@
 		intensity = 0;
 	if (bd->props.state & BL_CORE_SUSPENDED)
 		intensity = 0;
-	if (bd->props.state & GENERICBL_BATTLOW)
-		intensity &= bl_machinfo->limit_mask;
 
 	bl_machinfo->set_bl_intensity(intensity);
 
diff --git a/drivers/video/backlight/max8925_bl.c b/drivers/video/backlight/max8925_bl.c
index 7b738d6..f3aa608 100644
--- a/drivers/video/backlight/max8925_bl.c
+++ b/drivers/video/backlight/max8925_bl.c
@@ -116,7 +116,7 @@
 	if (!pdata)
 		return;
 
-	np = of_find_node_by_name(nproot, "backlight");
+	np = of_get_child_by_name(nproot, "backlight");
 	if (!np) {
 		dev_err(&pdev->dev, "failed to find backlight node\n");
 		return;
@@ -125,6 +125,8 @@
 	if (!of_property_read_u32(np, "maxim,max8925-dual-string", &val))
 		pdata->dual_string = val;
 
+	of_node_put(np);
+
 	pdev->dev.platform_data = pdata;
 }
 
diff --git a/drivers/video/backlight/otm3225a.c b/drivers/video/backlight/otm3225a.c
new file mode 100644
index 0000000..2472e21
--- /dev/null
+++ b/drivers/video/backlight/otm3225a.c
@@ -0,0 +1,252 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Driver for ORISE Technology OTM3225A SOC for TFT LCD
+ * Copyright (C) 2017, EETS GmbH, Felix Brack <fb@ltec.ch>
+ *
+ * This driver implements a lcd device for the ORISE OTM3225A display
+ * controller. The control interface to the display is SPI and the display's
+ * memory is updated over the 16-bit RGB interface.
+ * The main source of information for writing this driver was provided by the
+ * OTM3225A datasheet from ORISE Technology. Some information arise from the
+ * ILI9328 datasheet from ILITEK as well as from the datasheets and sample code
+ * provided by Crystalfontz America Inc. who sells the CFAF240320A-032T, a 3.2"
+ * TFT LC display using the OTM3225A controller.
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/lcd.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+
+#define OTM3225A_INDEX_REG	0x70
+#define OTM3225A_DATA_REG	0x72
+
+/* instruction register list */
+#define DRIVER_OUTPUT_CTRL_1	0x01
+#define DRIVER_WAVEFORM_CTRL	0x02
+#define ENTRY_MODE		0x03
+#define SCALING_CTRL		0x04
+#define DISPLAY_CTRL_1		0x07
+#define DISPLAY_CTRL_2		0x08
+#define DISPLAY_CTRL_3		0x09
+#define FRAME_CYCLE_CTRL	0x0A
+#define EXT_DISP_IFACE_CTRL_1	0x0C
+#define FRAME_MAKER_POS		0x0D
+#define EXT_DISP_IFACE_CTRL_2	0x0F
+#define POWER_CTRL_1		0x10
+#define POWER_CTRL_2		0x11
+#define POWER_CTRL_3		0x12
+#define POWER_CTRL_4		0x13
+#define GRAM_ADDR_HORIZ_SET	0x20
+#define GRAM_ADDR_VERT_SET	0x21
+#define GRAM_READ_WRITE		0x22
+#define POWER_CTRL_7		0x29
+#define FRAME_RATE_CTRL		0x2B
+#define GAMMA_CTRL_1		0x30
+#define GAMMA_CTRL_2		0x31
+#define GAMMA_CTRL_3		0x32
+#define GAMMA_CTRL_4		0x35
+#define GAMMA_CTRL_5		0x36
+#define GAMMA_CTRL_6		0x37
+#define GAMMA_CTRL_7		0x38
+#define GAMMA_CTRL_8		0x39
+#define GAMMA_CTRL_9		0x3C
+#define GAMMA_CTRL_10		0x3D
+#define WINDOW_HORIZ_RAM_START	0x50
+#define WINDOW_HORIZ_RAM_END	0x51
+#define WINDOW_VERT_RAM_START	0x52
+#define WINDOW_VERT_RAM_END	0x53
+#define DRIVER_OUTPUT_CTRL_2	0x60
+#define BASE_IMG_DISPLAY_CTRL	0x61
+#define VERT_SCROLL_CTRL	0x6A
+#define PD1_DISPLAY_POS		0x80
+#define PD1_RAM_START		0x81
+#define PD1_RAM_END		0x82
+#define PD2_DISPLAY_POS		0x83
+#define PD2_RAM_START		0x84
+#define PD2_RAM_END		0x85
+#define PANEL_IFACE_CTRL_1	0x90
+#define PANEL_IFACE_CTRL_2	0x92
+#define PANEL_IFACE_CTRL_4	0x95
+#define PANEL_IFACE_CTRL_5	0x97
+
+struct otm3225a_data {
+	struct spi_device *spi;
+	struct lcd_device *ld;
+	int power;
+};
+
+struct otm3225a_spi_instruction {
+	unsigned char reg;	/* register to write */
+	unsigned short value;	/* data to write to 'reg' */
+	unsigned short delay;	/* delay in ms after write */
+};
+
+static struct otm3225a_spi_instruction display_init[] = {
+	{ DRIVER_OUTPUT_CTRL_1,		0x0000, 0 },
+	{ DRIVER_WAVEFORM_CTRL,		0x0700, 0 },
+	{ ENTRY_MODE,			0x50A0, 0 },
+	{ SCALING_CTRL,			0x0000, 0 },
+	{ DISPLAY_CTRL_2,		0x0606, 0 },
+	{ DISPLAY_CTRL_3,		0x0000, 0 },
+	{ FRAME_CYCLE_CTRL,		0x0000, 0 },
+	{ EXT_DISP_IFACE_CTRL_1,	0x0000, 0 },
+	{ FRAME_MAKER_POS,		0x0000, 0 },
+	{ EXT_DISP_IFACE_CTRL_2,	0x0002, 0 },
+	{ POWER_CTRL_2,			0x0007, 0 },
+	{ POWER_CTRL_3,			0x0000, 0 },
+	{ POWER_CTRL_4,			0x0000, 200 },
+	{ DISPLAY_CTRL_1,		0x0101, 0 },
+	{ POWER_CTRL_1,			0x12B0, 0 },
+	{ POWER_CTRL_2,			0x0007, 0 },
+	{ POWER_CTRL_3,			0x01BB, 50 },
+	{ POWER_CTRL_4,			0x0013, 0 },
+	{ POWER_CTRL_7,			0x0010, 50 },
+	{ GAMMA_CTRL_1,			0x000A, 0 },
+	{ GAMMA_CTRL_2,			0x1326, 0 },
+	{ GAMMA_CTRL_3,			0x0A29, 0 },
+	{ GAMMA_CTRL_4,			0x0A0A, 0 },
+	{ GAMMA_CTRL_5,			0x1E03, 0 },
+	{ GAMMA_CTRL_6,			0x031E, 0 },
+	{ GAMMA_CTRL_7,			0x0706, 0 },
+	{ GAMMA_CTRL_8,			0x0303, 0 },
+	{ GAMMA_CTRL_9,			0x010E, 0 },
+	{ GAMMA_CTRL_10,		0x040E, 0 },
+	{ WINDOW_HORIZ_RAM_START,	0x0000, 0 },
+	{ WINDOW_HORIZ_RAM_END,		0x00EF, 0 },
+	{ WINDOW_VERT_RAM_START,	0x0000, 0 },
+	{ WINDOW_VERT_RAM_END,		0x013F, 0 },
+	{ DRIVER_OUTPUT_CTRL_2,		0x2700, 0 },
+	{ BASE_IMG_DISPLAY_CTRL,	0x0001, 0 },
+	{ VERT_SCROLL_CTRL,		0x0000, 0 },
+	{ PD1_DISPLAY_POS,		0x0000, 0 },
+	{ PD1_RAM_START,		0x0000, 0 },
+	{ PD1_RAM_END,			0x0000, 0 },
+	{ PD2_DISPLAY_POS,		0x0000, 0 },
+	{ PD2_RAM_START,		0x0000, 0 },
+	{ PD2_RAM_END,			0x0000, 0 },
+	{ PANEL_IFACE_CTRL_1,		0x0010, 0 },
+	{ PANEL_IFACE_CTRL_2,		0x0000, 0 },
+	{ PANEL_IFACE_CTRL_4,		0x0210, 0 },
+	{ PANEL_IFACE_CTRL_5,		0x0000, 0 },
+	{ DISPLAY_CTRL_1,		0x0133, 0 },
+};
+
+static struct otm3225a_spi_instruction display_enable_rgb_interface[] = {
+	{ ENTRY_MODE,			0x1080, 0 },
+	{ GRAM_ADDR_HORIZ_SET,		0x0000, 0 },
+	{ GRAM_ADDR_VERT_SET,		0x0000, 0 },
+	{ EXT_DISP_IFACE_CTRL_1,	0x0111, 500 },
+};
+
+static struct otm3225a_spi_instruction display_off[] = {
+	{ DISPLAY_CTRL_1,	0x0131, 100 },
+	{ DISPLAY_CTRL_1,	0x0130, 100 },
+	{ DISPLAY_CTRL_1,	0x0100, 0 },
+	{ POWER_CTRL_1,		0x0280, 0 },
+	{ POWER_CTRL_3,		0x018B, 0 },
+};
+
+static struct otm3225a_spi_instruction display_on[] = {
+	{ POWER_CTRL_1,		0x1280, 0 },
+	{ DISPLAY_CTRL_1,	0x0101, 100 },
+	{ DISPLAY_CTRL_1,	0x0121, 0 },
+	{ DISPLAY_CTRL_1,	0x0123, 100 },
+	{ DISPLAY_CTRL_1,	0x0133, 10 },
+};
+
+static void otm3225a_write(struct spi_device *spi,
+			   struct otm3225a_spi_instruction *instruction,
+			   unsigned int count)
+{
+	unsigned char buf[3];
+
+	while (count--) {
+		/* address register using index register */
+		buf[0] = OTM3225A_INDEX_REG;
+		buf[1] = 0x00;
+		buf[2] = instruction->reg;
+		spi_write(spi, buf, 3);
+
+		/* write data to addressed register */
+		buf[0] = OTM3225A_DATA_REG;
+		buf[1] = (instruction->value >> 8) & 0xff;
+		buf[2] = instruction->value & 0xff;
+		spi_write(spi, buf, 3);
+
+		/* execute delay if any */
+		if (instruction->delay)
+			msleep(instruction->delay);
+		instruction++;
+	}
+}
+
+static int otm3225a_set_power(struct lcd_device *ld, int power)
+{
+	struct otm3225a_data *dd = lcd_get_data(ld);
+
+	if (power == dd->power)
+		return 0;
+
+	if (power > FB_BLANK_UNBLANK)
+		otm3225a_write(dd->spi, display_off, ARRAY_SIZE(display_off));
+	else
+		otm3225a_write(dd->spi, display_on, ARRAY_SIZE(display_on));
+	dd->power = power;
+
+	return 0;
+}
+
+static int otm3225a_get_power(struct lcd_device *ld)
+{
+	struct otm3225a_data *dd = lcd_get_data(ld);
+
+	return dd->power;
+}
+
+static struct lcd_ops otm3225a_ops = {
+	.set_power = otm3225a_set_power,
+	.get_power = otm3225a_get_power,
+};
+
+static int otm3225a_probe(struct spi_device *spi)
+{
+	struct otm3225a_data *dd;
+	struct lcd_device *ld;
+	struct device *dev = &spi->dev;
+
+	dd = devm_kzalloc(dev, sizeof(struct otm3225a_data), GFP_KERNEL);
+	if (dd == NULL)
+		return -ENOMEM;
+
+	ld = devm_lcd_device_register(dev, dev_name(dev), dev, dd,
+				      &otm3225a_ops);
+	if (IS_ERR(ld))
+		return PTR_ERR(ld);
+
+	dd->spi = spi;
+	dd->ld = ld;
+	dev_set_drvdata(dev, dd);
+
+	dev_info(dev, "Initializing and switching to RGB interface");
+	otm3225a_write(spi, display_init, ARRAY_SIZE(display_init));
+	otm3225a_write(spi, display_enable_rgb_interface,
+		       ARRAY_SIZE(display_enable_rgb_interface));
+	return 0;
+}
+
+static struct spi_driver otm3225a_driver = {
+	.driver = {
+		.name = "otm3225a",
+		.owner = THIS_MODULE,
+	},
+	.probe = otm3225a_probe,
+};
+
+module_spi_driver(otm3225a_driver);
+
+MODULE_AUTHOR("Felix Brack <fb@ltec.ch>");
+MODULE_DESCRIPTION("OTM3225A TFT LCD driver");
+MODULE_VERSION("1.0.0");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/video/backlight/pandora_bl.c b/drivers/video/backlight/pandora_bl.c
index a186bc6..9618766 100644
--- a/drivers/video/backlight/pandora_bl.c
+++ b/drivers/video/backlight/pandora_bl.c
@@ -35,11 +35,15 @@
 #define MAX_VALUE 63
 #define MAX_USER_VALUE (MAX_VALUE - MIN_VALUE)
 
-#define PANDORABL_WAS_OFF BL_CORE_DRIVER1
+struct pandora_private {
+	unsigned old_state;
+#define PANDORABL_WAS_OFF 1
+};
 
 static int pandora_backlight_update_status(struct backlight_device *bl)
 {
 	int brightness = bl->props.brightness;
+	struct pandora_private *priv = bl_get_data(bl);
 	u8 r;
 
 	if (bl->props.power != FB_BLANK_UNBLANK)
@@ -53,7 +57,7 @@
 		brightness = MAX_USER_VALUE;
 
 	if (brightness == 0) {
-		if (bl->props.state & PANDORABL_WAS_OFF)
+		if (priv->old_state == PANDORABL_WAS_OFF)
 			goto done;
 
 		/* first disable PWM0 output, then clock */
@@ -66,7 +70,7 @@
 		goto done;
 	}
 
-	if (bl->props.state & PANDORABL_WAS_OFF) {
+	if (priv->old_state == PANDORABL_WAS_OFF) {
 		/*
 		 * set PWM duty cycle to max. TPS61161 seems to use this
 		 * to calibrate it's PWM sensitivity when it starts.
@@ -93,9 +97,9 @@
 
 done:
 	if (brightness != 0)
-		bl->props.state &= ~PANDORABL_WAS_OFF;
+		priv->old_state = 0;
 	else
-		bl->props.state |= PANDORABL_WAS_OFF;
+		priv->old_state = PANDORABL_WAS_OFF;
 
 	return 0;
 }
@@ -109,13 +113,20 @@
 {
 	struct backlight_properties props;
 	struct backlight_device *bl;
+	struct pandora_private *priv;
 	u8 r;
 
+	priv = devm_kmalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv) {
+		dev_err(&pdev->dev, "failed to allocate driver private data\n");
+		return -ENOMEM;
+	}
+
 	memset(&props, 0, sizeof(props));
 	props.max_brightness = MAX_USER_VALUE;
 	props.type = BACKLIGHT_RAW;
 	bl = devm_backlight_device_register(&pdev->dev, pdev->name, &pdev->dev,
-					NULL, &pandora_backlight_ops, &props);
+					priv, &pandora_backlight_ops, &props);
 	if (IS_ERR(bl)) {
 		dev_err(&pdev->dev, "failed to register backlight\n");
 		return PTR_ERR(bl);
@@ -126,7 +137,7 @@
 	/* 64 cycle period, ON position 0 */
 	twl_i2c_write_u8(TWL_MODULE_PWM, 0x80, TWL_PWM0_ON);
 
-	bl->props.state |= PANDORABL_WAS_OFF;
+	priv->old_state = PANDORABL_WAS_OFF;
 	bl->props.brightness = MAX_USER_VALUE;
 	backlight_update_status(bl);
 
diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
index 1c2289d..44ac5bd 100644
--- a/drivers/video/backlight/pwm_bl.c
+++ b/drivers/video/backlight/pwm_bl.c
@@ -10,6 +10,7 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/delay.h>
 #include <linux/gpio/consumer.h>
 #include <linux/gpio.h>
 #include <linux/module.h>
@@ -35,6 +36,8 @@
 	struct gpio_desc	*enable_gpio;
 	unsigned int		scale;
 	bool			legacy;
+	unsigned int		post_pwm_on_delay;
+	unsigned int		pwm_off_delay;
 	int			(*notify)(struct device *,
 					  int brightness);
 	void			(*notify_after)(struct device *,
@@ -54,10 +57,14 @@
 	if (err < 0)
 		dev_err(pb->dev, "failed to enable power supply\n");
 
+	pwm_enable(pb->pwm);
+
+	if (pb->post_pwm_on_delay)
+		msleep(pb->post_pwm_on_delay);
+
 	if (pb->enable_gpio)
 		gpiod_set_value_cansleep(pb->enable_gpio, 1);
 
-	pwm_enable(pb->pwm);
 	pb->enabled = true;
 }
 
@@ -66,12 +73,15 @@
 	if (!pb->enabled)
 		return;
 
-	pwm_config(pb->pwm, 0, pb->period);
-	pwm_disable(pb->pwm);
-
 	if (pb->enable_gpio)
 		gpiod_set_value_cansleep(pb->enable_gpio, 0);
 
+	if (pb->pwm_off_delay)
+		msleep(pb->pwm_off_delay);
+
+	pwm_config(pb->pwm, 0, pb->period);
+	pwm_disable(pb->pwm);
+
 	regulator_disable(pb->power_supply);
 	pb->enabled = false;
 }
@@ -177,6 +187,14 @@
 		data->max_brightness--;
 	}
 
+	/*
+	 * These values are optional and set as 0 by default, the out values
+	 * are modified only if a valid u32 value can be decoded.
+	 */
+	of_property_read_u32(node, "post-pwm-on-delay-ms",
+			     &data->post_pwm_on_delay);
+	of_property_read_u32(node, "pwm-off-delay-ms", &data->pwm_off_delay);
+
 	data->enable_gpio = -EINVAL;
 	return 0;
 }
@@ -275,6 +293,8 @@
 	pb->exit = data->exit;
 	pb->dev = &pdev->dev;
 	pb->enabled = false;
+	pb->post_pwm_on_delay = data->post_pwm_on_delay;
+	pb->pwm_off_delay = data->pwm_off_delay;
 
 	pb->enable_gpio = devm_gpiod_get_optional(&pdev->dev, "enable",
 						  GPIOD_ASIS);
@@ -301,14 +321,14 @@
 
 	/*
 	 * If the GPIO is not known to be already configured as output, that
-	 * is, if gpiod_get_direction returns either GPIOF_DIR_IN or -EINVAL,
-	 * change the direction to output and set the GPIO as active.
+	 * is, if gpiod_get_direction returns either 1 or -EINVAL, change the
+	 * direction to output and set the GPIO as active.
 	 * Do not force the GPIO to active when it was already output as it
 	 * could cause backlight flickering or we would enable the backlight too
 	 * early. Leave the decision of the initial backlight state for later.
 	 */
 	if (pb->enable_gpio &&
-	    gpiod_get_direction(pb->enable_gpio) != GPIOF_DIR_OUT)
+	    gpiod_get_direction(pb->enable_gpio) != 0)
 		gpiod_direction_output(pb->enable_gpio, 1);
 
 	pb->power_supply = devm_regulator_get(&pdev->dev, "power");
diff --git a/drivers/video/backlight/rave-sp-backlight.c b/drivers/video/backlight/rave-sp-backlight.c
new file mode 100644
index 0000000..462f14a
--- /dev/null
+++ b/drivers/video/backlight/rave-sp-backlight.c
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/*
+ * LCD Backlight driver for RAVE SP
+ *
+ * Copyright (C) 2018 Zodiac Inflight Innovations
+ *
+ */
+
+#include <linux/backlight.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mfd/rave-sp.h>
+#include <linux/platform_device.h>
+
+#define	RAVE_SP_BACKLIGHT_LCD_EN	BIT(7)
+
+static int rave_sp_backlight_update_status(struct backlight_device *bd)
+{
+	const struct backlight_properties *p = &bd->props;
+	const u8 intensity =
+		(p->power == FB_BLANK_UNBLANK) ? p->brightness : 0;
+	struct rave_sp *sp = dev_get_drvdata(&bd->dev);
+	u8 cmd[] = {
+		[0] = RAVE_SP_CMD_SET_BACKLIGHT,
+		[1] = 0,
+		[2] = intensity ? RAVE_SP_BACKLIGHT_LCD_EN | intensity : 0,
+		[3] = 0,
+		[4] = 0,
+	};
+
+	return rave_sp_exec(sp, cmd, sizeof(cmd), NULL, 0);
+}
+
+static const struct backlight_ops rave_sp_backlight_ops = {
+	.options	= BL_CORE_SUSPENDRESUME,
+	.update_status	= rave_sp_backlight_update_status,
+};
+
+static struct backlight_properties rave_sp_backlight_props = {
+	.type		= BACKLIGHT_PLATFORM,
+	.max_brightness = 100,
+	.brightness	= 50,
+};
+
+static int rave_sp_backlight_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct backlight_device *bd;
+
+	bd = devm_backlight_device_register(dev, pdev->name, dev->parent,
+					    dev_get_drvdata(dev->parent),
+					    &rave_sp_backlight_ops,
+					    &rave_sp_backlight_props);
+	if (IS_ERR(bd))
+		return PTR_ERR(bd);
+
+	backlight_update_status(bd);
+
+	return 0;
+}
+
+static const struct of_device_id rave_sp_backlight_of_match[] = {
+	{ .compatible = "zii,rave-sp-backlight" },
+	{}
+};
+
+static struct platform_driver rave_sp_backlight_driver = {
+	.probe = rave_sp_backlight_probe,
+	.driver	= {
+		.name = KBUILD_MODNAME,
+		.of_match_table = rave_sp_backlight_of_match,
+	},
+};
+module_platform_driver(rave_sp_backlight_driver);
+
+MODULE_DEVICE_TABLE(of, rave_sp_backlight_of_match);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Andrey Vostrikov <andrey.vostrikov@cogentembedded.com>");
+MODULE_AUTHOR("Nikita Yushchenko <nikita.yoush@cogentembedded.com>");
+MODULE_AUTHOR("Andrey Smirnov <andrew.smirnov@gmail.com>");
+MODULE_DESCRIPTION("RAVE SP Backlight driver");
diff --git a/drivers/video/backlight/tps65217_bl.c b/drivers/video/backlight/tps65217_bl.c
index 380917c..762e3fe 100644
--- a/drivers/video/backlight/tps65217_bl.c
+++ b/drivers/video/backlight/tps65217_bl.c
@@ -184,11 +184,11 @@
 tps65217_bl_parse_dt(struct platform_device *pdev)
 {
 	struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent);
-	struct device_node *node = of_node_get(tps->dev->of_node);
+	struct device_node *node;
 	struct tps65217_bl_pdata *pdata, *err;
 	u32 val;
 
-	node = of_find_node_by_name(node, "backlight");
+	node = of_get_child_by_name(tps->dev->of_node, "backlight");
 	if (!node)
 		return ERR_PTR(-ENODEV);
 
diff --git a/include/linux/backlight.h b/include/linux/backlight.h
index 2baab6f..7fbf053 100644
--- a/include/linux/backlight.h
+++ b/include/linux/backlight.h
@@ -84,10 +84,6 @@
 
 #define BL_CORE_SUSPENDED	(1 << 0)	/* backlight is suspended */
 #define BL_CORE_FBBLANK		(1 << 1)	/* backlight is under an fb blank event */
-#define BL_CORE_DRIVER4		(1 << 28)	/* reserved for driver specific use */
-#define BL_CORE_DRIVER3		(1 << 29)	/* reserved for driver specific use */
-#define BL_CORE_DRIVER2		(1 << 30)	/* reserved for driver specific use */
-#define BL_CORE_DRIVER1		(1 << 31)	/* reserved for driver specific use */
 
 };
 
diff --git a/include/linux/mfd/as3711.h b/include/linux/mfd/as3711.h
index 34cc858..ddd0b95 100644
--- a/include/linux/mfd/as3711.h
+++ b/include/linux/mfd/as3711.h
@@ -108,9 +108,9 @@
 };
 
 struct as3711_bl_pdata {
-	const char *su1_fb;
+	bool su1_fb;
 	int su1_max_uA;
-	const char *su2_fb;
+	bool su2_fb;
 	int su2_max_uA;
 	enum as3711_su2_feedback su2_feedback;
 	enum as3711_su2_fbprot su2_fbprot;
diff --git a/include/linux/mfd/rave-sp.h b/include/linux/mfd/rave-sp.h
index 796fb97..fe0ce7b 100644
--- a/include/linux/mfd/rave-sp.h
+++ b/include/linux/mfd/rave-sp.h
@@ -21,6 +21,7 @@
 	RAVE_SP_CMD_STATUS			= 0xA0,
 	RAVE_SP_CMD_SW_WDT			= 0xA1,
 	RAVE_SP_CMD_PET_WDT			= 0xA2,
+	RAVE_SP_CMD_SET_BACKLIGHT		= 0xA6,
 	RAVE_SP_CMD_RESET			= 0xA7,
 	RAVE_SP_CMD_RESET_REASON		= 0xA8,
 
diff --git a/include/linux/pwm_backlight.h b/include/linux/pwm_backlight.h
index e8afbd7..8ea265a 100644
--- a/include/linux/pwm_backlight.h
+++ b/include/linux/pwm_backlight.h
@@ -14,6 +14,8 @@
 	unsigned int lth_brightness;
 	unsigned int pwm_period_ns;
 	unsigned int *levels;
+	unsigned int post_pwm_on_delay;
+	unsigned int pwm_off_delay;
 	/* TODO remove once all users are switched to gpiod_* API */
 	int enable_gpio;
 	int (*init)(struct device *dev);