mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 11:11:45 -04:00
- Core Frameworks
- Remove unused/obsolete code/comments
- New Functionality
- Allow less granular brightness specification for high-res PWMs; pwm_bl
- Align brightness {inc,dec}rements with that perceived by the human-eye; pwm_bl
- Fix-ups
- Prepare for the introduction of -Wimplicit-fall-through; adp8860_bl
- Bug Fixes
- Fix uninitialised variable; pwm_bl
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEEdrbJNaO+IJqU8IdIUa+KL4f8d2EFAlt6gwcACgkQUa+KL4f8
d2EKfA//Vbomk1W0DtqBuyKUask0gcaunuICWtKZG5TnUOJctp7Jmno4UrCmkvHD
FDoOJcq3LoI/xfh68tEhvUHqYbFQrOPJC0K8jCszVzdACUsz1+Gw1oCgmQUPGg9r
TG9QlQZuimbqWzmH2xQquH2H6yVe+2xJZ1U6X4KPLP0OKkSwrOfm6sYrV7Qus+uw
1T77j8s9c5n+qiyAQt7vUBbwBDAhn33QMNqLU72QR6KmJ4A8VS8nyPFTZGXeX8nz
WvrpJ3wqKRHXW2Fe4YKzs4fXMIDJpjQn8Ls8vn8ESRL+Pd+UvGsLUyZ5uYG9Opht
NN7UGlSRjRdaX3NiiFH8/XS16bnQk2lsrVjOIfvaSmZbMCND2UAc7M1xkxhBG6h/
LKwi9RJiTxYswf/XgSAgMfv7Ge1CCIAZljMnDuJZmMEW49tKkAbc12tNypw/yujX
yg0ynHb1yBGUM4EbEhuhfgLx067ARXv/fuvMdfxcUlqG1RBhrpA/xw4OueILemwM
dJE9IwCRChWxgnlq2Oirnt4pPjR1k5tui4pR5qXvULm8J2PLLSrBM3WUlbcE/m0f
jxkSuEAWLvyd+dPwl1dNm9uLSho8N8TR2f921AUeyFmFbozPeSEGUiAeMCY0ly5M
IUg5caqVF3NvkKlW+lmL9Ik8Gd6j1JGEnaJE8NUKRzdu4ZLev6k=
=C/pI
-----END PGP SIGNATURE-----
Merge tag 'backlight-next-4.19' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/backlight
Pull backlight updates from Lee Jones:
"Core Framework:
- Remove unused/obsolete code/comments
New Functionality:
- Allow less granular brightness specification for high-res PWMs; pwm_bl
- Align brightness {inc,dec}rements with that perceived by the human-eye; pwm_bl
Fix-ups:
- Prepare for the introduction of -Wimplicit-fall-through; adp8860_bl
Bug Fixes:
- Fix uninitialised variable; pwm_bl"
* tag 'backlight-next-4.19' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/backlight:
backlight: pwm_bl: Fix uninitialized variable
backlight: adp8860: Mark expected switch fall-through
backlight: Remove obsolete comment for ->state
dt-bindings: pwm-backlight: Move brightness-levels to optional
backlight: pwm_bl: Compute brightness of LED linearly to human eye
dt-bindings: pwm-backlight: Add a num-interpolation-steps property
backlight: pwm_bl: Linear interpolation between brightness-levels
This commit is contained in:
commit
61c4fc1eaf
4 changed files with 247 additions and 21 deletions
|
|
@ -690,6 +690,7 @@ static int adp8860_probe(struct i2c_client *client,
|
|||
switch (ADP8860_MANID(reg_val)) {
|
||||
case ADP8863_MANUFID:
|
||||
data->gdwn_dis = !!pdata->gdwn_dis;
|
||||
/* fall through */
|
||||
case ADP8860_MANUFID:
|
||||
data->en_ambl_sens = !!pdata->en_ambl_sens;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -143,11 +143,116 @@ static const struct backlight_ops pwm_backlight_ops = {
|
|||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
#define PWM_LUMINANCE_SCALE 10000 /* luminance scale */
|
||||
|
||||
/* An integer based power function */
|
||||
static u64 int_pow(u64 base, int exp)
|
||||
{
|
||||
u64 result = 1;
|
||||
|
||||
while (exp) {
|
||||
if (exp & 1)
|
||||
result *= base;
|
||||
exp >>= 1;
|
||||
base *= base;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* CIE lightness to PWM conversion.
|
||||
*
|
||||
* The CIE 1931 lightness formula is what actually describes how we perceive
|
||||
* light:
|
||||
* Y = (L* / 902.3) if L* ≤ 0.08856
|
||||
* Y = ((L* + 16) / 116)^3 if L* > 0.08856
|
||||
*
|
||||
* Where Y is the luminance, the amount of light coming out of the screen, and
|
||||
* is a number between 0.0 and 1.0; and L* is the lightness, how bright a human
|
||||
* perceives the screen to be, and is a number between 0 and 100.
|
||||
*
|
||||
* The following function does the fixed point maths needed to implement the
|
||||
* above formula.
|
||||
*/
|
||||
static u64 cie1931(unsigned int lightness, unsigned int scale)
|
||||
{
|
||||
u64 retval;
|
||||
|
||||
lightness *= 100;
|
||||
if (lightness <= (8 * scale)) {
|
||||
retval = DIV_ROUND_CLOSEST_ULL(lightness * 10, 9023);
|
||||
} else {
|
||||
retval = int_pow((lightness + (16 * scale)) / 116, 3);
|
||||
retval = DIV_ROUND_CLOSEST_ULL(retval, (scale * scale));
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a default correction table for PWM values to create linear brightness
|
||||
* for LED based backlights using the CIE1931 algorithm.
|
||||
*/
|
||||
static
|
||||
int pwm_backlight_brightness_default(struct device *dev,
|
||||
struct platform_pwm_backlight_data *data,
|
||||
unsigned int period)
|
||||
{
|
||||
unsigned int counter = 0;
|
||||
unsigned int i, n;
|
||||
u64 retval;
|
||||
|
||||
/*
|
||||
* Count the number of bits needed to represent the period number. The
|
||||
* number of bits is used to calculate the number of levels used for the
|
||||
* brightness-levels table, the purpose of this calculation is have a
|
||||
* pre-computed table with enough levels to get linear brightness
|
||||
* perception. The period is divided by the number of bits so for a
|
||||
* 8-bit PWM we have 255 / 8 = 32 brightness levels or for a 16-bit PWM
|
||||
* we have 65535 / 16 = 4096 brightness levels.
|
||||
*
|
||||
* Note that this method is based on empirical testing on different
|
||||
* devices with PWM of 8 and 16 bits of resolution.
|
||||
*/
|
||||
n = period;
|
||||
while (n) {
|
||||
counter += n % 2;
|
||||
n >>= 1;
|
||||
}
|
||||
|
||||
data->max_brightness = DIV_ROUND_UP(period, counter);
|
||||
data->levels = devm_kcalloc(dev, data->max_brightness,
|
||||
sizeof(*data->levels), GFP_KERNEL);
|
||||
if (!data->levels)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Fill the table using the cie1931 algorithm */
|
||||
for (i = 0; i < data->max_brightness; i++) {
|
||||
retval = cie1931((i * PWM_LUMINANCE_SCALE) /
|
||||
data->max_brightness, PWM_LUMINANCE_SCALE) *
|
||||
period;
|
||||
retval = DIV_ROUND_CLOSEST_ULL(retval, PWM_LUMINANCE_SCALE);
|
||||
if (retval > UINT_MAX)
|
||||
return -EINVAL;
|
||||
data->levels[i] = (unsigned int)retval;
|
||||
}
|
||||
|
||||
data->dft_brightness = data->max_brightness / 2;
|
||||
data->max_brightness--;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 = 0;
|
||||
struct property *prop;
|
||||
unsigned int *table;
|
||||
int length;
|
||||
u32 value;
|
||||
int ret;
|
||||
|
|
@ -157,16 +262,20 @@ static int pwm_backlight_parse_dt(struct device *dev,
|
|||
|
||||
memset(data, 0, sizeof(*data));
|
||||
|
||||
/* determine the number of brightness levels */
|
||||
/*
|
||||
* Determine the number of brightness levels, if this property is not
|
||||
* set a default table of brightness levels will be used.
|
||||
*/
|
||||
prop = of_find_property(node, "brightness-levels", &length);
|
||||
if (!prop)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
|
||||
data->max_brightness = length / sizeof(u32);
|
||||
|
||||
/* 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)
|
||||
|
|
@ -184,6 +293,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--;
|
||||
}
|
||||
|
||||
|
|
@ -211,6 +398,14 @@ static int pwm_backlight_parse_dt(struct device *dev,
|
|||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static
|
||||
int pwm_backlight_brightness_default(struct device *dev,
|
||||
struct platform_pwm_backlight_data *data,
|
||||
unsigned int period)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int pwm_backlight_initial_power_state(const struct pwm_bl_data *pb)
|
||||
|
|
@ -251,7 +446,9 @@ static int pwm_backlight_probe(struct platform_device *pdev)
|
|||
struct backlight_device *bl;
|
||||
struct device_node *node = pdev->dev.of_node;
|
||||
struct pwm_bl_data *pb;
|
||||
struct pwm_state state;
|
||||
struct pwm_args pargs;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
if (!data) {
|
||||
|
|
@ -276,17 +473,6 @@ static int pwm_backlight_probe(struct platform_device *pdev)
|
|||
goto err_alloc;
|
||||
}
|
||||
|
||||
if (data->levels) {
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i <= data->max_brightness; i++)
|
||||
if (data->levels[i] > pb->scale)
|
||||
pb->scale = data->levels[i];
|
||||
|
||||
pb->levels = data->levels;
|
||||
} else
|
||||
pb->scale = data->max_brightness;
|
||||
|
||||
pb->notify = data->notify;
|
||||
pb->notify_after = data->notify_after;
|
||||
pb->check_fb = data->check_fb;
|
||||
|
|
@ -353,6 +539,26 @@ static int pwm_backlight_probe(struct platform_device *pdev)
|
|||
|
||||
dev_dbg(&pdev->dev, "got pwm for backlight\n");
|
||||
|
||||
if (!data->levels) {
|
||||
/* Get the PWM period (in nanoseconds) */
|
||||
pwm_get_state(pb->pwm, &state);
|
||||
|
||||
ret = pwm_backlight_brightness_default(&pdev->dev, data,
|
||||
state.period);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev,
|
||||
"failed to setup default brightness table\n");
|
||||
goto err_alloc;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i <= data->max_brightness; i++) {
|
||||
if (data->levels[i] > pb->scale)
|
||||
pb->scale = data->levels[i];
|
||||
|
||||
pb->levels = data->levels;
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: pwm_apply_args() should be removed when switching to
|
||||
* the atomic PWM API.
|
||||
|
|
|
|||
Loading…
Reference in a new issue