2019-06-09 19:11:44

by Jacek Anaszewski

[permalink] [raw]
Subject: [PATCH v5 00/26] Add generic support for composing LED class device name

Changes from v4:

- switched "charge" function name to "charging"
- added "cpu", "mute", "micmute", "disk-activity", "panic", "mtd" LED functions
to cover all existing triggers and removed now redundant "nand" and "mmc"
- added "capslock", "scrollock", "numlock" LED functions
- removed now redundant "keyboard" and "keypad" since there is "kbd_backlight"
already available
- removed "tv" LED function as depreciated
- switched LED_COLOR_ID_COUNT to LED_COLOR_ID_MAX
- fixed led_classdev_register_ext() to not leave struct led_classdev's
name pointing to no longer existing composed_name stack variable
- fixed leds-as3645 and leds-aat1290 to no longer rely on struct led_classdev's
name property
- added basic LED class device name validation to get_led_device_info.sh
- tweaked LED naming section in leds_class.txt to allow devicename section
also for non hot-pluggable devices
- always initialize all fields of struct led_init_data to zero on declaration
in drivers
- fix leds-gpio to avoid overwriting the LED name coming from platform_data
- add description of LED function names with regard to whether devicename
section is initialized or not

Changes from v3:

- allow for devicename section for hot-pluggable devices
- move led_colors array to led-core.c to avoid build break
due to Kconfig dependency issue
- add a patch fixing led_colors array name clash with ALSA driver
- change led-enumerator DT property name to more meaningful function-enumerator
- add LED_FUNCTION_KBD_BACKLIGHT
- change naming and add new proprties to struct led_init_data
and struct led_properties

Changes from v2:

- removed from drivers the responsibility of calling led_compose_name()
- added struct device* argument to led_compose_name() to allow using
dev_<level> logging functions for more informative logs
- adjusted the list of LED_FUNCTION definitions according to the v2 review
remarks
- renamed default_desc to default_label in the struct led_init_data
- added led-enumerator DT property to the common LED bindings
- removed LED_COLOR_NAME definitions from include/dt-bindings/leds/common.h
- change DT color property type from string to integer
- change struct initialization list to explicit property assignment in leds-sc27xx-bltc.c
- use led->client->name for led_hw_name in leds-lm3692x.c
- few other minor improvements to docs etc.

Changes from v1:

- improved led_parse_properties() to parse label property at first
and return immediately after parsing succeeds
- added tool get_led_device_info.sh for retrieving LED class device's
parent device related information
- extended LED naming section of Documentation/leds/leds-class.txt
- adjusted the list of LED_FUNCTION definitions according to the v1 review
remarks
- added standard LED_COLOR_NAME definitions
- removed functions.h and moved both LED_FUNCTION and LED_COLOR_NAME
definitions to include/dt-bindings/common.h
- rebased leds-as3645a changes on top of the patch switching to fwnode
property API
- updated DT bindings to use new LED_COLOR_NAME definitions
- improved common LED bindings to not use address unit for sub-nodes
without reg property

Generally I still insist on deprecating label property and devicename
section of LED name. The tool I added for obtaining LED device name
proves availability of the related information in other places in
the sysfs. Other discussed use cases are covered in the updated
Documentation/leds/leds-class.txt.

Beside that, I tried also to create macros for automatic composition
of "-N" suffixed LED functions, so that it would not be necessary
to pollute common.h with plenty repetitions of the same function,
differing only with the postfix. Unfortunately, the preprocessor
of the dtc compiler seems not to accept string concatenetation.
I.e. it is not possible to to the following assighment:

function = "hdd""-1"

If anyone knows how to obviate this shortocoming please let me know.

Original cover letter:

LED class device naming pattern included devicename section, which had
unpleasant effect of varying userspace interface dependent on underlaying
hardware. Moreover, this information was redundant in the LED name, since
the LED controller name could have been obtained from sysfs device group

This patch set introduces a led_compose_name() function in the LED core,
which unifies and simplifies LED class device name composition. This
change is accompanied by the improvements in the common LED DT bindings
where two new properties are introduced: "function" and "color" . The two
deprecate the old "label" property which was leaving too much room for
interpretation, leading to inconsistent LED naming.

There are also changes in LED DT node naming, which are in line with
DT maintainer's request from [0].

Since some DT LED naming unification, related to not including devicename
section in "label" DT property, is being requested during reviews of new
LED class drivers for almost a year now, then those drivers are the first
candidates for optimalization and the first users of the new
led_compose_name() API. The modifications were tested with Qemu,
by stubbing the driver internals where hardware interaction was needed
for proper probing.

Thanks,
Jacek Anaszewski

Jacek Anaszewski (26):
leds: class: Improve LED and LED flash class registration API
dt-bindings: leds: Add LED_COLOR_ID definitions
dt-bindings: leds: Add LED_FUNCTION definitions
dt-bindings: leds: Add properties for LED name construction
leds: core: Add support for composing LED class device names
dt-bindings: sc27xx-blt: Add function and color properties
leds: sc27xx-blt: Use generic support for composing LED names
dt-bindings: lt3593: Add function and color properties
leds: lt3593: Use generic support for composing LED names
dt-bindings: lp8860: Add function and color properties
leds: lp8860: Use generic support for composing LED names
dt-bindings: lm3692x: Add function and color properties
leds: lm3692x: Use generic support for composing LED names
dt-bindings: lm36010: Add function and color properties
leds: lm3601x: Use generic support for composing LED names
dt-bindings: cr0014114: Add function and color properties
leds: cr0014114: Use generic support for composing LED names
dt-bindings: aat1290: Add function and color properties
leds: aat1290: Use generic support for composing LED names
dt-bindings: as3645a: Add function and color properties
leds: as3645a: Use generic support for composing LED names
dt-bindings: leds-gpio: Add function and color properties
leds: gpio: Use generic support for composing LED names
dt-bindings: an30259a: Add function and color properties
leds: an30259a: Use generic support for composing LED names
leds: Document standard LED functions

.../devicetree/bindings/leds/ams,as3645a.txt | 22 +-
Documentation/devicetree/bindings/leds/common.txt | 62 +++++-
.../devicetree/bindings/leds/leds-aat1290.txt | 12 +-
.../devicetree/bindings/leds/leds-an30259a.txt | 22 +-
.../devicetree/bindings/leds/leds-cr0014114.txt | 26 ++-
.../devicetree/bindings/leds/leds-gpio.txt | 23 ++-
.../devicetree/bindings/leds/leds-lm3601x.txt | 10 +-
.../devicetree/bindings/leds/leds-lm3692x.txt | 9 +-
.../devicetree/bindings/leds/leds-lp8860.txt | 9 +-
.../devicetree/bindings/leds/leds-lt3593.txt | 11 +-
.../devicetree/bindings/leds/leds-sc27xx-bltc.txt | 10 +-
Documentation/leds/led-functions.txt | 223 +++++++++++++++++++++
Documentation/leds/leds-class.txt | 70 ++++++-
drivers/leds/led-class-flash.c | 9 +-
drivers/leds/led-class.c | 49 +++--
drivers/leds/led-core.c | 127 ++++++++++++
drivers/leds/leds-aat1290.c | 16 +-
drivers/leds/leds-an30259a.c | 25 +--
drivers/leds/leds-as3645a.c | 74 +++----
drivers/leds/leds-cr0014114.c | 33 +--
drivers/leds/leds-gpio.c | 26 +--
drivers/leds/leds-lm3601x.c | 38 ++--
drivers/leds/leds-lm3692x.c | 22 +-
drivers/leds/leds-lp8860.c | 35 ++--
drivers/leds/leds-lt3593.c | 20 +-
drivers/leds/leds-pwm.c | 2 +-
drivers/leds/leds-sc27xx-bltc.c | 22 +-
drivers/leds/leds.h | 1 +
include/dt-bindings/leds/common.h | 55 ++++-
include/linux/led-class-flash.h | 15 +-
include/linux/leds.h | 79 +++++++-
tools/leds/get_led_device_info.sh | 201 +++++++++++++++++++
32 files changed, 1086 insertions(+), 272 deletions(-)
create mode 100644 Documentation/leds/led-functions.txt
create mode 100755 tools/leds/get_led_device_info.sh

--
2.11.0


2019-06-09 19:11:45

by Jacek Anaszewski

[permalink] [raw]
Subject: [PATCH v5 10/26] dt-bindings: lp8860: Add function and color properties

Refer to new "function" and "color" properties and mark "label"
as deprecated.

Signed-off-by: Jacek Anaszewski <[email protected]>
Reviewed-by: Rob Herring <[email protected]>
Reviewed-by: Dan Murphy <[email protected]>
---
Documentation/devicetree/bindings/leds/leds-lp8860.txt | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/leds/leds-lp8860.txt b/Documentation/devicetree/bindings/leds/leds-lp8860.txt
index 5f0e892ad759..9863220db4ba 100644
--- a/Documentation/devicetree/bindings/leds/leds-lp8860.txt
+++ b/Documentation/devicetree/bindings/leds/leds-lp8860.txt
@@ -20,12 +20,16 @@ Required child properties:
- reg : 0

Optional child properties:
- - label : see Documentation/devicetree/bindings/leds/common.txt
+ - function : see Documentation/devicetree/bindings/leds/common.txt
+ - color : see Documentation/devicetree/bindings/leds/common.txt
+ - label : see Documentation/devicetree/bindings/leds/common.txt (deprecated)
- linux,default-trigger :
see Documentation/devicetree/bindings/leds/common.txt

Example:

+#include <dt-bindings/leds/common.h>
+
led-controller@2d {
compatible = "ti,lp8860";
#address-cells = <1>;
@@ -36,7 +40,8 @@ led-controller@2d {

led@0 {
reg = <0>;
- label = "white:backlight";
+ function = LED_FUNCTION_BACKLIGHT;
+ color = <LED_COLOR_ID_WHITE>;
linux,default-trigger = "backlight";
};
}
--
2.11.0

2019-06-09 19:11:50

by Jacek Anaszewski

[permalink] [raw]
Subject: [PATCH v5 09/26] leds: lt3593: Use generic support for composing LED names

Switch to using generic LED support for composing LED class
device name.

Signed-off-by: Jacek Anaszewski <[email protected]>
Cc: Daniel Mack <[email protected]>
Acked-by: Pavel Machek <[email protected]>
---
drivers/leds/leds-lt3593.c | 20 ++++++++------------
1 file changed, 8 insertions(+), 12 deletions(-)

diff --git a/drivers/leds/leds-lt3593.c b/drivers/leds/leds-lt3593.c
index 83e8e58d81cb..c94995f0daa2 100644
--- a/drivers/leds/leds-lt3593.c
+++ b/drivers/leds/leds-lt3593.c
@@ -10,10 +10,10 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <uapi/linux/uleds.h>
+
+#define LED_LT3593_NAME "lt3593"

struct lt3593_led_data {
- char name[LED_MAX_NAME_SIZE];
struct led_classdev cdev;
struct gpio_desc *gpiod;
};
@@ -66,6 +66,7 @@ static int lt3593_led_probe(struct platform_device *pdev)
struct lt3593_led_data *led_data;
struct fwnode_handle *child;
int ret, state = LEDS_GPIO_DEFSTATE_OFF;
+ struct led_init_data init_data = {};
const char *tmp;

if (!dev->of_node)
@@ -86,14 +87,6 @@ static int lt3593_led_probe(struct platform_device *pdev)

child = device_get_next_child_node(dev, NULL);

- ret = fwnode_property_read_string(child, "label", &tmp);
- if (ret < 0)
- snprintf(led_data->name, sizeof(led_data->name),
- "lt3593::");
- else
- snprintf(led_data->name, sizeof(led_data->name),
- "lt3593:%s", tmp);
-
fwnode_property_read_string(child, "linux,default-trigger",
&led_data->cdev.default_trigger);

@@ -102,11 +95,14 @@ static int lt3593_led_probe(struct platform_device *pdev)
state = LEDS_GPIO_DEFSTATE_ON;
}

- led_data->cdev.name = led_data->name;
led_data->cdev.brightness_set_blocking = lt3593_led_set;
led_data->cdev.brightness = state ? LED_FULL : LED_OFF;

