Re: [PATCH v6 6/9] leds: multicolor: Introduce a multicolor class definition
Jacek On 9/19/19 4:32 PM, Jacek Anaszewski wrote: Dan, On 9/19/19 3:07 AM, Dan Murphy wrote: Jacek On 9/18/19 4:27 PM, Jacek Anaszewski wrote: Hi Dan, I think Greg's guidance clarified everything nicely - we will avoid sub-dirs in favour of prefixes to *intensity and *max_intensity. Yes I will make the change accordingly. It will simplify the code. Before you will send an update I have some improvement ideas regarding the remnants after the previous approach, where single color intensity update resulted in updating hardware state. Now the update will happen only on write to brightness file, so we will not need color_set/color_get ops anymore. I left those call backs in specifically for the LP50xx. Otherwise the LEDs are only updated when the brightness file is written. The LP50xx has an engine that performs the intensity computation for the specific LED. So there is no call back to the MC FW for calculating the intensity. The brightness and intensity are written directly to the device and the MCU in the device does all the computations so you have real time update. You can still handle that in brightness_set op. You need to compare which color channels have changed and update them in hardware in addition to setting LEDn_BRIGHTNESS register. And yes - even updating a single color will need two operations: If we kept the ops then the LP50xx device would only need one operation to the led intensity file to update the color. echo 231 > colors/red_intensity // only cache the color in MC core echo 100 > brightness // do the actual hw update And this is the way the LP55xx device works now. Note that brightness value doesn't have to be necessarily different from the previous one here, but writing brightness file will be needed to trigger the hw update. For the LP55xx device the LEDs are only updated when the brightness file is written. I think we can leave those call backs in if device driver or product development teams would like to use them. I'd not do that - it will be confusing. We can accomplish everything in brightness_set{_blocking} op. It will have also the advantage of same ABI semantics across all devices. Otherwise we would need separate documentation for devices like LP50xx. OK I am not going to argue this I will just remove the ops even though I don't agree. Removing the ops will just make the LP50xx driver more complex then what it needs to be. I will post v8 later today. I have also another question - what with linear vs logarithmic LP50xx brightness scale? I think we should make both options available to the userspace. I have no requirements from customers to provide this scaling. It can be an enhancement to the driver later if we get the request. Dan
Re: [PATCH v6 6/9] leds: multicolor: Introduce a multicolor class definition
Dan, On 9/19/19 3:07 AM, Dan Murphy wrote: > Jacek > > On 9/18/19 4:27 PM, Jacek Anaszewski wrote: >> Hi Dan, >> >> I think Greg's guidance clarified everything nicely - >> we will avoid sub-dirs in favour of prefixes >> to *intensity and *max_intensity. > Yes I will make the change accordingly. It will simplify the code. >> >> Before you will send an update I have some improvement >> ideas regarding the remnants after the previous approach, >> where single color intensity update resulted in updating >> hardware state. Now the update will happen only on write to >> brightness file, so we will not need color_set/color_get ops >> anymore. > > I left those call backs in specifically for the LP50xx. Otherwise the > LEDs are only updated when the brightness file is written. > The LP50xx has an engine that performs the intensity computation for the > specific LED. So there is no call back to the MC FW for calculating the > intensity. > > The brightness and intensity are written directly to the device and the > MCU in the device does all the computations so you have real time update. You can still handle that in brightness_set op. You need to compare which color channels have changed and update them in hardware in addition to setting LEDn_BRIGHTNESS register. And yes - even updating a single color will need two operations: echo 231 > colors/red_intensity // only cache the color in MC core echo 100 > brightness // do the actual hw update Note that brightness value doesn't have to be necessarily different from the previous one here, but writing brightness file will be needed to trigger the hw update. > For the LP55xx device the LEDs are only updated when the brightness file > is written. > > I think we can leave those call backs in if device driver or product > development teams would like to use them. I'd not do that - it will be confusing. We can accomplish everything in brightness_set{_blocking} op. It will have also the advantage of same ABI semantics across all devices. Otherwise we would need separate documentation for devices like LP50xx. I have also another question - what with linear vs logarithmic LP50xx brightness scale? I think we should make both options available to the userspace. -- Best regards, Jacek Anaszewski
Re: [PATCH v6 6/9] leds: multicolor: Introduce a multicolor class definition
Jacek On 9/18/19 4:27 PM, Jacek Anaszewski wrote: Hi Dan, I think Greg's guidance clarified everything nicely - we will avoid sub-dirs in favour of prefixes to *intensity and *max_intensity. Yes I will make the change accordingly. It will simplify the code. Before you will send an update I have some improvement ideas regarding the remnants after the previous approach, where single color intensity update resulted in updating hardware state. Now the update will happen only on write to brightness file, so we will not need color_set/color_get ops anymore. I left those call backs in specifically for the LP50xx. Otherwise the LEDs are only updated when the brightness file is written. The LP50xx has an engine that performs the intensity computation for the specific LED. So there is no call back to the MC FW for calculating the intensity. The brightness and intensity are written directly to the device and the MCU in the device does all the computations so you have real time update. For the LP55xx device the LEDs are only updated when the brightness file is written. I think we can leave those call backs in if device driver or product development teams would like to use them. Dan On 9/17/19 7:59 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 --- v6 removed color_id and color_mix files, used sysfs_create_groups instead of kobject call for LED color directory, kept kobject_create for the "colors" directory, removed the calculate function, updated the export for the intensity calculations. drivers/leds/Kconfig | 10 + drivers/leds/Makefile| 1 + drivers/leds/led-class-multicolor.c | 306 +++ include/linux/led-class-multicolor.h | 90 4 files changed, 407 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 1988de1d64c0..71e7fd4f6f15 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -30,6 +30,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. + config LEDS_BRIGHTNESS_HW_CHANGED bool "LED Class brightness_hw_changed attribute support" depends on LEDS_CLASS diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index 41fb073a39c1..897b810257dd 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_NEW_LEDS)+= led-core.o obj-$(CONFIG_LEDS_CLASS) += led-class.o obj-$(CONFIG_LEDS_CLASS_FLASH)+= led-class-flash.o +obj-$(CONFIG_LEDS_CLASS_MULTI_COLOR) += led-class-multicolor.o obj-$(CONFIG_LEDS_TRIGGERS) += led-triggers.o # LED Platform Drivers diff --git a/drivers/leds/led-class-multicolor.c b/drivers/leds/led-class-multicolor.c new file mode 100644 index ..d43bd344ed4c --- /dev/null +++ b/drivers/leds/led-class-multicolor.c @@ -0,0 +1,306 @@ +// SPDX-License-Identifier: GPL-2.0 +// LED Multi Color class interface +// Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/ + +#include +#include +#include +#include +#include +#include + +#include "leds.h" + +struct led_mc_color_entry { + struct led_classdev_mc *mcled_cdev; + + struct device_attribute max_intensity_attr; + struct device_attribute intensity_attr; + + enum led_brightness max_intensity; + enum led_brightness intensity; + + struct list_head list; + + int led_color_id; +}; + +void led_mc_calc_brightness(struct led_classdev_mc *mcled_cdev, + enum led_brightness brightness, + int brightness_val[]) +{ + struct led_classdev_mc_data *data = mcled_cdev->data; + struct led_mc_color_entry *priv; + int i = 0; + + list_for_each_entry(priv, &data->color_list, list) { + brightness_val[i] = brightness * + priv->intensity / priv->max_intensity; + i++; + } +} +EXPORT_SYMBOL_GPL(led_mc_calc_brightness); + +static ssize_t intensity_store(struct device *dev, +
Re: [PATCH v6 6/9] leds: multicolor: Introduce a multicolor class definition
Hi Dan, I think Greg's guidance clarified everything nicely - we will avoid sub-dirs in favour of prefixes to *intensity and *max_intensity. Before you will send an update I have some improvement ideas regarding the remnants after the previous approach, where single color intensity update resulted in updating hardware state. Now the update will happen only on write to brightness file, so we will not need color_set/color_get ops anymore. On 9/17/19 7:59 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 > --- > > v6 removed color_id and color_mix files, used sysfs_create_groups instead of > kobject call for LED color directory, kept kobject_create for the "colors" > directory, > removed the calculate function, updated the export for the intensity > calculations. > > > drivers/leds/Kconfig | 10 + > drivers/leds/Makefile| 1 + > drivers/leds/led-class-multicolor.c | 306 +++ > include/linux/led-class-multicolor.h | 90 > 4 files changed, 407 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 1988de1d64c0..71e7fd4f6f15 100644 > --- a/drivers/leds/Kconfig > +++ b/drivers/leds/Kconfig > @@ -30,6 +30,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. > + > config LEDS_BRIGHTNESS_HW_CHANGED > bool "LED Class brightness_hw_changed attribute support" > depends on LEDS_CLASS > diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile > index 41fb073a39c1..897b810257dd 100644 > --- a/drivers/leds/Makefile > +++ b/drivers/leds/Makefile > @@ -4,6 +4,7 @@ > obj-$(CONFIG_NEW_LEDS) += led-core.o > obj-$(CONFIG_LEDS_CLASS) += led-class.o > obj-$(CONFIG_LEDS_CLASS_FLASH) += led-class-flash.o > +obj-$(CONFIG_LEDS_CLASS_MULTI_COLOR) += led-class-multicolor.o > obj-$(CONFIG_LEDS_TRIGGERS) += led-triggers.o > > # LED Platform Drivers > diff --git a/drivers/leds/led-class-multicolor.c > b/drivers/leds/led-class-multicolor.c > new file mode 100644 > index ..d43bd344ed4c > --- /dev/null > +++ b/drivers/leds/led-class-multicolor.c > @@ -0,0 +1,306 @@ > +// SPDX-License-Identifier: GPL-2.0 > +// LED Multi Color class interface > +// Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/ > + > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "leds.h" > + > +struct led_mc_color_entry { > + struct led_classdev_mc *mcled_cdev; > + > + struct device_attribute max_intensity_attr; > + struct device_attribute intensity_attr; > + > + enum led_brightness max_intensity; > + enum led_brightness intensity; > + > + struct list_head list; > + > + int led_color_id; > +}; > + > +void led_mc_calc_brightness(struct led_classdev_mc *mcled_cdev, > + enum led_brightness brightness, > + int brightness_val[]) > +{ > + struct led_classdev_mc_data *data = mcled_cdev->data; > + struct led_mc_color_entry *priv; > + int i = 0; > + > + list_for_each_entry(priv, &data->color_list, list) { > + brightness_val[i] = brightness * > + priv->intensity / priv->max_intensity; > + i++; > + } > +} > +EXPORT_SYMBOL_GPL(led_mc_calc_brightness); > + > +static ssize_t intensity_store(struct device *dev, > + struct device_attribute *intensity_attr, > + const char *buf, size_t size) > +{ > + struct led_mc_color_entry *priv = container_of(intensity_attr, > + struct led_mc_color_entry, > + intensity_attr); > + struct led_classdev_mc_data *data = priv->mcled_cdev->data; > + struct led_classdev_mc *mcled_cdev = data->mcled_cdev; > + struct led_classdev *led_cdev = priv->mcled_cdev->led_cdev; > + unsigned long value; > + ssize_t ret; > + > + mutex_lock(&led_cdev->led_access); >
Re: [PATCH v6 6/9] leds: multicolor: Introduce a multicolor class definition
On Wed, Sep 18, 2019 at 12:09:12PM -0500, Dan Murphy wrote: > Greg > > > > > +static int led_multicolor_init_color(struct led_classdev_mc_data *data, > > +struct led_classdev_mc *mcled_cdev, > > +int color_id, int color_index) > > +{ > > + struct led_classdev *led_cdev = mcled_cdev->led_cdev; > > + struct led_mc_color_entry *mc_priv; > > + int ret; > > + > > + mc_priv = devm_kzalloc(led_cdev->dev, sizeof(*mc_priv), GFP_KERNEL); > > + if (!mc_priv) > > + return -ENOMEM; > > + > > + mc_priv->led_color_id = color_id; > > + mc_priv->mcled_cdev = mcled_cdev; > > + > > + led_color_group.name = led_colors[color_id]; > > + ret = sysfs_create_group(data->color_kobj, &led_color_group); > > + if (ret) > > + return ret; > > + > > + sysfs_attr_init(&mc_priv->intensity_attr.attr); > > + mc_priv->intensity_attr.attr.name = "intensity"; > > + mc_priv->intensity_attr.attr.mode = 666; > > + mc_priv->intensity_attr.store = intensity_store; > > + mc_priv->intensity_attr.show = intensity_show; > > + ret = sysfs_add_file_to_group(data->color_kobj, > > + &mc_priv->intensity_attr.attr, > > + led_color_group.name); > > + if (ret) > > + return ret; > > + > > + sysfs_attr_init(&mc_priv->max_intensity_attr.attr); > > + mc_priv->max_intensity_attr.attr.name = "max_intensity"; > > + mc_priv->max_intensity_attr.attr.mode = 444; > > + mc_priv->max_intensity_attr.show = max_intensity_show; > > + ret = sysfs_add_file_to_group(data->color_kobj, > > + &mc_priv->max_intensity_attr.attr, > > + led_color_group.name); > > + if (ret) > > + goto err_out; > > + > > + mc_priv->max_intensity = LED_FULL; > > + list_add_tail(&mc_priv->list, &data->color_list); > > + > > +err_out: > > + return ret; > > +} > > + > > +static int led_multicolor_init_color_dir(struct led_classdev_mc_data *data, > > +struct led_classdev_mc *mcled_cdev) > > +{ > > + struct led_classdev *led_cdev = mcled_cdev->led_cdev; > > + u32 color_id; > > + int ret; > > + int i, j = 0; > > + > > + data->color_kobj = kobject_create_and_add("colors", > > + &led_cdev->dev->kobj); > > We need some guidance here on how to properly create sub directories more > then 1 level deep. Short answer, don't. Long answer, use a 'struct device' but ONLY IF YOU KNOW WHAT YOU ARE DOING! Follow the short answer please. > In short under the LED class device parent directory we want to create a > directory called "colors". Ok, that's simple. > Under that directory we want to create a directory corresponding to the > monochrome LED color. Why? > Under that directory we have the files to for intensity and max_intensity > for the monochrome LED. Why not just have colors/monochrome_intensity and colors/monochrome_max_intensity as your files in the colors/ directory? > We can use the LED class kobject to create the colors directory using the > sysfs calls but the issue comes when creating the LED color directory. Yes. > We don't have a kobj for colors to associate those directories to. And you shouldn't :) > The only API we see to use the kobject_create_and_add which then gives > us the colors directory kobj. Don't do that, you will break userspace code hard if you do that. NEVER put a raw kobject after a 'struct device' in the sysfs tree if you expect normal userspace libraries to be able to understand what is going on. That's why this is "hard", you are not supposed to be doing it. > So the directory structure would look like this which is explained in this > patch https://lore.kernel.org/patchwork/patch/1128444/ > > Directory Layout Example > > root:/sys/class/leds/rgb:grouped_leds# ls -lR colors/ > colors/: > drwxr-xr-x 2 root root 0 Jun 28 20:21 blue > rwxr-xr-x 2 root root 0 Jun 28 20:21 green > drwxr-xr-x 2 root root 0 Jun 28 20:21 red > > colors/blue: > -rw--- 1 root root 4096 Jun 28 20:21 intensity > -r 1 root root 4096 Jun 28 20:27 max_intensity > +colors/green: > -rw--- 1 root root 4096 Jun 28 20:22 intensity > -r 1 root root 4096 Jun 28 20:27 max_intensity > > colors/red: > -rw--- 1 root root 4096 Jun 28 20:21 intensity > -r 1 root root 4096 Jun 28 20:27 max_intensity No, just add blue, green, red to the prefix of those files and all should be fine. Don't try to get fancy and use subdirs, that way lies madness. > I have reviewed your example code and read your blogs and papers on the > subject but nothing really talks about sub-sub directories. Because you shouldn't do it, I didn't think I had t
Re: [PATCH v6 6/9] leds: multicolor: Introduce a multicolor class definition
Greg +static int led_multicolor_init_color(struct led_classdev_mc_data *data, +struct led_classdev_mc *mcled_cdev, +int color_id, int color_index) +{ + struct led_classdev *led_cdev = mcled_cdev->led_cdev; + struct led_mc_color_entry *mc_priv; + int ret; + + mc_priv = devm_kzalloc(led_cdev->dev, sizeof(*mc_priv), GFP_KERNEL); + if (!mc_priv) + return -ENOMEM; + + mc_priv->led_color_id = color_id; + mc_priv->mcled_cdev = mcled_cdev; + + led_color_group.name = led_colors[color_id]; + ret = sysfs_create_group(data->color_kobj, &led_color_group); + if (ret) + return ret; + + sysfs_attr_init(&mc_priv->intensity_attr.attr); + mc_priv->intensity_attr.attr.name = "intensity"; + mc_priv->intensity_attr.attr.mode = 666; + mc_priv->intensity_attr.store = intensity_store; + mc_priv->intensity_attr.show = intensity_show; + ret = sysfs_add_file_to_group(data->color_kobj, + &mc_priv->intensity_attr.attr, + led_color_group.name); + if (ret) + return ret; + + sysfs_attr_init(&mc_priv->max_intensity_attr.attr); + mc_priv->max_intensity_attr.attr.name = "max_intensity"; + mc_priv->max_intensity_attr.attr.mode = 444; + mc_priv->max_intensity_attr.show = max_intensity_show; + ret = sysfs_add_file_to_group(data->color_kobj, + &mc_priv->max_intensity_attr.attr, + led_color_group.name); + if (ret) + goto err_out; + + mc_priv->max_intensity = LED_FULL; + list_add_tail(&mc_priv->list, &data->color_list); + +err_out: + return ret; +} + +static int led_multicolor_init_color_dir(struct led_classdev_mc_data *data, +struct led_classdev_mc *mcled_cdev) +{ + struct led_classdev *led_cdev = mcled_cdev->led_cdev; + u32 color_id; + int ret; + int i, j = 0; + + data->color_kobj = kobject_create_and_add("colors", + &led_cdev->dev->kobj); We need some guidance here on how to properly create sub directories more then 1 level deep. In short under the LED class device parent directory we want to create a directory called "colors". Under that directory we want to create a directory corresponding to the monochrome LED color. Under that directory we have the files to for intensity and max_intensity for the monochrome LED. We can use the LED class kobject to create the colors directory using the sysfs calls but the issue comes when creating the LED color directory. We don't have a kobj for colors to associate those directories to. The only API we see to use the kobject_create_and_add which then gives us the colors directory kobj. So the directory structure would look like this which is explained in this patch https://lore.kernel.org/patchwork/patch/1128444/ Directory Layout Example root:/sys/class/leds/rgb:grouped_leds# ls -lR colors/ colors/: drwxr-xr-x 2 root root 0 Jun 28 20:21 blue rwxr-xr-x 2 root root 0 Jun 28 20:21 green drwxr-xr-x 2 root root 0 Jun 28 20:21 red colors/blue: -rw--- 1 root root 4096 Jun 28 20:21 intensity -r 1 root root 4096 Jun 28 20:27 max_intensity +colors/green: -rw--- 1 root root 4096 Jun 28 20:22 intensity -r 1 root root 4096 Jun 28 20:27 max_intensity colors/red: -rw--- 1 root root 4096 Jun 28 20:21 intensity -r 1 root root 4096 Jun 28 20:27 max_intensity I have reviewed your example code and read your blogs and papers on the subject but nothing really talks about sub-sub directories. Now if this is a no-no in the kernel that is fine we can adjust but Jacek wanted to get your opinon/guidance on this topic. Dan
[PATCH v6 6/9] leds: multicolor: Introduce a multicolor class definition
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 --- v6 removed color_id and color_mix files, used sysfs_create_groups instead of kobject call for LED color directory, kept kobject_create for the "colors" directory, removed the calculate function, updated the export for the intensity calculations. drivers/leds/Kconfig | 10 + drivers/leds/Makefile| 1 + drivers/leds/led-class-multicolor.c | 306 +++ include/linux/led-class-multicolor.h | 90 4 files changed, 407 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 1988de1d64c0..71e7fd4f6f15 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -30,6 +30,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. + config LEDS_BRIGHTNESS_HW_CHANGED bool "LED Class brightness_hw_changed attribute support" depends on LEDS_CLASS diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index 41fb073a39c1..897b810257dd 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_NEW_LEDS) += led-core.o obj-$(CONFIG_LEDS_CLASS) += led-class.o obj-$(CONFIG_LEDS_CLASS_FLASH) += led-class-flash.o +obj-$(CONFIG_LEDS_CLASS_MULTI_COLOR) += led-class-multicolor.o obj-$(CONFIG_LEDS_TRIGGERS)+= led-triggers.o # LED Platform Drivers diff --git a/drivers/leds/led-class-multicolor.c b/drivers/leds/led-class-multicolor.c new file mode 100644 index ..d43bd344ed4c --- /dev/null +++ b/drivers/leds/led-class-multicolor.c @@ -0,0 +1,306 @@ +// SPDX-License-Identifier: GPL-2.0 +// LED Multi Color class interface +// Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/ + +#include +#include +#include +#include +#include +#include + +#include "leds.h" + +struct led_mc_color_entry { + struct led_classdev_mc *mcled_cdev; + + struct device_attribute max_intensity_attr; + struct device_attribute intensity_attr; + + enum led_brightness max_intensity; + enum led_brightness intensity; + + struct list_head list; + + int led_color_id; +}; + +void led_mc_calc_brightness(struct led_classdev_mc *mcled_cdev, + enum led_brightness brightness, + int brightness_val[]) +{ + struct led_classdev_mc_data *data = mcled_cdev->data; + struct led_mc_color_entry *priv; + int i = 0; + + list_for_each_entry(priv, &data->color_list, list) { + brightness_val[i] = brightness * + priv->intensity / priv->max_intensity; + i++; + } +} +EXPORT_SYMBOL_GPL(led_mc_calc_brightness); + +static ssize_t intensity_store(struct device *dev, + struct device_attribute *intensity_attr, + const char *buf, size_t size) +{ + struct led_mc_color_entry *priv = container_of(intensity_attr, + struct led_mc_color_entry, + intensity_attr); + struct led_classdev_mc_data *data = priv->mcled_cdev->data; + struct led_classdev_mc *mcled_cdev = data->mcled_cdev; + struct led_classdev *led_cdev = priv->mcled_cdev->led_cdev; + unsigned long value; + ssize_t ret; + + mutex_lock(&led_cdev->led_access); + + ret = kstrtoul(buf, 10, &value); + if (ret) + goto unlock; + + if (value > priv->max_intensity) { + ret = -EINVAL; + goto unlock; + } + + priv->intensity = value; + + if (mcled_cdev->ops) { + ret = mcled_cdev->ops->set_color_brightness(mcled_cdev, + priv->led_color_id, + priv->intensity); + if (ret) + goto unlock; + } + + ret = size; + +unlock: + mutex_unlock(&led_cdev->led_access); +