Received: by 10.223.176.5 with SMTP id f5csp704049wra; Wed, 7 Feb 2018 06:15:08 -0800 (PST) X-Google-Smtp-Source: AH8x226D9/WkqMDpOuf89VUjboQsLnBLdSCUUvtqYnIxlECl1tFH/N3CFUTYbXZg8IvT3IcHuztS X-Received: by 2002:a17:902:5814:: with SMTP id m20-v6mr6077919pli.434.1518012908006; Wed, 07 Feb 2018 06:15:08 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1518012907; cv=none; d=google.com; s=arc-20160816; b=zBL54ZqT1C81Te4YEItcC0AOKiVSwNcYeivyekwAClOVGR2Hx9UnL4Jyf+Mt1ftWyI Xob0/+BWYZUqhkfZ1V1roQ79WNArUwlA29LNQp5HmXvLHh3Sf96cBTmyQKdS7bJlXc0E en9IVXKqzbbiMMEYaSI0Z4x5VX0H20VchPRLJeOUDTO22w/FJFhvSb3WZ0wX7aw98ZE7 7f//ZoXVo+rlBWuBlvNOOzT0RJbbHNos6R4flAQw0ctLyJy9ui2kya5RhGvVc/j44HNh xIlapysTUpPf/4TDQ6XozMM8esmtAbDLHwfy7XDxJjaESYaqGgbkOX44KvfwqT6QMSrU 5yvQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:arc-authentication-results; bh=pEfHeFLSYXnTCguQj5DNNCKtVT5F257ZY5Om+UxABNQ=; b=KH6QCjiysV1Pv/E1n+1Lvd8qa3iCPz+xw341sSjty+tL9QrjYViVkijbCO8ot6TY+a cq3KiIqoRAkwNLHoLoqEVAfCMATPeZU3NBBArUhYbxlHeh/kVR6Rz7WRX4+qBS1Ji5qf mrlG6braSSB3w7BkmC7+06hU10sRIkSukyi7UfE7L7qJvP3AKis8v7gBTI8iCq5gFIdV ZYWNwZErK07DWg12MVOOPA5Ry0mi6M4wwfTeHOr9GM/4JmKUDaKdArAnteebRV3CDYQv sGx14sVGH2uEK7bTOApT0e4OAoEf6Me35bjH0SHVSV9iBktB4oPm1aUuezjobg/rB1rV qwLw== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=collabora.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id m3-v6si1158961pll.18.2018.02.07.06.14.53; Wed, 07 Feb 2018 06:15:07 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=collabora.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754338AbeBGONv (ORCPT + 99 others); Wed, 7 Feb 2018 09:13:51 -0500 Received: from bhuna.collabora.co.uk ([46.235.227.227]:41510 "EHLO bhuna.collabora.co.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754261AbeBGONs (ORCPT ); Wed, 7 Feb 2018 09:13:48 -0500 Received: from [127.0.0.1] (localhost [127.0.0.1]) (Authenticated sender: eballetbo) with ESMTPSA id 7AC9A270A75 From: Enric Balletbo i Serra To: Daniel Thompson , Doug Anderson , Pavel Machek , Rob Herring Cc: Jingoo Han , Richard Purdie , Jacek Anaszewski , Brian Norris , Guenter Roeck , Lee Jones , Alexandru Stan , linux-leds@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v2 1/4] backlight: pwm_bl: linear interpolation between brightness-levels Date: Wed, 7 Feb 2018 15:13:34 +0100 Message-Id: <20180207141337.22247-2-enric.balletbo@collabora.com> X-Mailer: git-send-email 2.15.1 In-Reply-To: <20180207141337.22247-1-enric.balletbo@collabora.com> References: <20180207141337.22247-1-enric.balletbo@collabora.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 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 --- Changes since v1: - None. drivers/video/backlight/pwm_bl.c | 86 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c index 8e3f1245f5c5..9dbf0b3e806f 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, 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; struct property *prop; + unsigned int *table; int length; u32 value; int ret; @@ -167,6 +171,7 @@ static int pwm_backlight_parse_dt(struct device *dev, /* 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 +189,87 @@ 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. + */ + table = kcalloc(num_levels, sizeof(*table), 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 for the new interpolated + * table. + */ + devm_kfree(dev, data->levels); + data->levels = devm_kcalloc(dev, num_levels, + sizeof(*data->levels), + GFP_KERNEL); + memcpy(data->levels, table, + num_levels * sizeof(*table)); + kfree(table); + /* + * Reassign max_brightness value to the new total number + * of brightness levels. + */ + data->max_brightness = num_levels; + } + data->max_brightness--; } -- 2.15.1