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:
"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 @@ Example:
power-supply = <&vdd_bl_reg>;
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
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/
......
......@@ -246,7 +246,7 @@ static int fbtft_request_gpios_dt(struct fbtft_par *par)
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 @@ void fbtft_register_backlight(struct fbtft_par *par)
/* 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,
......
......@@ -229,6 +229,7 @@ struct fbtft_par {
ktime_t update_time;
bool bgr;
void *extra;
bool polarity;
};
#define NUMARGS(...) (sizeof((int[]){__VA_ARGS__})/sizeof(int))
......
......@@ -150,6 +150,13 @@ config LCD_HX8357
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 @@ config BACKLIGHT_ARCXCNN
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
......@@ -13,6 +13,7 @@ obj-$(CONFIG_LCD_LD9040) += ld9040.o
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_TOSA) += tosa_bl.o
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
......@@ -28,8 +28,6 @@ enum as3711_bl_type {
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_bl_register(struct platform_device *pdev,
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 @@ static int as3711_backlight_parse_dt(struct device *dev)
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 @@ static int as3711_backlight_parse_dt(struct device *dev)
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 @@ static int as3711_backlight_parse_dt(struct device *dev)
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 @@ static int as3711_backlight_parse_dt(struct device *dev)
* 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 @@ static int as3711_backlight_probe(struct platform_device *pdev)
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 @@ static int as3711_backlight_probe(struct platform_device *pdev)
if (pdata->su2_fb) {
su = &supply->su2;
su->fb_name = pdata->su2_fb;
su->type = AS3711_BL_SU2;
switch (pdata->su2_fbprot) {
......
......@@ -21,9 +21,6 @@ static int genericbl_intensity;
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 @@ static int genericbl_send_intensity(struct backlight_device *bd)
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);
......
......@@ -116,7 +116,7 @@ static void max8925_backlight_dt_init(struct platform_device *pdev)
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 @@ static void max8925_backlight_dt_init(struct platform_device *pdev)
if (!of_property_read_u32(np, "maxim,max8925-dual-string", &val))
pdata->dual_string = val;
of_node_put(np);
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 @@
#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 @@ static int pandora_backlight_update_status(struct backlight_device *bl)
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 @@ static int pandora_backlight_update_status(struct backlight_device *bl)
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 @@ static int pandora_backlight_update_status(struct backlight_device *bl)
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 @@ static int pandora_backlight_probe(struct platform_device *pdev)
{
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 @@ static int pandora_backlight_probe(struct platform_device *pdev)
/* 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);
......
......@@ -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 pwm_bl_data {
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 @@ static void pwm_backlight_power_on(struct pwm_bl_data *pb, int brightness)
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 @@ static void pwm_backlight_power_off(struct pwm_bl_data *pb)
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 @@ static int pwm_backlight_parse_dt(struct device *dev,
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 @@ static int pwm_backlight_probe(struct platform_device *pdev)
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 @@ static int pwm_backlight_probe(struct platform_device *pdev)
/*
* 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");
......
// 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);