Skip to content

Commit

Permalink
backlight: pwm_bl: Linear interpolation between brightness-levels
Browse files Browse the repository at this point in the history
Setting num-interpolated-steps in the dts will allow you to have linear
interpolation between values of brightness-levels. This way a high
resolution pwm duty cycle can be used without having to list out every
possible value in the dts. This system also allows for gamma corrected
values.

The most simple example is interpolate between two brightness values a
number of steps, this can be done setting the following in the dts:

  brightness-levels = <0 65535>;
  num-interpolated-steps = <1024>;
  default-brightness-level = <512>;

This will create a brightness-level table with the following values:

  <0 63 126 189 252 315 378 441 ... 64260 64323 64386 64449 65535>

Another use case can be describe a gamma corrected curve, as we have
better sensitivity at low luminance than high luminance we probably
want have smaller steps for low brightness levels values and bigger
steps for high brightness levels values. This can be achieved with
the following in the dts:

  brightness-levels = <0 4096 65535>;
  num-interpolated-steps = <1024>;
  default-brightness-level = <512>;

This will create a brightness-levels table with the following values:

  <0 4 8 12 16 20 ... 4096 4156 4216 4276 ... 65535>

Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
Acked-by: Daniel Thompson <daniel.thompson@linaro.org>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
  • Loading branch information
Enric Balletbo i Serra authored and Lee Jones committed Jul 4, 2018
1 parent ce397d2 commit 573fe6d
Showing 1 changed file with 83 additions and 0 deletions.
83 changes: 83 additions & 0 deletions drivers/video/backlight/pwm_bl.c
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,11 @@ static int pwm_backlight_parse_dt(struct device *dev,
struct platform_pwm_backlight_data *data)
{
struct device_node *node = dev->of_node;
unsigned int num_levels = 0;
unsigned int levels_count;
unsigned int num_steps;
struct property *prop;
unsigned int *table;
int length;
u32 value;
int ret;
Expand All @@ -167,6 +171,7 @@ static int pwm_backlight_parse_dt(struct device *dev,
/* read brightness levels from DT property */
if (data->max_brightness > 0) {
size_t size = sizeof(*data->levels) * data->max_brightness;
unsigned int i, j, n = 0;

data->levels = devm_kzalloc(dev, size, GFP_KERNEL);
if (!data->levels)
Expand All @@ -184,6 +189,84 @@ static int pwm_backlight_parse_dt(struct device *dev,
return ret;

data->dft_brightness = value;

/*
* This property is optional, if is set enables linear
* interpolation between each of the values of brightness levels
* and creates a new pre-computed table.
*/
of_property_read_u32(node, "num-interpolated-steps",
&num_steps);

/*
* Make sure that there is at least two entries in the
* brightness-levels table, otherwise we can't interpolate
* between two points.
*/
if (num_steps) {
if (data->max_brightness < 2) {
dev_err(dev, "can't interpolate\n");
return -EINVAL;
}

/*
* Recalculate the number of brightness levels, now
* taking in consideration the number of interpolated
* steps between two levels.
*/
for (i = 0; i < data->max_brightness - 1; i++) {
if ((data->levels[i + 1] - data->levels[i]) /
num_steps)
num_levels += num_steps;
else
num_levels++;
}
num_levels++;
dev_dbg(dev, "new number of brightness levels: %d\n",
num_levels);

/*
* Create a new table of brightness levels with all the
* interpolated steps.
*/
size = sizeof(*table) * num_levels;
table = devm_kzalloc(dev, size, GFP_KERNEL);
if (!table)
return -ENOMEM;

/* Fill the interpolated table. */
levels_count = 0;
for (i = 0; i < data->max_brightness - 1; i++) {
value = data->levels[i];
n = (data->levels[i + 1] - value) / num_steps;
if (n > 0) {
for (j = 0; j < num_steps; j++) {
table[levels_count] = value;
value += n;
levels_count++;
}
} else {
table[levels_count] = data->levels[i];
levels_count++;
}
}
table[levels_count] = data->levels[i];

/*
* As we use interpolation lets remove current
* brightness levels table and replace for the
* new interpolated table.
*/
devm_kfree(dev, data->levels);
data->levels = table;

/*
* Reassign max_brightness value to the new total number
* of brightness levels.
*/
data->max_brightness = num_levels;
}

data->max_brightness--;
}

Expand Down

0 comments on commit 573fe6d

Please sign in to comment.