Received: by 10.223.176.5 with SMTP id f5csp1788168wra; Thu, 8 Feb 2018 03:33:01 -0800 (PST) X-Google-Smtp-Source: AH8x226ToqbhfH+xLrb5IvFS7TxMc347FMcgYsvcXgOboonH/MLu6FrzCVB2C4JBjSe5U9cKhB1t X-Received: by 10.98.210.134 with SMTP id c128mr348920pfg.199.1518089581481; Thu, 08 Feb 2018 03:33:01 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1518089581; cv=none; d=google.com; s=arc-20160816; b=xxAamqxZydDFsnZpWUZB8N39sBpfGcfy6Krs5VqdIhMgKiDqakft/+xASUNgJhSpsU mVR6d9IXOKlC4lSOFkiQI3FI/p6UZiUDpPUPO/8JrevffZ54XD61a0AzUfw3YnV/7kos Cs+eBA0Ay6q/nPr79YUlZtZRzf4iuFv3iaGLjF66uh3084YjRTyIsl+TK7VQ9MwXl36e WY8HTwcZzNJu18Zf7Vx3ICaPOIjfEAqTOLgQHkImKEBgySIhFGqajEFmhMB0veE/FxOU rdRTZwP0iWbNhqYxLHVrxPWzM9JE1qjmqz8LrKmboHtSWohyx+iyqcvdvSgvm2Z+9P4b rrCg== 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=lD4G2re4joID6dvcSPoH6Q/odt1R4sL22QnU7kbtBGA=; b=dUTFAAh1Yq5NV0FYlHIB0ZWBcI4iRLnZRvqGpABIUpTcvA2N7766OZ1Uu1XpfkCDpL ZjBjKkVzoDzAnoMOIZ19MLaFplbrVt0pWWkBl8G4nx/2IOKjIKbe0wSjE60MGgxq8A7t opktEP0byGNPHGBbemZCjpKHAy1zGtt871Tv9y9GMpFHnnQtTvn3ER+UfnicD9gEq6nU Ah048YAiwXXu6Fvg3VLYSPNe+8e85iaw7u6y9ymv2fPFwB7sIop8xngnZQEjbFZssUqG UeLiK7olIXTzd6s45vR8+9BpmnfV0CQSjeblfFFu41145YPLr7xGLfFP5libKbl88qQ5 5y3A== 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 x88si461639pfj.307.2018.02.08.03.32.48; Thu, 08 Feb 2018 03:33:01 -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 S1752492AbeBHLbi (ORCPT + 99 others); Thu, 8 Feb 2018 06:31:38 -0500 Received: from bhuna.collabora.co.uk ([46.235.227.227]:46252 "EHLO bhuna.collabora.co.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750881AbeBHLal (ORCPT ); Thu, 8 Feb 2018 06:30:41 -0500 Received: from [127.0.0.1] (localhost [127.0.0.1]) (Authenticated sender: eballetbo) with ESMTPSA id BD6B42664C6 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, kernel@collabora.com Subject: [PATCH v3 1/4] backlight: pwm_bl: linear interpolation between brightness-levels Date: Thu, 8 Feb 2018 12:30:29 +0100 Message-Id: <20180208113032.27810-2-enric.balletbo@collabora.com> X-Mailer: git-send-email 2.15.1 In-Reply-To: <20180208113032.27810-1-enric.balletbo@collabora.com> References: <20180208113032.27810-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 v2: Requested by Daniel Thompson: - Use a devres alloc for table creatiion and then just swap pointers. - No need to use calloc because the loop initializes every element. Changes since v1: - None. drivers/video/backlight/pwm_bl.c | 83 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c index 8e3f1245f5c5..f0a108ab570a 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,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--; } -- 2.15.1