Commit 0f105cf4 authored by Linus Torvalds's avatar Linus Torvalds

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
parents 883cad5b d5318d30
...@@ -17,6 +17,10 @@ Optional properties: ...@@ -17,6 +17,10 @@ Optional properties:
"pwms" property (see PWM binding[0]) "pwms" property (see PWM binding[0])
- enable-gpios: contains a single GPIO specifier for the GPIO which enables - enable-gpios: contains a single GPIO specifier for the GPIO which enables
and disables the backlight (see GPIO binding[1]) 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 [0]: Documentation/devicetree/bindings/pwm/pwm.txt
[1]: Documentation/devicetree/bindings/gpio/gpio.txt [1]: Documentation/devicetree/bindings/gpio/gpio.txt
...@@ -32,4 +36,6 @@ Example: ...@@ -32,4 +36,6 @@ Example:
power-supply = <&vdd_bl_reg>; power-supply = <&vdd_bl_reg>;
enable-gpios = <&gpio 58 0>; enable-gpios = <&gpio 58 0>;
post-pwm-on-delay-ms = <10>;
pwm-off-delay-ms = <10>;
}; };
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";
};
}
...@@ -2606,6 +2606,7 @@ BACKLIGHT CLASS/SUBSYSTEM ...@@ -2606,6 +2606,7 @@ BACKLIGHT CLASS/SUBSYSTEM
M: Lee Jones <lee.jones@linaro.org> M: Lee Jones <lee.jones@linaro.org>
M: Daniel Thompson <daniel.thompson@linaro.org> M: Daniel Thompson <daniel.thompson@linaro.org>
M: Jingoo Han <jingoohan1@gmail.com> 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 T: git git://git.kernel.org/pub/scm/linux/kernel/git/lee/backlight.git
S: Maintained S: Maintained
F: drivers/video/backlight/ F: drivers/video/backlight/
......
...@@ -246,7 +246,7 @@ static int fbtft_request_gpios_dt(struct fbtft_par *par) ...@@ -246,7 +246,7 @@ static int fbtft_request_gpios_dt(struct fbtft_par *par)
static int fbtft_backlight_update_status(struct backlight_device *bd) static int fbtft_backlight_update_status(struct backlight_device *bd)
{ {
struct fbtft_par *par = bl_get_data(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, fbtft_par_dbg(DEBUG_BACKLIGHT, par,
"%s: polarity=%d, power=%d, fb_blank=%d\n", "%s: polarity=%d, power=%d, fb_blank=%d\n",
...@@ -296,7 +296,7 @@ void fbtft_register_backlight(struct fbtft_par *par) ...@@ -296,7 +296,7 @@ void fbtft_register_backlight(struct fbtft_par *par)
/* Assume backlight is off, get polarity from current state of pin */ /* Assume backlight is off, get polarity from current state of pin */
bl_props.power = FB_BLANK_POWERDOWN; bl_props.power = FB_BLANK_POWERDOWN;
if (!gpio_get_value(par->gpio.led[0])) 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), bd = backlight_device_register(dev_driver_string(par->info->device),
par->info->device, par, par->info->device, par,
......
...@@ -229,6 +229,7 @@ struct fbtft_par { ...@@ -229,6 +229,7 @@ struct fbtft_par {
ktime_t update_time; ktime_t update_time;
bool bgr; bool bgr;
void *extra; void *extra;
bool polarity;
}; };
#define NUMARGS(...) (sizeof((int[]){__VA_ARGS__})/sizeof(int)) #define NUMARGS(...) (sizeof((int[]){__VA_ARGS__})/sizeof(int))
......
...@@ -150,6 +150,13 @@ config LCD_HX8357 ...@@ -150,6 +150,13 @@ config LCD_HX8357
If you have a HX-8357 LCD panel, say Y to enable its LCD control If you have a HX-8357 LCD panel, say Y to enable its LCD control
driver. 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 endif # LCD_CLASS_DEVICE
# #
...@@ -467,6 +474,12 @@ config BACKLIGHT_ARCXCNN ...@@ -467,6 +474,12 @@ config BACKLIGHT_ARCXCNN
If you have an ARCxCnnnn family backlight say Y to enable If you have an ARCxCnnnn family backlight say Y to enable
the backlight driver. 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_CLASS_DEVICE
endif # BACKLIGHT_LCD_SUPPORT endif # BACKLIGHT_LCD_SUPPORT
...@@ -13,6 +13,7 @@ obj-$(CONFIG_LCD_LD9040) += ld9040.o ...@@ -13,6 +13,7 @@ obj-$(CONFIG_LCD_LD9040) += ld9040.o
obj-$(CONFIG_LCD_LMS283GF05) += lms283gf05.o obj-$(CONFIG_LCD_LMS283GF05) += lms283gf05.o
obj-$(CONFIG_LCD_LMS501KF03) += lms501kf03.o obj-$(CONFIG_LCD_LMS501KF03) += lms501kf03.o
obj-$(CONFIG_LCD_LTV350QV) += ltv350qv.o obj-$(CONFIG_LCD_LTV350QV) += ltv350qv.o
obj-$(CONFIG_LCD_OTM3225A) += otm3225a.o
obj-$(CONFIG_LCD_PLATFORM) += platform_lcd.o obj-$(CONFIG_LCD_PLATFORM) += platform_lcd.o
obj-$(CONFIG_LCD_S6E63M0) += s6e63m0.o obj-$(CONFIG_LCD_S6E63M0) += s6e63m0.o
obj-$(CONFIG_LCD_TDO24M) += tdo24m.o obj-$(CONFIG_LCD_TDO24M) += tdo24m.o
...@@ -57,3 +58,4 @@ obj-$(CONFIG_BACKLIGHT_TOSA) += tosa_bl.o ...@@ -57,3 +58,4 @@ obj-$(CONFIG_BACKLIGHT_TOSA) += tosa_bl.o
obj-$(CONFIG_BACKLIGHT_TPS65217) += tps65217_bl.o obj-$(CONFIG_BACKLIGHT_TPS65217) += tps65217_bl.o
obj-$(CONFIG_BACKLIGHT_WM831X) += wm831x_bl.o obj-$(CONFIG_BACKLIGHT_WM831X) += wm831x_bl.o
obj-$(CONFIG_BACKLIGHT_ARCXCNN) += arcxcnn_bl.o obj-$(CONFIG_BACKLIGHT_ARCXCNN) += arcxcnn_bl.o
obj-$(CONFIG_BACKLIGHT_RAVE_SP) += rave-sp-backlight.o
...@@ -28,8 +28,6 @@ enum as3711_bl_type { ...@@ -28,8 +28,6 @@ enum as3711_bl_type {
struct as3711_bl_data { struct as3711_bl_data {
bool powered; bool powered;
const char *fb_name;
struct device *fb_dev;
enum as3711_bl_type type; enum as3711_bl_type type;
int brightness; int brightness;
struct backlight_device *bl; struct backlight_device *bl;
...@@ -262,10 +260,10 @@ static int as3711_bl_register(struct platform_device *pdev, ...@@ -262,10 +260,10 @@ static int as3711_bl_register(struct platform_device *pdev,
static int as3711_backlight_parse_dt(struct device *dev) static int as3711_backlight_parse_dt(struct device *dev)
{ {
struct as3711_bl_pdata *pdata = dev_get_platdata(dev); struct as3711_bl_pdata *pdata = dev_get_platdata(dev);
struct device_node *bl = struct device_node *bl, *fb;
of_find_node_by_name(dev->parent->of_node, "backlight"), *fb;
int ret; int ret;
bl = of_get_child_by_name(dev->parent->of_node, "backlight");
if (!bl) { if (!bl) {
dev_dbg(dev, "backlight node not found\n"); dev_dbg(dev, "backlight node not found\n");
return -ENODEV; return -ENODEV;
...@@ -273,26 +271,30 @@ static int as3711_backlight_parse_dt(struct device *dev) ...@@ -273,26 +271,30 @@ static int as3711_backlight_parse_dt(struct device *dev)
fb = of_parse_phandle(bl, "su1-dev", 0); fb = of_parse_phandle(bl, "su1-dev", 0);
if (fb) { 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); ret = of_property_read_u32(bl, "su1-max-uA", &pdata->su1_max_uA);
if (pdata->su1_max_uA <= 0) if (pdata->su1_max_uA <= 0)
ret = -EINVAL; ret = -EINVAL;
if (ret < 0) if (ret < 0)
return ret; goto err_put_bl;
} }
fb = of_parse_phandle(bl, "su2-dev", 0); fb = of_parse_phandle(bl, "su2-dev", 0);
if (fb) { if (fb) {
int count = 0; 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); ret = of_property_read_u32(bl, "su2-max-uA", &pdata->su2_max_uA);
if (pdata->su2_max_uA <= 0) if (pdata->su2_max_uA <= 0)
ret = -EINVAL; ret = -EINVAL;
if (ret < 0) if (ret < 0)
return ret; goto err_put_bl;
if (of_find_property(bl, "su2-feedback-voltage", NULL)) { if (of_find_property(bl, "su2-feedback-voltage", NULL)) {
pdata->su2_feedback = AS3711_SU2_VOLTAGE; pdata->su2_feedback = AS3711_SU2_VOLTAGE;
...@@ -314,8 +316,10 @@ static int as3711_backlight_parse_dt(struct device *dev) ...@@ -314,8 +316,10 @@ static int as3711_backlight_parse_dt(struct device *dev)
pdata->su2_feedback = AS3711_SU2_CURR_AUTO; pdata->su2_feedback = AS3711_SU2_CURR_AUTO;
count++; count++;
} }
if (count != 1) if (count != 1) {
return -EINVAL; ret = -EINVAL;
goto err_put_bl;
}
count = 0; count = 0;
if (of_find_property(bl, "su2-fbprot-lx-sd4", NULL)) { if (of_find_property(bl, "su2-fbprot-lx-sd4", NULL)) {
...@@ -334,8 +338,10 @@ static int as3711_backlight_parse_dt(struct device *dev) ...@@ -334,8 +338,10 @@ static int as3711_backlight_parse_dt(struct device *dev)
pdata->su2_fbprot = AS3711_SU2_GPIO4; pdata->su2_fbprot = AS3711_SU2_GPIO4;
count++; count++;
} }
if (count != 1) if (count != 1) {
return -EINVAL; ret = -EINVAL;
goto err_put_bl;
}
count = 0; count = 0;
if (of_find_property(bl, "su2-auto-curr1", NULL)) { if (of_find_property(bl, "su2-auto-curr1", NULL)) {
...@@ -355,11 +361,20 @@ static int as3711_backlight_parse_dt(struct device *dev) ...@@ -355,11 +361,20 @@ static int as3711_backlight_parse_dt(struct device *dev)
* At least one su2-auto-curr* must be specified iff * At least one su2-auto-curr* must be specified iff
* AS3711_SU2_CURR_AUTO is used * AS3711_SU2_CURR_AUTO is used
*/ */
if (!count ^ (pdata->su2_feedback != AS3711_SU2_CURR_AUTO)) if (!count ^ (pdata->su2_feedback != AS3711_SU2_CURR_AUTO)) {
return -EINVAL; ret = -EINVAL;
goto err_put_bl;
}
} }
of_node_put(bl);
return 0; return 0;
err_put_bl:
of_node_put(bl);
return ret;
} }
static int as3711_backlight_probe(struct platform_device *pdev) static int as3711_backlight_probe(struct platform_device *pdev)
...@@ -412,7 +427,6 @@ static int as3711_backlight_probe(struct platform_device *pdev) ...@@ -412,7 +427,6 @@ static int as3711_backlight_probe(struct platform_device *pdev)
if (pdata->su1_fb) { if (pdata->su1_fb) {
su = &supply->su1; su = &supply->su1;
su->fb_name = pdata->su1_fb;
su->type = AS3711_BL_SU1; su->type = AS3711_BL_SU1;
max_brightness = min(pdata->su1_max_uA, 31); max_brightness = min(pdata->su1_max_uA, 31);
...@@ -423,7 +437,6 @@ static int as3711_backlight_probe(struct platform_device *pdev) ...@@ -423,7 +437,6 @@ static int as3711_backlight_probe(struct platform_device *pdev)
if (pdata->su2_fb) { if (pdata->su2_fb) {
su = &supply->su2; su = &supply->su2;
su->fb_name = pdata->su2_fb;
su->type = AS3711_BL_SU2; su->type = AS3711_BL_SU2;
switch (pdata->su2_fbprot) { switch (pdata->su2_fbprot) {
......
...@@ -21,9 +21,6 @@ static int genericbl_intensity; ...@@ -21,9 +21,6 @@ static int genericbl_intensity;
static struct backlight_device *generic_backlight_device; static struct backlight_device *generic_backlight_device;
static struct generic_bl_info *bl_machinfo; 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) static int genericbl_send_intensity(struct backlight_device *bd)
{ {
int intensity = bd->props.brightness; int intensity = bd->props.brightness;
...@@ -34,8 +31,6 @@ static int genericbl_send_intensity(struct backlight_device *bd) ...@@ -34,8 +31,6 @@ static int genericbl_send_intensity(struct backlight_device *bd)
intensity = 0; intensity = 0;
if (bd->props.state & BL_CORE_SUSPENDED) if (bd->props.state & BL_CORE_SUSPENDED)
intensity = 0; intensity = 0;
if (bd->props.state & GENERICBL_BATTLOW)
intensity &= bl_machinfo->limit_mask;
bl_machinfo->set_bl_intensity(intensity); bl_machinfo->set_bl_intensity(intensity);
......
...@@ -116,7 +116,7 @@ static void max8925_backlight_dt_init(struct platform_device *pdev) ...@@ -116,7 +116,7 @@ static void max8925_backlight_dt_init(struct platform_device *pdev)
if (!pdata) if (!pdata)
return; return;
np = of_find_node_by_name(nproot, "backlight"); np = of_get_child_by_name(nproot, "backlight");
if (!np) { if (!np) {
dev_err(&pdev->dev, "failed to find backlight node\n"); dev_err(&pdev->dev, "failed to find backlight node\n");
return; return;
...@@ -125,6 +125,8 @@ static void max8925_backlight_dt_init(struct platform_device *pdev) ...@@ -125,6 +125,8 @@ static void max8925_backlight_dt_init(struct platform_device *pdev)
if (!of_property_read_u32(np, "maxim,max8925-dual-string", &val)) if (!of_property_read_u32(np, "maxim,max8925-dual-string", &val))
pdata->dual_string = val; pdata->dual_string = val;
of_node_put(np);
pdev->dev.platform_data = pdata; pdev->dev.platform_data = pdata;
} }
......
// 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");
...@@ -35,11 +35,15 @@ ...@@ -35,11 +35,15 @@
#define MAX_VALUE 63 #define MAX_VALUE 63
#define MAX_USER_VALUE (MAX_VALUE - MIN_VALUE) #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) static int pandora_backlight_update_status(struct backlight_device *bl)
{ {
int brightness = bl->props.brightness; int brightness = bl->props.brightness;
struct pandora_private *priv = bl_get_data(bl);
u8 r; u8 r;
if (bl->props.power != FB_BLANK_UNBLANK) if (bl->props.power != FB_BLANK_UNBLANK)
...@@ -53,7 +57,7 @@ static int pandora_backlight_update_status(struct backlight_device *bl) ...@@ -53,7 +57,7 @@ static int pandora_backlight_update_status(struct backlight_device *bl)
brightness = MAX_USER_VALUE; brightness = MAX_USER_VALUE;
if (brightness == 0) { if (brightness == 0) {
if (bl->props.state & PANDORABL_WAS_OFF) if (priv->old_state == PANDORABL_WAS_OFF)
goto done; goto done;
/* first disable PWM0 output, then clock */ /* first disable PWM0 output, then clock */
...@@ -66,7 +70,7 @@ static int pandora_backlight_update_status(struct backlight_device *bl) ...@@ -66,7 +70,7 @@ static int pandora_backlight_update_status(struct backlight_device *bl)
goto done; 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 * set PWM duty cycle to max. TPS61161 seems to use this
* to calibrate it's PWM sensitivity when it starts. * to calibrate it's PWM sensitivity when it starts.
...@@ -93,9 +97,9 @@ static int pandora_backlight_update_status(struct backlight_device *bl) ...@@ -93,9 +97,9 @@ static int pandora_backlight_update_status(struct backlight_device *bl)
done: done:
if (brightness != 0) if (brightness != 0)
bl->props.state &= ~PANDORABL_WAS_OFF; priv->old_state = 0;
else else
bl->props.state |= PANDORABL_WAS_OFF; priv->old_state = PANDORABL_WAS_OFF;
return 0; return 0;
} }
...@@ -109,13 +113,20 @@ static int pandora_backlight_probe(struct platform_device *pdev) ...@@ -109,13 +113,20 @@ static int pandora_backlight_probe(struct platform_device *pdev)
{ {
struct backlight_properties props; struct backlight_properties props;
struct backlight_device *bl; struct backlight_device *bl;
struct pandora_private *priv;
u8 r; 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)); memset(&props, 0, sizeof(props));
props.max_brightness = MAX_USER_VALUE; props.max_brightness = MAX_USER_VALUE;
props.type = BACKLIGHT_RAW; props.type = BACKLIGHT_RAW;
bl = devm_backlight_device_register(&pdev->dev, pdev->name, &pdev->dev, 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)) { if (IS_ERR(bl)) {
dev_err(&pdev->dev, "failed to register backlight\n"); dev_err(&pdev->dev, "failed to register backlight\n");
return PTR_ERR(bl); return PTR_ERR(bl);
...@@ -126,7 +137,7 @@ static int pandora_backlight_probe(struct platform_device *pdev) ...@@ -126,7 +137,7 @@ static int pandora_backlight_probe(struct platform_device *pdev)
/* 64 cycle period, ON position 0 */ /* 64 cycle period, ON position 0 */
twl_i2c_write_u8(TWL_MODULE_PWM, 0x80, TWL_PWM0_ON); 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; bl->props.brightness = MAX_USER_VALUE;
backlight_update_status(bl); backlight_update_status(bl);
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#include <linux/delay.h>
#include <linux/gpio/consumer.h> #include <linux/gpio/consumer.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -35,6 +36,8 @@ struct pwm_bl_data { ...@@ -35,6 +36,8 @@ struct pwm_bl_data {
struct gpio_desc *enable_gpio; struct gpio_desc *enable_gpio;
unsigned int scale; unsigned int scale;
bool legacy; bool legacy;
unsigned int post_pwm_on_delay;
unsigned int pwm_off_delay;
int (*notify)(struct device *, int (*notify)(struct device *,
int brightness); int brightness);
void (*notify_after)(struct device *, void (*notify_after)(struct device *,
...@@ -54,10 +57,14 @@ static void pwm_backlight_power_on(struct pwm_bl_data *pb, int brightness) ...@@ -54,10 +57,14 @@ static void pwm_backlight_power_on(struct pwm_bl_data *pb, int brightness)
if (err < 0) if (err < 0)
dev_err(pb->dev, "failed to enable power supply\n"); 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) if (pb->enable_gpio)
gpiod_set_value_cansleep(pb->enable_gpio, 1); gpiod_set_value_cansleep(pb->enable_gpio, 1);
pwm_enable(pb->pwm);
pb->enabled = true; pb->enabled = true;
} }
...@@ -66,12 +73,15 @@ static void pwm_backlight_power_off(struct pwm_bl_data *pb) ...@@ -66,12 +73,15 @@ static void pwm_backlight_power_off(struct pwm_bl_data *pb)
if (!pb->enabled) if (!pb->enabled)
return; return;
pwm_config(pb->pwm, 0, pb->period);
pwm_disable(pb->pwm);
if (pb->enable_gpio) if (pb->enable_gpio)
gpiod_set_value_cansleep(pb->enable_gpio, 0); 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); regulator_disable(pb->power_supply);
pb->enabled = false; pb->enabled = false;
} }
...@@ -177,6 +187,14 @@ static int pwm_backlight_parse_dt(struct device *dev, ...@@ -177,6 +187,14 @@ static int pwm_backlight_parse_dt(struct device *dev,
data->max_brightness--; 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; data->enable_gpio = -EINVAL;
return 0; return 0;
} }
...@@ -275,6 +293,8 @@ static int pwm_backlight_probe(struct platform_device *pdev) ...@@ -275,6 +293,8 @@ static int pwm_backlight_probe(struct platform_device *pdev)
pb->exit = data->exit; pb->exit = data->exit;
pb->dev = &pdev->dev; pb->dev = &pdev->dev;
pb->enabled = false; 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", pb->enable_gpio = devm_gpiod_get_optional(&pdev->dev, "enable",
GPIOD_ASIS); GPIOD_ASIS);
...@@ -301,14 +321,14 @@ static int pwm_backlight_probe(struct platform_device *pdev) ...@@ -301,14 +321,14 @@ static int pwm_backlight_probe(struct platform_device *pdev)
/* /*
* If the GPIO is not known to be already configured as output, that * 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, * is, if gpiod_get_direction returns either 1 or -EINVAL, change the
* change the direction to output and set the GPIO as active. * direction to output and set the GPIO as active.
* Do not force the GPIO to active when it was already output as it * 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 * could cause backlight flickering or we would enable the backlight too
* early. Leave the decision of the initial backlight state for later. * early. Leave the decision of the initial backlight state for later.
*/ */
if (pb->enable_gpio && 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); gpiod_direction_output(pb->enable_gpio, 1);
pb->power_supply = devm_regulator_get(&pdev->dev, "power"); pb->power_supply = devm_regulator_get(&pdev->dev, "power");
......
// 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");
...@@ -184,11 +184,11 @@ static struct tps65217_bl_pdata * ...@@ -184,11 +184,11 @@ static struct tps65217_bl_pdata *
tps65217_bl_parse_dt(struct platform_device *pdev) tps65217_bl_parse_dt(struct platform_device *pdev)
{ {
struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent); 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; struct tps65217_bl_pdata *pdata, *err;
u32 val; u32 val;
node = of_find_node_by_name(node, "backlight"); node = of_get_child_by_name(tps->dev->of_node, "backlight");
if (!node) if (!node)
return ERR_PTR(-ENODEV); return ERR_PTR(-ENODEV);
......
...@@ -84,10 +84,6 @@ struct backlight_properties { ...@@ -84,10 +84,6 @@ struct backlight_properties {
#define BL_CORE_SUSPENDED (1 << 0) /* backlight is suspended */ #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_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 */
}; };
......
...@@ -108,9 +108,9 @@ struct as3711_regulator_pdata { ...@@ -108,9 +108,9 @@ struct as3711_regulator_pdata {
}; };
struct as3711_bl_pdata { struct as3711_bl_pdata {
const char *su1_fb; bool su1_fb;
int su1_max_uA; int su1_max_uA;
const char *su2_fb; bool su2_fb;
int su2_max_uA; int su2_max_uA;
enum as3711_su2_feedback su2_feedback; enum as3711_su2_feedback su2_feedback;
enum as3711_su2_fbprot su2_fbprot; enum as3711_su2_fbprot su2_fbprot;
......
...@@ -21,6 +21,7 @@ enum rave_sp_command { ...@@ -21,6 +21,7 @@ enum rave_sp_command {
RAVE_SP_CMD_STATUS = 0xA0, RAVE_SP_CMD_STATUS = 0xA0,
RAVE_SP_CMD_SW_WDT = 0xA1, RAVE_SP_CMD_SW_WDT = 0xA1,
RAVE_SP_CMD_PET_WDT = 0xA2, RAVE_SP_CMD_PET_WDT = 0xA2,
RAVE_SP_CMD_SET_BACKLIGHT = 0xA6,
RAVE_SP_CMD_RESET = 0xA7, RAVE_SP_CMD_RESET = 0xA7,
RAVE_SP_CMD_RESET_REASON = 0xA8, RAVE_SP_CMD_RESET_REASON = 0xA8,
......
...@@ -14,6 +14,8 @@ struct platform_pwm_backlight_data { ...@@ -14,6 +14,8 @@ struct platform_pwm_backlight_data {
unsigned int lth_brightness; unsigned int lth_brightness;
unsigned int pwm_period_ns; unsigned int pwm_period_ns;
unsigned int *levels; unsigned int *levels;
unsigned int post_pwm_on_delay;
unsigned int pwm_off_delay;
/* TODO remove once all users are switched to gpiod_* API */ /* TODO remove once all users are switched to gpiod_* API */
int enable_gpio; int enable_gpio;
int (*init)(struct device *dev); int (*init)(struct device *dev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment