Skip to content

Commit 573fe6d

Browse files
Enric Balletbo i SerraLee Jones
authored andcommitted
backlight: pwm_bl: Linear interpolation between brightness-levels
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>
1 parent ce397d2 commit 573fe6d

File tree

1 file changed

+83
-0
lines changed

1 file changed

+83
-0
lines changed

drivers/video/backlight/pwm_bl.c

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,11 @@ static int pwm_backlight_parse_dt(struct device *dev,
147147
struct platform_pwm_backlight_data *data)
148148
{
149149
struct device_node *node = dev->of_node;
150+
unsigned int num_levels = 0;
151+
unsigned int levels_count;
152+
unsigned int num_steps;
150153
struct property *prop;
154+
unsigned int *table;
151155
int length;
152156
u32 value;
153157
int ret;
@@ -167,6 +171,7 @@ static int pwm_backlight_parse_dt(struct device *dev,
167171
/* read brightness levels from DT property */
168172
if (data->max_brightness > 0) {
169173
size_t size = sizeof(*data->levels) * data->max_brightness;
174+
unsigned int i, j, n = 0;
170175

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

186191
data->dft_brightness = value;
192+
193+
/*
194+
* This property is optional, if is set enables linear
195+
* interpolation between each of the values of brightness levels
196+
* and creates a new pre-computed table.
197+
*/
198+
of_property_read_u32(node, "num-interpolated-steps",
199+
&num_steps);
200+
201+
/*
202+
* Make sure that there is at least two entries in the
203+
* brightness-levels table, otherwise we can't interpolate
204+
* between two points.
205+
*/
206+
if (num_steps) {
207+
if (data->max_brightness < 2) {
208+
dev_err(dev, "can't interpolate\n");
209+
return -EINVAL;
210+
}
211+
212+
/*
213+
* Recalculate the number of brightness levels, now
214+
* taking in consideration the number of interpolated
215+
* steps between two levels.
216+
*/
217+
for (i = 0; i < data->max_brightness - 1; i++) {
218+
if ((data->levels[i + 1] - data->levels[i]) /
219+
num_steps)
220+
num_levels += num_steps;
221+
else
222+
num_levels++;
223+
}
224+
num_levels++;
225+
dev_dbg(dev, "new number of brightness levels: %d\n",
226+
num_levels);
227+
228+
/*
229+
* Create a new table of brightness levels with all the
230+
* interpolated steps.
231+
*/
232+
size = sizeof(*table) * num_levels;
233+
table = devm_kzalloc(dev, size, GFP_KERNEL);
234+
if (!table)
235+
return -ENOMEM;
236+
237+
/* Fill the interpolated table. */
238+
levels_count = 0;
239+
for (i = 0; i < data->max_brightness - 1; i++) {
240+
value = data->levels[i];
241+
n = (data->levels[i + 1] - value) / num_steps;
242+
if (n > 0) {
243+
for (j = 0; j < num_steps; j++) {
244+
table[levels_count] = value;
245+
value += n;
246+
levels_count++;
247+
}
248+
} else {
249+
table[levels_count] = data->levels[i];
250+
levels_count++;
251+
}
252+
}
253+
table[levels_count] = data->levels[i];
254+
255+
/*
256+
* As we use interpolation lets remove current
257+
* brightness levels table and replace for the
258+
* new interpolated table.
259+
*/
260+
devm_kfree(dev, data->levels);
261+
data->levels = table;
262+
263+
/*
264+
* Reassign max_brightness value to the new total number
265+
* of brightness levels.
266+
*/
267+
data->max_brightness = num_levels;
268+
}
269+
187270
data->max_brightness--;
188271
}
189272

0 commit comments

Comments
 (0)