aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEnric Balletbo i Serra <enric.balletbo@collabora.com>2018-04-09 04:33:30 -0400
committerLee Jones <lee.jones@linaro.org>2018-07-04 05:30:46 -0400
commit573fe6d1c25c81b0af856ffafb516db7e8d978c5 (patch)
tree3030df9310ebb37825159ab167a03aa97edeb475
parentce397d215ccd07b8ae3f71db689aedb85d56ab40 (diff)
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>
-rw-r--r--drivers/video/backlight/pwm_bl.c83
1 files changed, 83 insertions, 0 deletions
diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
index 44ac5bde4e9d..105f199a656d 100644
--- a/drivers/video/backlight/pwm_bl.c
+++ b/drivers/video/backlight/pwm_bl.c
@@ -147,7 +147,11 @@ static int pwm_backlight_parse_dt(struct device *dev,
147 struct platform_pwm_backlight_data *data) 147 struct platform_pwm_backlight_data *data)
148{ 148{
149 struct device_node *node = dev->of_node; 149 struct device_node *node = dev->of_node;
150 unsigned int num_levels = 0;
151 unsigned int levels_count;
152 unsigned int num_steps;
150 struct property *prop; 153 struct property *prop;
154 unsigned int *table;
151 int length; 155 int length;
152 u32 value; 156 u32 value;
153 int ret; 157 int ret;
@@ -167,6 +171,7 @@ static int pwm_backlight_parse_dt(struct device *dev,
167 /* read brightness levels from DT property */ 171 /* read brightness levels from DT property */
168 if (data->max_brightness > 0) { 172 if (data->max_brightness > 0) {
169 size_t size = sizeof(*data->levels) * data->max_brightness; 173 size_t size = sizeof(*data->levels) * data->max_brightness;
174 unsigned int i, j, n = 0;
170 175
171 data->levels = devm_kzalloc(dev, size, GFP_KERNEL); 176 data->levels = devm_kzalloc(dev, size, GFP_KERNEL);
172 if (!data->levels) 177 if (!data->levels)
@@ -184,6 +189,84 @@ static int pwm_backlight_parse_dt(struct device *dev,
184 return ret; 189 return ret;
185 190
186 data->dft_brightness = value; 191 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
187 data->max_brightness--; 270 data->max_brightness--;
188 } 271 }
189 272