lkml.org 
[lkml]   [2019]   [Jun]   [20]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
SubjectRe: [PATCH v3 6/9] leds: multicolor: Introduce a multicolor class definition
From
Date
Jacek

Thanks for the review

On 6/20/19 11:10 AM, Jacek Anaszewski wrote:
> Hi Dan,
>
> Thank you for the v5.
>
> I will confine myself to commenting only some parts since
> the rest will undergo rework due to removal of sync API.
>
> On 5/23/19 9:08 PM, Dan Murphy wrote:
>> Introduce a multicolor class that groups colored LEDs
>> within a LED node.
>>
>> The framework allows for dynamically setting individual LEDs
>> or setting brightness levels of LEDs and updating them virtually
>> simultaneously.
>>
>> Signed-off-by: Dan Murphy <dmurphy@ti.com>
>> ---
>>   drivers/leds/Kconfig                 |  10 +
>>   drivers/leds/Makefile                |   1 +
>>   drivers/leds/led-class-multicolor.c  | 421 +++++++++++++++++++++++++++
>>   include/linux/led-class-multicolor.h |  95 ++++++
>>   4 files changed, 527 insertions(+)
>>   create mode 100644 drivers/leds/led-class-multicolor.c
>>   create mode 100644 include/linux/led-class-multicolor.h
>>
>> diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
>> index 0414adebb177..0696a13c9527 100644
>> --- a/drivers/leds/Kconfig
>> +++ b/drivers/leds/Kconfig
>> @@ -29,6 +29,16 @@ config LEDS_CLASS_FLASH
>>         for the flash related features of a LED device. It can be built
>>         as a module.
>>   +config LEDS_CLASS_MULTI_COLOR
>> +    tristate "LED Mulit Color LED Class Support"
>> +    depends on LEDS_CLASS
>> +    help
>> +      This option enables the multicolor LED sysfs class in
>> /sys/class/leds.
>> +      It wraps LED Class and adds multicolor LED specific sysfs
>> attributes
>> +      and kernel internal API to it. You'll need this to provide
>> support
>> +      for multicolor LEDs that are grouped together. This class is not
>> +      intended for single color LEDs.  It can be built as a module.
>
> extra whitespace:
>
> s/ It can/It can/

Ack

