@@ -143,6 +143,107 @@ static const struct backlight_ops pwm_backlight_ops = {
143
143
};
144
144
145
145
#ifdef CONFIG_OF
146
+ #define PWM_LUMINANCE_SCALE 10000 /* luminance scale */
147
+
148
+ /* An integer based power function */
149
+ static u64 int_pow (u64 base , int exp )
150
+ {
151
+ u64 result = 1 ;
152
+
153
+ while (exp ) {
154
+ if (exp & 1 )
155
+ result *= base ;
156
+ exp >>= 1 ;
157
+ base *= base ;
158
+ }
159
+
160
+ return result ;
161
+ }
162
+
163
+ /*
164
+ * CIE lightness to PWM conversion.
165
+ *
166
+ * The CIE 1931 lightness formula is what actually describes how we perceive
167
+ * light:
168
+ * Y = (L* / 902.3) if L* ≤ 0.08856
169
+ * Y = ((L* + 16) / 116)^3 if L* > 0.08856
170
+ *
171
+ * Where Y is the luminance, the amount of light coming out of the screen, and
172
+ * is a number between 0.0 and 1.0; and L* is the lightness, how bright a human
173
+ * perceives the screen to be, and is a number between 0 and 100.
174
+ *
175
+ * The following function does the fixed point maths needed to implement the
176
+ * above formula.
177
+ */
178
+ static u64 cie1931 (unsigned int lightness , unsigned int scale )
179
+ {
180
+ u64 retval ;
181
+
182
+ lightness *= 100 ;
183
+ if (lightness <= (8 * scale )) {
184
+ retval = DIV_ROUND_CLOSEST_ULL (lightness * 10 , 9023 );
185
+ } else {
186
+ retval = int_pow ((lightness + (16 * scale )) / 116 , 3 );
187
+ retval = DIV_ROUND_CLOSEST_ULL (retval , (scale * scale ));
188
+ }
189
+
190
+ return retval ;
191
+ }
192
+
193
+ /*
194
+ * Create a default correction table for PWM values to create linear brightness
195
+ * for LED based backlights using the CIE1931 algorithm.
196
+ */
197
+ static
198
+ int pwm_backlight_brightness_default (struct device * dev ,
199
+ struct platform_pwm_backlight_data * data ,
200
+ unsigned int period )
201
+ {
202
+ unsigned int counter = 0 ;
203
+ unsigned int i , n ;
204
+ u64 retval ;
205
+
206
+ /*
207
+ * Count the number of bits needed to represent the period number. The
208
+ * number of bits is used to calculate the number of levels used for the
209
+ * brightness-levels table, the purpose of this calculation is have a
210
+ * pre-computed table with enough levels to get linear brightness
211
+ * perception. The period is divided by the number of bits so for a
212
+ * 8-bit PWM we have 255 / 8 = 32 brightness levels or for a 16-bit PWM
213
+ * we have 65535 / 16 = 4096 brightness levels.
214
+ *
215
+ * Note that this method is based on empirical testing on different
216
+ * devices with PWM of 8 and 16 bits of resolution.
217
+ */
218
+ n = period ;
219
+ while (n ) {
220
+ counter += n % 2 ;
221
+ n >>= 1 ;
222
+ }
223
+
224
+ data -> max_brightness = DIV_ROUND_UP (period , counter );
225
+ data -> levels = devm_kcalloc (dev , data -> max_brightness ,
226
+ sizeof (* data -> levels ), GFP_KERNEL );
227
+ if (!data -> levels )
228
+ return - ENOMEM ;
229
+
230
+ /* Fill the table using the cie1931 algorithm */
231
+ for (i = 0 ; i < data -> max_brightness ; i ++ ) {
232
+ retval = cie1931 ((i * PWM_LUMINANCE_SCALE ) /
233
+ data -> max_brightness , PWM_LUMINANCE_SCALE ) *
234
+ period ;
235
+ retval = DIV_ROUND_CLOSEST_ULL (retval , PWM_LUMINANCE_SCALE );
236
+ if (retval > UINT_MAX )
237
+ return - EINVAL ;
238
+ data -> levels [i ] = (unsigned int )retval ;
239
+ }
240
+
241
+ data -> dft_brightness = data -> max_brightness / 2 ;
242
+ data -> max_brightness -- ;
243
+
244
+ return 0 ;
245
+ }
246
+
146
247
static int pwm_backlight_parse_dt (struct device * dev ,
147
248
struct platform_pwm_backlight_data * data )
148
249
{
@@ -161,10 +262,13 @@ static int pwm_backlight_parse_dt(struct device *dev,
161
262
162
263
memset (data , 0 , sizeof (* data ));
163
264
164
- /* determine the number of brightness levels */
265
+ /*
266
+ * Determine the number of brightness levels, if this property is not
267
+ * set a default table of brightness levels will be used.
268
+ */
165
269
prop = of_find_property (node , "brightness-levels" , & length );
166
270
if (!prop )
167
- return - EINVAL ;
271
+ return 0 ;
168
272
169
273
data -> max_brightness = length / sizeof (u32 );
170
274
@@ -294,6 +398,14 @@ static int pwm_backlight_parse_dt(struct device *dev,
294
398
{
295
399
return - ENODEV ;
296
400
}
401
+
402
+ static
403
+ int pwm_backlight_brightness_default (struct device * dev ,
404
+ struct platform_pwm_backlight_data * data ,
405
+ unsigned int period )
406
+ {
407
+ return - ENODEV ;
408
+ }
297
409
#endif
298
410
299
411
static int pwm_backlight_initial_power_state (const struct pwm_bl_data * pb )
@@ -334,7 +446,9 @@ static int pwm_backlight_probe(struct platform_device *pdev)
334
446
struct backlight_device * bl ;
335
447
struct device_node * node = pdev -> dev .of_node ;
336
448
struct pwm_bl_data * pb ;
449
+ struct pwm_state state ;
337
450
struct pwm_args pargs ;
451
+ unsigned int i ;
338
452
int ret ;
339
453
340
454
if (!data ) {
@@ -359,17 +473,6 @@ static int pwm_backlight_probe(struct platform_device *pdev)
359
473
goto err_alloc ;
360
474
}
361
475
362
- if (data -> levels ) {
363
- unsigned int i ;
364
-
365
- for (i = 0 ; i <= data -> max_brightness ; i ++ )
366
- if (data -> levels [i ] > pb -> scale )
367
- pb -> scale = data -> levels [i ];
368
-
369
- pb -> levels = data -> levels ;
370
- } else
371
- pb -> scale = data -> max_brightness ;
372
-
373
476
pb -> notify = data -> notify ;
374
477
pb -> notify_after = data -> notify_after ;
375
478
pb -> check_fb = data -> check_fb ;
@@ -436,6 +539,26 @@ static int pwm_backlight_probe(struct platform_device *pdev)
436
539
437
540
dev_dbg (& pdev -> dev , "got pwm for backlight\n" );
438
541
542
+ if (!data -> levels ) {
543
+ /* Get the PWM period (in nanoseconds) */
544
+ pwm_get_state (pb -> pwm , & state );
545
+
546
+ ret = pwm_backlight_brightness_default (& pdev -> dev , data ,
547
+ state .period );
548
+ if (ret < 0 ) {
549
+ dev_err (& pdev -> dev ,
550
+ "failed to setup default brightness table\n" );
551
+ goto err_alloc ;
552
+ }
553
+ }
554
+
555
+ for (i = 0 ; i <= data -> max_brightness ; i ++ ) {
556
+ if (data -> levels [i ] > pb -> scale )
557
+ pb -> scale = data -> levels [i ];
558
+
559
+ pb -> levels = data -> levels ;
560
+ }
561
+
439
562
/*
440
563
* FIXME: pwm_apply_args() should be removed when switching to
441
564
* the atomic PWM API.
0 commit comments