Port the parsing logic for num-interpolated-steps from linux, which populates brightness-levels between 2 brightness level by linear interpolation. This is useful if the amount of brightness levels exeeds what can practically can be written into the devicetree array. Signed-off-by: Ingo Reitz <9l@9lo.re> --- drivers/video/backlight-pwm.c | 76 ++++++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/drivers/video/backlight-pwm.c b/drivers/video/backlight-pwm.c index 14fad55637..581fa0237c 100644 --- a/drivers/video/backlight-pwm.c +++ b/drivers/video/backlight-pwm.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -101,7 +102,9 @@ static int pwm_backlight_parse_dt(struct device *dev, { struct device_node *node = dev->of_node; struct property *prop; - int length; + unsigned int length; + unsigned int num_steps = 0; + unsigned int *table; u32 value; int ret, i; @@ -134,6 +137,77 @@ static int pwm_backlight_parse_dt(struct device *dev, if (ret < 0) return ret; + /* + * 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); + + if (num_steps) { + unsigned int num_input_levels = length; + unsigned int i; + u32 x1, x2, x, dx; + u32 y1, y2; + s64 dy; + + /* + * Make sure that there is at least two entries in the + * brightness-levels table, otherwise we can't interpolate + * between two points. + */ + if (num_input_levels < 2) { + dev_err(dev, "can't interpolate\n"); + return -EINVAL; + } + + /* + * Recalculate the number of brightness levels, now + * taking in consideration the number o f interpolated + * steps between two levels. + */ + length = (num_input_levels - 1) * num_steps + 1; + dev_dbg(dev, "new number of brightness levels: %d\n", + length); + + /* + * Create a new table of brightness levels with all the + * interpolated steps. + */ + table = devm_kcalloc(dev, length, sizeof(*table), + GFP_KERNEL); + if (!table) + return -ENOMEM; + /* + * Fill the interpolated table[x] = y + * by draw lines between each (x1, y1) to (x2, y2). + */ + dx = num_steps; + for (i = 0; i < num_input_levels - 1; i++) { + x1 = i * dx; + x2 = x1 + dx; + y1 = pwm_backlight->levels[i]; + y2 = pwm_backlight->levels[i + 1]; + dy = (s64)y2 - y1; + + for (x = x1; x < x2; x++) { + table[x] = + y1 + div_s64(dy * (x - x1), dx); + } + } + /* Fill in the last point, since no line starts here. */ + table[x2] = y2; + + /* + * As we use interpolation lets remove current + * brightness levels table and replace for the + * new interpolated table. + */ + devm_kfree(dev, pwm_backlight->levels); + pwm_backlight->levels = table; + } + pwm_backlight->backlight.brightness_max = length - 1; for (i = 0; i < length; i++) -- 2.54.0