>
> [...]
>> +
>> +static int multicolor_set_brightness(struct led_classdev *led_cdev,
>> +                 enum led_brightness brightness)
>> +{
>> +    struct led_classdev_mc *mcled_cdev = lcdev_to_mccdev(led_cdev);
>> +    struct led_classdev_mc_data *data = mcled_cdev->data;
>> +    struct led_multicolor_ops *ops = mcled_cdev->ops;
>> +    struct led_classdev_mc_priv *priv;
>> +    unsigned long state = brightness;
>> +    int adj_value;
>> +    ssize_t ret = -EINVAL;
>> +
>> +    mutex_lock(&led_cdev->led_access);
>> +
>> +    if (ops->set_module_brightness) {
>> +        ret = ops->set_module_brightness(mcled_cdev, state);
>> +        goto unlock;
>> +    }
>> +
>> +    list_for_each_entry(priv, &data->color_list, list) {
>> +        if (state && priv->brightness && priv->max_brightness) {
>> +            adj_value = state * ((priv->brightness * 100) /
>> priv->max_brightness);
>> +            adj_value = adj_value / 100;
>
> Why the multiplication an then division by 100? And priv->max_brightness
> stays unaltered? This changes the proportions. My python script works
> just fine without those.

Because the kernel does not do floating point math and the calculation
is using the ratio

between the intensity and max_intensity and multiplying against the
requested brightness.

priv->intensity = 100 (This is the current intensity of the color LED)

priv->max_intensity = 255

state = 80 (This is the requested cluster brightness)

100/255 = 0.392 which is 0.

0 * 80 = 0 this is not what the value should be

But with the multiplier.

10000/255 = 39.2 which is 39 which means that the intensity is only 39%
of the

max_intensity.

39 * 80 = 3120  So to preserve the 39% from the 80 we multiply the
percentage * requested cluster brightness

3120 / 100 = 31 then we normalize back

I am not sure how your script is working without the multiplier.


>
>> +        } else
>> +            adj_value = LED_OFF;
>> +
>> +        ret = ops->set_color_brightness(priv->mcled_cdev,
>> +                        priv->color_id,    adj_value);
>> +        if (ret < 0)
>> +            goto unlock;
>> +    }
>> +
>> +unlock:
>> +    mutex_unlock(&led_cdev->led_access);
>> +    return ret;
>> +}
> [...]
>> +int led_classdev_multicolor_register_ext(struct device *parent,
>> +                     struct led_classdev_mc *mcled_cdev,
>> +                     struct led_init_data *init_data)
>> +{
>> +    struct led_classdev *led_cdev;
>> +    struct led_multicolor_ops *ops;
>> +    struct led_classdev_mc_data *data;
>> +    int ret;
>> +    int i;
>> +
>> +    if (!mcled_cdev)
>> +        return -EINVAL;
>> +
>> +    ops = mcled_cdev->ops;
>> +    if (!ops || !ops->set_color_brightness)
>> +        return -EINVAL;
>> +
>> +    data = kzalloc(sizeof(*data), GFP_KERNEL);
>> +    if (!data)
>> +        return -ENOMEM;
>> +
>> +    mcled_cdev->data = data;
>> +    led_cdev = &mcled_cdev->led_cdev;
>> +
>> +    if (led_cdev->brightness_set_blocking)
>> +        led_cdev->brightness_set_blocking = multicolor_set_brightness;
>
> This is weird. In leds-lp50xx.c you don't initialize
> brightness_set_blocking and this still works?

I will have to look.  I don't believe I retested this on lp50xx only the
lp55xx code.

>
> I believe this is kind of omission.
>
> And it is not reasonable to just override driver supplied op with
> generic one just like that.
>
> I propose to initialize brightness_set or brightness_set_blocking
> op as we used to do it for monochrome LEDs. Those function(s) on
> driver side will either use device's hardware support for setting
> color lightness, or will call a generic function provided by
> LED multi color class for calculating intensities of all colors
> it comprises in the cluster.
>
> I know this is different to what we've discussed on IRC, but now
> it looks for me the most reasonable way to go.

So you want the device driver to handle the brightness request and call
into the framework for

calculating the color intensities?

That would work as well and solves a problem of HW supported brightness
control like the LP50xx.

The LP50xx would not need to call into the function for calculated
intensities.


>
>> + INIT_LIST_HEAD(&data->color_list);
>> +
>> +    /* Register led class device */
>> +    ret = led_classdev_register_ext(parent, led_cdev, init_data);
>> +    if (ret)
>> +        return ret;
>> +
>> +    ret = led_multicolor_init_color_dir(data, mcled_cdev);
>> +    if (ret)
>> +        return ret;
>> +
>> +    /* Select the sysfs attributes to be created for the device */
>> +    for (i = 0; i < mcled_cdev->num_leds; i++) {
>> +        ret = led_multicolor_init_color(data, mcled_cdev,
>> +                        mcled_cdev->available_colors[i]);
>> +        if (ret)
>> +            break;
>> +    }
>> +
>> +    return ret;
>> +}
>> +EXPORT_SYMBOL_GPL(led_classdev_multicolor_register_ext);
>> +
>> +void led_classdev_multicolor_unregister(struct led_classdev_mc
>> *mcled_cdev)
>> +{
>> +    if (!mcled_cdev)
>> +        return;
>> +
>> +    led_classdev_unregister(&mcled_cdev->led_cdev);
>> +}
>> +EXPORT_SYMBOL_GPL(led_classdev_multicolor_unregister);
>> +
>> +static void devm_led_classdev_multicolor_release(struct device *dev,
>> void *res)
>> +{
>> +    led_classdev_multicolor_unregister(*(struct led_classdev_mc
>> **)res);
>> +}
>> +
>> +/**
>> + * devm_of_led_classdev_register - resource managed
>> led_classdev_register()
>> + *
>> + * @parent: parent of LED device
>> + * @led_cdev: the led_classdev structure for this device.
>> + */
>> +int devm_led_classdev_multicolor_register(struct device *parent,
>> +                      struct led_classdev_mc *mcled_cdev)
>> +{
>> +    struct led_classdev_mc **dr;
>> +    int ret;
>> +
>> +    dr = devres_alloc(devm_led_classdev_multicolor_release,
>> +              sizeof(*dr), GFP_KERNEL);
>> +    if (!dr)
>> +        return -ENOMEM;
>> +
>> +    ret = led_classdev_multicolor_register(parent, mcled_cdev);
>> +    if (ret) {
>> +        devres_free(dr);
>> +        return ret;
>> +    }
>> +
>> +    *dr = mcled_cdev;
>> +    devres_add(parent, dr);
>> +
>> +    return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(devm_led_classdev_multicolor_register);
>> +
>> +static int devm_led_classdev_multicolor_match(struct device *dev,
>> +                          void *res, void *data)
>> +{
>> +    struct mcled_cdev **p = res;
>> +
>> +    if (WARN_ON(!p || !*p))
>> +        return 0;
>> +
>> +    return *p == data;
>> +}
>> +
>> +/**
>> + * devm_led_classdev_multicolor_unregister() - resource managed
>> + *                    led_classdev_multicolor_unregister()
>> + * @parent: The device to unregister.
>> + * @mcled_cdev: the led_classdev_mc structure for this device.
>> + */
>> +void devm_led_classdev_multicolor_unregister(struct device *dev,
>> +                  struct led_classdev_mc *mcled_cdev)
>> +{
>> +    WARN_ON(devres_release(dev,
>> +                   devm_led_classdev_multicolor_release,
>> +                   devm_led_classdev_multicolor_match, mcled_cdev));
>> +}
>> +EXPORT_SYMBOL_GPL(devm_led_classdev_multicolor_unregister);
>> +
>> +MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
>> +MODULE_DESCRIPTION("Multi Color LED class interface");
>> +MODULE_LICENSE("GPL v2");
>> diff --git a/include/linux/led-class-multicolor.h
>> b/include/linux/led-class-multicolor.h
>> new file mode 100644
>> index 000000000000..f9e71d984b03
>> --- /dev/null
>> +++ b/include/linux/led-class-multicolor.h
>> @@ -0,0 +1,95 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +
>> +/* LED Multicolor class interface
>> + * Copyright (C) 2019 Texas Instruments Incorporated -
>> http://www.ti.com/
>> + */
> Let's have C++ comment style also here.
>
ACK


>> +#ifndef __LINUX_MULTICOLOR_LEDS_H_INCLUDED
>> +#define __LINUX_MULTICOLOR_LEDS_H_INCLUDED
>> +
>> +#include <linux/leds.h>
>> +#include <dt-bindings/leds/common.h>
> [...]
>
>

\
 
 \ /
  Last update: 2019-06-20 22:07    [W:0.081 / U:0.500 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site