diff --git a/target/linux/generic/backport-5.4/901-add-fwnode_get_name.patch b/target/linux/generic/backport-5.4/901-add-fwnode_get_name.patch new file mode 100644 index 0000000000..8c5de17433 --- /dev/null +++ b/target/linux/generic/backport-5.4/901-add-fwnode_get_name.patch @@ -0,0 +1,175 @@ +From bc0500c1e43d95cca5352d2345fb0769f314ba22 Mon Sep 17 00:00:00 2001 +From: Sakari Ailus +Date: Thu, 3 Oct 2019 15:32:12 +0300 +Subject: [PATCH] device property: Add fwnode_get_name for returning the name + of a node + +The fwnode framework did not have means to obtain the name of a node. Add +that now, in form of the fwnode_get_name() function and a corresponding +get_name fwnode op. OF and ACPI support is included. + +Signed-off-by: Sakari Ailus +Acked-by: Rob Herring (for OF) +Reviewed-by: Andy Shevchenko +Signed-off-by: Rafael J. Wysocki +--- + drivers/acpi/property.c | 26 ++++++++++++++++++++++++++ + drivers/base/property.c | 11 +++++++++++ + drivers/base/swnode.c | 12 ++++++++++++ + drivers/of/property.c | 6 ++++++ + include/linux/fwnode.h | 2 ++ + include/linux/property.h | 1 + + 6 files changed, 58 insertions(+) + +diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c +index 3eacf474e1e39b..a501c1c584b5ce 100644 +--- a/drivers/acpi/property.c ++++ b/drivers/acpi/property.c +@@ -1317,6 +1317,31 @@ acpi_fwnode_get_reference_args(const struct fwnode_handle *fwnode, + args_count, args); + } + ++static const char *acpi_fwnode_get_name(const struct fwnode_handle *fwnode) ++{ ++ const struct acpi_device *adev; ++ struct fwnode_handle *parent; ++ ++ /* Is this the root node? */ ++ parent = fwnode_get_parent(fwnode); ++ if (!parent) ++ return "\\"; ++ ++ fwnode_handle_put(parent); ++ ++ if (is_acpi_data_node(fwnode)) { ++ const struct acpi_data_node *dn = to_acpi_data_node(fwnode); ++ ++ return dn->name; ++ } ++ ++ adev = to_acpi_device_node(fwnode); ++ if (WARN_ON(!adev)) ++ return NULL; ++ ++ return acpi_device_bid(adev); ++} ++ + static struct fwnode_handle * + acpi_fwnode_get_parent(struct fwnode_handle *fwnode) + { +@@ -1357,6 +1382,7 @@ acpi_fwnode_device_get_match_data(const struct fwnode_handle *fwnode, + .get_parent = acpi_node_get_parent, \ + .get_next_child_node = acpi_get_next_subnode, \ + .get_named_child_node = acpi_fwnode_get_named_child_node, \ ++ .get_name = acpi_fwnode_get_name, \ + .get_reference_args = acpi_fwnode_get_reference_args, \ + .graph_get_next_endpoint = \ + acpi_graph_get_next_endpoint, \ +diff --git a/drivers/base/property.c b/drivers/base/property.c +index f2e555e68b56a4..9b5ec88e72d8bf 100644 +--- a/drivers/base/property.c ++++ b/drivers/base/property.c +@@ -556,6 +556,17 @@ int device_add_properties(struct device *dev, + } + EXPORT_SYMBOL_GPL(device_add_properties); + ++/** ++ * fwnode_get_name - Return the name of a node ++ * @fwnode: The firmware node ++ * ++ * Returns a pointer to the node name. ++ */ ++const char *fwnode_get_name(const struct fwnode_handle *fwnode) ++{ ++ return fwnode_call_ptr_op(fwnode, get_name); ++} ++ + /** + * fwnode_get_parent - Return parent firwmare node + * @fwnode: Firmware whose parent is retrieved +diff --git a/drivers/base/swnode.c b/drivers/base/swnode.c +index 9cde143201f5f4..eacca6a6626b7a 100644 +--- a/drivers/base/swnode.c ++++ b/drivers/base/swnode.c +@@ -515,6 +515,17 @@ static int software_node_read_string_array(const struct fwnode_handle *fwnode, + propname, val, nval); + } + ++static const char * ++software_node_get_name(const struct fwnode_handle *fwnode) ++{ ++ const struct swnode *swnode = to_swnode(fwnode); ++ ++ if (!swnode) ++ return "(null)"; ++ ++ return kobject_name(&swnode->kobj); ++} ++ + static struct fwnode_handle * + software_node_get_parent(const struct fwnode_handle *fwnode) + { +@@ -615,6 +626,7 @@ static const struct fwnode_operations software_node_ops = { + .property_present = software_node_property_present, + .property_read_int_array = software_node_read_int_array, + .property_read_string_array = software_node_read_string_array, ++ .get_name = software_node_get_name, + .get_parent = software_node_get_parent, + .get_next_child_node = software_node_get_next_child, + .get_named_child_node = software_node_get_named_child_node, +diff --git a/drivers/of/property.c b/drivers/of/property.c +index d7fa75e31f2241..5bed634551ea65 100644 +--- a/drivers/of/property.c ++++ b/drivers/of/property.c +@@ -872,6 +872,11 @@ of_fwnode_property_read_string_array(const struct fwnode_handle *fwnode, + of_property_count_strings(node, propname); + } + ++static const char *of_fwnode_get_name(const struct fwnode_handle *fwnode) ++{ ++ return kbasename(to_of_node(fwnode)->full_name); ++} ++ + static struct fwnode_handle * + of_fwnode_get_parent(const struct fwnode_handle *fwnode) + { +@@ -993,6 +998,7 @@ const struct fwnode_operations of_fwnode_ops = { + .property_present = of_fwnode_property_present, + .property_read_int_array = of_fwnode_property_read_int_array, + .property_read_string_array = of_fwnode_property_read_string_array, ++ .get_name = of_fwnode_get_name, + .get_parent = of_fwnode_get_parent, + .get_next_child_node = of_fwnode_get_next_child_node, + .get_named_child_node = of_fwnode_get_named_child_node, +diff --git a/include/linux/fwnode.h b/include/linux/fwnode.h +index ababd6bc82f33c..2bbf55739a5736 100644 +--- a/include/linux/fwnode.h ++++ b/include/linux/fwnode.h +@@ -56,6 +56,7 @@ struct fwnode_reference_args { + * otherwise. + * @property_read_string_array: Read an array of string properties. Return zero + * on success, a negative error code otherwise. ++ * @get_name: Return the name of an fwnode. + * @get_parent: Return the parent of an fwnode. + * @get_next_child_node: Return the next child node in an iteration. + * @get_named_child_node: Return a child node with a given name. +@@ -82,6 +83,7 @@ struct fwnode_operations { + (*property_read_string_array)(const struct fwnode_handle *fwnode_handle, + const char *propname, const char **val, + size_t nval); ++ const char *(*get_name)(const struct fwnode_handle *fwnode); + struct fwnode_handle *(*get_parent)(const struct fwnode_handle *fwnode); + struct fwnode_handle * + (*get_next_child_node)(const struct fwnode_handle *fwnode, +diff --git a/include/linux/property.h b/include/linux/property.h +index ea27c5811e1b32..afa84c47bf169a 100644 +--- a/include/linux/property.h ++++ b/include/linux/property.h +@@ -80,6 +80,7 @@ struct fwnode_handle *fwnode_find_reference(const struct fwnode_handle *fwnode, + const char *name, + unsigned int index); + ++const char *fwnode_get_name(const struct fwnode_handle *fwnode); + struct fwnode_handle *fwnode_get_parent(const struct fwnode_handle *fwnode); + struct fwnode_handle *fwnode_get_next_parent( + struct fwnode_handle *fwnode); diff --git a/target/linux/generic/backport-5.4/902-export-fwnode-get-name.patch b/target/linux/generic/backport-5.4/902-export-fwnode-get-name.patch new file mode 100644 index 0000000000..664d771776 --- /dev/null +++ b/target/linux/generic/backport-5.4/902-export-fwnode-get-name.patch @@ -0,0 +1,10 @@ +--- a/drivers/base/property.c ++++ b/drivers/base/property.c +@@ -566,6 +566,7 @@ const char *fwnode_get_name(const struct + { + return fwnode_call_ptr_op(fwnode, get_name); + } ++EXPORT_SYMBOL_GPL(fwnode_get_name); + + /** + * fwnode_get_next_parent - Iterate to the node's parent diff --git a/target/linux/generic/files/drivers/leds/led-class-multicolor.c b/target/linux/generic/files/drivers/leds/led-class-multicolor.c new file mode 100644 index 0000000000..e317408583 --- /dev/null +++ b/target/linux/generic/files/drivers/leds/led-class-multicolor.c @@ -0,0 +1,203 @@ +// SPDX-License-Identifier: GPL-2.0 +// LED Multicolor class interface +// Copyright (C) 2019-20 Texas Instruments Incorporated - http://www.ti.com/ +// Author: Dan Murphy + +#include +#include +#include +#include +#include +#include + +#include "leds.h" + +int led_mc_calc_color_components(struct led_classdev_mc *mcled_cdev, + enum led_brightness brightness) +{ + struct led_classdev *led_cdev = &mcled_cdev->led_cdev; + int i; + + for (i = 0; i < mcled_cdev->num_colors; i++) + mcled_cdev->subled_info[i].brightness = brightness * + mcled_cdev->subled_info[i].intensity / + led_cdev->max_brightness; + + return 0; +} +EXPORT_SYMBOL_GPL(led_mc_calc_color_components); + +static ssize_t multi_intensity_store(struct device *dev, + struct device_attribute *intensity_attr, + const char *buf, size_t size) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct led_classdev_mc *mcled_cdev = lcdev_to_mccdev(led_cdev); + int nrchars, offset = 0; + int intensity_value[LED_COLOR_ID_MAX]; + int i; + ssize_t ret; + + mutex_lock(&led_cdev->led_access); + + for (i = 0; i < mcled_cdev->num_colors; i++) { + ret = sscanf(buf + offset, "%i%n", + &intensity_value[i], &nrchars); + if (ret != 1) { + ret = -EINVAL; + goto err_out; + } + offset += nrchars; + } + + offset++; + if (offset < size) { + ret = -EINVAL; + goto err_out; + } + + for (i = 0; i < mcled_cdev->num_colors; i++) + mcled_cdev->subled_info[i].intensity = intensity_value[i]; + + led_set_brightness(led_cdev, led_cdev->brightness); + ret = size; +err_out: + mutex_unlock(&led_cdev->led_access); + return ret; +} + +static ssize_t multi_intensity_show(struct device *dev, + struct device_attribute *intensity_attr, + char *buf) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct led_classdev_mc *mcled_cdev = lcdev_to_mccdev(led_cdev); + int len = 0; + int i; + + for (i = 0; i < mcled_cdev->num_colors; i++) { + len += sprintf(buf + len, "%d", + mcled_cdev->subled_info[i].intensity); + if (i < mcled_cdev->num_colors - 1) + len += sprintf(buf + len, " "); + } + + buf[len++] = '\n'; + return len; +} +static DEVICE_ATTR_RW(multi_intensity); + +static ssize_t multi_index_show(struct device *dev, + struct device_attribute *multi_index_attr, + char *buf) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct led_classdev_mc *mcled_cdev = lcdev_to_mccdev(led_cdev); + int len = 0; + int index; + int i; + + for (i = 0; i < mcled_cdev->num_colors; i++) { + index = mcled_cdev->subled_info[i].color_index; + len += sprintf(buf + len, "%s", led_colors[index]); + if (i < mcled_cdev->num_colors - 1) + len += sprintf(buf + len, " "); + } + + buf[len++] = '\n'; + return len; +} +static DEVICE_ATTR_RO(multi_index); + +static struct attribute *led_multicolor_attrs[] = { + &dev_attr_multi_intensity.attr, + &dev_attr_multi_index.attr, + NULL, +}; +ATTRIBUTE_GROUPS(led_multicolor); + +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; + + if (!mcled_cdev) + return -EINVAL; + + if (mcled_cdev->num_colors <= 0) + return -EINVAL; + + if (mcled_cdev->num_colors > LED_COLOR_ID_MAX) + return -EINVAL; + + led_cdev = &mcled_cdev->led_cdev; + mcled_cdev->led_cdev.groups = led_multicolor_groups; + + return led_classdev_register_ext(parent, led_cdev, init_data); +} +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); +} + +int devm_led_classdev_multicolor_register_ext(struct device *parent, + struct led_classdev_mc *mcled_cdev, + struct led_init_data *init_data) +{ + 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_ext(parent, mcled_cdev, + init_data); + if (ret) { + devres_free(dr); + return ret; + } + + *dr = mcled_cdev; + devres_add(parent, dr); + + return 0; +} +EXPORT_SYMBOL_GPL(devm_led_classdev_multicolor_register_ext); + +static int devm_led_classdev_multicolor_match(struct device *dev, + void *res, void *data) +{ + struct led_classdev_mc **p = res; + + if (WARN_ON(!p || !*p)) + return 0; + + return *p == data; +} + +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 "); +MODULE_DESCRIPTION("Multicolor LED class interface"); +MODULE_LICENSE("GPL v2"); diff --git a/target/linux/generic/files/include/linux/led-class-multicolor.h b/target/linux/generic/files/include/linux/led-class-multicolor.h new file mode 100644 index 0000000000..210d57bcd7 --- /dev/null +++ b/target/linux/generic/files/include/linux/led-class-multicolor.h @@ -0,0 +1,109 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* LED Multicolor class interface + * Copyright (C) 2019-20 Texas Instruments Incorporated - http://www.ti.com/ + */ + +#ifndef _LINUX_MULTICOLOR_LEDS_H_INCLUDED +#define _LINUX_MULTICOLOR_LEDS_H_INCLUDED + +#include +#include + +struct mc_subled { + unsigned int color_index; + unsigned int brightness; + unsigned int intensity; + unsigned int channel; +}; + +struct led_classdev_mc { + /* led class device */ + struct led_classdev led_cdev; + unsigned int num_colors; + + struct mc_subled *subled_info; +}; + +static inline struct led_classdev_mc *lcdev_to_mccdev( + struct led_classdev *led_cdev) +{ + return container_of(led_cdev, struct led_classdev_mc, led_cdev); +} + +#if IS_ENABLED(CONFIG_LEDS_CLASS_MULTICOLOR) +/** + * 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 multicolor device initialization data + * + * Returns: 0 on success or negative error value on failure + */ +int led_classdev_multicolor_register_ext(struct device *parent, + struct led_classdev_mc *mcled_cdev, + struct led_init_data *init_data); + +/** + * 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 + */ +void led_classdev_multicolor_unregister(struct led_classdev_mc *mcled_cdev); + +/* Calculate brightness for the monochrome LED cluster */ +int led_mc_calc_color_components(struct led_classdev_mc *mcled_cdev, + enum led_brightness brightness); + +int devm_led_classdev_multicolor_register_ext(struct device *parent, + struct led_classdev_mc *mcled_cdev, + struct led_init_data *init_data); + +void devm_led_classdev_multicolor_unregister(struct device *parent, + struct led_classdev_mc *mcled_cdev); +#else + +static inline int led_classdev_multicolor_register_ext(struct device *parent, + struct led_classdev_mc *mcled_cdev, + struct led_init_data *init_data) +{ + return 0; +} + +static inline void led_classdev_multicolor_unregister(struct led_classdev_mc *mcled_cdev) {}; +static inline int led_mc_calc_color_components(struct led_classdev_mc *mcled_cdev, + enum led_brightness brightness) +{ + return 0; +} + +static inline int devm_led_classdev_multicolor_register_ext(struct device *parent, + struct led_classdev_mc *mcled_cdev, + struct led_init_data *init_data) +{ + return 0; +} + +static inline void devm_led_classdev_multicolor_unregister(struct device *parent, + struct led_classdev_mc *mcled_cdev) +{}; + +#endif /* IS_ENABLED(CONFIG_LEDS_CLASS_MULTICOLOR) */ + +static inline int led_classdev_multicolor_register(struct device *parent, + struct led_classdev_mc *mcled_cdev) +{ + return led_classdev_multicolor_register_ext(parent, mcled_cdev, NULL); +} + +static inline int devm_led_classdev_multicolor_register(struct device *parent, + struct led_classdev_mc *mcled_cdev) +{ + return devm_led_classdev_multicolor_register_ext(parent, mcled_cdev, + NULL); +} + +#endif /* _LINUX_MULTICOLOR_LEDS_H_INCLUDED */ diff --git a/target/linux/generic/pending-5.4/841-add-leds-class-multicolor.patch b/target/linux/generic/pending-5.4/841-add-leds-class-multicolor.patch new file mode 100644 index 0000000000..08f2053ca7 --- /dev/null +++ b/target/linux/generic/pending-5.4/841-add-leds-class-multicolor.patch @@ -0,0 +1,30 @@ +--- a/drivers/leds/Kconfig ++++ b/drivers/leds/Kconfig +@@ -30,6 +30,17 @@ config LEDS_CLASS_FLASH + for the flash related features of a LED device. It can be built + as a module. + ++config LEDS_CLASS_MULTICOLOR ++ tristate "LED Multicolor Class Support" ++ depends on LEDS_CLASS ++ default n ++ 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 +--- 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_MULTICOLOR) += led-class-multicolor.o + obj-$(CONFIG_LEDS_TRIGGERS) += led-triggers.o + + # LED Platform Drivers