* [PATCH v10 1/6] leds: rgb: leds-ktd202x: Get device properties through fwnode to support ACPI
2024-05-31 11:41 [PATCH v10 0/6] KTD2026 indicator LED for X86 Xiaomi Pad2 Hans de Goede
@ 2024-05-31 11:41 ` Hans de Goede
2024-05-31 11:41 ` [PATCH v10 2/6] leds: rgb: leds-ktd202x: I2C ID tables for KTD2026 and 2027 Hans de Goede
` (7 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Hans de Goede @ 2024-05-31 11:41 UTC (permalink / raw)
To: Ilpo Järvinen, Andy Shevchenko, Pavel Machek, Lee Jones,
Kate Hsuan, Sebastian Reichel
Cc: Hans de Goede, platform-driver-x86, André Apitzsch,
linux-leds, linux-pm
From: Kate Hsuan <hpa@redhat.com>
This LED controller is installed on a Xiaomi pad2 and it is an x86
platform. The original driver is based on the device tree and can't be
used for this ACPI based system. This patch migrated the driver to use
fwnode to access the properties. Moreover, the fwnode API supports the
device tree so this work won't affect the original implementations.
Signed-off-by: Kate Hsuan <hpa@redhat.com>
Tested-by: André Apitzsch <git@apitzsch.eu> # on BQ Aquaris M5
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Reviewed-by: Andy Shevchenko <andy@kernel.org>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
drivers/leds/rgb/Kconfig | 1 -
drivers/leds/rgb/leds-ktd202x.c | 64 +++++++++++++++++----------------
2 files changed, 34 insertions(+), 31 deletions(-)
diff --git a/drivers/leds/rgb/Kconfig b/drivers/leds/rgb/Kconfig
index 8fc12d6a2958..222d943d826a 100644
--- a/drivers/leds/rgb/Kconfig
+++ b/drivers/leds/rgb/Kconfig
@@ -17,7 +17,6 @@ config LEDS_GROUP_MULTICOLOR
config LEDS_KTD202X
tristate "LED support for KTD202x Chips"
depends on I2C
- depends on OF
select REGMAP_I2C
help
This option enables support for the Kinetic KTD2026/KTD2027
diff --git a/drivers/leds/rgb/leds-ktd202x.c b/drivers/leds/rgb/leds-ktd202x.c
index 514965795a10..f1c810c415a4 100644
--- a/drivers/leds/rgb/leds-ktd202x.c
+++ b/drivers/leds/rgb/leds-ktd202x.c
@@ -99,7 +99,7 @@ struct ktd202x {
struct device *dev;
struct regmap *regmap;
bool enabled;
- int num_leds;
+ unsigned long num_leds;
struct ktd202x_led leds[] __counted_by(num_leds);
};
@@ -381,16 +381,19 @@ static int ktd202x_blink_mc_set(struct led_classdev *cdev,
mc->num_colors);
}
-static int ktd202x_setup_led_rgb(struct ktd202x *chip, struct device_node *np,
+static int ktd202x_setup_led_rgb(struct ktd202x *chip, struct fwnode_handle *fwnode,
struct ktd202x_led *led, struct led_init_data *init_data)
{
+ struct fwnode_handle *child;
struct led_classdev *cdev;
- struct device_node *child;
struct mc_subled *info;
int num_channels;
int i = 0;
- num_channels = of_get_available_child_count(np);
+ num_channels = 0;
+ fwnode_for_each_available_child_node(fwnode, child)
+ num_channels++;
+
if (!num_channels || num_channels > chip->num_leds)
return -EINVAL;
@@ -398,22 +401,22 @@ static int ktd202x_setup_led_rgb(struct ktd202x *chip, struct device_node *np,
if (!info)
return -ENOMEM;
- for_each_available_child_of_node(np, child) {
+ fwnode_for_each_available_child_node(fwnode, child) {
u32 mono_color;
u32 reg;
int ret;
- ret = of_property_read_u32(child, "reg", ®);
+ ret = fwnode_property_read_u32(child, "reg", ®);
if (ret != 0 || reg >= chip->num_leds) {
- dev_err(chip->dev, "invalid 'reg' of %pOFn\n", child);
- of_node_put(child);
- return -EINVAL;
+ dev_err(chip->dev, "invalid 'reg' of %pfw\n", child);
+ fwnode_handle_put(child);
+ return ret;
}
- ret = of_property_read_u32(child, "color", &mono_color);
+ ret = fwnode_property_read_u32(child, "color", &mono_color);
if (ret < 0 && ret != -EINVAL) {
- dev_err(chip->dev, "failed to parse 'color' of %pOF\n", child);
- of_node_put(child);
+ dev_err(chip->dev, "failed to parse 'color' of %pfw\n", child);
+ fwnode_handle_put(child);
return ret;
}
@@ -433,16 +436,16 @@ static int ktd202x_setup_led_rgb(struct ktd202x *chip, struct device_node *np,
return devm_led_classdev_multicolor_register_ext(chip->dev, &led->mcdev, init_data);
}
-static int ktd202x_setup_led_single(struct ktd202x *chip, struct device_node *np,
+static int ktd202x_setup_led_single(struct ktd202x *chip, struct fwnode_handle *fwnode,
struct ktd202x_led *led, struct led_init_data *init_data)
{
struct led_classdev *cdev;
u32 reg;
int ret;
- ret = of_property_read_u32(np, "reg", ®);
+ ret = fwnode_property_read_u32(fwnode, "reg", ®);
if (ret != 0 || reg >= chip->num_leds) {
- dev_err(chip->dev, "invalid 'reg' of %pOFn\n", np);
+ dev_err(chip->dev, "invalid 'reg' of %pfw\n", fwnode);
return -EINVAL;
}
led->index = reg;
@@ -454,7 +457,7 @@ static int ktd202x_setup_led_single(struct ktd202x *chip, struct device_node *np
return devm_led_classdev_register_ext(chip->dev, &led->cdev, init_data);
}
-static int ktd202x_add_led(struct ktd202x *chip, struct device_node *np, unsigned int index)
+static int ktd202x_add_led(struct ktd202x *chip, struct fwnode_handle *fwnode, unsigned int index)
{
struct ktd202x_led *led = &chip->leds[index];
struct led_init_data init_data = {};
@@ -463,21 +466,21 @@ static int ktd202x_add_led(struct ktd202x *chip, struct device_node *np, unsigne
int ret;
/* Color property is optional in single color case */
- ret = of_property_read_u32(np, "color", &color);
+ ret = fwnode_property_read_u32(fwnode, "color", &color);
if (ret < 0 && ret != -EINVAL) {
- dev_err(chip->dev, "failed to parse 'color' of %pOF\n", np);
+ dev_err(chip->dev, "failed to parse 'color' of %pfw\n", fwnode);
return ret;
}
led->chip = chip;
- init_data.fwnode = of_fwnode_handle(np);
+ init_data.fwnode = fwnode;
if (color == LED_COLOR_ID_RGB) {
cdev = &led->mcdev.led_cdev;
- ret = ktd202x_setup_led_rgb(chip, np, led, &init_data);
+ ret = ktd202x_setup_led_rgb(chip, fwnode, led, &init_data);
} else {
cdev = &led->cdev;
- ret = ktd202x_setup_led_single(chip, np, led, &init_data);
+ ret = ktd202x_setup_led_single(chip, fwnode, led, &init_data);
}
if (ret) {
@@ -490,15 +493,14 @@ static int ktd202x_add_led(struct ktd202x *chip, struct device_node *np, unsigne
return 0;
}
-static int ktd202x_probe_dt(struct ktd202x *chip)
+static int ktd202x_probe_fw(struct ktd202x *chip)
{
- struct device_node *np = dev_of_node(chip->dev), *child;
+ struct fwnode_handle *child;
+ struct device *dev = chip->dev;
int count;
int i = 0;
- chip->num_leds = (int)(unsigned long)of_device_get_match_data(chip->dev);
-
- count = of_get_available_child_count(np);
+ count = device_get_child_node_count(dev);
if (!count || count > chip->num_leds)
return -EINVAL;
@@ -507,11 +509,11 @@ static int ktd202x_probe_dt(struct ktd202x *chip)
/* Allow the device to execute the complete reset */
usleep_range(200, 300);
- for_each_available_child_of_node(np, child) {
+ device_for_each_child_node(dev, child) {
int ret = ktd202x_add_led(chip, child, i);
if (ret) {
- of_node_put(child);
+ fwnode_handle_put(child);
return ret;
}
i++;
@@ -554,6 +556,8 @@ static int ktd202x_probe(struct i2c_client *client)
return ret;
}
+ chip->num_leds = (unsigned long)i2c_get_match_data(client);
+
chip->regulators[0].supply = "vin";
chip->regulators[1].supply = "vio";
ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(chip->regulators), chip->regulators);
@@ -568,7 +572,7 @@ static int ktd202x_probe(struct i2c_client *client)
return ret;
}
- ret = ktd202x_probe_dt(chip);
+ ret = ktd202x_probe_fw(chip);
if (ret < 0) {
regulator_bulk_disable(ARRAY_SIZE(chip->regulators), chip->regulators);
return ret;
@@ -605,7 +609,7 @@ static void ktd202x_shutdown(struct i2c_client *client)
static const struct of_device_id ktd202x_match_table[] = {
{ .compatible = "kinetic,ktd2026", .data = (void *)KTD2026_NUM_LEDS },
{ .compatible = "kinetic,ktd2027", .data = (void *)KTD2027_NUM_LEDS },
- {},
+ {}
};
MODULE_DEVICE_TABLE(of, ktd202x_match_table);
--
2.45.1
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH v10 2/6] leds: rgb: leds-ktd202x: I2C ID tables for KTD2026 and 2027
2024-05-31 11:41 [PATCH v10 0/6] KTD2026 indicator LED for X86 Xiaomi Pad2 Hans de Goede
2024-05-31 11:41 ` [PATCH v10 1/6] leds: rgb: leds-ktd202x: Get device properties through fwnode to support ACPI Hans de Goede
@ 2024-05-31 11:41 ` Hans de Goede
2024-05-31 11:41 ` [PATCH v10 3/6] leds: rgb: leds-ktd202x: Initialize mutex earlier Hans de Goede
` (6 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Hans de Goede @ 2024-05-31 11:41 UTC (permalink / raw)
To: Ilpo Järvinen, Andy Shevchenko, Pavel Machek, Lee Jones,
Kate Hsuan, Sebastian Reichel
Cc: Hans de Goede, platform-driver-x86, André Apitzsch,
linux-leds, linux-pm
From: Kate Hsuan <hpa@redhat.com>
Add an i2c_device_id id_table to match manually instantiated
(non device-tree / ACPI instantiated) KTD202x controllers as
found on some x86 boards.
This table shows the maximum support LED channel for KTD2026
(three LEDs) and KTD-2027 (4 LEDs).
Link: https://www.kinet-ic.com/uploads/KTD2026-7-04h.pdf
Signed-off-by: Kate Hsuan <hpa@redhat.com>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Reviewed-by: Andy Shevchenko <andy@kernel.org>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
drivers/leds/rgb/leds-ktd202x.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/leds/rgb/leds-ktd202x.c b/drivers/leds/rgb/leds-ktd202x.c
index f1c810c415a4..60ca6ec34336 100644
--- a/drivers/leds/rgb/leds-ktd202x.c
+++ b/drivers/leds/rgb/leds-ktd202x.c
@@ -606,6 +606,13 @@ static void ktd202x_shutdown(struct i2c_client *client)
regmap_write(chip->regmap, KTD202X_REG_RESET_CONTROL, KTD202X_RSTR_RESET);
}
+static const struct i2c_device_id ktd202x_id[] = {
+ {"ktd2026", KTD2026_NUM_LEDS},
+ {"ktd2027", KTD2027_NUM_LEDS},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, ktd202x_id);
+
static const struct of_device_id ktd202x_match_table[] = {
{ .compatible = "kinetic,ktd2026", .data = (void *)KTD2026_NUM_LEDS },
{ .compatible = "kinetic,ktd2027", .data = (void *)KTD2027_NUM_LEDS },
@@ -621,6 +628,7 @@ static struct i2c_driver ktd202x_driver = {
.probe = ktd202x_probe,
.remove = ktd202x_remove,
.shutdown = ktd202x_shutdown,
+ .id_table = ktd202x_id,
};
module_i2c_driver(ktd202x_driver);
--
2.45.1
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH v10 3/6] leds: rgb: leds-ktd202x: Initialize mutex earlier
2024-05-31 11:41 [PATCH v10 0/6] KTD2026 indicator LED for X86 Xiaomi Pad2 Hans de Goede
2024-05-31 11:41 ` [PATCH v10 1/6] leds: rgb: leds-ktd202x: Get device properties through fwnode to support ACPI Hans de Goede
2024-05-31 11:41 ` [PATCH v10 2/6] leds: rgb: leds-ktd202x: I2C ID tables for KTD2026 and 2027 Hans de Goede
@ 2024-05-31 11:41 ` Hans de Goede
2024-05-31 11:41 ` [PATCH v10 4/6] leds: core: Add led_mc_set_brightness() function Hans de Goede
` (5 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Hans de Goede @ 2024-05-31 11:41 UTC (permalink / raw)
To: Ilpo Järvinen, Andy Shevchenko, Pavel Machek, Lee Jones,
Kate Hsuan, Sebastian Reichel
Cc: Hans de Goede, platform-driver-x86, André Apitzsch,
linux-leds, linux-pm
The mutex must be initialized before the LED class device is registered
otherwise there is a race where it may get used before it is initialized:
DEBUG_LOCKS_WARN_ON(lock->magic != lock)
WARNING: CPU: 2 PID: 2045 at kernel/locking/mutex.c:587 __mutex_lock
...
RIP: 0010:__mutex_lock+0x7db/0xc10
...
set_brightness_delayed_set_brightness.part.0+0x17/0x60
set_brightness_delayed+0xf1/0x100
process_one_work+0x222/0x5a0
Move the mutex_init() call earlier to avoid this race condition and
switch to devm_mutex_init() to avoid the need to add error-exit
cleanup to probe() if probe() fails later on.
Reviewed-by: Andy Shevchenko <andy@kernel.org>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
Changes in v9:
- Use devm_mutex_init() instead of plain mutex_init()
Changes in v8:
- New patch in v8 of this series
---
drivers/leds/rgb/leds-ktd202x.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/leds/rgb/leds-ktd202x.c b/drivers/leds/rgb/leds-ktd202x.c
index 60ca6ec34336..d5c442163c46 100644
--- a/drivers/leds/rgb/leds-ktd202x.c
+++ b/drivers/leds/rgb/leds-ktd202x.c
@@ -556,6 +556,10 @@ static int ktd202x_probe(struct i2c_client *client)
return ret;
}
+ ret = devm_mutex_init(dev, &chip->mutex);
+ if (ret)
+ return ret;
+
chip->num_leds = (unsigned long)i2c_get_match_data(client);
chip->regulators[0].supply = "vin";
@@ -584,8 +588,6 @@ static int ktd202x_probe(struct i2c_client *client)
return ret;
}
- mutex_init(&chip->mutex);
-
return 0;
}
@@ -594,8 +596,6 @@ static void ktd202x_remove(struct i2c_client *client)
struct ktd202x *chip = i2c_get_clientdata(client);
ktd202x_chip_disable(chip);
-
- mutex_destroy(&chip->mutex);
}
static void ktd202x_shutdown(struct i2c_client *client)
--
2.45.1
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH v10 4/6] leds: core: Add led_mc_set_brightness() function
2024-05-31 11:41 [PATCH v10 0/6] KTD2026 indicator LED for X86 Xiaomi Pad2 Hans de Goede
` (2 preceding siblings ...)
2024-05-31 11:41 ` [PATCH v10 3/6] leds: rgb: leds-ktd202x: Initialize mutex earlier Hans de Goede
@ 2024-05-31 11:41 ` Hans de Goede
2024-05-31 11:41 ` [PATCH v10 5/6] leds: trigger: Add led_mc_trigger_event() function Hans de Goede
` (4 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Hans de Goede @ 2024-05-31 11:41 UTC (permalink / raw)
To: Ilpo Järvinen, Andy Shevchenko, Pavel Machek, Lee Jones,
Kate Hsuan, Sebastian Reichel
Cc: Hans de Goede, platform-driver-x86, André Apitzsch,
linux-leds, linux-pm, Jacek Anaszewski
Add a new led_mc_set_brightness() function for in kernel color/brightness
changing of multi-color LEDs.
led-class-multicolor can be build as a module and led_mc_set_brightness()
will have the builtin callers, so put led_mc_set_brightness() inside
led-core instead, just like how led_set_brightness() is part of the core
and not of the led-class object.
This also adds a new LED_MULTI_COLOR led_classdev flag to allow
led_mc_set_brightness() to verify that it is operating on a multi-color
LED classdev, avoiding casting the passed in LED classdev to a multi-color
LED classdev, when it actually is not a multi-color LED.
Reviewed-by: Jacek Anaszewski <jacek.anaszewski@gmail.com>
Reviewed-by: Andy Shevchenko <andy@kernel.org>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
drivers/leds/led-class-multicolor.c | 1 +
drivers/leds/led-core.c | 31 +++++++++++++++++++++++++++++
include/linux/leds.h | 20 +++++++++++++++++++
3 files changed, 52 insertions(+)
diff --git a/drivers/leds/led-class-multicolor.c b/drivers/leds/led-class-multicolor.c
index ec62a4811613..df01c0e66c8b 100644
--- a/drivers/leds/led-class-multicolor.c
+++ b/drivers/leds/led-class-multicolor.c
@@ -134,6 +134,7 @@ int led_classdev_multicolor_register_ext(struct device *parent,
return -EINVAL;
led_cdev = &mcled_cdev->led_cdev;
+ led_cdev->flags |= LED_MULTI_COLOR;
mcled_cdev->led_cdev.groups = led_multicolor_groups;
return led_classdev_register_ext(parent, led_cdev, init_data);
diff --git a/drivers/leds/led-core.c b/drivers/leds/led-core.c
index 89c9806cc97f..ef7d1c6767ca 100644
--- a/drivers/leds/led-core.c
+++ b/drivers/leds/led-core.c
@@ -8,6 +8,7 @@
*/
#include <linux/kernel.h>
+#include <linux/led-class-multicolor.h>
#include <linux/leds.h>
#include <linux/list.h>
#include <linux/module.h>
@@ -362,6 +363,36 @@ int led_set_brightness_sync(struct led_classdev *led_cdev, unsigned int value)
}
EXPORT_SYMBOL_GPL(led_set_brightness_sync);
+/*
+ * This is a led-core function because just like led_set_brightness()
+ * it is used in the kernel by e.g. triggers.
+ */
+void led_mc_set_brightness(struct led_classdev *led_cdev,
+ unsigned int *intensity_value, unsigned int num_colors,
+ unsigned int brightness)
+{
+ struct led_classdev_mc *mcled_cdev;
+ unsigned int i;
+
+ if (!(led_cdev->flags & LED_MULTI_COLOR)) {
+ dev_err_once(led_cdev->dev, "error not a multi-color LED\n");
+ return;
+ }
+
+ mcled_cdev = lcdev_to_mccdev(led_cdev);
+ if (num_colors != mcled_cdev->num_colors) {
+ dev_err_once(led_cdev->dev, "error num_colors mismatch %u != %u\n",
+ num_colors, mcled_cdev->num_colors);
+ return;
+ }
+
+ for (i = 0; i < mcled_cdev->num_colors; i++)
+ mcled_cdev->subled_info[i].intensity = intensity_value[i];
+
+ led_set_brightness(led_cdev, brightness);
+}
+EXPORT_SYMBOL_GPL(led_mc_set_brightness);
+
int led_update_brightness(struct led_classdev *led_cdev)
{
int ret;
diff --git a/include/linux/leds.h b/include/linux/leds.h
index 6300313c46b7..ae07e44f1dcb 100644
--- a/include/linux/leds.h
+++ b/include/linux/leds.h
@@ -107,6 +107,7 @@ struct led_classdev {
#define LED_BRIGHT_HW_CHANGED BIT(21)
#define LED_RETAIN_AT_SHUTDOWN BIT(22)
#define LED_INIT_DEFAULT_TRIGGER BIT(23)
+#define LED_MULTI_COLOR BIT(24)
/* set_brightness_work / blink_timer flags, atomic, private. */
unsigned long work_flags;
@@ -373,6 +374,25 @@ void led_set_brightness(struct led_classdev *led_cdev, unsigned int brightness);
*/
int led_set_brightness_sync(struct led_classdev *led_cdev, unsigned int value);
+/**
+ * led_mc_set_brightness - set mc LED color intensity values and brightness
+ * @led_cdev: the LED to set
+ * @intensity_value: array of per color intensity values to set
+ * @num_colors: amount of entries in intensity_value array
+ * @brightness: the brightness to set the LED to
+ *
+ * Set a multi-color LED's per color intensity values and brightness.
+ * If necessary, this cancels the software blink timer. This function is
+ * guaranteed not to sleep.
+ *
+ * Calling this function on a non multi-color led_classdev or with the wrong
+ * num_colors value is an error. In this case an error will be logged once
+ * and the call will do nothing.
+ */
+void led_mc_set_brightness(struct led_classdev *led_cdev,
+ unsigned int *intensity_value, unsigned int num_colors,
+ unsigned int brightness);
+
/**
* led_update_brightness - update LED brightness
* @led_cdev: the LED to query
--
2.45.1
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH v10 5/6] leds: trigger: Add led_mc_trigger_event() function
2024-05-31 11:41 [PATCH v10 0/6] KTD2026 indicator LED for X86 Xiaomi Pad2 Hans de Goede
` (3 preceding siblings ...)
2024-05-31 11:41 ` [PATCH v10 4/6] leds: core: Add led_mc_set_brightness() function Hans de Goede
@ 2024-05-31 11:41 ` Hans de Goede
2024-05-31 11:41 ` [PATCH v10 6/6] power: supply: power-supply-leds: Add charging_orange_full_green trigger for RGB LED Hans de Goede
` (3 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Hans de Goede @ 2024-05-31 11:41 UTC (permalink / raw)
To: Ilpo Järvinen, Andy Shevchenko, Pavel Machek, Lee Jones,
Kate Hsuan, Sebastian Reichel
Cc: Hans de Goede, platform-driver-x86, André Apitzsch,
linux-leds, linux-pm, Jacek Anaszewski
Add a new led_mc_trigger_event() function for triggers which want to
change the color of a multi-color LED based on their trigger conditions.
Reviewed-by: Jacek Anaszewski <jacek.anaszewski@gmail.com>
Reviewed-by: Andy Shevchenko <andy@kernel.org>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
drivers/leds/led-triggers.c | 20 ++++++++++++++++++++
include/linux/leds.h | 6 ++++++
2 files changed, 26 insertions(+)
diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c
index b1b323b19301..638aa6591092 100644
--- a/drivers/leds/led-triggers.c
+++ b/drivers/leds/led-triggers.c
@@ -396,6 +396,26 @@ void led_trigger_event(struct led_trigger *trig,
}
EXPORT_SYMBOL_GPL(led_trigger_event);
+void led_mc_trigger_event(struct led_trigger *trig,
+ unsigned int *intensity_value, unsigned int num_colors,
+ enum led_brightness brightness)
+{
+ struct led_classdev *led_cdev;
+
+ if (!trig)
+ return;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(led_cdev, &trig->led_cdevs, trig_list) {
+ if (!(led_cdev->flags & LED_MULTI_COLOR))
+ continue;
+
+ led_mc_set_brightness(led_cdev, intensity_value, num_colors, brightness);
+ }
+ rcu_read_unlock();
+}
+EXPORT_SYMBOL_GPL(led_mc_trigger_event);
+
static void led_trigger_blink_setup(struct led_trigger *trig,
unsigned long delay_on,
unsigned long delay_off,
diff --git a/include/linux/leds.h b/include/linux/leds.h
index ae07e44f1dcb..517b6198df07 100644
--- a/include/linux/leds.h
+++ b/include/linux/leds.h
@@ -510,6 +510,9 @@ void led_trigger_register_simple(const char *name,
struct led_trigger **trigger);
void led_trigger_unregister_simple(struct led_trigger *trigger);
void led_trigger_event(struct led_trigger *trigger, enum led_brightness event);
+void led_mc_trigger_event(struct led_trigger *trig,
+ unsigned int *intensity_value, unsigned int num_colors,
+ enum led_brightness brightness);
void led_trigger_blink(struct led_trigger *trigger, unsigned long delay_on,
unsigned long delay_off);
void led_trigger_blink_oneshot(struct led_trigger *trigger,
@@ -552,6 +555,9 @@ static inline void led_trigger_register_simple(const char *name,
static inline void led_trigger_unregister_simple(struct led_trigger *trigger) {}
static inline void led_trigger_event(struct led_trigger *trigger,
enum led_brightness event) {}
+static inline void led_mc_trigger_event(struct led_trigger *trig,
+ unsigned int *intensity_value, unsigned int num_colors,
+ enum led_brightness brightness) {}
static inline void led_trigger_blink(struct led_trigger *trigger,
unsigned long delay_on,
unsigned long delay_off) {}
--
2.45.1
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH v10 6/6] power: supply: power-supply-leds: Add charging_orange_full_green trigger for RGB LED
2024-05-31 11:41 [PATCH v10 0/6] KTD2026 indicator LED for X86 Xiaomi Pad2 Hans de Goede
` (4 preceding siblings ...)
2024-05-31 11:41 ` [PATCH v10 5/6] leds: trigger: Add led_mc_trigger_event() function Hans de Goede
@ 2024-05-31 11:41 ` Hans de Goede
2024-05-31 12:01 ` [PATCH v10 0/6] KTD2026 indicator LED for X86 Xiaomi Pad2 Lee Jones
` (2 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Hans de Goede @ 2024-05-31 11:41 UTC (permalink / raw)
To: Ilpo Järvinen, Andy Shevchenko, Pavel Machek, Lee Jones,
Kate Hsuan, Sebastian Reichel
Cc: Hans de Goede, platform-driver-x86, André Apitzsch,
linux-leds, linux-pm, Sebastian Reichel
From: Kate Hsuan <hpa@redhat.com>
Add a charging_orange_full_green LED trigger and the trigger is based on
led_mc_trigger_event() which can set an RGB LED when the trigger is
triggered. The LED will show orange when the battery status is charging.
The LED will show green when the battery status is full.
Link: https://lore.kernel.org/linux-leds/f40a0b1a-ceac-e269-c2dd-0158c5b4a1ad@gmail.com/
Acked-by: Sebastian Reichel <sebastian.reichel@collabora.com>
Signed-off-by: Kate Hsuan <hpa@redhat.com>
Reviewed-by: Andy Shevchenko <andy@kernel.org>
[hdegoede@redhat.com change color order to RGB]
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
drivers/power/supply/power_supply_leds.c | 23 +++++++++++++++++++++++
include/linux/power_supply.h | 2 ++
2 files changed, 25 insertions(+)
diff --git a/drivers/power/supply/power_supply_leds.c b/drivers/power/supply/power_supply_leds.c
index c7db29d5fcb8..73935de844d9 100644
--- a/drivers/power/supply/power_supply_leds.c
+++ b/drivers/power/supply/power_supply_leds.c
@@ -22,6 +22,8 @@
static void power_supply_update_bat_leds(struct power_supply *psy)
{
union power_supply_propval status;
+ unsigned int intensity_green[3] = { 0, 255, 0 };
+ unsigned int intensity_orange[3] = { 255, 128, 0 };
if (power_supply_get_property(psy, POWER_SUPPLY_PROP_STATUS, &status))
return;
@@ -36,12 +38,20 @@ static void power_supply_update_bat_leds(struct power_supply *psy)
/* Going from blink to LED on requires a LED_OFF event to stop blink */
led_trigger_event(psy->charging_blink_full_solid_trig, LED_OFF);
led_trigger_event(psy->charging_blink_full_solid_trig, LED_FULL);
+ led_mc_trigger_event(psy->charging_orange_full_green_trig,
+ intensity_green,
+ ARRAY_SIZE(intensity_green),
+ LED_FULL);
break;
case POWER_SUPPLY_STATUS_CHARGING:
led_trigger_event(psy->charging_full_trig, LED_FULL);
led_trigger_event(psy->charging_trig, LED_FULL);
led_trigger_event(psy->full_trig, LED_OFF);
led_trigger_blink(psy->charging_blink_full_solid_trig, 0, 0);
+ led_mc_trigger_event(psy->charging_orange_full_green_trig,
+ intensity_orange,
+ ARRAY_SIZE(intensity_orange),
+ LED_FULL);
break;
default:
led_trigger_event(psy->charging_full_trig, LED_OFF);
@@ -49,6 +59,8 @@ static void power_supply_update_bat_leds(struct power_supply *psy)
led_trigger_event(psy->full_trig, LED_OFF);
led_trigger_event(psy->charging_blink_full_solid_trig,
LED_OFF);
+ led_trigger_event(psy->charging_orange_full_green_trig,
+ LED_OFF);
break;
}
}
@@ -74,6 +86,11 @@ static int power_supply_create_bat_triggers(struct power_supply *psy)
if (!psy->charging_blink_full_solid_trig_name)
goto charging_blink_full_solid_failed;
+ psy->charging_orange_full_green_trig_name = kasprintf(GFP_KERNEL,
+ "%s-charging-orange-full-green", psy->desc->name);
+ if (!psy->charging_orange_full_green_trig_name)
+ goto charging_red_full_green_failed;
+
led_trigger_register_simple(psy->charging_full_trig_name,
&psy->charging_full_trig);
led_trigger_register_simple(psy->charging_trig_name,
@@ -82,9 +99,13 @@ static int power_supply_create_bat_triggers(struct power_supply *psy)
&psy->full_trig);
led_trigger_register_simple(psy->charging_blink_full_solid_trig_name,
&psy->charging_blink_full_solid_trig);
+ led_trigger_register_simple(psy->charging_orange_full_green_trig_name,
+ &psy->charging_orange_full_green_trig);
return 0;
+charging_red_full_green_failed:
+ kfree(psy->charging_blink_full_solid_trig_name);
charging_blink_full_solid_failed:
kfree(psy->full_trig_name);
full_failed:
@@ -101,10 +122,12 @@ static void power_supply_remove_bat_triggers(struct power_supply *psy)
led_trigger_unregister_simple(psy->charging_trig);
led_trigger_unregister_simple(psy->full_trig);
led_trigger_unregister_simple(psy->charging_blink_full_solid_trig);
+ led_trigger_unregister_simple(psy->charging_orange_full_green_trig);
kfree(psy->charging_blink_full_solid_trig_name);
kfree(psy->full_trig_name);
kfree(psy->charging_trig_name);
kfree(psy->charging_full_trig_name);
+ kfree(psy->charging_orange_full_green_trig_name);
}
/* Generated power specific LEDs triggers. */
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 8e5705a56b85..c852cc882501 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -319,6 +319,8 @@ struct power_supply {
char *online_trig_name;
struct led_trigger *charging_blink_full_solid_trig;
char *charging_blink_full_solid_trig_name;
+ struct led_trigger *charging_orange_full_green_trig;
+ char *charging_orange_full_green_trig_name;
#endif
};
--
2.45.1
^ permalink raw reply related [flat|nested] 10+ messages in thread* Re: [PATCH v10 0/6] KTD2026 indicator LED for X86 Xiaomi Pad2
2024-05-31 11:41 [PATCH v10 0/6] KTD2026 indicator LED for X86 Xiaomi Pad2 Hans de Goede
` (5 preceding siblings ...)
2024-05-31 11:41 ` [PATCH v10 6/6] power: supply: power-supply-leds: Add charging_orange_full_green trigger for RGB LED Hans de Goede
@ 2024-05-31 12:01 ` Lee Jones
2024-05-31 12:02 ` Lee Jones
2024-05-31 13:54 ` [GIT PULL] Immutable branch between LEDs, Power and RGB due for the v6.11 merge window Lee Jones
8 siblings, 0 replies; 10+ messages in thread
From: Lee Jones @ 2024-05-31 12:01 UTC (permalink / raw)
To: Ilpo Järvinen, Andy Shevchenko, Pavel Machek, Lee Jones,
Kate Hsuan, Sebastian Reichel, Hans de Goede
Cc: platform-driver-x86, André Apitzsch, linux-leds, linux-pm
On Fri, 31 May 2024 13:41:18 +0200, Hans de Goede wrote:
> Here is v10 of Kate's series to add support for Xiaomi Pad2 indicator LED,
> this is unchanged from v9 except for being rebased on top of 6.10-rc1 and
> dropping patch 7/7 since that one has been merged through the pdx86 tree.
>
> Patch 6/6 has an Acked-by from Sebastien for merging this patch through
> the leds tree since it depends on the earlier patches.
>
> [...]
Applied, thanks!
[1/6] leds: rgb: leds-ktd202x: Get device properties through fwnode to support ACPI
commit: f14aa5ea415b8add245e976bfab96a12986c6843
[2/6] leds: rgb: leds-ktd202x: I2C ID tables for KTD2026 and 2027
commit: 75bd07aef47e1a984229e6ec702e8b9aee0226e4
[3/6] leds: rgb: leds-ktd202x: Initialize mutex earlier
commit: e1b08c6f5b92d408a9fcc1030a340caeb9852250
[4/6] leds: core: Add led_mc_set_brightness() function
commit: 5607ca92e6274dfb85d0ff7c4e91e6c4ddb6d25c
[5/6] leds: trigger: Add led_mc_trigger_event() function
commit: 0921a57c91648b08857b47a2f26fa7942f06120f
[6/6] power: supply: power-supply-leds: Add charging_orange_full_green trigger for RGB LED
commit: 9af12f57f1f9785f231d31a7365ad244c656b7ff
--
Lee Jones [李琼斯]
^ permalink raw reply [flat|nested] 10+ messages in thread* Re: [PATCH v10 0/6] KTD2026 indicator LED for X86 Xiaomi Pad2
2024-05-31 11:41 [PATCH v10 0/6] KTD2026 indicator LED for X86 Xiaomi Pad2 Hans de Goede
` (6 preceding siblings ...)
2024-05-31 12:01 ` [PATCH v10 0/6] KTD2026 indicator LED for X86 Xiaomi Pad2 Lee Jones
@ 2024-05-31 12:02 ` Lee Jones
2024-05-31 13:54 ` [GIT PULL] Immutable branch between LEDs, Power and RGB due for the v6.11 merge window Lee Jones
8 siblings, 0 replies; 10+ messages in thread
From: Lee Jones @ 2024-05-31 12:02 UTC (permalink / raw)
To: Hans de Goede
Cc: Ilpo Järvinen, Andy Shevchenko, Pavel Machek, Kate Hsuan,
Sebastian Reichel, platform-driver-x86, André Apitzsch,
linux-leds, linux-pm
On Fri, 31 May 2024, Hans de Goede wrote:
> Hi All,
>
> Here is v10 of Kate's series to add support for Xiaomi Pad2 indicator LED,
> this is unchanged from v9 except for being rebased on top of 6.10-rc1 and
> dropping patch 7/7 since that one has been merged through the pdx86 tree.
>
> Patch 6/6 has an Acked-by from Sebastien for merging this patch through
> the leds tree since it depends on the earlier patches.
>
> I have some further power-supply LED triggers work pending:
> https://lore.kernel.org/linux-pm/20240510194012.138192-1-hdegoede@redhat.com/
> which applies on top of this series. So this is going to either require
> an IB for Sebastian to merge into his tree before applying those, or
> (once ready) that series can be applied through the LEDs tree too. Since this
> follow up series deals with LED triggers I think that either way makes sense.
>
> This work includes:
> 1. Migrate the original driver to fwnode to support x86 platforms.
> 2. Support for multi-color LED trigger events.
> 3. The LED shows orange when charging and the LED shows green when the
> battery is full.
Applied and sent for testing.
All being well, I'll submit a PR soon.
--
Lee Jones [李琼斯]
^ permalink raw reply [flat|nested] 10+ messages in thread* [GIT PULL] Immutable branch between LEDs, Power and RGB due for the v6.11 merge window
2024-05-31 11:41 [PATCH v10 0/6] KTD2026 indicator LED for X86 Xiaomi Pad2 Hans de Goede
` (7 preceding siblings ...)
2024-05-31 12:02 ` Lee Jones
@ 2024-05-31 13:54 ` Lee Jones
8 siblings, 0 replies; 10+ messages in thread
From: Lee Jones @ 2024-05-31 13:54 UTC (permalink / raw)
To: Hans de Goede
Cc: Ilpo Järvinen, Andy Shevchenko, Pavel Machek, Kate Hsuan,
Sebastian Reichel, platform-driver-x86, André Apitzsch,
linux-leds, linux-pm
Enjoy!
The following changes since commit 1613e604df0cd359cf2a7fbd9be7a0bcfacfabd0:
Linux 6.10-rc1 (2024-05-26 15:20:12 -0700)
are available in the Git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/lee/leds.git ib-leds-platform-power-v6.11
for you to fetch changes up to 9af12f57f1f9785f231d31a7365ad244c656b7ff:
power: supply: power-supply-leds: Add charging_orange_full_green trigger for RGB LED (2024-05-31 12:57:43 +0100)
----------------------------------------------------------------
Immutable branch between LEDs, Power and RGB due for the v6.11 merge window
----------------------------------------------------------------
Hans de Goede (3):
leds: rgb: leds-ktd202x: Initialize mutex earlier
leds: core: Add led_mc_set_brightness() function
leds: trigger: Add led_mc_trigger_event() function
Kate Hsuan (3):
leds: rgb: leds-ktd202x: Get device properties through fwnode to support ACPI
leds: rgb: leds-ktd202x: I2C ID tables for KTD2026 and 2027
power: supply: power-supply-leds: Add charging_orange_full_green trigger for RGB LED
drivers/leds/led-class-multicolor.c | 1 +
drivers/leds/led-core.c | 31 +++++++++++++
drivers/leds/led-triggers.c | 20 ++++++++
drivers/leds/rgb/Kconfig | 1 -
drivers/leds/rgb/leds-ktd202x.c | 80 ++++++++++++++++++--------------
drivers/power/supply/power_supply_leds.c | 23 +++++++++
include/linux/leds.h | 26 +++++++++++
include/linux/power_supply.h | 2 +
8 files changed, 149 insertions(+), 35 deletions(-)
--
Lee Jones [李琼斯]
^ permalink raw reply [flat|nested] 10+ messages in thread