Commit 84e010ec authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull backlight update from Lee Jones:
 "Careful, it's a big one!

   - Fix pwm_bl driver interpolation issues by switching to a linear
     algorithm"

* tag 'backlight-next-5.11' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/backlight:
  backlight: pwm_bl: Fix interpolation
parents 278f54c4 789eb04b
Loading
Loading
Loading
Loading
+31 −39
Original line number Diff line number Diff line
@@ -230,8 +230,7 @@ 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_levels;
	unsigned int num_steps = 0;
	struct property *prop;
	unsigned int *table;
@@ -260,12 +259,11 @@ static int pwm_backlight_parse_dt(struct device *dev,
	if (!prop)
		return 0;

	data->max_brightness = length / sizeof(u32);
	num_levels = 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;
	if (num_levels > 0) {
		size_t size = sizeof(*data->levels) * num_levels;

		data->levels = devm_kzalloc(dev, size, GFP_KERNEL);
		if (!data->levels)
@@ -273,7 +271,7 @@ static int pwm_backlight_parse_dt(struct device *dev,

		ret = of_property_read_u32_array(node, "brightness-levels",
						 data->levels,
						 data->max_brightness);
						 num_levels);
		if (ret < 0)
			return ret;

@@ -298,7 +296,13 @@ static int pwm_backlight_parse_dt(struct device *dev,
		 * between two points.
		 */
		if (num_steps) {
			if (data->max_brightness < 2) {
			unsigned int num_input_levels = num_levels;
			unsigned int i;
			u32 x1, x2, x, dx;
			u32 y1, y2;
			s64 dy;

			if (num_input_levels < 2) {
				dev_err(dev, "can't interpolate\n");
				return -EINVAL;
			}
@@ -308,14 +312,7 @@ static int pwm_backlight_parse_dt(struct device *dev,
			 * 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++;
			num_levels = (num_input_levels - 1) * num_steps + 1;
			dev_dbg(dev, "new number of brightness levels: %d\n",
				num_levels);

@@ -327,24 +324,25 @@ static int pwm_backlight_parse_dt(struct device *dev,
			table = devm_kzalloc(dev, size, 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 = data->levels[i];
				y2 = data->levels[i + 1];
				dy = (s64)y2 - y1;

			/* 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++;
				for (x = x1; x < x2; x++) {
					table[x] = y1 +
						div_s64(dy * (x - x1), dx);
				}
			}
			table[levels_count] = data->levels[i];
			/* Fill in the last point, since no line starts here. */
			table[x2] = y2;

			/*
			 * As we use interpolation lets remove current
@@ -353,15 +351,9 @@ static int pwm_backlight_parse_dt(struct device *dev,
			 */
			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--;
		data->max_brightness = num_levels - 1;
	}

	return 0;