Commit d0b3cfee authored by Linus Torvalds's avatar Linus Torvalds

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

Pull backlight updates from Lee Jones:
 "Core Frameworks
   - Obtain scale type through sysfs

  New Functionality:
   - Provide Device Tree functionality in rave-sp-backlight
   - Calculate if scale type is (non-)linear in pwm_bl

  Fix-ups:
   - Simplify code in lm3630a_bl
   - Trivial rename/whitespace/typo fixes in lms283gf05
   - Remove superfluous NULL check in tosa_lcd
   - Fix power state initialisation in gpio_backlight
   - List supported file in MAINTAINERS

  Bug Fixes:
   - Kconfig - default to not building unless requested in
     {LED,BACKLIGHT}_CLASS_DEVICE"

* tag 'backlight-next-5.4' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/backlight:
  backlight: pwm_bl: Set scale type for brightness curves specified in the DT
  backlight: pwm_bl: Set scale type for CIE 1931 curves
  backlight: Expose brightness curve type through sysfs
  MAINTAINERS: Add entry for stable backlight sysfs ABI documentation
  backlight: gpio-backlight: Correct initial power state handling
  video: backlight: tosa_lcd: drop check because i2c_unregister_device() is NULL safe
  video: backlight: Drop default m for {LCD,BACKLIGHT_CLASS_DEVICE}
  backlight: lms283gf05: Fix a typo in the description passed to 'devm_gpio_request_one()'
  backlight: lm3630a: Switch to use fwnode_property_count_uXX()
  backlight: rave-sp: Leave initial state and register with correct device