- ret = devm_led_classdev_register(dev, &led_data->cdev);
+ init_data.fwnode = child;
+ init_data.devicename = LED_LT3593_NAME;
+ init_data.default_label = ":";
+
+ ret = devm_led_classdev_register_ext(dev, &led_data->cdev, &init_data);
if (ret < 0) {
fwnode_handle_put(child);
return ret;
--
2.11.0

2019-06-09 19:11:52

by Jacek Anaszewski

[permalink] [raw]
Subject: [PATCH v5 25/26] leds: an30259a: Use generic support for composing LED names

Switch to using generic LED support for composing LED class
device name.

Signed-off-by: Jacek Anaszewski <[email protected]>
Cc: Simon Shields <[email protected]>
---
drivers/leds/leds-an30259a.c | 25 +++++++++++++------------
1 file changed, 13 insertions(+), 12 deletions(-)

diff --git a/drivers/leds/leds-an30259a.c b/drivers/leds/leds-an30259a.c
index 1c1f0c8c56f4..fa722d45269e 100644
--- a/drivers/leds/leds-an30259a.c
+++ b/drivers/leds/leds-an30259a.c
@@ -13,7 +13,6 @@
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/regmap.h>
-#include <uapi/linux/uleds.h>

#define AN30259A_MAX_LEDS 3

@@ -54,6 +53,8 @@
#define AN30259A_BLINK_MAX_TIME 7500 /* ms */
#define AN30259A_SLOPE_RESOLUTION 500 /* ms */

+#define AN30259A_NAME "an30259a"
+
#define STATE_OFF 0
#define STATE_KEEP 1
#define STATE_ON 2
@@ -62,11 +63,11 @@ struct an30259a;

struct an30259a_led {
struct an30259a *chip;
+ struct fwnode_handle *fwnode;
struct led_classdev cdev;
u32 num;
u32 default_state;
bool sloping;
- char label[LED_MAX_NAME_SIZE];
};

struct an30259a {
@@ -226,14 +227,7 @@ static int an30259a_dt_init(struct i2c_client *client,

led->num = source;
led->chip = chip;
-
- if (of_property_read_string(child, "label", &str))
- snprintf(led->label, sizeof(led->label), "an30259a::");
- else
- snprintf(led->label, sizeof(led->label), "an30259a:%s",
- str);
-
- led->cdev.name = led->label;
+ led->fwnode = of_fwnode_handle(child);

if (!of_property_read_string(child, "default-state", &str)) {
if (!strcmp(str, "on"))
@@ -312,13 +306,20 @@ static int an30259a_probe(struct i2c_client *client)
chip->regmap = devm_regmap_init_i2c(client, &an30259a_regmap_config);

for (i = 0; i < chip->num_leds; i++) {
+ struct led_init_data init_data = {};
+
an30259a_init_default_state(&chip->leds[i]);
chip->leds[i].cdev.brightness_set_blocking =
an30259a_brightness_set;
chip->leds[i].cdev.blink_set = an30259a_blink_set;

- err = devm_led_classdev_register(&client->dev,
- &chip->leds[i].cdev);
+ init_data.fwnode = chip->leds[i].fwnode;
+ init_data.devicename = AN30259A_NAME;
+ init_data.default_label = ":";
+
+ err = devm_led_classdev_register_ext(&client->dev,
+ &chip->leds[i].cdev,
+ &init_data);
if (err < 0)
goto exit;
}
--
2.11.0

2019-06-09 19:11:59

by Jacek Anaszewski

[permalink] [raw]
Subject: [PATCH v5 20/26] dt-bindings: as3645a: Add function and color properties

Refer to new "function" and "color" properties and mark "label"
as deprecated.

Also, fix malformed syntax of address-cells and size-cells
in the example.

Signed-off-by: Jacek Anaszewski <[email protected]>
Cc: Sakari Ailus <[email protected]>
Reviewed-by: Rob Herring <[email protected]>
---
.../devicetree/bindings/leds/ams,as3645a.txt | 22 ++++++++++++++--------
1 file changed, 14 insertions(+), 8 deletions(-)

diff --git a/Documentation/devicetree/bindings/leds/ams,as3645a.txt b/Documentation/devicetree/bindings/leds/ams,as3645a.txt
index fdc40e354a64..4af2987b25e9 100644
--- a/Documentation/devicetree/bindings/leds/ams,as3645a.txt
+++ b/Documentation/devicetree/bindings/leds/ams,as3645a.txt
@@ -39,7 +39,9 @@ ams,input-max-microamp: Maximum flash controller input current. The
Optional properties of the flash child node
===========================================

-label : The label of the flash LED.
+function : See Documentation/devicetree/bindings/leds/common.txt.
+color : See Documentation/devicetree/bindings/leds/common.txt.
+label : See Documentation/devicetree/bindings/leds/common.txt (deprecated).


Required properties of the indicator child node (1)
@@ -52,28 +54,32 @@ led-max-microamp: Maximum indicator current. The allowed values are
Optional properties of the indicator child node
===============================================

-label : The label of the indicator LED.
+function : See Documentation/devicetree/bindings/leds/common.txt.
+color : See Documentation/devicetree/bindings/leds/common.txt.
+label : See Documentation/devicetree/bindings/leds/common.txt (deprecated).


Example
=======

+#include <dt-bindings/leds/common.h>
+
as3645a@30 {
- #address-cells: 1
- #size-cells: 0
+ #address-cells = <1>;
+ #size-cells = <0>;
reg = <0x30>;
compatible = "ams,as3645a";
- flash@0 {
+ led@0 {
reg = <0x0>;
flash-timeout-us = <150000>;
flash-max-microamp = <320000>;
led-max-microamp = <60000>;
ams,input-max-microamp = <1750000>;
- label = "as3645a:flash";
+ function = LED_FUNCTION_FLASH;
};
- indicator@1 {
+ led@1 {
reg = <0x1>;
led-max-microamp = <10000>;
- label = "as3645a:indicator";
+ function = LED_FUNCTION_INDICATOR;
};
};
--
2.11.0

2019-06-09 19:12:04

by Jacek Anaszewski

[permalink] [raw]
Subject: [PATCH v5 08/26] dt-bindings: lt3593: Add function and color properties

Refer to new "function" and "color" properties and mark "label"
as deprecated.

Signed-off-by: Jacek Anaszewski <[email protected]>
Cc: Daniel Mack <[email protected]>
Reviewed-by: Rob Herring <[email protected]>
---
Documentation/devicetree/bindings/leds/leds-lt3593.txt | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/leds/leds-lt3593.txt b/Documentation/devicetree/bindings/leds/leds-lt3593.txt
index 6b2cabc36c0c..24eccdaa6322 100644
--- a/Documentation/devicetree/bindings/leds/leds-lt3593.txt
+++ b/Documentation/devicetree/bindings/leds/leds-lt3593.txt
@@ -9,8 +9,10 @@ The hardware supports only one LED. The properties of this LED are
configured in a sub-node in the device node.

Optional sub-node properties:
-- label: A label for the LED. If none is given, the LED will be
- named "lt3595::".
+- function: See Documentation/devicetree/bindings/leds/common.txt
+- color: See Documentation/devicetree/bindings/leds/common.txt
+- label: A label for the LED. If none is given, the LED will be
+ named "lt3595::" (deprecated)
- linux,default-trigger: The default trigger for the LED.
See Documentation/devicetree/bindings/leds/common.txt
- default-state: The initial state of the LED.
@@ -21,12 +23,15 @@ be handled by its own device node.

Example:

+#include <dt-bindings/leds/common.h>
+
led-controller {
compatible = "lltc,lt3593";
lltc,ctrl-gpios = <&gpio 0 GPIO_ACTIVE_HIGH>;

led {
- label = "white:backlight";
+ function = LED_FUNCTION_BACKLIGHT;
+ color = <LED_COLOR_ID_WHITE>;
default-state = "on";
};
};
--
2.11.0

2019-06-09 19:12:07

by Jacek Anaszewski

[permalink] [raw]
Subject: [PATCH v5 05/26] leds: core: Add support for composing LED class device names

Add generic support for composing LED class device name. The newly
introduced led_compose_name() function composes device name according
to either <color:function> or <devicename:color:function> pattern,
depending on the configuration of initialization data.

Backward compatibility with in-driver hard-coded LED class device
names is assured thanks to the default_label and devicename properties
of newly introduced struct led_init_data.

In case none of the aforementioned properties was found, then, for OF
nodes, the node name is adopted for LED class device name.

At the occassion of amending the Documentation/leds/leds-class.txt
unify spelling: colour -> color.

Alongside these changes added is a new tool - tools/leds/get_led_device_info.sh.
The tool allows retrieving details of a LED class device's parent device,
which proves that using vendor or product name for devicename part
of LED name doesn't convey any added value since that information had been
already available in sysfs. The script performs also basic validation
of a LED class device name.

Signed-off-by: Jacek Anaszewski <[email protected]>
Cc: Baolin Wang <[email protected]>
Cc: Pavel Machek <[email protected]>
Cc: Dan Murphy <[email protected]>
Cc: Daniel Mack <[email protected]>
Cc: Linus Walleij <[email protected]>
Cc: Oleh Kravchenko <[email protected]>
Cc: Sakari Ailus <[email protected]>
Cc: Simon Shields <[email protected]>
---
Documentation/leds/leds-class.txt | 67 ++++++++++++-
drivers/leds/led-class.c | 20 +++-
drivers/leds/led-core.c | 127 ++++++++++++++++++++++++
drivers/leds/leds.h | 1 +
include/linux/leds.h | 45 +++++++++
tools/leds/get_led_device_info.sh | 201 ++++++++++++++++++++++++++++++++++++++
6 files changed, 455 insertions(+), 6 deletions(-)
create mode 100755 tools/leds/get_led_device_info.sh

diff --git a/Documentation/leds/leds-class.txt b/Documentation/leds/leds-class.txt
index 8b39cc6b03ee..e7316e37b57d 100644
--- a/Documentation/leds/leds-class.txt
+++ b/Documentation/leds/leds-class.txt
@@ -43,9 +43,70 @@ LED Device Naming

Is currently of the form:

-"devicename:colour:function"
-
-There have been calls for LED properties such as colour to be exported as
+"devicename:color:function"
+
+devicename: It should refer to a unique identifier created by the kernel,
+ like e.g. phyN for network devices or inputN for input devices,
+ rather than to the hardware. The information related to the product
+ and the bus to which given device is hooked is available in the
+ sysfs and can be retrieved using get_led_device_info.sh script
+ from tools/leds. Generally this section is expected mostly for
+ LEDs that are somehow associated with other devices.
+
+color: one of the color strings from led_colors array defined
+ in drivers/leds/led-core.c.
+
+function: one of the LED_FUNCTION* definitions from the header
+ include/dt-bindings/leds/common.h.
+
+If required color or function is missing, please submit a patch
+to [email protected], adding required entries.
+
+It is possible that more than one LED with the same color and function will
+be required for given platform, differing only with an ordinal number.
+In this case it is preferable to just concatenate the predefined LED_FUNCTION*
+name with required "-N" suffix in the driver. fwnode based drivers can use
+function-enumerator property for that and then the concatenation will be handled
+automatically by the LED core upon LED class device registration.
+
+LED subsystem has also a protection against name clash, that may occur
+when LED class device is created by a driver of hot-pluggable device and
+it doesn't provide unique devicename section. In this case numerical
+suffix (e.g. "_1", "_2", "_3" etc.) is added to the requested LED class
+device name.
+
+There might be still LED class drivers around using vendor or product name
+for devicename, but this approach is now deprecated as it doesn't convey
+any added value. Product information can be found in other places in sysfs
+(see tools/leds/get_led_device_info.sh).
+
+Examples of proper LED names:
+
+"red:disk"
+"white:flash"
+"red:indicator"
+"phy1:green:wlan"
+"phy3::wlan"
+":kbd_backlight"
+"input5::kbd_backlight"
+"input3::numlock"
+"input3::scrolllock"
+"input3::capslock"
+"mmc1::status"
+"white:status"
+
+get_led_device_info.sh script can be used for verifying if the LED name
+meets the requirements pointed out here. It performs validation of the LED class
+devicename sections and gives hints on expected value for a section in case
+the validation fails for it. So far the script supports validation
+of associations between LEDs and following types of devices:
+
+- input devices
+- ieee80211 compliant USB devices
+
+The script is open to extensions.
+
+There have been calls for LED properties such as color to be exported as
individual led class attributes. As a solution which doesn't incur as much
overhead, I suggest these become part of the device name. The naming scheme
above leaves scope for further attributes should they be needed. If sections
diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
index a564948e5f53..e3af0b71c9a9 100644
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -257,17 +257,31 @@ int led_classdev_register_ext(struct device *parent,
struct led_classdev *led_cdev,
struct led_init_data *init_data)
{
- char name[LED_MAX_NAME_SIZE];
+ char composed_name[LED_MAX_NAME_SIZE];
+ char final_name[LED_MAX_NAME_SIZE];
+ const char *proposed_name = composed_name;
int ret;

- ret = led_classdev_next_name(led_cdev->name, name, sizeof(name));
+ if (init_data) {
+ if (init_data->devname_mandatory && !init_data->devicename) {
+ dev_err(parent, "Mandatory device name is missing");
+ return -EINVAL;
+ }
+ ret = led_compose_name(parent, init_data, composed_name);
+ if (ret < 0)
+ return ret;
+ } else {
+ proposed_name = led_cdev->name;
+ }
+
+ ret = led_classdev_next_name(proposed_name, final_name, sizeof(final_name));
if (ret < 0)
return ret;

mutex_init(&led_cdev->led_access);
mutex_lock(&led_cdev->led_access);
led_cdev->dev = device_create_with_groups(leds_class, parent, 0,
- led_cdev, led_cdev->groups, "%s", name);
+ led_cdev, led_cdev->groups, "%s", final_name);
if (IS_ERR(led_cdev->dev)) {
mutex_unlock(&led_cdev->led_access);
return PTR_ERR(led_cdev->dev);
diff --git a/drivers/leds/led-core.c b/drivers/leds/led-core.c
index e3da7c03da1b..dcd14ea40687 100644
--- a/drivers/leds/led-core.c
+++ b/drivers/leds/led-core.c
@@ -17,8 +17,10 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
+#include <linux/property.h>
#include <linux/rwsem.h>
#include <linux/slab.h>
+#include <uapi/linux/uleds.h>
#include "leds.h"

DECLARE_RWSEM(leds_list_lock);
@@ -27,6 +29,18 @@ EXPORT_SYMBOL_GPL(leds_list_lock);
LIST_HEAD(leds_list);
EXPORT_SYMBOL_GPL(leds_list);

+const char *led_colors[LED_COLOR_ID_MAX] = {
+ [LED_COLOR_ID_WHITE] = "white",
+ [LED_COLOR_ID_RED] = "red",
+ [LED_COLOR_ID_GREEN] = "green",
+ [LED_COLOR_ID_BLUE] = "blue",
+ [LED_COLOR_ID_AMBER] = "amber",
+ [LED_COLOR_ID_VIOLET] = "violet",
+ [LED_COLOR_ID_YELLOW] = "yellow",
+ [LED_COLOR_ID_IR] = "ir",
+};
+EXPORT_SYMBOL_GPL(led_colors);
+
static int __led_set_brightness(struct led_classdev *led_cdev,
enum led_brightness value)
{
@@ -357,3 +371,116 @@ void led_sysfs_enable(struct led_classdev *led_cdev)
led_cdev->flags &= ~LED_SYSFS_DISABLE;
}
EXPORT_SYMBOL_GPL(led_sysfs_enable);
+
+static void led_parse_fwnode_props(struct device *dev,
+ struct fwnode_handle *fwnode,
+ struct led_properties *props)
+{
+ int ret;
+
+ if (!fwnode)
+ return;
+
+ if (fwnode_property_present(fwnode, "label")) {
+ ret = fwnode_property_read_string(fwnode, "label", &props->label);
+ if (ret)
+ dev_err(dev, "Error parsing \'label\' property (%d)\n", ret);
+ return;
+ }
+
+ if (fwnode_property_present(fwnode, "color")) {
+ ret = fwnode_property_read_u32(fwnode, "color", &props->color);
+ if (ret)
+ dev_err(dev, "Error parsing \'color\' property (%d)\n", ret);
+ else if (props->color >= LED_COLOR_ID_MAX)
+ dev_err(dev, "LED color identifier out of range\n");
+ else
+ props->color_present = true;
+ }
+
+
+ if (fwnode_property_present(fwnode, "function")) {
+ ret = fwnode_property_read_string(fwnode, "function", &props->function);
+ if (ret) {
+ dev_err(dev,
+ "Error parsing \'function\' property (%d)\n",
+ ret);
+ }
+ } else {
+ return;
+ }
+
+ if (fwnode_property_present(fwnode, "function-enumerator")) {
+ ret = fwnode_property_read_u32(fwnode, "function-enumerator",
+ &props->func_enum);
+ if (ret) {
+ dev_err(dev,
+ "Error parsing \'function-enumerator\' property (%d)\n",
+ ret);
+ } else {
+ props->func_enum_present = true;
+ }
+ }
+}
+
+int led_compose_name(struct device *dev, struct led_init_data *init_data,
+ char *led_classdev_name)
+{
+ struct led_properties props = {};
+ struct fwnode_handle *fwnode = init_data->fwnode;
+ const char *devicename = init_data->devicename;
+
+ if (!led_classdev_name)
+ return -EINVAL;
+
+ led_parse_fwnode_props(dev, fwnode, &props);
+
+ if (props.label) {
+ /*
+ * If init_data.devicename is NULL, then it indicates that
+ * DT label should be used as-is for LED class device name.
+ * Otherwise the label is prepended with devicename to compose
+ * the final LED class device name.
+ */
+ if (!devicename) {
+ strncpy(led_classdev_name, props.label,
+ LED_MAX_NAME_SIZE);
+ } else {
+ snprintf(led_classdev_name, LED_MAX_NAME_SIZE, "%s:%s",
+ devicename, props.label);
+ }
+ } else if (props.function || props.color_present) {
+ char tmp_buf[LED_MAX_NAME_SIZE];
+
+ if (props.func_enum_present) {
+ snprintf(tmp_buf, LED_MAX_NAME_SIZE, "%s:%s-%d",
+ props.color_present ? led_colors[props.color] : "",
+ props.function ?: "", props.func_enum);
+ } else {
+ snprintf(tmp_buf, LED_MAX_NAME_SIZE, "%s:%s",
+ props.color_present ? led_colors[props.color] : "",
+ props.function ?: "");
+ }
+ if (init_data->devname_mandatory) {
+ snprintf(led_classdev_name, LED_MAX_NAME_SIZE, "%s:%s",
+ devicename, tmp_buf);
+ } else {
+ strncpy(led_classdev_name, tmp_buf, LED_MAX_NAME_SIZE);
+
+ }
+ } else if (init_data->default_label) {
+ if (!devicename) {
+ dev_err(dev, "Legacy LED naming requires devicename segment");
+ return -EINVAL;
+ }
+ snprintf(led_classdev_name, LED_MAX_NAME_SIZE, "%s:%s",
+ devicename, init_data->default_label);
+ } else if (is_of_node(fwnode)) {
+ strncpy(led_classdev_name, to_of_node(fwnode)->name,
+ LED_MAX_NAME_SIZE);
+ } else
+ return -EINVAL;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(led_compose_name);
diff --git a/drivers/leds/leds.h b/drivers/leds/leds.h
index 7d38e6b9a740..0d223c1f93b2 100644
--- a/drivers/leds/leds.h
+++ b/drivers/leds/leds.h
@@ -31,5 +31,6 @@ void led_set_brightness_nosleep(struct led_classdev *led_cdev,
extern struct rw_semaphore leds_list_lock;
extern struct list_head leds_list;
extern struct list_head trigger_list;
+extern const char *led_colors[LED_COLOR_ID_MAX];

#endif /* __LEDS_H_INCLUDED */
diff --git a/include/linux/leds.h b/include/linux/leds.h
index fab83a2d7bff..03e9795fa23b 100644
--- a/include/linux/leds.h
+++ b/include/linux/leds.h
@@ -12,6 +12,7 @@
#ifndef __LINUX_LEDS_H_INCLUDED
#define __LINUX_LEDS_H_INCLUDED

+#include <dt-bindings/leds/common.h>
#include <linux/device.h>
#include <linux/kernfs.h>
#include <linux/list.h>
@@ -37,6 +38,25 @@ enum led_brightness {
struct led_init_data {
/* device fwnode handle */
struct fwnode_handle *fwnode;
+ /*
+ * default <color:function> tuple, for backward compatibility
+ * with in-driver hard-coded LED names used as a fallback when
+ * DT "label" property is absent; it should be set to NULL
+ * in new LED class drivers.
+ */
+ const char *default_label;
+ /*
+ * string to be used for devicename section of LED class device
+ * either for label based LED name composition path or for fwnode
+ * based when devname_mandatory is true
+ */
+ const char *devicename;
+ /*
+ * indicates if LED name should always comprise devicename section;
+ * only LEDs exposed by drivers of hot-pluggable devices should
+ * set it to true
+ */
+ bool devname_mandatory;
};

struct led_classdev {
@@ -262,6 +282,22 @@ extern void led_sysfs_disable(struct led_classdev *led_cdev);
extern void led_sysfs_enable(struct led_classdev *led_cdev);

/**
+ * led_compose_name - compose LED class device name
+ * @dev: LED controller device object
+ * @child: child fwnode_handle describing a LED or a group of synchronized LEDs;
+ * it must be provided only for fwnode based LEDs
+ * @led_classdev_name: composed LED class device name
+ *
+ * Create LED class device name basing on the provided init_data argument.
+ * The name can have <devicename:color:function> or <color:function>.
+ * form, depending on the init_data configuration.
+ *
+ * Returns: 0 on success or negative error value on failure
+ */
+extern int led_compose_name(struct device *dev, struct led_init_data *init_data,
+ char *led_classdev_name);
+
+/**
* led_sysfs_is_disabled - check if LED sysfs interface is disabled
* @led_cdev: the LED to query
*
@@ -438,6 +474,15 @@ struct led_platform_data {
struct led_info *leds;
};

+struct led_properties {
+ u32 color;
+ bool color_present;
+ const char *function;
+ u32 func_enum;
+ bool func_enum_present;
+ const char *label;
+};
+
struct gpio_desc;
typedef int (*gpio_blink_set_t)(struct gpio_desc *desc, int state,
unsigned long *delay_on,
diff --git a/tools/leds/get_led_device_info.sh b/tools/leds/get_led_device_info.sh
new file mode 100755
index 000000000000..ccfa442db5fe
--- /dev/null
+++ b/tools/leds/get_led_device_info.sh
@@ -0,0 +1,201 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+
+led_common_defs_path="include/dt-bindings/leds/common.h"
+
+num_args=$#
+if [ $num_args -eq 1 ]; then
+ linux_top=$(dirname `realpath $0` | awk -F/ \
+ '{ \
+ i=1; \
+ while (i <= NF - 2) { \
+ printf $i"/"; \
+ i++; \
+ }; \
+ }')
+ led_defs_path=$linux_top/$led_common_defs_path
+elif [ $num_args -eq 2 ]; then
+ led_defs_path=`realpath $2`
+else
+ echo "Usage: get_led_device_info.sh LED_CDEV_PATH [LED_COMMON_DEFS_PATH]"
+ exit 1
+fi
+
+if [ ! -f $led_defs_path ]; then
+ echo "$led_defs_path doesn't exist"
+ exit 1
+fi
+
+led_cdev_path=`echo $1 | sed s'/\/$//'`
+
+ls "$led_cdev_path/brightness" > /dev/null 2>&1
+if [ $? -ne 0 ]; then
+ echo "Device \"$led_cdev_path\" does not exist."
+ exit 1
+fi
+
+bus=`readlink $led_cdev_path/device/subsystem | sed s'/.*\///'`
+usb_subdev=`readlink $led_cdev_path | grep usb | sed s'/\(.*usb[0-9]*\/[0-9]*-[0-9]*\)\/.*/\1/'`
+ls "$led_cdev_path/device/of_node/compatible" > /dev/null 2>&1
+of_node_missing=$?
+
+if [ "$bus" = "input" ]; then
+ input_node=`readlink $led_cdev_path/device | sed s'/.*\///'`
+ if [ ! -z "$usb_subdev" ]; then
+ bus="usb"
+ fi
+fi
+
+if [ "$bus" = "usb" ]; then
+ usb_interface=`readlink $led_cdev_path | sed s'/.*\(usb[0-9]*\)/\1/' | cut -d\/ -f3`
+ cd $led_cdev_path/../$usb_subdev
+ driver=`readlink $usb_interface/driver | sed s'/.*\///'`
+ if [ -d "$usb_interface/ieee80211" ]; then
+ wifi_phy=`ls -l $usb_interface/ieee80211 | grep phy | awk '{print $9}'`
+ fi
+ idVendor=`cat idVendor`
+ idProduct=`cat idProduct`
+ manufacturer=`cat manufacturer`
+ product=`cat product`
+elif [ "$bus" = "input" ]; then
+ cd $led_cdev_path
+ product=`cat device/name`
+ driver=`cat device/device/driver/description`
+elif [ $of_node_missing -eq 0 ]; then
+ cd $led_cdev_path
+ compatible=`cat device/of_node/compatible`
+ if [ "$compatible" = "gpio-leds" ]; then
+ driver="leds-gpio"
+ elif [ "$compatible" = "pwm-leds" ]; then
+ driver="leds-pwm"
+ else
+ manufacturer=`echo $compatible | awk -F, '{print $1}'`
+ product=`echo $compatible | awk -F, '{print $2}'`
+ fi
+else
+ echo "Unknown device type."
+ exit 1
+fi
+
+printf "\n#####################################\n"
+printf "# LED class device hardware details #\n"
+printf "#####################################\n\n"
+
+printf "bus:\t\t\t$bus\n"
+
+if [ ! -z "$idVendor" ]; then
+ printf "idVendor:\t\t$idVendor\n"
+fi
+
+if [ ! -z "$idProduct" ]; then
+ printf "idProduct:\t\t$idProduct\n"
+fi
+
+if [ ! -z "$manufacturer" ]; then
+ printf "manufacturer:\t\t$manufacturer\n"
+fi
+
+if [ ! -z "$product" ]; then
+ printf "product:\t\t$product\n"
+fi
+
+if [ ! -z "$driver" ]; then
+ printf "driver:\t\t\t$driver\n"
+fi
+
+if [ ! -z "$input_node" ]; then
+ printf "associated input node:\t$input_node\n"
+fi
+
+printf "\n####################################\n"
+printf "# LED class device name validation #\n"
+printf "####################################\n\n"
+
+led_name=`echo $led_cdev_path | sed s'/.*\///'`
+
+num_sections=`echo $led_name | awk -F: '{print NF}'`
+
+if [ $num_sections -eq 1 ]; then
+ printf "\":\" delimiter not detected.\t[ FAILED ]\n"
+ exit 1
+elif [ $num_sections -eq 2 ]; then
+ color=`echo $led_name | cut -d: -f1`
+ function=`echo $led_name | cut -d: -f2`
+elif [ $num_sections -eq 3 ]; then
+ devicename=`echo $led_name | cut -d: -f1`
+ color=`echo $led_name | cut -d: -f2`
+ function=`echo $led_name | cut -d: -f3`
+else
+ printf "Detected %d sections in the LED class device name - should the script be updated?\n" $num_sections
+ exit 1
+fi
+
+S_DEV="devicename"
+S_CLR="color "
+S_FUN="function "
+status_tab=20
+
+print_msg_ok()
+{
+ local section_name="$1"
+ local section_val="$2"
+ local msg="$3"
+ printf "$section_name :\t%-${status_tab}.${status_tab}s %s %s\n" "$section_val" "[ OK ] " "$msg"
+}
+
+print_msg_failed()
+{
+ local section_name="$1"
+ local section_val="$2"
+ local msg="$3"
+ printf "$section_name :\t%-${status_tab}.${status_tab}s %s %s\n" "$section_val" "[ FAILED ]" "$msg"
+}
+
+if [ ! -z "$input_node" ]; then
+ expected_devname=$input_node
+elif [ ! -z "$wifi_phy" ]; then
+ expected_devname=$wifi_phy
+fi
+
+if [ ! -z "$devicename" ]; then
+ if [ ! -z "$expected_devname" ]; then
+ if [ "$devicename" = "$expected_devname" ]; then
+ print_msg_ok "$S_DEV" "$devicename"
+ else
+ print_msg_failed "$S_DEV" "$devicename" "Expected: $expected_devname"
+ fi
+ else
+ if [ "$devicename" = "$manufacturer" ]; then
+ print_msg_failed "$S_DEV" "$devicename" "Redundant: use of vendor name is discouraged"
+ elif [ "$devicename" = "$product" ]; then
+ print_msg_failed "$S_DEV" "$devicename" "Redundant: use of product name is discouraged"
+ else
+ print_msg_failed "$S_DEV" "$devicename" "Unknown devicename - should the script be updated?"
+ fi
+ fi
+elif [ ! -z "$expected_devname" ]; then
+ print_msg_failed "$S_DEV" "blank" "Expected: $expected_devname"
+fi
+
+if [ ! -z "$color" ]; then
+ color_upper=`echo $color | tr [:lower:] [:upper:]`
+ color_id_definition=$(cat $led_defs_path | grep "_$color_upper\s" | awk '{print $2}')
+ if [ ! -z "$color_id_definition" ]; then
+ print_msg_ok "$S_CLR" "$color" "Matching definition: $color_id_definition"
+ else
+ print_msg_failed "$S_CLR" "$color" "Definition not found in $led_defs_path"
+ fi
+
+fi
+
+if [ ! -z "$function" ]; then
+ # strip optional enumerator
+ function=`echo $function | sed s'/\(.*\)-[0-9]*$/\1/'`
+ fun_definition=$(cat $led_defs_path | grep "\"$function\"" | awk '{print $2}')
+ if [ ! -z "$fun_definition" ]; then
+ print_msg_ok "$S_FUN" "$function" "Matching definition: $fun_definition"
+ else
+ print_msg_failed "$S_FUN" "$function" "Definition not found in $led_defs_path"
+ fi
+
+fi
--
2.11.0

2019-06-09 19:12:15

by Jacek Anaszewski

[permalink] [raw]
Subject: [PATCH v5 07/26] leds: sc27xx-blt: Use generic support for composing LED names

Switch to using generic LED support for composing LED class
device name.

Signed-off-by: Jacek Anaszewski <[email protected]>
Cc: Baolin Wang <[email protected]>
Acked-by: Pavel Machek <[email protected]>
---
drivers/leds/leds-sc27xx-bltc.c | 22 +++++++++-------------
1 file changed, 9 insertions(+), 13 deletions(-)

diff --git a/drivers/leds/leds-sc27xx-bltc.c b/drivers/leds/leds-sc27xx-bltc.c
index fecf27fb1cdc..0ede87420bfc 100644
--- a/drivers/leds/leds-sc27xx-bltc.c
+++ b/drivers/leds/leds-sc27xx-bltc.c
@@ -6,7 +6,6 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
-#include <uapi/linux/uleds.h>

/* PMIC global control register definition */
#define SC27XX_MODULE_EN0 0xc08
@@ -46,7 +45,7 @@
#define SC27XX_DELTA_T_MAX (SC27XX_LEDS_STEP * 255)

struct sc27xx_led {
- char name[LED_MAX_NAME_SIZE];
+ struct fwnode_handle *fwnode;
struct led_classdev ldev;
struct sc27xx_led_priv *priv;
u8 line;
@@ -249,19 +248,24 @@ static int sc27xx_led_register(struct device *dev, struct sc27xx_led_priv *priv)

for (i = 0; i < SC27XX_LEDS_MAX; i++) {
struct sc27xx_led *led = &priv->leds[i];
+ struct led_init_data init_data = {};

if (!led->active)
continue;

led->line = i;
led->priv = priv;
- led->ldev.name = led->name;
led->ldev.brightness_set_blocking = sc27xx_led_set;
led->ldev.pattern_set = sc27xx_led_pattern_set;
led->ldev.pattern_clear = sc27xx_led_pattern_clear;
led->ldev.default_trigger = "pattern";

- err = devm_led_classdev_register(dev, &led->ldev);
+ init_data.fwnode = led->fwnode;
+ init_data.devicename = "sc27xx";
+ init_data.default_label = ":";
+
+ err = devm_led_classdev_register_ext(dev, &led->ldev,
+ &init_data);
if (err)
return err;
}
@@ -274,7 +278,6 @@ static int sc27xx_led_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node, *child;
struct sc27xx_led_priv *priv;
- const char *str;
u32 base, count, reg;
int err;

@@ -316,15 +319,8 @@ static int sc27xx_led_probe(struct platform_device *pdev)
return -EINVAL;
}

+ priv->leds[reg].fwnode = of_fwnode_handle(child);
priv->leds[reg].active = true;
-
- err = of_property_read_string(child, "label", &str);
- if (err)
- snprintf(priv->leds[reg].name, LED_MAX_NAME_SIZE,
- "sc27xx::");
- else
- snprintf(priv->leds[reg].name, LED_MAX_NAME_SIZE,
- "sc27xx:%s", str);
}

err = sc27xx_led_register(dev, priv);
--
2.11.0

2019-06-09 19:12:21

by Jacek Anaszewski

[permalink] [raw]
Subject: [PATCH v5 21/26] leds: as3645a: Use generic support for composing LED names

Switch to using generic LED support for composing LED class
device name.

After switching to new led_classdev_register_ext() the validity
of struct led_classdev's name property is no longer guaranteed,
and therefore rely on struct device's kobj.name instead.

Signed-off-by: Jacek Anaszewski <[email protected]>
Cc: Sakari Ailus <[email protected]>
---
drivers/leds/leds-as3645a.c | 74 +++++++++++++++++----------------------------
1 file changed, 28 insertions(+), 46 deletions(-)

diff --git a/drivers/leds/leds-as3645a.c b/drivers/leds/leds-as3645a.c
index 14ab6b0e4de9..a7126f45064e 100644
--- a/drivers/leds/leds-as3645a.c
+++ b/drivers/leds/leds-as3645a.c
@@ -124,11 +124,6 @@ struct as3645a_config {
u32 peak;
};

-struct as3645a_names {
- char flash[32];
- char indicator[32];
-};
-
struct as3645a {
struct i2c_client *client;

@@ -484,12 +479,10 @@ static int as3645a_detect(struct as3645a *flash)
}

static int as3645a_parse_node(struct as3645a *flash,
- struct as3645a_names *names,
struct fwnode_handle *fwnode)
{
struct as3645a_config *cfg = &flash->cfg;
struct fwnode_handle *child;
- const char *name;
int rval;

fwnode_for_each_child_node(fwnode, child) {
@@ -517,17 +510,6 @@ static int as3645a_parse_node(struct as3645a *flash,
return -ENODEV;
}

- rval = fwnode_property_read_string(flash->flash_node, "label", &name);
- if (!rval) {
- strlcpy(names->flash, name, sizeof(names->flash));
- } else if (is_of_node(fwnode)) {
- snprintf(names->flash, sizeof(names->flash),
- "%pOFn:flash", to_of_node(fwnode));
- } else {
- dev_err(&flash->client->dev, "flash node has no label!\n");
- return -EINVAL;
- }
-
rval = fwnode_property_read_u32(flash->flash_node, "flash-timeout-us",
&cfg->flash_timeout_us);
if (rval < 0) {
@@ -565,17 +547,6 @@ static int as3645a_parse_node(struct as3645a *flash,
goto out_err;
}

- rval = fwnode_property_read_string(flash->indicator_node, "label",
- &name);
- if (!rval) {
- strlcpy(names->indicator, name, sizeof(names->indicator));
- } else if (is_of_node(fwnode)) {
- snprintf(names->indicator, sizeof(names->indicator),
- "%pOFn:indicator", to_of_node(fwnode));
- } else {
- dev_err(&flash->client->dev, "indicator node has no label!\n");
- return -EINVAL;
- }

rval = fwnode_property_read_u32(flash->indicator_node,
"led-max-microamp",
@@ -595,21 +566,25 @@ static int as3645a_parse_node(struct as3645a *flash,
return rval;
}

-static int as3645a_led_class_setup(struct as3645a *flash,
- struct as3645a_names *names)
+static int as3645a_led_class_setup(struct as3645a *flash)
{
struct led_classdev *fled_cdev = &flash->fled.led_cdev;
struct led_classdev *iled_cdev = &flash->iled_cdev;
+ struct led_init_data init_data = {};
struct led_flash_setting *cfg;
int rval;

- iled_cdev->name = names->indicator;
iled_cdev->brightness_set_blocking = as3645a_set_indicator_brightness;
iled_cdev->max_brightness =
flash->cfg.indicator_max_ua / AS_INDICATOR_INTENSITY_STEP;
iled_cdev->flags = LED_CORE_SUSPENDRESUME;

- rval = led_classdev_register(&flash->client->dev, iled_cdev);
+ init_data.fwnode = flash->indicator_node;
+ init_data.devicename = AS_NAME;
+ init_data.default_label = "indicator";
+
+ rval = led_classdev_register_ext(&flash->client->dev, iled_cdev,
+ &init_data);
if (rval < 0)
return rval;

@@ -627,7 +602,6 @@ static int as3645a_led_class_setup(struct as3645a *flash,

flash->fled.ops = &as3645a_led_flash_ops;

- fled_cdev->name = names->flash;
fled_cdev->brightness_set_blocking = as3645a_set_assist_brightness;
/* Value 0 is off in LED class. */
fled_cdev->max_brightness =
@@ -635,15 +609,23 @@ static int as3645a_led_class_setup(struct as3645a *flash,
flash->cfg.assist_max_ua) + 1;
fled_cdev->flags = LED_DEV_CAP_FLASH | LED_CORE_SUSPENDRESUME;

- rval = led_classdev_flash_register(&flash->client->dev, &flash->fled);
- if (rval) {
- led_classdev_unregister(iled_cdev);
- dev_err(&flash->client->dev,
- "led_classdev_flash_register() failed, error %d\n",
- rval);
- }
+ init_data.fwnode = flash->flash_node;
+ init_data.devicename = AS_NAME;
+ init_data.default_label = "flash";
+
+ rval = led_classdev_flash_register_ext(&flash->client->dev,
+ &flash->fled, &init_data);
+ if (rval)
+ goto out_err;

return rval;
+
+out_err:
+ led_classdev_unregister(iled_cdev);
+ dev_err(&flash->client->dev,
+ "led_classdev_flash_register() failed, error %d\n",
+ rval);
+ return rval;
}

static int as3645a_v4l2_setup(struct as3645a *flash)
@@ -667,8 +649,9 @@ static int as3645a_v4l2_setup(struct as3645a *flash)
},
};

- strlcpy(cfg.dev_name, led->name, sizeof(cfg.dev_name));
- strlcpy(cfgind.dev_name, flash->iled_cdev.name, sizeof(cfg.dev_name));
+ strlcpy(cfg.dev_name, led->dev->kobj.name, sizeof(cfg.dev_name));
+ strlcpy(cfgind.dev_name, flash->iled_cdev.dev->kobj.name,
+ sizeof(cfg.dev_name));

flash->vf = v4l2_flash_init(
&flash->client->dev, flash->flash_node, &flash->fled, NULL,
@@ -689,7 +672,6 @@ static int as3645a_v4l2_setup(struct as3645a *flash)

static int as3645a_probe(struct i2c_client *client)
{
- struct as3645a_names names;
struct as3645a *flash;
int rval;

@@ -702,7 +684,7 @@ static int as3645a_probe(struct i2c_client *client)

flash->client = client;

- rval = as3645a_parse_node(flash, &names, dev_fwnode(&client->dev));
+ rval = as3645a_parse_node(flash, dev_fwnode(&client->dev));
if (rval < 0)
return rval;

@@ -717,7 +699,7 @@ static int as3645a_probe(struct i2c_client *client)
if (rval)
goto out_mutex_destroy;

- rval = as3645a_led_class_setup(flash, &names);
+ rval = as3645a_led_class_setup(flash);
if (rval)
goto out_mutex_destroy;

--
2.11.0

2019-06-09 19:12:26

by Jacek Anaszewski

[permalink] [raw]
Subject: [PATCH v5 15/26] leds: lm3601x: Use generic support for composing LED names

Switch to using generic LED support for composing LED class
device name.

Signed-off-by: Jacek Anaszewski <[email protected]>
Tested-by: Dan Murphy <[email protected]>
Acked-by: Pavel Machek <[email protected]>
---
drivers/leds/leds-lm3601x.c | 38 +++++++++++++++++---------------------
1 file changed, 17 insertions(+), 21 deletions(-)

diff --git a/drivers/leds/leds-lm3601x.c b/drivers/leds/leds-lm3601x.c
index 081aa71e43a3..b02972f1a341 100644
--- a/drivers/leds/leds-lm3601x.c
+++ b/drivers/leds/leds-lm3601x.c
@@ -10,7 +10,6 @@
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/slab.h>
-#include <uapi/linux/uleds.h>

#define LM3601X_LED_IR 0x0
#define LM3601X_LED_TORCH 0x1
@@ -90,8 +89,6 @@ struct lm3601x_led {
struct regmap *regmap;
struct mutex lock;

- char led_name[LED_MAX_NAME_SIZE];
-
unsigned int flash_timeout;
unsigned int last_flag;

@@ -322,10 +319,12 @@ static const struct led_flash_ops flash_ops = {
.fault_get = lm3601x_flash_fault_get,
};

-static int lm3601x_register_leds(struct lm3601x_led *led)
+static int lm3601x_register_leds(struct lm3601x_led *led,
+ struct fwnode_handle *fwnode)
{
struct led_classdev *led_cdev;
struct led_flash_setting *setting;
+ struct led_init_data init_data = {};

led->fled_cdev.ops = &flash_ops;

@@ -342,20 +341,25 @@ static int lm3601x_register_leds(struct lm3601x_led *led)
setting->val = led->flash_current_max;

led_cdev = &led->fled_cdev.led_cdev;
- led_cdev->name = led->led_name;
led_cdev->brightness_set_blocking = lm3601x_brightness_set;
led_cdev->max_brightness = DIV_ROUND_UP(led->torch_current_max,
LM3601X_TORCH_REG_DIV);
led_cdev->flags |= LED_DEV_CAP_FLASH;

- return led_classdev_flash_register(&led->client->dev, &led->fled_cdev);
+ init_data.fwnode = fwnode;
+ init_data.devicename = led->client->name;
+ init_data.default_label = (led->led_mode == LM3601X_LED_TORCH) ?
+ "torch" : "infrared";
+
+ return led_classdev_flash_register_ext(&led->client->dev,
+ &led->fled_cdev, &init_data);
}

-static int lm3601x_parse_node(struct lm3601x_led *led)
+static int lm3601x_parse_node(struct lm3601x_led *led,
+ struct fwnode_handle **fwnode)
{
struct fwnode_handle *child = NULL;
int ret = -ENODEV;
- const char *name;

child = device_get_next_child_node(&led->client->dev, child);
if (!child) {
@@ -376,17 +380,6 @@ static int lm3601x_parse_node(struct lm3601x_led *led)
goto out_err;
}

- ret = fwnode_property_read_string(child, "label", &name);
- if (ret) {
- if (led->led_mode == LM3601X_LED_TORCH)
- name = "torch";
- else
- name = "infrared";
- }
-
- snprintf(led->led_name, sizeof(led->led_name),
- "%s:%s", led->client->name, name);
-
ret = fwnode_property_read_u32(child, "led-max-microamp",
&led->torch_current_max);
if (ret) {
@@ -411,6 +404,8 @@ static int lm3601x_parse_node(struct lm3601x_led *led)
goto out_err;
}

+ *fwnode = child;
+
out_err:
fwnode_handle_put(child);
return ret;
@@ -419,6 +414,7 @@ static int lm3601x_parse_node(struct lm3601x_led *led)
static int lm3601x_probe(struct i2c_client *client)
{
struct lm3601x_led *led;
+ struct fwnode_handle *fwnode;
int ret;

led = devm_kzalloc(&client->dev, sizeof(*led), GFP_KERNEL);
@@ -428,7 +424,7 @@ static int lm3601x_probe(struct i2c_client *client)
led->client = client;
i2c_set_clientdata(client, led);

- ret = lm3601x_parse_node(led);
+ ret = lm3601x_parse_node(led, &fwnode);
if (ret)
return -ENODEV;

@@ -442,7 +438,7 @@ static int lm3601x_probe(struct i2c_client *client)

mutex_init(&led->lock);

- return lm3601x_register_leds(led);
+ return lm3601x_register_leds(led, fwnode);
}

static int lm3601x_remove(struct i2c_client *client)
--
2.11.0

2019-06-09 19:12:33

by Jacek Anaszewski

[permalink] [raw]
Subject: [PATCH v5 06/26] dt-bindings: sc27xx-blt: Add function and color properties

Refer to new "function" and "color" properties and mark "label"
as deprecated.

Signed-off-by: Jacek Anaszewski <[email protected]>
Cc: Baolin Wang <[email protected]>
Reviewed-by: Rob Herring <[email protected]>
---
Documentation/devicetree/bindings/leds/leds-sc27xx-bltc.txt | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/Documentation/devicetree/bindings/leds/leds-sc27xx-bltc.txt b/Documentation/devicetree/bindings/leds/leds-sc27xx-bltc.txt
index dddf84f9c7ea..df2b4e1c492b 100644
--- a/Documentation/devicetree/bindings/leds/leds-sc27xx-bltc.txt
+++ b/Documentation/devicetree/bindings/leds/leds-sc27xx-bltc.txt
@@ -14,7 +14,9 @@ Required child properties:
- reg: Port this LED is connected to.

Optional child properties:
-- label: See Documentation/devicetree/bindings/leds/common.txt.
+- function: See Documentation/devicetree/bindings/leds/common.txt.
+- color: See Documentation/devicetree/bindings/leds/common.txt.
+- label: See Documentation/devicetree/bindings/leds/common.txt (deprecated).

Examples:

@@ -25,17 +27,17 @@ led-controller@200 {
reg = <0x200>;

led@0 {
- label = "red";
+ color = <LED_COLOR_ID_RED>;
reg = <0x0>;
};

led@1 {
- label = "green";
+ color = <LED_COLOR_ID_GREEN>;
reg = <0x1>;
};

led@2 {
- label = "blue";
+ color = <LED_COLOR_ID_BLUE>;
reg = <0x2>;
};
};
--
2.11.0

2019-06-09 19:12:45

by Jacek Anaszewski

[permalink] [raw]
Subject: [PATCH v5 01/26] leds: class: Improve LED and LED flash class registration API

Replace of_led_classdev_register() with led_classdev_register_ext(), which
accepts easily extendable struct led_init_data, instead of the fixed
struct device_node argument. The latter can be now passed in an fwnode
property of the struct led_init_data.

The modification is driven by the need for passing additional arguments
required for the forthcoming generic mechanism for composing LED names.
Currently the LED name is conveyed in the "name" char pointer property of
the struct led_classdev. This is redundant since LED class device name
is accessible throughout the whole LED class device life time via
associated struct device's kobj->name property.

The change will not break any existing clients since the patch alters
also existing led_classdev{_flash}_register() macro wrappers, that pass
NULL in place of init_data, which leads to using legacy name
initialization path basing on the struct led_classdev's "name" property.

Three existing users of devm_of_led_classdev_registers() are modified
to use devm_led_classdev_register(), which will not impact their
operation since they in fact didn't need to pass struct device_node on
registration from the beginning.

Signed-off-by: Jacek Anaszewski <[email protected]>
Cc: Baolin Wang <[email protected]>
Cc: Pavel Machek <[email protected]>
Cc: Dan Murphy <[email protected]>
Cc: Daniel Mack <[email protected]>
Cc: Linus Walleij <[email protected]>
Cc: Oleh Kravchenko <[email protected]>
Cc: Sakari Ailus <[email protected]>
Cc: Simon Shields <[email protected]>
---
drivers/leds/led-class-flash.c | 9 +++++----
drivers/leds/led-class.c | 29 +++++++++++++++++------------
drivers/leds/leds-cr0014114.c | 3 +--
drivers/leds/leds-gpio.c | 2 +-
drivers/leds/leds-pwm.c | 2 +-
include/linux/led-class-flash.h | 15 ++++++++++-----
include/linux/leds.h | 34 ++++++++++++++++++++++++----------
7 files changed, 59 insertions(+), 35 deletions(-)

diff --git a/drivers/leds/led-class-flash.c b/drivers/leds/led-class-flash.c
index cf398275a53c..8d1c1177bb9a 100644
--- a/drivers/leds/led-class-flash.c
+++ b/drivers/leds/led-class-flash.c
@@ -285,8 +285,9 @@ static void led_flash_init_sysfs_groups(struct led_classdev_flash *fled_cdev)
led_cdev->groups = flash_groups;
}

-int led_classdev_flash_register(struct device *parent,
- struct led_classdev_flash *fled_cdev)
+int led_classdev_flash_register_ext(struct device *parent,
+ struct led_classdev_flash *fled_cdev,
+ struct led_init_data *init_data)
{
struct led_classdev *led_cdev;
const struct led_flash_ops *ops;
@@ -312,13 +313,13 @@ int led_classdev_flash_register(struct device *parent,
}

/* Register led class device */
- ret = led_classdev_register(parent, led_cdev);
+ ret = led_classdev_register_ext(parent, led_cdev, init_data);
if (ret < 0)
return ret;

return 0;
}
-EXPORT_SYMBOL_GPL(led_classdev_flash_register);
+EXPORT_SYMBOL_GPL(led_classdev_flash_register_ext);

void led_classdev_flash_unregister(struct led_classdev_flash *fled_cdev)
{
diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
index 85848c5da705..a564948e5f53 100644
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -17,6 +17,7 @@
#include <linux/leds.h>
#include <linux/list.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/timer.h>
@@ -245,14 +246,16 @@ static int led_classdev_next_name(const char *init_name, char *name,
}

/**
- * of_led_classdev_register - register a new object of led_classdev class.
+ * led_classdev_register_ext - register a new object of led_classdev class
+ * with init data.
*
* @parent: parent of LED device
* @led_cdev: the led_classdev structure for this device.
- * @np: DT node describing this LED
+ * @init_data: LED class device initialization data
*/
-int of_led_classdev_register(struct device *parent, struct device_node *np,
- struct led_classdev *led_cdev)
+int led_classdev_register_ext(struct device *parent,
+ struct led_classdev *led_cdev,
+ struct led_init_data *init_data)
{
char name[LED_MAX_NAME_SIZE];
int ret;
@@ -269,7 +272,8 @@ int of_led_classdev_register(struct device *parent, struct device_node *np,
mutex_unlock(&led_cdev->led_access);
return PTR_ERR(led_cdev->dev);
}
- led_cdev->dev->of_node = np;
+ if (init_data && init_data->fwnode)
+ led_cdev->dev->of_node = to_of_node(init_data->fwnode);

if (ret)
dev_warn(parent, "Led %s renamed to %s due to name collision",
@@ -314,7 +318,7 @@ int of_led_classdev_register(struct device *parent, struct device_node *np,

return 0;
}
-EXPORT_SYMBOL_GPL(of_led_classdev_register);
+EXPORT_SYMBOL_GPL(led_classdev_register_ext);

/**
* led_classdev_unregister - unregisters a object of led_properties class.
@@ -359,14 +363,15 @@ static void devm_led_classdev_release(struct device *dev, void *res)
}

/**
- * devm_of_led_classdev_register - resource managed led_classdev_register()
+ * devm_led_classdev_register_ext - resource managed led_classdev_register_ext()
*
* @parent: parent of LED device
* @led_cdev: the led_classdev structure for this device.
+ * @init_data: LED class device initialization data
*/
-int devm_of_led_classdev_register(struct device *parent,
- struct device_node *np,
- struct led_classdev *led_cdev)
+int devm_led_classdev_register_ext(struct device *parent,
+ struct led_classdev *led_cdev,
+ struct led_init_data *init_data)
{
struct led_classdev **dr;
int rc;
@@ -375,7 +380,7 @@ int devm_of_led_classdev_register(struct device *parent,
if (!dr)
return -ENOMEM;

- rc = of_led_classdev_register(parent, np, led_cdev);
+ rc = led_classdev_register_ext(parent, led_cdev, init_data);
if (rc) {
devres_free(dr);
return rc;
@@ -386,7 +391,7 @@ int devm_of_led_classdev_register(struct device *parent,

return 0;
}
-EXPORT_SYMBOL_GPL(devm_of_led_classdev_register);
+EXPORT_SYMBOL_GPL(devm_led_classdev_register_ext);

static int devm_led_classdev_match(struct device *dev, void *res, void *data)
{
diff --git a/drivers/leds/leds-cr0014114.c b/drivers/leds/leds-cr0014114.c
index 0e4262462cb9..1c82152764d2 100644
--- a/drivers/leds/leds-cr0014114.c
+++ b/drivers/leds/leds-cr0014114.c
@@ -207,8 +207,7 @@ static int cr0014114_probe_dt(struct cr0014114 *priv)
led->ldev.max_brightness = CR_MAX_BRIGHTNESS;
led->ldev.brightness_set_blocking = cr0014114_set_sync;

- ret = devm_of_led_classdev_register(priv->dev, np,
- &led->ldev);
+ ret = devm_led_classdev_register(priv->dev, &led->ldev);
if (ret) {
dev_err(priv->dev,
"failed to register LED device %s, err %d",
diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c
index 998f2ff6914d..b26cf78993d1 100644
--- a/drivers/leds/leds-gpio.c
+++ b/drivers/leds/leds-gpio.c
@@ -112,7 +112,7 @@ static int create_gpio_led(const struct gpio_led *template,
if (ret < 0)
return ret;

- return devm_of_led_classdev_register(parent, np, &led_dat->cdev);
+ return devm_led_classdev_register(parent, &led_dat->cdev);
}

struct gpio_leds_priv {
diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c
index af08bcdc4fd8..fcb3e87a9887 100644
--- a/drivers/leds/leds-pwm.c
+++ b/drivers/leds/leds-pwm.c
@@ -114,7 +114,7 @@ static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv,
if (!led_data->period && (led->pwm_period_ns > 0))
led_data->period = led->pwm_period_ns;

- ret = devm_of_led_classdev_register(dev, child, &led_data->cdev);
+ ret = devm_led_classdev_register(dev, &led_data->cdev);
if (ret == 0) {
priv->num_leds++;
led_pwm_set(&led_data->cdev, led_data->cdev.brightness);
diff --git a/include/linux/led-class-flash.h b/include/linux/led-class-flash.h
index 700efaa9e115..ded8d9fa6149 100644
--- a/include/linux/led-class-flash.h
+++ b/include/linux/led-class-flash.h
@@ -90,15 +90,20 @@ static inline struct led_classdev_flash *lcdev_to_flcdev(
}

/**
- * led_classdev_flash_register - register a new object of led_classdev class
- * with support for flash LEDs
- * @parent: the flash LED to register
+ * led_classdev_flash_register_ext - register a new object of LED class with
+ * init data and with support for flash LEDs
+ * @parent: LED flash controller device this flash LED is driven by
* @fled_cdev: the led_classdev_flash structure for this device
+ * @init_data: the LED class flash device initialization data
*
* Returns: 0 on success or negative error value on failure
*/
-extern int led_classdev_flash_register(struct device *parent,
- struct led_classdev_flash *fled_cdev);
+extern int led_classdev_flash_register_ext(struct device *parent,
+ struct led_classdev_flash *fled_cdev,
+ struct led_init_data *init_data);
+
+#define led_classdev_flash_register(parent, fled_cdev) \
+ led_classdev_flash_register_ext(parent, fled_cdev, NULL)

/**
* led_classdev_flash_unregister - unregisters an object of led_classdev class
diff --git a/include/linux/leds.h b/include/linux/leds.h
index 78204650fe2a..fab83a2d7bff 100644
--- a/include/linux/leds.h
+++ b/include/linux/leds.h
@@ -34,6 +34,11 @@ enum led_brightness {
LED_FULL = 255,
};

+struct led_init_data {
+ /* device fwnode handle */
+ struct fwnode_handle *fwnode;
+};
+
struct led_classdev {
const char *name;
enum led_brightness brightness;
@@ -129,16 +134,25 @@ struct led_classdev {
struct mutex led_access;
};

-extern int of_led_classdev_register(struct device *parent,
- struct device_node *np,
- struct led_classdev *led_cdev);
-#define led_classdev_register(parent, led_cdev) \
- of_led_classdev_register(parent, NULL, led_cdev)
-extern int devm_of_led_classdev_register(struct device *parent,
- struct device_node *np,
- struct led_classdev *led_cdev);
-#define devm_led_classdev_register(parent, led_cdev) \
- devm_of_led_classdev_register(parent, NULL, led_cdev)
+/**
+ * led_classdev_register_ext - register a new object of LED class with
+ * init data
+ * @parent: LED controller device this LED is driven by
+ * @led_cdev: the led_classdev structure for this device
+ * @init_data: the LED class device initialization data
+ *
+ * Returns: 0 on success or negative error value on failure
+ */
+extern int led_classdev_register_ext(struct device *parent,
+ struct led_classdev *led_cdev,
+ struct led_init_data *init_data);
+#define led_classdev_register(parent, led_cdev) \
+ led_classdev_register_ext(parent, led_cdev, NULL)
+extern int devm_led_classdev_register_ext(struct device *parent,
+ struct led_classdev *led_cdev,
+ struct led_init_data *init_data);
+#define devm_led_classdev_register(parent, led_cdev) \
+ devm_led_classdev_register_ext(parent, led_cdev, NULL)
extern void led_classdev_unregister(struct led_classdev *led_cdev);
extern void devm_led_classdev_unregister(struct device *parent,
struct led_classdev *led_cdev);
--
2.11.0

2019-06-09 19:12:51

by Jacek Anaszewski

[permalink] [raw]
Subject: [PATCH v5 04/26] dt-bindings: leds: Add properties for LED name construction

Introduce dedicated properties for conveying information about
LED function and color. Mark old "label" property as deprecated.

Additionally function-enumerator property is being provided
for the cases when neither function nor color can be used
for LED differentiation.

Signed-off-by: Jacek Anaszewski <[email protected]>
Cc: Baolin Wang <[email protected]>
Cc: Pavel Machek <[email protected]>
Cc: Dan Murphy <[email protected]>
Cc: Daniel Mack <[email protected]>
Cc: Linus Walleij <[email protected]>
Cc: Oleh Kravchenko <[email protected]>
Cc: Sakari Ailus <[email protected]>
Cc: Simon Shields <[email protected]>
Reviewed-by: Rob Herring <[email protected]>
---
Documentation/devicetree/bindings/leds/common.txt | 62 ++++++++++++++++++++---
1 file changed, 54 insertions(+), 8 deletions(-)

diff --git a/Documentation/devicetree/bindings/leds/common.txt b/Documentation/devicetree/bindings/leds/common.txt
index 70876ac11367..9fa6f9795d50 100644
--- a/Documentation/devicetree/bindings/leds/common.txt
+++ b/Documentation/devicetree/bindings/leds/common.txt
@@ -10,14 +10,30 @@ can influence the way of the LED device initialization, the LED components
have to be tightly coupled with the LED device binding. They are represented
by child nodes of the parent LED device binding.

+
Optional properties for child nodes:
- led-sources : List of device current outputs the LED is connected to. The
outputs are identified by the numbers that must be defined
in the LED device binding documentation.
+
+- function: LED functon. Use one of the LED_FUNCTION_* prefixed definitions
+ from the header include/dt-bindings/leds/common.h.
+ If there is no matching LED_FUNCTION available, add a new one.
+
+- color : Color of the LED. Use one of the LED_COLOR_ID_* prefixed definitions
+ from the header include/dt-bindings/leds/common.h.
+ If there is no matching LED_COLOR_ID available, add a new one.
+
+- function-enumerator: Integer to be used when more than one instance
+ of the same function is needed, differing only with
+ an ordinal number.
+
- label : The label for this LED. If omitted, the label is taken from the node
name (excluding the unit address). It has to uniquely identify
a device, i.e. no other LED class device can be assigned the same
- label.
+ label. This property is deprecated - use 'function' and 'color'
+ properties instead. function-enumerator has no effect when this
+ property is present.

- default-state : The initial state of the LED. Valid values are "on", "off",
and "keep". If the LED is already on or off and the default-state property is
@@ -99,29 +115,59 @@ Required properties for trigger source:

* Examples

-gpio-leds {
+#include <dt-bindings/leds/common.h>
+
+led-controller@0 {
compatible = "gpio-leds";

- system-status {
- label = "Status";
+ led0 {
+ function = LED_FUNCTION_STATUS;
linux,default-trigger = "heartbeat";
gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>;
};

- usb {
+ led1 {
+ function = LED_FUNCTION_USB;
gpios = <&gpio0 1 GPIO_ACTIVE_HIGH>;
trigger-sources = <&ohci_port1>, <&ehci_port1>;
};
};

-max77693-led {
+led-controller@0 {
compatible = "maxim,max77693-led";

- camera-flash {
- label = "Flash";
+ led {
+ function = LED_FUNCTION_FLASH;
+ color = <LED_COLOR_ID_WHITE>;
led-sources = <0>, <1>;
led-max-microamp = <50000>;
flash-max-microamp = <320000>;
flash-max-timeout-us = <500000>;
};
};
+
+led-controller@30 {
+ compatible = "panasonic,an30259a";
+ reg = <0x30>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ led@1 {
+ reg = <1>;
+ linux,default-trigger = "heartbeat";
+ function = LED_FUNCTION_INDICATOR;
+ function-enumerator = <1>;
+ };
+
+ led@2 {
+ reg = <2>;
+ function = LED_FUNCTION_INDICATOR;
+ function-enumerator = <2>;
+ };
+
+ led@3 {
+ reg = <3>;
+ function = LED_FUNCTION_INDICATOR;
+ function-enumerator = <3>;
+ };
+};
--
2.11.0

2019-06-09 19:13:32

by Jacek Anaszewski

[permalink] [raw]
Subject: [PATCH v5 02/26] dt-bindings: leds: Add LED_COLOR_ID definitions

Add common LED color identifiers.

Signed-off-by: Jacek Anaszewski <[email protected]>
Cc: Baolin Wang <[email protected]>
Cc: Daniel Mack <[email protected]>
Cc: Linus Walleij <[email protected]>
Cc: Oleh Kravchenko <[email protected]>
Cc: Sakari Ailus <[email protected]>
Cc: Simon Shields <[email protected]>
Reviewed-by: Rob Herring <[email protected]>
Acked-by: Pavel Machek <[email protected]>
Reviewed-by: Dan Murphy <[email protected]>
---
include/dt-bindings/leds/common.h | 11 +++++++++++
1 file changed, 11 insertions(+)

diff --git a/include/dt-bindings/leds/common.h b/include/dt-bindings/leds/common.h
index e171d0a6beb2..217ee9e0dd6c 100644
--- a/include/dt-bindings/leds/common.h
+++ b/include/dt-bindings/leds/common.h
@@ -19,4 +19,15 @@
#define LEDS_BOOST_ADAPTIVE 1
#define LEDS_BOOST_FIXED 2

+/* Standard LED colors */
+#define LED_COLOR_ID_WHITE 0
+#define LED_COLOR_ID_RED 1
+#define LED_COLOR_ID_GREEN 2
+#define LED_COLOR_ID_BLUE 3
+#define LED_COLOR_ID_AMBER 4
+#define LED_COLOR_ID_VIOLET 5
+#define LED_COLOR_ID_YELLOW 6
+#define LED_COLOR_ID_IR 7
+#define LED_COLOR_ID_MAX 8
+
#endif /* __DT_BINDINGS_LEDS_H */
--
2.11.0

2019-06-09 19:23:27

by Jacek Anaszewski

[permalink] [raw]
Subject: [PATCH v5 24/26] dt-bindings: an30259a: Add function and color properties

Refer to new "function" and "color" properties and mark "label"
as deprecated.

Signed-off-by: Jacek Anaszewski <[email protected]>
Cc: Simon Shields <[email protected]>
Reviewed-by: Rob Herring <[email protected]>
---
.../devicetree/bindings/leds/leds-an30259a.txt | 22 +++++++++++++++++-----
1 file changed, 17 insertions(+), 5 deletions(-)

diff --git a/Documentation/devicetree/bindings/leds/leds-an30259a.txt b/Documentation/devicetree/bindings/leds/leds-an30259a.txt
index 6ffb861083c0..cbd833906b2b 100644
--- a/Documentation/devicetree/bindings/leds/leds-an30259a.txt
+++ b/Documentation/devicetree/bindings/leds/leds-an30259a.txt
@@ -15,10 +15,19 @@ Required sub-node properties:
- reg: Pin that the LED is connected to. Must be 1, 2, or 3.

Optional sub-node properties:
- - label: see Documentation/devicetree/bindings/leds/common.txt
- - linux,default-trigger: see Documentation/devicetree/bindings/leds/common.txt
+ - function :
+ see Documentation/devicetree/bindings/leds/common.txt
+ - color :
+ see Documentation/devicetree/bindings/leds/common.txt
+ - label :
+ see Documentation/devicetree/bindings/leds/common.txt (deprecated)
+ - linux,default-trigger :
+ see Documentation/devicetree/bindings/leds/common.txt

Example:
+
+#include <dt-bindings/leds/common.h>
+
led-controller@30 {
compatible = "panasonic,an30259a";
reg = <0x30>;
@@ -28,16 +37,19 @@ led-controller@30 {
led@1 {
reg = <1>;
linux,default-trigger = "heartbeat";
- label = "red:indicator";
+ function = LED_FUNCTION_INDICATOR;
+ color = <LED_COLOR_ID_RED>;
};

led@2 {
reg = <2>;
- label = "green:indicator";
+ function = LED_FUNCTION_INDICATOR;
+ color = <LED_COLOR_ID_GREEN>;
};

led@3 {
reg = <3>;
- label = "blue:indicator";
+ function = LED_FUNCTION_INDICATOR;
+ color = <LED_COLOR_ID_BLUE>;
};
};
--
2.11.0

2019-06-09 19:29:56

by Jacek Anaszewski

[permalink] [raw]
Subject: [PATCH v5 17/26] leds: cr0014114: Use generic support for composing LED names

Switch to using generic LED support for composing LED class
device name.

At this occassion remove initialization of struct led_classdev's
dev->of_node property in the driver, since now it will be taken from
fwnode assigned to struct led_init_data and passed to the new
devm_led_classdev_register_ext() API.

Signed-off-by: Jacek Anaszewski <[email protected]>
Cc: Oleh Kravchenko <[email protected]>
Acked-by: Pavel Machek <[email protected]>
---
drivers/leds/leds-cr0014114.c | 32 +++++++++++---------------------
1 file changed, 11 insertions(+), 21 deletions(-)

diff --git a/drivers/leds/leds-cr0014114.c b/drivers/leds/leds-cr0014114.c
index 1c82152764d2..2da448ae718e 100644
--- a/drivers/leds/leds-cr0014114.c
+++ b/drivers/leds/leds-cr0014114.c
@@ -8,7 +8,6 @@
#include <linux/of_device.h>
#include <linux/spi/spi.h>
#include <linux/workqueue.h>
-#include <uapi/linux/uleds.h>

/*
* CR0014114 SPI protocol descrtiption:
@@ -40,8 +39,9 @@
#define CR_FW_DELAY_MSEC 10
#define CR_RECOUNT_DELAY (HZ * 3600)

+#define CR_DEV_NAME "cr0014114"
+
struct cr0014114_led {
- char name[LED_MAX_NAME_SIZE];
struct cr0014114 *priv;
struct led_classdev ldev;
u8 brightness;
@@ -167,8 +167,7 @@ static int cr0014114_set_sync(struct led_classdev *ldev,
struct cr0014114_led,
ldev);

- dev_dbg(led->priv->dev, "Set brightness of %s to %d\n",
- led->name, brightness);
+ dev_dbg(led->priv->dev, "Set brightness to %d\n", brightness);

mutex_lock(&led->priv->lock);
led->brightness = (u8)brightness;
@@ -183,41 +182,32 @@ static int cr0014114_probe_dt(struct cr0014114 *priv)
size_t i = 0;
struct cr0014114_led *led;
struct fwnode_handle *child;
- struct device_node *np;
+ struct led_init_data init_data = {};
int ret;
- const char *str;

device_for_each_child_node(priv->dev, child) {
- np = to_of_node(child);
led = &priv->leds[i];

- ret = fwnode_property_read_string(child, "label", &str);
- if (ret)
- snprintf(led->name, sizeof(led->name),
- "cr0014114::");
- else
- snprintf(led->name, sizeof(led->name),
- "cr0014114:%s", str);
-
fwnode_property_read_string(child, "linux,default-trigger",
&led->ldev.default_trigger);

led->priv = priv;
- led->ldev.name = led->name;
led->ldev.max_brightness = CR_MAX_BRIGHTNESS;
led->ldev.brightness_set_blocking = cr0014114_set_sync;

- ret = devm_led_classdev_register(priv->dev, &led->ldev);
+ init_data.fwnode = child;
+ init_data.devicename = CR_DEV_NAME;
+ init_data.default_label = ":";
+
+ ret = devm_led_classdev_register_ext(priv->dev, &led->ldev,
+ &init_data);
if (ret) {
dev_err(priv->dev,
- "failed to register LED device %s, err %d",
- led->name, ret);
+ "failed to register LED device, err %d", ret);
fwnode_handle_put(child);
return ret;
}

- led->ldev.dev->of_node = np;
-
i++;
}

--
2.11.0

2019-06-09 19:29:58

by Jacek Anaszewski

[permalink] [raw]
Subject: [PATCH v5 18/26] dt-bindings: aat1290: Add function and color properties

Refer to new "function" and "color" properties and mark "label"
as deprecated.

Signed-off-by: Jacek Anaszewski <[email protected]>
Reviewed-by: Rob Herring <[email protected]>
---
Documentation/devicetree/bindings/leds/leds-aat1290.txt | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/Documentation/devicetree/bindings/leds/leds-aat1290.txt b/Documentation/devicetree/bindings/leds/leds-aat1290.txt
index 85c0c58617f6..62ed17ec075b 100644
--- a/Documentation/devicetree/bindings/leds/leds-aat1290.txt
+++ b/Documentation/devicetree/bindings/leds/leds-aat1290.txt
@@ -32,15 +32,18 @@ Required properties of the LED child node:
formula: T = 8.82 * 10^9 * Ct.

Optional properties of the LED child node:
-- label : see Documentation/devicetree/bindings/leds/common.txt
+- function : see Documentation/devicetree/bindings/leds/common.txt
+- color : see Documentation/devicetree/bindings/leds/common.txt
+- label : see Documentation/devicetree/bindings/leds/common.txt (deprecated)

Example (by Ct = 220nF, Rset = 160kohm and exynos4412-trats2 board with
a switch that allows for routing strobe signal either from the host or from
the camera sensor):

#include "exynos4412.dtsi"
+#include <dt-bindings/leds/common.h>

-aat1290 {
+led-controller {
compatible = "skyworks,aat1290";
flen-gpios = <&gpj1 1 GPIO_ACTIVE_HIGH>;
enset-gpios = <&gpj1 2 GPIO_ACTIVE_HIGH>;
@@ -50,8 +53,9 @@ aat1290 {
pinctrl-1 = <&camera_flash_host>;
pinctrl-2 = <&camera_flash_isp>;

- camera_flash: flash-led {
- label = "aat1290-flash";
+ camera_flash: led {
+ function = LED_FUNCTION_FLASH;
+ color = <LED_COLOR_ID_WHITE>;
led-max-microamp = <520833>;
flash-max-microamp = <1012500>;
flash-max-timeout-us = <1940000>;
--
2.11.0

2019-06-09 19:30:19

by Jacek Anaszewski

[permalink] [raw]
Subject: [PATCH v5 23/26] leds: gpio: Use generic support for composing LED names

Switch to using generic LED support for composing LED class
device name.

Signed-off-by: Jacek Anaszewski <[email protected]>
Cc: Linus Walleij <[email protected]>
---
drivers/leds/leds-gpio.c | 26 +++++++++++++-------------
1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c
index b26cf78993d1..fe70613aca34 100644
--- a/drivers/leds/leds-gpio.c
+++ b/drivers/leds/leds-gpio.c
@@ -77,11 +77,11 @@ static int gpio_blink_set(struct led_classdev *led_cdev,

static int create_gpio_led(const struct gpio_led *template,
struct gpio_led_data *led_dat, struct device *parent,
- struct device_node *np, gpio_blink_set_t blink_set)
+ struct fwnode_handle *fwnode, gpio_blink_set_t blink_set)
{
+ struct led_init_data init_data = {};
int ret, state;

- led_dat->cdev.name = template->name;
led_dat->cdev.default_trigger = template->default_trigger;
led_dat->can_sleep = gpiod_cansleep(led_dat->gpiod);
if (!led_dat->can_sleep)
@@ -112,7 +112,16 @@ static int create_gpio_led(const struct gpio_led *template,
if (ret < 0)
return ret;

- return devm_led_classdev_register(parent, &led_dat->cdev);
+ if (template->name) {
+ led_dat->cdev.name = template->name;
+ ret = devm_led_classdev_register(parent, &led_dat->cdev);
+ } else {
+ init_data.fwnode = fwnode;
+ ret = devm_led_classdev_register_ext(parent, &led_dat->cdev,
+ &init_data);
+ }
+
+ return ret;
}

struct gpio_leds_priv {
@@ -145,15 +154,6 @@ static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev)
struct gpio_led_data *led_dat = &priv->leds[priv->num_leds];
struct gpio_led led = {};
const char *state = NULL;
- struct device_node *np = to_of_node(child);
-
- ret = fwnode_property_read_string(child, "label", &led.name);
- if (ret && IS_ENABLED(CONFIG_OF) && np)
- led.name = np->name;
- if (!led.name) {
- fwnode_handle_put(child);
- return ERR_PTR(-EINVAL);
- }

led.gpiod = devm_fwnode_get_gpiod_from_child(dev, NULL, child,
GPIOD_ASIS,
@@ -185,7 +185,7 @@ static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev)
if (fwnode_property_present(child, "panic-indicator"))
led.panic_indicator = 1;

- ret = create_gpio_led(&led, led_dat, dev, np, NULL);
+ ret = create_gpio_led(&led, led_dat, dev, child, NULL);
if (ret < 0) {
fwnode_handle_put(child);
return ERR_PTR(ret);
--
2.11.0

2019-06-10 02:54:20

by Baolin Wang

[permalink] [raw]
Subject: Re: [PATCH v5 07/26] leds: sc27xx-blt: Use generic support for composing LED names

Hi Jacek,

On Mon, 10 Jun 2019 at 03:08, Jacek Anaszewski
<[email protected]> wrote:
>
> Switch to using generic LED support for composing LED class
> device name.
>
> Signed-off-by: Jacek Anaszewski <[email protected]>
> Cc: Baolin Wang <[email protected]>
> Acked-by: Pavel Machek <[email protected]>

Thanks.
Reviewed-by: Baolin Wang <[email protected]>

--
Baolin Wang
Best Regards

2019-06-26 19:06:42

by Jacek Anaszewski

[permalink] [raw]
Subject: Re: [PATCH v5 05/26] leds: core: Add support for composing LED class device names

Gentle reminder.

Pavel, Dan - any conclusions?

This patch is the main part of the proposed changes,
so it would be good to spot any remaining issues.

What needs a consensus is also a new
Documentation/leds/led-functions.txt file I introduce
in the patch 26/26.

Best regards,
Jacek Anaszewski

On 6/9/19 9:07 PM, Jacek Anaszewski wrote:
> Add generic support for composing LED class device name. The newly
> introduced led_compose_name() function composes device name according
> to either <color:function> or <devicename:color:function> pattern,
> depending on the configuration of initialization data.
>
> Backward compatibility with in-driver hard-coded LED class device
> names is assured thanks to the default_label and devicename properties
> of newly introduced struct led_init_data.
>
> In case none of the aforementioned properties was found, then, for OF
> nodes, the node name is adopted for LED class device name.
>
> At the occassion of amending the Documentation/leds/leds-class.txt
> unify spelling: colour -> color.
>
> Alongside these changes added is a new tool - tools/leds/get_led_device_info.sh.
> The tool allows retrieving details of a LED class device's parent device,
> which proves that using vendor or product name for devicename part
> of LED name doesn't convey any added value since that information had been
> already available in sysfs. The script performs also basic validation
> of a LED class device name.
>
> Signed-off-by: Jacek Anaszewski <[email protected]>
> Cc: Baolin Wang <[email protected]>
> Cc: Pavel Machek <[email protected]>
> Cc: Dan Murphy <[email protected]>
> Cc: Daniel Mack <[email protected]>
> Cc: Linus Walleij <[email protected]>
> Cc: Oleh Kravchenko <[email protected]>
> Cc: Sakari Ailus <[email protected]>
> Cc: Simon Shields <[email protected]>
> ---
> Documentation/leds/leds-class.txt | 67 ++++++++++++-
> drivers/leds/led-class.c | 20 +++-
> drivers/leds/led-core.c | 127 ++++++++++++++++++++++++
> drivers/leds/leds.h | 1 +
> include/linux/leds.h | 45 +++++++++
> tools/leds/get_led_device_info.sh | 201 ++++++++++++++++++++++++++++++++++++++
> 6 files changed, 455 insertions(+), 6 deletions(-)
> create mode 100755 tools/leds/get_led_device_info.sh
>
> diff --git a/Documentation/leds/leds-class.txt b/Documentation/leds/leds-class.txt
> index 8b39cc6b03ee..e7316e37b57d 100644
> --- a/Documentation/leds/leds-class.txt
> +++ b/Documentation/leds/leds-class.txt
> @@ -43,9 +43,70 @@ LED Device Naming
>
> Is currently of the form:
>
> -"devicename:colour:function"
> -
> -There have been calls for LED properties such as colour to be exported as
> +"devicename:color:function"
> +
> +devicename: It should refer to a unique identifier created by the kernel,
> + like e.g. phyN for network devices or inputN for input devices,
> + rather than to the hardware. The information related to the product
> + and the bus to which given device is hooked is available in the
> + sysfs and can be retrieved using get_led_device_info.sh script
> + from tools/leds. Generally this section is expected mostly for
> + LEDs that are somehow associated with other devices.
> +
> +color: one of the color strings from led_colors array defined
> + in drivers/leds/led-core.c.
> +
> +function: one of the LED_FUNCTION* definitions from the header
> + include/dt-bindings/leds/common.h.
> +
> +If required color or function is missing, please submit a patch
> +to [email protected], adding required entries.
> +
> +It is possible that more than one LED with the same color and function will
> +be required for given platform, differing only with an ordinal number.
> +In this case it is preferable to just concatenate the predefined LED_FUNCTION*
> +name with required "-N" suffix in the driver. fwnode based drivers can use
> +function-enumerator property for that and then the concatenation will be handled
> +automatically by the LED core upon LED class device registration.
> +
> +LED subsystem has also a protection against name clash, that may occur
> +when LED class device is created by a driver of hot-pluggable device and
> +it doesn't provide unique devicename section. In this case numerical
> +suffix (e.g. "_1", "_2", "_3" etc.) is added to the requested LED class
> +device name.
> +
> +There might be still LED class drivers around using vendor or product name
> +for devicename, but this approach is now deprecated as it doesn't convey
> +any added value. Product information can be found in other places in sysfs
> +(see tools/leds/get_led_device_info.sh).
> +
> +Examples of proper LED names:
> +
> +"red:disk"
> +"white:flash"
> +"red:indicator"
> +"phy1:green:wlan"
> +"phy3::wlan"
> +":kbd_backlight"
> +"input5::kbd_backlight"
> +"input3::numlock"
> +"input3::scrolllock"
> +"input3::capslock"
> +"mmc1::status"
> +"white:status"
> +
> +get_led_device_info.sh script can be used for verifying if the LED name
> +meets the requirements pointed out here. It performs validation of the LED class
> +devicename sections and gives hints on expected value for a section in case
> +the validation fails for it. So far the script supports validation
> +of associations between LEDs and following types of devices:
> +
> +- input devices
> +- ieee80211 compliant USB devices
> +
> +The script is open to extensions.
> +
> +There have been calls for LED properties such as color to be exported as
> individual led class attributes. As a solution which doesn't incur as much
> overhead, I suggest these become part of the device name. The naming scheme
> above leaves scope for further attributes should they be needed. If sections
> diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
> index a564948e5f53..e3af0b71c9a9 100644
> --- a/drivers/leds/led-class.c
> +++ b/drivers/leds/led-class.c
> @@ -257,17 +257,31 @@ int led_classdev_register_ext(struct device *parent,
> struct led_classdev *led_cdev,
> struct led_init_data *init_data)
> {
> - char name[LED_MAX_NAME_SIZE];
> + char composed_name[LED_MAX_NAME_SIZE];
> + char final_name[LED_MAX_NAME_SIZE];
> + const char *proposed_name = composed_name;
> int ret;
>
> - ret = led_classdev_next_name(led_cdev->name, name, sizeof(name));
> + if (init_data) {
> + if (init_data->devname_mandatory && !init_data->devicename) {
> + dev_err(parent, "Mandatory device name is missing");
> + return -EINVAL;
> + }
> + ret = led_compose_name(parent, init_data, composed_name);
> + if (ret < 0)
> + return ret;
> + } else {
> + proposed_name = led_cdev->name;
> + }
> +
> + ret = led_classdev_next_name(proposed_name, final_name, sizeof(final_name));
> if (ret < 0)
> return ret;
>
> mutex_init(&led_cdev->led_access);
> mutex_lock(&led_cdev->led_access);
> led_cdev->dev = device_create_with_groups(leds_class, parent, 0,
> - led_cdev, led_cdev->groups, "%s", name);
> + led_cdev, led_cdev->groups, "%s", final_name);
> if (IS_ERR(led_cdev->dev)) {
> mutex_unlock(&led_cdev->led_access);
> return PTR_ERR(led_cdev->dev);
> diff --git a/drivers/leds/led-core.c b/drivers/leds/led-core.c
> index e3da7c03da1b..dcd14ea40687 100644
> --- a/drivers/leds/led-core.c
> +++ b/drivers/leds/led-core.c
> @@ -17,8 +17,10 @@
> #include <linux/module.h>
> #include <linux/mutex.h>
> #include <linux/of.h>
> +#include <linux/property.h>
> #include <linux/rwsem.h>
> #include <linux/slab.h>
> +#include <uapi/linux/uleds.h>
> #include "leds.h"
>
> DECLARE_RWSEM(leds_list_lock);
> @@ -27,6 +29,18 @@ EXPORT_SYMBOL_GPL(leds_list_lock);
> LIST_HEAD(leds_list);
> EXPORT_SYMBOL_GPL(leds_list);
>
> +const char *led_colors[LED_COLOR_ID_MAX] = {
> + [LED_COLOR_ID_WHITE] = "white",
> + [LED_COLOR_ID_RED] = "red",
> + [LED_COLOR_ID_GREEN] = "green",
> + [LED_COLOR_ID_BLUE] = "blue",
> + [LED_COLOR_ID_AMBER] = "amber",
> + [LED_COLOR_ID_VIOLET] = "violet",
> + [LED_COLOR_ID_YELLOW] = "yellow",
> + [LED_COLOR_ID_IR] = "ir",
> +};
> +EXPORT_SYMBOL_GPL(led_colors);
> +
> static int __led_set_brightness(struct led_classdev *led_cdev,
> enum led_brightness value)
> {
> @@ -357,3 +371,116 @@ void led_sysfs_enable(struct led_classdev *led_cdev)
> led_cdev->flags &= ~LED_SYSFS_DISABLE;
> }
> EXPORT_SYMBOL_GPL(led_sysfs_enable);
> +
> +static void led_parse_fwnode_props(struct device *dev,
> + struct fwnode_handle *fwnode,
> + struct led_properties *props)
> +{
> + int ret;
> +
> + if (!fwnode)
> + return;
> +
> + if (fwnode_property_present(fwnode, "label")) {
> + ret = fwnode_property_read_string(fwnode, "label", &props->label);
> + if (ret)
> + dev_err(dev, "Error parsing \'label\' property (%d)\n", ret);
> + return;
> + }
> +
> + if (fwnode_property_present(fwnode, "color")) {
> + ret = fwnode_property_read_u32(fwnode, "color", &props->color);
> + if (ret)
> + dev_err(dev, "Error parsing \'color\' property (%d)\n", ret);
> + else if (props->color >= LED_COLOR_ID_MAX)
> + dev_err(dev, "LED color identifier out of range\n");
> + else
> + props->color_present = true;
> + }
> +
> +
> + if (fwnode_property_present(fwnode, "function")) {
> + ret = fwnode_property_read_string(fwnode, "function", &props->function);
> + if (ret) {
> + dev_err(dev,
> + "Error parsing \'function\' property (%d)\n",
> + ret);
> + }
> + } else {
> + return;
> + }
> +
> + if (fwnode_property_present(fwnode, "function-enumerator")) {
> + ret = fwnode_property_read_u32(fwnode, "function-enumerator",
> + &props->func_enum);
> + if (ret) {
> + dev_err(dev,
> + "Error parsing \'function-enumerator\' property (%d)\n",
> + ret);
> + } else {
> + props->func_enum_present = true;
> + }
> + }
> +}
> +
> +int led_compose_name(struct device *dev, struct led_init_data *init_data,
> + char *led_classdev_name)
> +{
> + struct led_properties props = {};
> + struct fwnode_handle *fwnode = init_data->fwnode;
> + const char *devicename = init_data->devicename;
> +
> + if (!led_classdev_name)
> + return -EINVAL;
> +
> + led_parse_fwnode_props(dev, fwnode, &props);
> +
> + if (props.label) {
> + /*
> + * If init_data.devicename is NULL, then it indicates that
> + * DT label should be used as-is for LED class device name.
> + * Otherwise the label is prepended with devicename to compose
> + * the final LED class device name.
> + */
> + if (!devicename) {
> + strncpy(led_classdev_name, props.label,
> + LED_MAX_NAME_SIZE);
> + } else {
> + snprintf(led_classdev_name, LED_MAX_NAME_SIZE, "%s:%s",
> + devicename, props.label);
> + }
> + } else if (props.function || props.color_present) {
> + char tmp_buf[LED_MAX_NAME_SIZE];
> +
> + if (props.func_enum_present) {
> + snprintf(tmp_buf, LED_MAX_NAME_SIZE, "%s:%s-%d",
> + props.color_present ? led_colors[props.color] : "",
> + props.function ?: "", props.func_enum);
> + } else {
> + snprintf(tmp_buf, LED_MAX_NAME_SIZE, "%s:%s",
> + props.color_present ? led_colors[props.color] : "",
> + props.function ?: "");
> + }
> + if (init_data->devname_mandatory) {
> + snprintf(led_classdev_name, LED_MAX_NAME_SIZE, "%s:%s",
> + devicename, tmp_buf);
> + } else {
> + strncpy(led_classdev_name, tmp_buf, LED_MAX_NAME_SIZE);
> +
> + }
> + } else if (init_data->default_label) {
> + if (!devicename) {
> + dev_err(dev, "Legacy LED naming requires devicename segment");
> + return -EINVAL;
> + }
> + snprintf(led_classdev_name, LED_MAX_NAME_SIZE, "%s:%s",
> + devicename, init_data->default_label);
> + } else if (is_of_node(fwnode)) {
> + strncpy(led_classdev_name, to_of_node(fwnode)->name,
> + LED_MAX_NAME_SIZE);
> + } else
> + return -EINVAL;
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(led_compose_name);
> diff --git a/drivers/leds/leds.h b/drivers/leds/leds.h
> index 7d38e6b9a740..0d223c1f93b2 100644
> --- a/drivers/leds/leds.h
> +++ b/drivers/leds/leds.h
> @@ -31,5 +31,6 @@ void led_set_brightness_nosleep(struct led_classdev *led_cdev,
> extern struct rw_semaphore leds_list_lock;
> extern struct list_head leds_list;
> extern struct list_head trigger_list;
> +extern const char *led_colors[LED_COLOR_ID_MAX];
>
> #endif /* __LEDS_H_INCLUDED */
> diff --git a/include/linux/leds.h b/include/linux/leds.h
> index fab83a2d7bff..03e9795fa23b 100644
> --- a/include/linux/leds.h
> +++ b/include/linux/leds.h
> @@ -12,6 +12,7 @@
> #ifndef __LINUX_LEDS_H_INCLUDED
> #define __LINUX_LEDS_H_INCLUDED
>
> +#include <dt-bindings/leds/common.h>
> #include <linux/device.h>
> #include <linux/kernfs.h>
> #include <linux/list.h>
> @@ -37,6 +38,25 @@ enum led_brightness {
> struct led_init_data {
> /* device fwnode handle */
> struct fwnode_handle *fwnode;
> + /*
> + * default <color:function> tuple, for backward compatibility
> + * with in-driver hard-coded LED names used as a fallback when
> + * DT "label" property is absent; it should be set to NULL
> + * in new LED class drivers.
> + */
> + const char *default_label;
> + /*
> + * string to be used for devicename section of LED class device
> + * either for label based LED name composition path or for fwnode
> + * based when devname_mandatory is true
> + */
> + const char *devicename;
> + /*
> + * indicates if LED name should always comprise devicename section;
> + * only LEDs exposed by drivers of hot-pluggable devices should
> + * set it to true
> + */
> + bool devname_mandatory;
> };
>
> struct led_classdev {
> @@ -262,6 +282,22 @@ extern void led_sysfs_disable(struct led_classdev *led_cdev);
> extern void led_sysfs_enable(struct led_classdev *led_cdev);
>
> /**
> + * led_compose_name - compose LED class device name
> + * @dev: LED controller device object
> + * @child: child fwnode_handle describing a LED or a group of synchronized LEDs;
> + * it must be provided only for fwnode based LEDs
> + * @led_classdev_name: composed LED class device name
> + *
> + * Create LED class device name basing on the provided init_data argument.
> + * The name can have <devicename:color:function> or <color:function>.
> + * form, depending on the init_data configuration.
> + *
> + * Returns: 0 on success or negative error value on failure
> + */
> +extern int led_compose_name(struct device *dev, struct led_init_data *init_data,
> + char *led_classdev_name);
> +
> +/**
> * led_sysfs_is_disabled - check if LED sysfs interface is disabled
> * @led_cdev: the LED to query
> *
> @@ -438,6 +474,15 @@ struct led_platform_data {
> struct led_info *leds;
> };
>
> +struct led_properties {
> + u32 color;
> + bool color_present;
> + const char *function;
> + u32 func_enum;
> + bool func_enum_present;
> + const char *label;
> +};
> +
> struct gpio_desc;
> typedef int (*gpio_blink_set_t)(struct gpio_desc *desc, int state,
> unsigned long *delay_on,
> diff --git a/tools/leds/get_led_device_info.sh b/tools/leds/get_led_device_info.sh
> new file mode 100755
> index 000000000000..ccfa442db5fe
> --- /dev/null
> +++ b/tools/leds/get_led_device_info.sh
> @@ -0,0 +1,201 @@
> +#!/bin/sh
> +# SPDX-License-Identifier: GPL-2.0
> +
> +led_common_defs_path="include/dt-bindings/leds/common.h"
> +
> +num_args=$#
> +if [ $num_args -eq 1 ]; then
> + linux_top=$(dirname `realpath $0` | awk -F/ \
> + '{ \
> + i=1; \
> + while (i <= NF - 2) { \
> + printf $i"/"; \
> + i++; \
> + }; \
> + }')
> + led_defs_path=$linux_top/$led_common_defs_path
> +elif [ $num_args -eq 2 ]; then
> + led_defs_path=`realpath $2`
> +else
> + echo "Usage: get_led_device_info.sh LED_CDEV_PATH [LED_COMMON_DEFS_PATH]"
> + exit 1
> +fi
> +
> +if [ ! -f $led_defs_path ]; then
> + echo "$led_defs_path doesn't exist"
> + exit 1
> +fi
> +
> +led_cdev_path=`echo $1 | sed s'/\/$//'`
> +
> +ls "$led_cdev_path/brightness" > /dev/null 2>&1
> +if [ $? -ne 0 ]; then
> + echo "Device \"$led_cdev_path\" does not exist."
> + exit 1
> +fi
> +
> +bus=`readlink $led_cdev_path/device/subsystem | sed s'/.*\///'`
> +usb_subdev=`readlink $led_cdev_path | grep usb | sed s'/\(.*usb[0-9]*\/[0-9]*-[0-9]*\)\/.*/\1/'`
> +ls "$led_cdev_path/device/of_node/compatible" > /dev/null 2>&1
> +of_node_missing=$?
> +
> +if [ "$bus" = "input" ]; then
> + input_node=`readlink $led_cdev_path/device | sed s'/.*\///'`
> + if [ ! -z "$usb_subdev" ]; then
> + bus="usb"
> + fi
> +fi
> +
> +if [ "$bus" = "usb" ]; then
> + usb_interface=`readlink $led_cdev_path | sed s'/.*\(usb[0-9]*\)/\1/' | cut -d\/ -f3`
> + cd $led_cdev_path/../$usb_subdev
> + driver=`readlink $usb_interface/driver | sed s'/.*\///'`
> + if [ -d "$usb_interface/ieee80211" ]; then
> + wifi_phy=`ls -l $usb_interface/ieee80211 | grep phy | awk '{print $9}'`
> + fi
> + idVendor=`cat idVendor`
> + idProduct=`cat idProduct`
> + manufacturer=`cat manufacturer`
> + product=`cat product`
> +elif [ "$bus" = "input" ]; then
> + cd $led_cdev_path
> + product=`cat device/name`
> + driver=`cat device/device/driver/description`
> +elif [ $of_node_missing -eq 0 ]; then
> + cd $led_cdev_path
> + compatible=`cat device/of_node/compatible`
> + if [ "$compatible" = "gpio-leds" ]; then
> + driver="leds-gpio"
> + elif [ "$compatible" = "pwm-leds" ]; then
> + driver="leds-pwm"
> + else
> + manufacturer=`echo $compatible | awk -F, '{print $1}'`
> + product=`echo $compatible | awk -F, '{print $2}'`
> + fi
> +else
> + echo "Unknown device type."
> + exit 1
> +fi
> +
> +printf "\n#####################################\n"
> +printf "# LED class device hardware details #\n"
> +printf "#####################################\n\n"
> +
> +printf "bus:\t\t\t$bus\n"
> +
> +if [ ! -z "$idVendor" ]; then
> + printf "idVendor:\t\t$idVendor\n"
> +fi
> +
> +if [ ! -z "$idProduct" ]; then
> + printf "idProduct:\t\t$idProduct\n"
> +fi
> +
> +if [ ! -z "$manufacturer" ]; then
> + printf "manufacturer:\t\t$manufacturer\n"
> +fi
> +
> +if [ ! -z "$product" ]; then
> + printf "product:\t\t$product\n"
> +fi
> +
> +if [ ! -z "$driver" ]; then
> + printf "driver:\t\t\t$driver\n"
> +fi
> +
> +if [ ! -z "$input_node" ]; then
> + printf "associated input node:\t$input_node\n"
> +fi
> +
> +printf "\n####################################\n"
> +printf "# LED class device name validation #\n"
> +printf "####################################\n\n"
> +
> +led_name=`echo $led_cdev_path | sed s'/.*\///'`
> +
> +num_sections=`echo $led_name | awk -F: '{print NF}'`
> +
> +if [ $num_sections -eq 1 ]; then
> + printf "\":\" delimiter not detected.\t[ FAILED ]\n"
> + exit 1
> +elif [ $num_sections -eq 2 ]; then
> + color=`echo $led_name | cut -d: -f1`
> + function=`echo $led_name | cut -d: -f2`
> +elif [ $num_sections -eq 3 ]; then
> + devicename=`echo $led_name | cut -d: -f1`
> + color=`echo $led_name | cut -d: -f2`
> + function=`echo $led_name | cut -d: -f3`
> +else
> + printf "Detected %d sections in the LED class device name - should the script be updated?\n" $num_sections
> + exit 1
> +fi
> +
> +S_DEV="devicename"
> +S_CLR="color "
> +S_FUN="function "
> +status_tab=20
> +
> +print_msg_ok()
> +{
> + local section_name="$1"
> + local section_val="$2"
> + local msg="$3"
> + printf "$section_name :\t%-${status_tab}.${status_tab}s %s %s\n" "$section_val" "[ OK ] " "$msg"
> +}
> +
> +print_msg_failed()
> +{
> + local section_name="$1"
> + local section_val="$2"
> + local msg="$3"
> + printf "$section_name :\t%-${status_tab}.${status_tab}s %s %s\n" "$section_val" "[ FAILED ]" "$msg"
> +}
> +
> +if [ ! -z "$input_node" ]; then
> + expected_devname=$input_node
> +elif [ ! -z "$wifi_phy" ]; then
> + expected_devname=$wifi_phy
> +fi
> +
> +if [ ! -z "$devicename" ]; then
> + if [ ! -z "$expected_devname" ]; then
> + if [ "$devicename" = "$expected_devname" ]; then
> + print_msg_ok "$S_DEV" "$devicename"
> + else
> + print_msg_failed "$S_DEV" "$devicename" "Expected: $expected_devname"
> + fi
> + else
> + if [ "$devicename" = "$manufacturer" ]; then
> + print_msg_failed "$S_DEV" "$devicename" "Redundant: use of vendor name is discouraged"
> + elif [ "$devicename" = "$product" ]; then
> + print_msg_failed "$S_DEV" "$devicename" "Redundant: use of product name is discouraged"
> + else
> + print_msg_failed "$S_DEV" "$devicename" "Unknown devicename - should the script be updated?"
> + fi
> + fi
> +elif [ ! -z "$expected_devname" ]; then
> + print_msg_failed "$S_DEV" "blank" "Expected: $expected_devname"
> +fi
> +
> +if [ ! -z "$color" ]; then
> + color_upper=`echo $color | tr [:lower:] [:upper:]`
> + color_id_definition=$(cat $led_defs_path | grep "_$color_upper\s" | awk '{print $2}')
> + if [ ! -z "$color_id_definition" ]; then
> + print_msg_ok "$S_CLR" "$color" "Matching definition: $color_id_definition"
> + else
> + print_msg_failed "$S_CLR" "$color" "Definition not found in $led_defs_path"
> + fi
> +
> +fi
> +
> +if [ ! -z "$function" ]; then
> + # strip optional enumerator
> + function=`echo $function | sed s'/\(.*\)-[0-9]*$/\1/'`
> + fun_definition=$(cat $led_defs_path | grep "\"$function\"" | awk '{print $2}')
> + if [ ! -z "$fun_definition" ]; then
> + print_msg_ok "$S_FUN" "$function" "Matching definition: $fun_definition"
> + else
> + print_msg_failed "$S_FUN" "$function" "Definition not found in $led_defs_path"
> + fi
> +
> +fi
>

2019-06-26 20:16:51

by Oleh Kravchenko

[permalink] [raw]
Subject: Re: [PATCH v5 05/26] leds: core: Add support for composing LED class device names

Hello Jacek,
so after this patch will be merged.

There will be a way to define custom function name by DeviceTree?

26.06.19 22:05, Jacek Anaszewski пише:
> Gentle reminder.
>
> Pavel, Dan - any conclusions?
>
> This patch is the main part of the proposed changes,
> so it would be good to spot any remaining issues.
>
> What needs a consensus is also a new
> Documentation/leds/led-functions.txt file I introduce
> in the patch 26/26.
>
> Best regards,
> Jacek Anaszewski

--
Best regards,
Oleh Kravchenko



Attachments:
signature.asc (849.00 B)
OpenPGP digital signature

2019-06-27 18:28:44

by Jacek Anaszewski

[permalink] [raw]
Subject: Re: [PATCH v5 05/26] leds: core: Add support for composing LED class device names

Hi Oleh,

On 6/26/19 10:07 PM, Oleh Kravchenko wrote:
> Hello Jacek,
> so after this patch will be merged.
>
> There will be a way to define custom function name by DeviceTree?

Yes. We standardize LED functions just to avoid spreading many similarly
looking function names with the same semantics.

We don't enforce using new function definitions in any way.
It is possible to assign whatever you want to the DT label property
(however now deprecated) or to the new DT function property.

It will be however preferable to use standard LED_FUNCTION definitions
for new mainline bindings and dts files. Of course, as documentation
states, it will be possible to propose new ones if none of existing
fit for given application. This is only an initial set.

> 26.06.19 22:05, Jacek Anaszewski пише:
>> Gentle reminder.
>>
>> Pavel, Dan - any conclusions?
>>
>> This patch is the main part of the proposed changes,
>> so it would be good to spot any remaining issues.
>>
>> What needs a consensus is also a new
>> Documentation/leds/led-functions.txt file I introduce
>> in the patch 26/26.
>>
>> Best regards,
>> Jacek Anaszewski
>

--
Best regards,
Jacek Anaszewski

2019-06-28 08:47:01

by Linus Walleij

[permalink] [raw]
Subject: Re: [PATCH v5 05/26] leds: core: Add support for composing LED class device names

On Sun, Jun 9, 2019 at 8:08 PM Jacek Anaszewski
<[email protected]> wrote:

> Add generic support for composing LED class device name. The newly
> introduced led_compose_name() function composes device name according
> to either <color:function> or <devicename:color:function> pattern,
> depending on the configuration of initialization data.
>
> Backward compatibility with in-driver hard-coded LED class device
> names is assured thanks to the default_label and devicename properties
> of newly introduced struct led_init_data.
>
> In case none of the aforementioned properties was found, then, for OF
> nodes, the node name is adopted for LED class device name.
>
> At the occassion of amending the Documentation/leds/leds-class.txt
> unify spelling: colour -> color.
>
> Alongside these changes added is a new tool - tools/leds/get_led_device_info.sh.
> The tool allows retrieving details of a LED class device's parent device,
> which proves that using vendor or product name for devicename part
> of LED name doesn't convey any added value since that information had been
> already available in sysfs. The script performs also basic validation
> of a LED class device name.
>
> Signed-off-by: Jacek Anaszewski <[email protected]>
> Cc: Baolin Wang <[email protected]>
> Cc: Pavel Machek <[email protected]>
> Cc: Dan Murphy <[email protected]>
> Cc: Daniel Mack <[email protected]>
> Cc: Linus Walleij <[email protected]>
> Cc: Oleh Kravchenko <[email protected]>
> Cc: Sakari Ailus <[email protected]>
> Cc: Simon Shields <[email protected]>

This is good progress on trying to bring order in chaos.

A problem with LEDs is that it invites bikeshedding because it is too
relateable.

So by the motto "rough consensus and running code":
Reviewed-by: Linus Walleij <[email protected]>

Yours,
Linus Walleij

2019-06-28 13:31:39

by David Laight

[permalink] [raw]
Subject: RE: [PATCH v5 05/26] leds: core: Add support for composing LED class device names

From: Linus Walleij
> Sent: 28 June 2019 09:46
...
> A problem with LEDs is that it invites bikeshedding because it is too
> relateable.

Bikeshedding leds :-)

It also isn't at all clear how to handle bi-colour and tri-colour leds.
ISTR the usual interface lets you set the brightness, but more often
leds are single brightness but multi-colour.
Eg the ethernet 'speed' led which is (usually) off/orange/green.

Changing the brightness either means changing the current or using PWM.
Both really require more hardware support than changing colours.

I've done some led driving (for a front panel) from a PLD (small FPGA).
As well as the obvious things I did:
- dim: 1/8th on at 80Hz.
- flash: 1/8th on at 4Hz.
- orange: 50-50 red-green at 80Hz on an RGB led.

There was also the 'ethernet activity' led which could either be driven
by the hardware, or forced on/off/flash by the driver.
If driven by the hardware, the software could read the current state.

None of this really fitted the Linux leds interface.

David

-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)

2019-07-03 22:01:23

by Pavel Machek

[permalink] [raw]
Subject: Re: [PATCH v5 05/26] leds: core: Add support for composing LED class device names

Hi!

Sorry for the delay.

> @@ -27,6 +29,18 @@ EXPORT_SYMBOL_GPL(leds_list_lock);
> LIST_HEAD(leds_list);
> EXPORT_SYMBOL_GPL(leds_list);
>
> +const char *led_colors[LED_COLOR_ID_MAX] = {

const char * const , if we want to play that game?


> + [LED_COLOR_ID_WHITE] = "white",
> + [LED_COLOR_ID_RED] = "red",
> + [LED_COLOR_ID_GREEN] = "green",
> + [LED_COLOR_ID_BLUE] = "blue",
> + [LED_COLOR_ID_AMBER] = "amber",
> + [LED_COLOR_ID_VIOLET] = "violet",
> + [LED_COLOR_ID_YELLOW] = "yellow",
> + [LED_COLOR_ID_IR] = "ir",
> +};
> +EXPORT_SYMBOL_GPL(led_colors);
> +

> + if (fwnode_property_present(fwnode, "label")) {
> + ret = fwnode_property_read_string(fwnode, "label", &props->label);
> + if (ret)
> + dev_err(dev, "Error parsing \'label\' property (%d)\n", ret);
> + return;

I don't think you need to escape ' with \.

> + if (fwnode_property_present(fwnode, "function")) {
> + ret = fwnode_property_read_string(fwnode, "function", &props->function);
> + if (ret) {
> + dev_err(dev,
> + "Error parsing \'function\' property (%d)\n",
> + ret);
> + }
> + } else {
> + return;
> + }

> +
> + if (fwnode_property_present(fwnode, "function-enumerator")) {

I'd do if (!fwnode_property_present()) return; in both occasions, to
save an indentation level; but that's nitpicking.

> + if (props.label) {
> + /*
> + * If init_data.devicename is NULL, then it indicates that
> + * DT label should be used as-is for LED class device name.
> + * Otherwise the label is prepended with devicename to compose
> + * the final LED class device name.
> + */
> + if (!devicename) {
> + strncpy(led_classdev_name, props.label,
> + LED_MAX_NAME_SIZE);
> + } else {
> + snprintf(led_classdev_name, LED_MAX_NAME_SIZE, "%s:%s",
> + devicename, props.label);
> + }

Unlike snprintf(), strncpy() does not guarantee NULL termination.

I did not check the shell script.

With that fixed,

Acked-by: Pavel Machek <[email protected]>

Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html


Attachments:
(No filename) (2.13 kB)
signature.asc (188.00 B)
Digital signature
Download all attachments

2019-07-03 22:06:21

by Pavel Machek

[permalink] [raw]
Subject: Various LED complexities was Re: [PATCH v5 05/26] leds: core: Add support for composing LED class device names

On Fri 2019-06-28 13:30:30, David Laight wrote:
> From: Linus Walleij
> > Sent: 28 June 2019 09:46
> ...
> > A problem with LEDs is that it invites bikeshedding because it is too
> > relateable.
>
> Bikeshedding leds :-)
>
> It also isn't at all clear how to handle bi-colour and tri-colour leds.
> ISTR the usual interface lets you set the brightness, but more often
> leds are single brightness but multi-colour.
> Eg the ethernet 'speed' led which is (usually) off/orange/green.
>
> Changing the brightness either means changing the current or using PWM.
> Both really require more hardware support than changing colours.
>
> I've done some led driving (for a front panel) from a PLD (small FPGA).
> As well as the obvious things I did:
> - dim: 1/8th on at 80Hz.
> - flash: 1/8th on at 4Hz.
> - orange: 50-50 red-green at 80Hz on an RGB led.
>
> There was also the 'ethernet activity' led which could either be driven
> by the hardware, or forced on/off/flash by the driver.
> If driven by the hardware, the software could read the current state.
>
> None of this really fitted the Linux leds interface.

Well, we are working on some of those :-). But lets discuss that in
separate threads.

In particular we are working on triggers and RGB LEDs.

bi-color LEDs seem to handled as two separate LEDs. Not much expected
to change there.

Pavel

--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html


Attachments:
(No filename) (1.51 kB)
signature.asc (188.00 B)
Digital signature
Download all attachments

2019-07-17 21:03:49

by Jacek Anaszewski

[permalink] [raw]
Subject: Re: [PATCH v5 05/26] leds: core: Add support for composing LED class device names

Hi Pavel,

On 7/4/19 12:00 AM, Pavel Machek wrote:
> Hi!
>
> Sorry for the delay.

No problem.

>> @@ -27,6 +29,18 @@ EXPORT_SYMBOL_GPL(leds_list_lock);
>> LIST_HEAD(leds_list);
>> EXPORT_SYMBOL_GPL(leds_list);
>>
>> +const char *led_colors[LED_COLOR_ID_MAX] = {
>
> const char * const , if we want to play that game?

Ack.

>> + [LED_COLOR_ID_WHITE] = "white",
>> + [LED_COLOR_ID_RED] = "red",
>> + [LED_COLOR_ID_GREEN] = "green",
>> + [LED_COLOR_ID_BLUE] = "blue",
>> + [LED_COLOR_ID_AMBER] = "amber",
>> + [LED_COLOR_ID_VIOLET] = "violet",
>> + [LED_COLOR_ID_YELLOW] = "yellow",
>> + [LED_COLOR_ID_IR] = "ir",
>> +};
>> +EXPORT_SYMBOL_GPL(led_colors);
>> +
>
>> + if (fwnode_property_present(fwnode, "label")) {
>> + ret = fwnode_property_read_string(fwnode, "label", &props->label);
>> + if (ret)
>> + dev_err(dev, "Error parsing \'label\' property (%d)\n", ret);
>> + return;
>
> I don't think you need to escape ' with \.

Right.

>> + if (fwnode_property_present(fwnode, "function")) {
>> + ret = fwnode_property_read_string(fwnode, "function", &props->function);
>> + if (ret) {
>> + dev_err(dev,
>> + "Error parsing \'function\' property (%d)\n",
>> + ret);
>> + }
>> + } else {
>> + return;
>> + }
>
>> +
>> + if (fwnode_property_present(fwnode, "function-enumerator")) {
>
> I'd do if (!fwnode_property_present()) return; in both occasions, to
> save an indentation level; but that's nitpicking.

Ack.

>> + if (props.label) {
>> + /*
>> + * If init_data.devicename is NULL, then it indicates that
>> + * DT label should be used as-is for LED class device name.
>> + * Otherwise the label is prepended with devicename to compose
>> + * the final LED class device name.
>> + */
>> + if (!devicename) {
>> + strncpy(led_classdev_name, props.label,
>> + LED_MAX_NAME_SIZE);
>> + } else {
>> + snprintf(led_classdev_name, LED_MAX_NAME_SIZE, "%s:%s",
>> + devicename, props.label);
>> + }
>
> Unlike snprintf(), strncpy() does not guarantee NULL termination.

Indeed. I'll change strncpy to strscpy.

> I did not check the shell script.
>
> With that fixed,
>
> Acked-by: Pavel Machek <[email protected]>

Thanks!

--
Best regards,
Jacek Anaszewski

2019-07-17 21:14:57

by Jacek Anaszewski

[permalink] [raw]
Subject: Re: [PATCH v5 00/26] Add generic support for composing LED class device name

Hi all,

I need explicit acks for some patches from this series, that
were either requested improvements or I modified them by myself
after v4.

The patches I am talking about are the following:

1/26
21/26
23/26
25/26

26/26 would be nice to have but I presume it needs more discussion
and analysis.

Best regards,
Jacek Anaszewski

On 6/9/19 9:07 PM, Jacek Anaszewski wrote:
> Changes from v4:
>
> - switched "charge" function name to "charging"
> - added "cpu", "mute", "micmute", "disk-activity", "panic", "mtd" LED functions
> to cover all existing triggers and removed now redundant "nand" and "mmc"
> - added "capslock", "scrollock", "numlock" LED functions
> - removed now redundant "keyboard" and "keypad" since there is "kbd_backlight"
> already available
> - removed "tv" LED function as depreciated
> - switched LED_COLOR_ID_COUNT to LED_COLOR_ID_MAX
> - fixed led_classdev_register_ext() to not leave struct led_classdev's
> name pointing to no longer existing composed_name stack variable
> - fixed leds-as3645 and leds-aat1290 to no longer rely on struct led_classdev's
> name property
> - added basic LED class device name validation to get_led_device_info.sh
> - tweaked LED naming section in leds_class.txt to allow devicename section
> also for non hot-pluggable devices
> - always initialize all fields of struct led_init_data to zero on declaration
> in drivers
> - fix leds-gpio to avoid overwriting the LED name coming from platform_data
> - add description of LED function names with regard to whether devicename
> section is initialized or not
>
> Changes from v3:
>
> - allow for devicename section for hot-pluggable devices
> - move led_colors array to led-core.c to avoid build break
> due to Kconfig dependency issue
> - add a patch fixing led_colors array name clash with ALSA driver
> - change led-enumerator DT property name to more meaningful function-enumerator
> - add LED_FUNCTION_KBD_BACKLIGHT
> - change naming and add new proprties to struct led_init_data
> and struct led_properties
>
> Changes from v2:
>
> - removed from drivers the responsibility of calling led_compose_name()
> - added struct device* argument to led_compose_name() to allow using
> dev_<level> logging functions for more informative logs
> - adjusted the list of LED_FUNCTION definitions according to the v2 review
> remarks
> - renamed default_desc to default_label in the struct led_init_data
> - added led-enumerator DT property to the common LED bindings
> - removed LED_COLOR_NAME definitions from include/dt-bindings/leds/common.h
> - change DT color property type from string to integer
> - change struct initialization list to explicit property assignment in leds-sc27xx-bltc.c
> - use led->client->name for led_hw_name in leds-lm3692x.c
> - few other minor improvements to docs etc.
>
> Changes from v1:
>
> - improved led_parse_properties() to parse label property at first
> and return immediately after parsing succeeds
> - added tool get_led_device_info.sh for retrieving LED class device's
> parent device related information
> - extended LED naming section of Documentation/leds/leds-class.txt
> - adjusted the list of LED_FUNCTION definitions according to the v1 review
> remarks
> - added standard LED_COLOR_NAME definitions
> - removed functions.h and moved both LED_FUNCTION and LED_COLOR_NAME
> definitions to include/dt-bindings/common.h
> - rebased leds-as3645a changes on top of the patch switching to fwnode
> property API
> - updated DT bindings to use new LED_COLOR_NAME definitions
> - improved common LED bindings to not use address unit for sub-nodes
> without reg property
>
> Generally I still insist on deprecating label property and devicename
> section of LED name. The tool I added for obtaining LED device name
> proves availability of the related information in other places in
> the sysfs. Other discussed use cases are covered in the updated
> Documentation/leds/leds-class.txt.
>
> Beside that, I tried also to create macros for automatic composition
> of "-N" suffixed LED functions, so that it would not be necessary
> to pollute common.h with plenty repetitions of the same function,
> differing only with the postfix. Unfortunately, the preprocessor
> of the dtc compiler seems not to accept string concatenetation.
> I.e. it is not possible to to the following assighment:
>
> function = "hdd""-1"
>
> If anyone knows how to obviate this shortocoming please let me know.
>
> Original cover letter:
>
> LED class device naming pattern included devicename section, which had
> unpleasant effect of varying userspace interface dependent on underlaying
> hardware. Moreover, this information was redundant in the LED name, since
> the LED controller name could have been obtained from sysfs device group
>
> This patch set introduces a led_compose_name() function in the LED core,
> which unifies and simplifies LED class device name composition. This
> change is accompanied by the improvements in the common LED DT bindings
> where two new properties are introduced: "function" and "color" . The two
> deprecate the old "label" property which was leaving too much room for
> interpretation, leading to inconsistent LED naming.
>
> There are also changes in LED DT node naming, which are in line with
> DT maintainer's request from [0].
>
> Since some DT LED naming unification, related to not including devicename
> section in "label" DT property, is being requested during reviews of new
> LED class drivers for almost a year now, then those drivers are the first
> candidates for optimalization and the first users of the new
> led_compose_name() API. The modifications were tested with Qemu,
> by stubbing the driver internals where hardware interaction was needed
> for proper probing.
>
> Thanks,
> Jacek Anaszewski
>
> Jacek Anaszewski (26):
> leds: class: Improve LED and LED flash class registration API
> dt-bindings: leds: Add LED_COLOR_ID definitions
> dt-bindings: leds: Add LED_FUNCTION definitions
> dt-bindings: leds: Add properties for LED name construction
> leds: core: Add support for composing LED class device names
> dt-bindings: sc27xx-blt: Add function and color properties
> leds: sc27xx-blt: Use generic support for composing LED names
> dt-bindings: lt3593: Add function and color properties
> leds: lt3593: Use generic support for composing LED names
> dt-bindings: lp8860: Add function and color properties
> leds: lp8860: Use generic support for composing LED names
> dt-bindings: lm3692x: Add function and color properties
> leds: lm3692x: Use generic support for composing LED names
> dt-bindings: lm36010: Add function and color properties
> leds: lm3601x: Use generic support for composing LED names
> dt-bindings: cr0014114: Add function and color properties
> leds: cr0014114: Use generic support for composing LED names
> dt-bindings: aat1290: Add function and color properties
> leds: aat1290: Use generic support for composing LED names
> dt-bindings: as3645a: Add function and color properties
> leds: as3645a: Use generic support for composing LED names
> dt-bindings: leds-gpio: Add function and color properties
> leds: gpio: Use generic support for composing LED names
> dt-bindings: an30259a: Add function and color properties
> leds: an30259a: Use generic support for composing LED names
> leds: Document standard LED functions
>
> .../devicetree/bindings/leds/ams,as3645a.txt | 22 +-
> Documentation/devicetree/bindings/leds/common.txt | 62 +++++-
> .../devicetree/bindings/leds/leds-aat1290.txt | 12 +-
> .../devicetree/bindings/leds/leds-an30259a.txt | 22 +-
> .../devicetree/bindings/leds/leds-cr0014114.txt | 26 ++-
> .../devicetree/bindings/leds/leds-gpio.txt | 23 ++-
> .../devicetree/bindings/leds/leds-lm3601x.txt | 10 +-
> .../devicetree/bindings/leds/leds-lm3692x.txt | 9 +-
> .../devicetree/bindings/leds/leds-lp8860.txt | 9 +-
> .../devicetree/bindings/leds/leds-lt3593.txt | 11 +-
> .../devicetree/bindings/leds/leds-sc27xx-bltc.txt | 10 +-
> Documentation/leds/led-functions.txt | 223 +++++++++++++++++++++
> Documentation/leds/leds-class.txt | 70 ++++++-
> drivers/leds/led-class-flash.c | 9 +-
> drivers/leds/led-class.c | 49 +++--
> drivers/leds/led-core.c | 127 ++++++++++++
> drivers/leds/leds-aat1290.c | 16 +-
> drivers/leds/leds-an30259a.c | 25 +--
> drivers/leds/leds-as3645a.c | 74 +++----
> drivers/leds/leds-cr0014114.c | 33 +--
> drivers/leds/leds-gpio.c | 26 +--
> drivers/leds/leds-lm3601x.c | 38 ++--
> drivers/leds/leds-lm3692x.c | 22 +-
> drivers/leds/leds-lp8860.c | 35 ++--
> drivers/leds/leds-lt3593.c | 20 +-
> drivers/leds/leds-pwm.c | 2 +-
> drivers/leds/leds-sc27xx-bltc.c | 22 +-
> drivers/leds/leds.h | 1 +
> include/dt-bindings/leds/common.h | 55 ++++-
> include/linux/led-class-flash.h | 15 +-
> include/linux/leds.h | 79 +++++++-
> tools/leds/get_led_device_info.sh | 201 +++++++++++++++++++
> 32 files changed, 1086 insertions(+), 272 deletions(-)
> create mode 100644 Documentation/leds/led-functions.txt
> create mode 100755 tools/leds/get_led_device_info.sh
>


2019-07-18 10:53:19

by Pavel Machek

[permalink] [raw]
Subject: Re: [PATCH v5 00/26] Add generic support for composing LED class device name


> Hi all,
>
> I need explicit acks for some patches from this series, that
> were either requested improvements or I modified them by myself
> after v4.
>
> The patches I am talking about are the following:
>
> 1/26
> 21/26
> 23/26
> 25/26

Acked-by: Pavel Machek <[email protected]>

> 26/26 would be nice to have but I presume it needs more discussion
> and analysis.

Idea is good, but I'd sort the file in different way.

Best regards,
Pavel

--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html


Attachments:
(No filename) (618.00 B)
signature.asc (188.00 B)
Digital signature
Download all attachments

2019-07-24 21:05:15

by Jacek Anaszewski

[permalink] [raw]
Subject: Re: [PATCH v5 00/26] Add generic support for composing LED class device name

On 7/18/19 12:52 PM, Pavel Machek wrote:
>
>> Hi all,
>>
>> I need explicit acks for some patches from this series, that
>> were either requested improvements or I modified them by myself
>> after v4.
>>
>> The patches I am talking about are the following:
>>
>> 1/26
>> 21/26
>> 23/26
>> 25/26
>
> Acked-by: Pavel Machek <[email protected]>

Applied the patch set without patch 26/26 for now.
I had to make some formatting related changes in leds-class.rst, in
part of the added text (we had leds-class.txt -> leds-class.rst
transition in the meantime) to fix resulting html formatting.
Basically they aimed to achieve nice bullets to compensate some
sphinx issue related to lack of line breaks after quoted strings.

Current shape of leds-class.rst on linux-leds.git for-next branch can
be looked up via [0].

>> 26/26 would be nice to have but I presume it needs more discussion
>> and analysis.
>
> Idea is good, but I'd sort the file in different way.
>
> Best regards,
> Pavel
>

[0]
https://git.kernel.org/pub/scm/linux/kernel/git/j.anaszewski/linux-leds.git/tree/Documentation/leds/leds-class.rst?h=for-next

--
Best regards,
Jacek Anaszewski