Dan, On 9/23/19 5:14 PM, Dan Murphy wrote: > Jacek > > On 9/21/19 8:30 AM, Jacek Anaszewski wrote: >> Dan, >> >> On 9/20/19 7:41 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. >> Let's update this to the corresponding changed fragment from >> the documentation after we finally agree upon it. > [...] >>> +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->mcled_cdev = mcled_cdev; >>> + >>> + ret = sysfs_create_group(&led_cdev->dev->kobj, &led_color_group); >>> + if (ret) >>> + return ret; >>> + >>> + for (i = 0; i < LED_COLOR_ID_MAX; i++) { >>> + color_id = (mcled_cdev->available_colors & (1 << i)); >> This is nitpicking but for me it would look cleaner if we had >> color_mask variable: >> >> color_id = (mcled_cdev->available_colors & color_mask); >> >>> + if (color_id) { >>> + ret = led_multicolor_init_color(data, mcled_cdev, i, j); >>> + if (ret) >>> + break; >>> + >>> + j++; >>> + } >> And do the shifting here: >> >> color_mask <<= 1; > > Ack but responded to your follow up email on using bit ops. Yeah, bitops will be better here. >>> + } >>> + >>> + 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_classdev_mc_data *data; >>> + int ret; >>> + >>> + if (!mcled_cdev) >>> + return -EINVAL; >>> + >>> + data = kzalloc(sizeof(*data), GFP_KERNEL); >>> + if (!data) >>> + return -ENOMEM; >>> + >>> + mcled_cdev->data = data; >>> + led_cdev = mcled_cdev->led_cdev; >>> + INIT_LIST_HEAD(&data->color_list); >>> + >>> + /* Register led class device */ >>> + ret = led_classdev_register_ext(parent, led_cdev, init_data); >>> + if (ret) >>> + return ret; >>> + >>> + return led_multicolor_init_color_dir(data, mcled_cdev); >>> +} >>> +EXPORT_SYMBOL_GPL(led_classdev_multicolor_register_ext); >>> + >>> +void led_classdev_multicolor_unregister(struct led_classdev_mc >>> *mcled_cdev) >>> +{ >>> + if (!mcled_cdev) >>> + return; >>> + >>> + sysfs_remove_group(&mcled_cdev->led_cdev->dev->kobj, >>> &led_color_group); >>> + 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. >>> + */ >> Let's move documentation to the header. We should to the same with >> the existing led-class.c API one day. > > Well this will go away if we remove the non-ext function. > > And this documentation needs to be updated anyway. > > >>> +int devm_led_classdev_multicolor_register(struct device *parent, >>> + struct led_classdev_mc *mcled_cdev) >> We don't need non-ext version for a new API. > > So we only need the ext version like in the flash class? Yes. We can always fallback to the old LED name initialization way that uses struct led_classdev's name property by setting init_data to NULL. >>> +{ >>> + 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@xxxxxx>"); >>> +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..afcaf429fba5 >>> --- /dev/null >>> +++ b/include/linux/led-class-multicolor.h >>> @@ -0,0 +1,76 @@ >>> +/* SPDX-License-Identifier: GPL-2.0 */ >>> +/* LED Multicolor class interface >>> + * Copyright (C) 2019 Texas Instruments Incorporated - >>> http://www.ti.com/ >>> + */ >>> + >>> +#ifndef __LINUX_MULTICOLOR_LEDS_H_INCLUDED >>> +#define __LINUX_MULTICOLOR_LEDS_H_INCLUDED >>> + >>> +#include <linux/leds.h> >>> +#include <dt-bindings/leds/common.h> >>> + >>> +struct led_classdev_mc; >>> + >>> +struct led_classdev_mc_data { >>> + struct led_classdev_mc *mcled_cdev; >>> + struct list_head color_list; >>> +}; >>> + >>> +struct led_classdev_mc { >>> + /* led class device */ >>> + struct led_classdev *led_cdev; >>> + >>> + /* Set brightness for a specific color id */ >>> + int (*set_color_brightness)(struct led_classdev_mc *mcled_cdev, >>> + int color_id, int value); >>> + >>> + struct led_classdev_mc_data *data; >>> + >>> + unsigned long available_colors; >>> + int num_leds; >>> +}; >>> + >>> +static inline struct led_classdev_mc *lcdev_to_mccdev( >>> + struct led_classdev *lcdev) >>> +{ >>> + return container_of(lcdev, struct led_classdev_mc, led_cdev); >>> +} >>> + >>> +/** >>> + * led_classdev_multicolor_register_ext - register a new object of >>> led_classdev >>> + * class with support for multicolor LEDs >>> + * @parent: the multicolor LED to register >>> + * @mcled_cdev: the led_classdev_mc structure for this device >>> + * @init_data: the LED class Multi color device initialization data >>> + * >>> + * Returns: 0 on success or negative error value on failure >>> + */ >>> +extern int led_classdev_multicolor_register_ext(struct device *parent, >> extern is implied by default for functions. We need also to do this >> cleanup in leds.h soem day. > > For clarity we can remove extern from all the APIs in the header? Yes, in a dedicated patch. >>> + struct led_classdev_mc *mcled_cdev, >>> + struct led_init_data *init_data); >>> + >>> +#define led_classdev_multicolor_register(parent, mcled_cdev) \ >>> + led_classdev_multicolor_register_ext(parent, mcled_cdev, NULL) >>> + >>> +/** >>> + * led_classdev_multicolor_unregister - unregisters an object of >>> led_classdev >>> + * class with support for multicolor LEDs >>> + * @mcled_cdev: the multicolor LED to unregister >>> + * >>> + * Unregister a previously registered via >>> led_classdev_multicolor_register >>> + * object >>> + */ >>> +extern void led_classdev_multicolor_unregister(struct >>> led_classdev_mc *mcled_cdev); >>> + >>> +extern int devm_led_classdev_multicolor_register(struct device *parent, >>> + struct led_classdev_mc *mcled_cdev); >>> + >>> +extern void devm_led_classdev_multicolor_unregister(struct device >>> *parent, >>> + struct led_classdev_mc *mcled_cdev); >>> + >>> +/* Set brightness for the monochrome LED cluster */ >>> +extern void led_mc_calc_brightness(struct led_classdev_mc *mcled_cdev, >>> + enum led_brightness brightness, >>> + int brightness_val[]); >>> + >>> +#endif /* __LINUX_MULTICOLOR_LEDS_H_INCLUDED */ >>> > -- Best regards, Jacek Anaszewski