parents 299d14d4 c0b64faf
What: /sys/class/backlight/<backlight>/scale
Date: July 2019
KernelVersion: 5.4
Contact: Daniel Thompson <daniel.thompson@linaro.org>
Description:
Description of the scale of the brightness curve.
The human eye senses brightness approximately logarithmically,
hence linear changes in brightness are perceived as being
non-linear. To achieve a linear perception of brightness changes
controls like sliders need to apply a logarithmic mapping for
backlights with a linear brightness curve.
Possible values of the attribute are:
unknown
The scale of the brightness curve is unknown.
linear
The brightness changes linearly with each step. Brightness
controls should apply a logarithmic mapping for a linear
perception.
non-linear
The brightness changes non-linearly with each step. Brightness
controls should use a linear mapping for a linear perception.
...@@ -2921,6 +2921,8 @@ F: drivers/video/backlight/ ...@@ -2921,6 +2921,8 @@ F: drivers/video/backlight/
F: include/linux/backlight.h F: include/linux/backlight.h
F: include/linux/pwm_backlight.h F: include/linux/pwm_backlight.h
F: Documentation/devicetree/bindings/leds/backlight F: Documentation/devicetree/bindings/leds/backlight
F: Documentation/ABI/stable/sysfs-class-backlight
F: Documentation/ABI/testing/sysfs-class-backlight
BATMAN ADVANCED BATMAN ADVANCED
M: Marek Lindner <mareklindner@neomailbox.ch> M: Marek Lindner <mareklindner@neomailbox.ch>
......
...@@ -10,7 +10,6 @@ menu "Backlight & LCD device support" ...@@ -10,7 +10,6 @@ menu "Backlight & LCD device support"
# #
config LCD_CLASS_DEVICE config LCD_CLASS_DEVICE
tristate "Lowlevel LCD controls" tristate "Lowlevel LCD controls"
default m
help help
This framework adds support for low-level control of LCD. This framework adds support for low-level control of LCD.
Some framebuffer devices connect to platform-specific LCD modules Some framebuffer devices connect to platform-specific LCD modules
...@@ -143,7 +142,6 @@ endif # LCD_CLASS_DEVICE ...@@ -143,7 +142,6 @@ endif # LCD_CLASS_DEVICE
# #
config BACKLIGHT_CLASS_DEVICE config BACKLIGHT_CLASS_DEVICE
tristate "Lowlevel Backlight controls" tristate "Lowlevel Backlight controls"
default m
help help
This framework adds support for low-level control of the LCD This framework adds support for low-level control of the LCD
backlight. This includes support for brightness and power. backlight. This includes support for brightness and power.
......
...@@ -32,6 +32,12 @@ static const char *const backlight_types[] = { ...@@ -32,6 +32,12 @@ static const char *const backlight_types[] = {
[BACKLIGHT_FIRMWARE] = "firmware", [BACKLIGHT_FIRMWARE] = "firmware",
}; };
static const char *const backlight_scale_types[] = {
[BACKLIGHT_SCALE_UNKNOWN] = "unknown",
[BACKLIGHT_SCALE_LINEAR] = "linear",
[BACKLIGHT_SCALE_NON_LINEAR] = "non-linear",
};
#if defined(CONFIG_FB) || (defined(CONFIG_FB_MODULE) && \ #if defined(CONFIG_FB) || (defined(CONFIG_FB_MODULE) && \
defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE)) defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE))
/* This callback gets called when something important happens inside a /* This callback gets called when something important happens inside a
...@@ -246,6 +252,18 @@ static ssize_t actual_brightness_show(struct device *dev, ...@@ -246,6 +252,18 @@ static ssize_t actual_brightness_show(struct device *dev,
} }
static DEVICE_ATTR_RO(actual_brightness); static DEVICE_ATTR_RO(actual_brightness);
static ssize_t scale_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct backlight_device *bd = to_backlight_device(dev);
if (WARN_ON(bd->props.scale > BACKLIGHT_SCALE_NON_LINEAR))
return sprintf(buf, "unknown\n");
return sprintf(buf, "%s\n", backlight_scale_types[bd->props.scale]);
}
static DEVICE_ATTR_RO(scale);
static struct class *backlight_class; static struct class *backlight_class;
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
...@@ -292,6 +310,7 @@ static struct attribute *bl_device_attrs[] = { ...@@ -292,6 +310,7 @@ static struct attribute *bl_device_attrs[] = {
&dev_attr_brightness.attr, &dev_attr_brightness.attr,
&dev_attr_actual_brightness.attr, &dev_attr_actual_brightness.attr,
&dev_attr_max_brightness.attr, &dev_attr_max_brightness.attr,
&dev_attr_scale.attr,
&dev_attr_type.attr, &dev_attr_type.attr,
NULL, NULL,
}; };
......
...@@ -59,13 +59,11 @@ static int gpio_backlight_probe_dt(struct platform_device *pdev, ...@@ -59,13 +59,11 @@ static int gpio_backlight_probe_dt(struct platform_device *pdev,
struct gpio_backlight *gbl) struct gpio_backlight *gbl)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
enum gpiod_flags flags;
int ret; int ret;
gbl->def_value = device_property_read_bool(dev, "default-on"); gbl->def_value = device_property_read_bool(dev, "default-on");
flags = gbl->def_value ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW;
gbl->gpiod = devm_gpiod_get(dev, NULL, flags); gbl->gpiod = devm_gpiod_get(dev, NULL, GPIOD_ASIS);
if (IS_ERR(gbl->gpiod)) { if (IS_ERR(gbl->gpiod)) {
ret = PTR_ERR(gbl->gpiod); ret = PTR_ERR(gbl->gpiod);
...@@ -79,6 +77,22 @@ static int gpio_backlight_probe_dt(struct platform_device *pdev, ...@@ -79,6 +77,22 @@ static int gpio_backlight_probe_dt(struct platform_device *pdev,
return 0; return 0;
} }
static int gpio_backlight_initial_power_state(struct gpio_backlight *gbl)
{
struct device_node *node = gbl->dev->of_node;
/* Not booted with device tree or no phandle link to the node */
if (!node || !node->phandle)
return gbl->def_value ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN;
/* if the enable GPIO is disabled, do not enable the backlight */
if (gpiod_get_value_cansleep(gbl->gpiod) == 0)
return FB_BLANK_POWERDOWN;
return FB_BLANK_UNBLANK;
}
static int gpio_backlight_probe(struct platform_device *pdev) static int gpio_backlight_probe(struct platform_device *pdev)
{ {
struct gpio_backlight_platform_data *pdata = struct gpio_backlight_platform_data *pdata =
...@@ -136,7 +150,9 @@ static int gpio_backlight_probe(struct platform_device *pdev) ...@@ -136,7 +150,9 @@ static int gpio_backlight_probe(struct platform_device *pdev)
return PTR_ERR(bl); return PTR_ERR(bl);
} }
bl->props.brightness = gbl->def_value; bl->props.power = gpio_backlight_initial_power_state(gbl);
bl->props.brightness = 1;
backlight_update_status(bl); backlight_update_status(bl);
platform_set_drvdata(pdev, bl); platform_set_drvdata(pdev, bl);
......
...@@ -377,8 +377,7 @@ static int lm3630a_parse_led_sources(struct fwnode_handle *node, ...@@ -377,8 +377,7 @@ static int lm3630a_parse_led_sources(struct fwnode_handle *node,
u32 sources[LM3630A_NUM_SINKS]; u32 sources[LM3630A_NUM_SINKS];
int ret, num_sources, i; int ret, num_sources, i;
num_sources = fwnode_property_read_u32_array(node, "led-sources", NULL, num_sources = fwnode_property_count_u32(node, "led-sources");
0);
if (num_sources < 0) if (num_sources < 0)
return default_led_sources; return default_led_sources;
else if (num_sources > ARRAY_SIZE(sources)) else if (num_sources > ARRAY_SIZE(sources))
......
...@@ -158,7 +158,7 @@ static int lms283gf05_probe(struct spi_device *spi) ...@@ -158,7 +158,7 @@ static int lms283gf05_probe(struct spi_device *spi)
ret = devm_gpio_request_one(&spi->dev, pdata->reset_gpio, ret = devm_gpio_request_one(&spi->dev, pdata->reset_gpio,
GPIOF_DIR_OUT | (!pdata->reset_inverted ? GPIOF_DIR_OUT | (!pdata->reset_inverted ?
GPIOF_INIT_HIGH : GPIOF_INIT_LOW), GPIOF_INIT_HIGH : GPIOF_INIT_LOW),
"LMS285GF05 RESET"); "LMS283GF05 RESET");
if (ret) if (ret)
return ret; return ret;
} }
......
...@@ -387,6 +387,31 @@ int pwm_backlight_brightness_default(struct device *dev, ...@@ -387,6 +387,31 @@ int pwm_backlight_brightness_default(struct device *dev,
} }
#endif #endif
static bool pwm_backlight_is_linear(struct platform_pwm_backlight_data *data)
{
unsigned int nlevels = data->max_brightness + 1;
unsigned int min_val = data->levels[0];
unsigned int max_val = data->levels[nlevels - 1];
/*
* Multiplying by 128 means that even in pathological cases such
* as (max_val - min_val) == nlevels the error at max_val is less
* than 1%.
*/
unsigned int slope = (128 * (max_val - min_val)) / nlevels;
unsigned int margin = (max_val - min_val) / 20; /* 5% */
int i;
for (i = 1; i < nlevels; i++) {
unsigned int linear_value = min_val + ((i * slope) / 128);
unsigned int delta = abs(linear_value - data->levels[i]);
if (delta > margin)
return false;
}
return true;
}
static int pwm_backlight_initial_power_state(const struct pwm_bl_data *pb) static int pwm_backlight_initial_power_state(const struct pwm_bl_data *pb)
{ {
struct device_node *node = pb->dev->of_node; struct device_node *node = pb->dev->of_node;
...@@ -536,6 +561,8 @@ static int pwm_backlight_probe(struct platform_device *pdev) ...@@ -536,6 +561,8 @@ static int pwm_backlight_probe(struct platform_device *pdev)
goto err_alloc; goto err_alloc;
} }
memset(&props, 0, sizeof(struct backlight_properties));
if (data->levels) { if (data->levels) {
/* /*
* For the DT case, only when brightness levels is defined * For the DT case, only when brightness levels is defined
...@@ -548,6 +575,11 @@ static int pwm_backlight_probe(struct platform_device *pdev) ...@@ -548,6 +575,11 @@ static int pwm_backlight_probe(struct platform_device *pdev)
pb->levels = data->levels; pb->levels = data->levels;
} }
if (pwm_backlight_is_linear(data))
props.scale = BACKLIGHT_SCALE_LINEAR;
else
props.scale = BACKLIGHT_SCALE_NON_LINEAR;
} else if (!data->max_brightness) { } else if (!data->max_brightness) {
/* /*
* If no brightness levels are provided and max_brightness is * If no brightness levels are provided and max_brightness is
...@@ -574,6 +606,8 @@ static int pwm_backlight_probe(struct platform_device *pdev) ...@@ -574,6 +606,8 @@ static int pwm_backlight_probe(struct platform_device *pdev)
pb->levels = data->levels; pb->levels = data->levels;
} }
props.scale = BACKLIGHT_SCALE_NON_LINEAR;
} else { } else {
/* /*
* That only happens for the non-DT case, where platform data * That only happens for the non-DT case, where platform data
...@@ -584,7 +618,6 @@ static int pwm_backlight_probe(struct platform_device *pdev) ...@@ -584,7 +618,6 @@ static int pwm_backlight_probe(struct platform_device *pdev)
pb->lth_brightness = data->lth_brightness * (state.period / pb->scale); pb->lth_brightness = data->lth_brightness * (state.period / pb->scale);
memset(&props, 0, sizeof(struct backlight_properties));
props.type = BACKLIGHT_RAW; props.type = BACKLIGHT_RAW;
props.max_brightness = data->max_brightness; props.max_brightness = data->max_brightness;
bl = backlight_device_register(dev_name(&pdev->dev), &pdev->dev, pb, bl = backlight_device_register(dev_name(&pdev->dev), &pdev->dev, pb,
......
...@@ -48,13 +48,19 @@ static int rave_sp_backlight_probe(struct platform_device *pdev) ...@@ -48,13 +48,19 @@ static int rave_sp_backlight_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct backlight_device *bd; struct backlight_device *bd;
bd = devm_backlight_device_register(dev, pdev->name, dev->parent, bd = devm_backlight_device_register(dev, pdev->name, dev,
dev_get_drvdata(dev->parent), dev_get_drvdata(dev->parent),
&rave_sp_backlight_ops, &rave_sp_backlight_ops,
&rave_sp_backlight_props); &rave_sp_backlight_props);
if (IS_ERR(bd)) if (IS_ERR(bd))
return PTR_ERR(bd); return PTR_ERR(bd);
/*
* If there is a phandle pointing to the device node we can
* assume that another device will manage the status changes.
* If not we make sure the backlight is in a consistent state.
*/
if (!dev->of_node->phandle)
backlight_update_status(bd); backlight_update_status(bd);
return 0; return 0;
......
...@@ -222,7 +222,6 @@ static int tosa_lcd_remove(struct spi_device *spi) ...@@ -222,7 +222,6 @@ static int tosa_lcd_remove(struct spi_device *spi)
{ {
struct tosa_lcd_data *data = spi_get_drvdata(spi); struct tosa_lcd_data *data = spi_get_drvdata(spi);
if (data->i2c)
i2c_unregister_device(data->i2c); i2c_unregister_device(data->i2c);
tosa_lcd_tg_off(data); tosa_lcd_tg_off(data);
......
...@@ -46,6 +46,12 @@ enum backlight_notification { ...@@ -46,6 +46,12 @@ enum backlight_notification {
BACKLIGHT_UNREGISTERED, BACKLIGHT_UNREGISTERED,
}; };
enum backlight_scale {
BACKLIGHT_SCALE_UNKNOWN = 0,
BACKLIGHT_SCALE_LINEAR,
BACKLIGHT_SCALE_NON_LINEAR,
};
struct backlight_device; struct backlight_device;
struct fb_info; struct fb_info;
...@@ -80,6 +86,8 @@ struct backlight_properties { ...@@ -80,6 +86,8 @@ struct backlight_properties {
enum backlight_type type; enum backlight_type type;
/* Flags used to signal drivers of state changes */ /* Flags used to signal drivers of state changes */
unsigned int state; unsigned int state;
/* Type of the brightness scale (linear, non-linear, ...) */
enum backlight_scale scale;
#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 */
......
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