Dan, On 10/16/19 5:59 PM, Dan Murphy wrote: > Introduce a multicolor class that groups colored LEDs > within a LED node. > > The multi color class groups monochrome LEDs and allows controlling two > aspects of the final combined color: hue and lightness. The former is > controlled via <color>_intensity files and the latter is controlled > via brightness file. > > Signed-off-by: Dan Murphy <dmurphy@xxxxxx> > --- [...] > +static int led_multicolor_init_color(struct led_classdev_mc *mcled_cdev, > + int color_id) > +{ > + struct led_classdev *led_cdev = mcled_cdev->led_cdev; > + struct led_mc_color_entry *mc_priv; > + char *intensity_file_name; > + char *max_intensity_file_name; > + size_t len; > + 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; > + > + sysfs_attr_init(&mc_priv->intensity_attr.attr); > + len = strlen(led_colors[color_id]) + strlen(INTENSITY_NAME) + 1; > + intensity_file_name = kzalloc(len, GFP_KERNEL); > + if (!intensity_file_name) > + return -ENOMEM; > + > + snprintf(intensity_file_name, len, "%s%s", > + led_colors[color_id], INTENSITY_NAME); > + mc_priv->intensity_attr.attr.name = intensity_file_name; > + mc_priv->intensity_attr.attr.mode = 0644; > + mc_priv->intensity_attr.store = intensity_store; > + mc_priv->intensity_attr.show = intensity_show; > + ret = sysfs_add_file_to_group(&led_cdev->dev->kobj, > + &mc_priv->intensity_attr.attr, > + led_color_group.name); > + if (ret) > + goto intensity_err_out; > + > + sysfs_attr_init(&mc_priv->max_intensity_attr.attr); > + len = strlen(led_colors[color_id]) + strlen(MAX_INTENSITY_NAME) + 1; > + max_intensity_file_name = kzalloc(len, GFP_KERNEL); > + if (!max_intensity_file_name) { > + ret = -ENOMEM; > + goto intensity_err_out; > + } > + > + snprintf(max_intensity_file_name, len, "%s%s", > + led_colors[color_id], MAX_INTENSITY_NAME); > + mc_priv->max_intensity_attr.attr.name = max_intensity_file_name; > + mc_priv->max_intensity_attr.attr.mode = 0444; > + mc_priv->max_intensity_attr.show = max_intensity_show; > + ret = sysfs_add_file_to_group(&led_cdev->dev->kobj, > + &mc_priv->max_intensity_attr.attr, > + led_color_group.name); > + if (ret) > + goto max_intensity_err_out; > + > + mc_priv->max_intensity = LED_FULL; > + list_add_tail(&mc_priv->list, &mcled_cdev->color_list); We don't need the list here since our collection of color LEDs will be fixed. Instead of the list we can do with a dynamically allocated array of a size depending on available color LEDs. It will allow also to get rid of lp55xx_map_channel() since random access to array elements will be possible via lookup tables mapping colors to array element id. And regarding my amendments to the DT parser - attached is the patch for your patch, that is compile-tested. > + > +max_intensity_err_out: > + kfree(max_intensity_file_name); > +intensity_err_out: > + kfree(intensity_file_name); > + return ret; > +} > + > -- Best regards, Jacek Anaszewski
From fb0ce79b97acf6ee68ec4a2a9e24d56080826766 Mon Sep 17 00:00:00 2001 From: Jacek Anaszewski <jacek.anaszewski@xxxxxxxxx> Date: Sat, 19 Oct 2019 19:45:18 +0200 Subject: [PATCH] DT parser amendments --- drivers/leds/leds-lp55xx-common.c | 109 ++++++++++++++++-------------- include/linux/platform_data/leds-lp55xx.h | 1 + 2 files changed, 61 insertions(+), 49 deletions(-) diff --git a/drivers/leds/leds-lp55xx-common.c b/drivers/leds/leds-lp55xx-common.c index 0764520bc4a8..0244ec9bad8d 100644 --- a/drivers/leds/leds-lp55xx-common.c +++ b/drivers/leds/leds-lp55xx-common.c @@ -590,82 +590,93 @@ void lp55xx_unregister_sysfs(struct lp55xx_chip *chip) } EXPORT_SYMBOL_GPL(lp55xx_unregister_sysfs); -static int lp5xx_parse_common_child(struct device_node *np, - struct lp55xx_led_config *cfg, - int chan_num, bool is_multicolor, - int color_num) +static int lp55xx_parse_common_child(struct device_node *np, + struct lp55xx_led_config *cfg, + int led_number, int *chan_nr) { - u32 led_number; int ret; of_property_read_string(np, "chan-name", - &cfg[chan_num].name); + &cfg[led_number].name); of_property_read_u8(np, "led-cur", - &cfg[chan_num].led_current); + &cfg[led_number].led_current); of_property_read_u8(np, "max-cur", - &cfg[chan_num].max_current); + &cfg[led_number].max_current); - ret = of_property_read_u32(np, "reg", &led_number); + ret = of_property_read_u32(np, "reg", chan_nr); if (ret) return ret; - if (led_number < 0 || led_number > 6) + if (chan_nr < 0 || chan_nr > cfg->max_channel) return -EINVAL; - if (is_multicolor) - cfg[chan_num].color_components[color_num].output_num = - led_number; - else - cfg[chan_num].chan_nr = led_number; - return 0; } -static int lp5xx_parse_channel_child(struct device_node *np, - struct lp55xx_led_config *cfg, - int child_number) +static int lp55xx_parse_mutli_led_child(struct device_node *child, + struct lp55xx_led_config *cfg, + int child_number, int color_number) { - struct device_node *child; - int channel_color; - int num_colors = 0; - u32 color_id; - int ret; - - cfg[child_number].default_trigger = - of_get_property(np, "linux,default-trigger", NULL); + int chan_nr, color_id, ret; - ret = of_property_read_u32(np, "color", &channel_color); + ret = lp55xx_parse_common_child(child, cfg, child_number, &chan_nr); if (ret) - channel_color = ret; + return ret; + ret = of_property_read_u32(child, "color", &color_id); + if (ret) + return ret; - if (channel_color == LED_COLOR_ID_MULTI) { - for_each_child_of_node(np, child) { - ret = lp5xx_parse_common_child(child, cfg, - child_number, true, - num_colors); - if (ret) - return ret; + cfg[child_number].color_components[color_number].color_id = color_id; + cfg[child_number].color_components[color_number].output_num = chan_nr; + set_bit(color_id, &cfg[child_number].available_colors); - ret = of_property_read_u32(child, "color", &color_id); - if (ret) - return ret; + return 0; +} - cfg[child_number].color_components[num_colors].color_id = - color_id; - set_bit(color_id, &cfg[child_number].available_colors); - num_colors++; - } +static int lp55xx_parse_mutli_led(struct device_node *np, + struct lp55xx_led_config *cfg, + int child_number) +{ + struct device_node *child; + int num_colors = 0, ret; - cfg[child_number].num_colors = num_colors; - } else { - return lp5xx_parse_common_child(np, cfg, child_number, false, - num_colors); + for_each_child_of_node(np, child) { + ret = lp55xx_parse_mutli_led_child(child, cfg, child_number, + num_colors); + if (ret) + return ret; + num_colors++; } return 0; } +static int lp55xx_parse_logical_led(struct device_node *np, + struct lp55xx_led_config *cfg, + int child_number) +{ + int led_color, ret; + + cfg[child_number].default_trigger = + of_get_property(np, "linux,default-trigger", NULL); + + ret = of_property_read_u32(np, "color", &led_color); + + if (ret) { + int chan_nr; + ret = lp55xx_parse_common_child(np, cfg, child_number, + &chan_nr); + if (ret < 0) + return ret; + cfg[child_number].chan_nr = chan_nr; + } else if (led_color == LED_COLOR_ID_MULTI) { + return lp55xx_parse_mutli_led(np, cfg, child_number); + } + + return ret; +} + struct lp55xx_platform_data *lp55xx_of_populate_pdata(struct device *dev, struct device_node *np) { @@ -694,7 +705,7 @@ struct lp55xx_platform_data *lp55xx_of_populate_pdata(struct device *dev, pdata->num_channels = num_channels; for_each_child_of_node(np, child) { - ret = lp5xx_parse_channel_child(child, cfg, i); + ret = lp55xx_parse_logical_led(child, cfg, i); if (ret) return ERR_PTR(-EINVAL); i++; diff --git a/include/linux/platform_data/leds-lp55xx.h b/include/linux/platform_data/leds-lp55xx.h index ead9d145de0d..dca21b19a283 100644 --- a/include/linux/platform_data/leds-lp55xx.h +++ b/include/linux/platform_data/leds-lp55xx.h @@ -28,6 +28,7 @@ struct lp55xx_led_config { u8 led_current; /* mA x10, 0 if led is not connected */ u8 max_current; int num_colors; + unsigned int max_channel; unsigned long available_colors; struct led_mc_color_conversion color_components[LP55XX_MAX_GROUPED_CHAN]; }; -- 2.11.0