aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2024-06-17 20:38:37 +0100
committerMark Brown <broonie@kernel.org>2024-06-17 20:38:37 +0100
commit2cb4156a2927bc97998db9bfb71ea567e84a8a98 (patch)
tree581cad2960cfa8bc33a05d3d1b28e9bf4d320393
parentae8577e9079568fe89fe3bf6ffa1d90fda2cfe0a (diff)
parent7c85503b6d597b84ea58fe3dd95cd9eaeb1f3206 (diff)
Merge branch 'for-leds-next' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/leds.git
-rw-r--r--Documentation/leds/leds-blinkm.rst2
-rw-r--r--MAINTAINERS2
-rw-r--r--drivers/leds/Kconfig1
-rw-r--r--drivers/leds/blink/leds-bcm63138.c1
-rw-r--r--drivers/leds/flash/leds-as3645a.c4
-rw-r--r--drivers/leds/flash/leds-mt6360.c5
-rw-r--r--drivers/leds/flash/leds-rt4505.c1
-rw-r--r--drivers/leds/led-core.c19
-rw-r--r--drivers/leds/led-triggers.c15
-rw-r--r--drivers/leds/leds-an30259a.c4
-rw-r--r--drivers/leds/leds-bd2802.c2
-rw-r--r--drivers/leds/leds-blinkm.c2
-rw-r--r--drivers/leds/leds-is31fl319x.c4
-rw-r--r--drivers/leds/leds-lm3530.c2
-rw-r--r--drivers/leds/leds-lm3532.c2
-rw-r--r--drivers/leds/leds-lm3642.c2
-rw-r--r--drivers/leds/leds-lm3697.c2
-rw-r--r--drivers/leds/leds-lp3944.c2
-rw-r--r--drivers/leds/leds-lp3952.c2
-rw-r--r--drivers/leds/leds-lp5521.c2
-rw-r--r--drivers/leds/leds-lp5562.c2
-rw-r--r--drivers/leds/leds-lp8501.c2
-rw-r--r--drivers/leds/leds-lp8860.c2
-rw-r--r--drivers/leds/leds-powernv.c28
-rw-r--r--drivers/leds/leds-spi-byte.c63
-rw-r--r--drivers/leds/leds-ss4200.c7
-rw-r--r--drivers/leds/leds-tlc591xx.c18
-rw-r--r--drivers/leds/leds-turris-omnia.c2
-rw-r--r--drivers/leds/rgb/leds-ncp5623.c16
-rw-r--r--drivers/leds/rgb/leds-qcom-lpg.c8
-rw-r--r--drivers/leds/simple/simatic-ipc-leds-gpio-apollolake.c1
-rw-r--r--drivers/leds/simple/simatic-ipc-leds-gpio-core.c1
-rw-r--r--drivers/leds/simple/simatic-ipc-leds-gpio-elkhartlake.c1
-rw-r--r--drivers/leds/simple/simatic-ipc-leds-gpio-f7188x.c1
-rw-r--r--drivers/leds/simple/simatic-ipc-leds.c1
-rw-r--r--drivers/leds/trigger/Kconfig16
-rw-r--r--drivers/leds/trigger/Makefile1
-rw-r--r--drivers/leds/trigger/ledtrig-input-events.c233
-rw-r--r--drivers/leds/trigger/ledtrig-timer.c5
39 files changed, 367 insertions, 117 deletions
diff --git a/Documentation/leds/leds-blinkm.rst b/Documentation/leds/leds-blinkm.rst
index c74b5bc877b1..2d3c226a371a 100644
--- a/Documentation/leds/leds-blinkm.rst
+++ b/Documentation/leds/leds-blinkm.rst
@@ -7,7 +7,7 @@ The leds-blinkm driver supports the devices of the BlinkM family.
They are RGB-LED modules driven by a (AT)tiny microcontroller and
communicate through I2C. The default address of these modules is
0x09 but this can be changed through a command. By this you could
-dasy-chain up to 127 BlinkMs on an I2C bus.
+daisy-chain up to 127 BlinkMs on an I2C bus.
The device accepts RGB and HSB color values through separate commands.
Also you can store blinking sequences as "scripts" in
diff --git a/MAINTAINERS b/MAINTAINERS
index e46204e66c56..b1a138fe7477 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -12525,7 +12525,7 @@ M: Pavel Machek <pavel@ucw.cz>
M: Lee Jones <lee@kernel.org>
L: linux-leds@vger.kernel.org
S: Maintained
-T: git git://git.kernel.org/pub/scm/linux/kernel/git/pavel/linux-leds.git
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/lee/leds.git
F: Documentation/devicetree/bindings/leds/
F: Documentation/leds/
F: drivers/leds/
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 05e6af88b88c..eafdf6e2ed7e 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -869,7 +869,6 @@ config LEDS_SPI_BYTE
tristate "LED support for SPI LED controller with a single byte"
depends on LEDS_CLASS
depends on SPI
- depends on OF
help
This option enables support for LED controller which use a single byte
for controlling the brightness. Currently the following controller is
diff --git a/drivers/leds/blink/leds-bcm63138.c b/drivers/leds/blink/leds-bcm63138.c
index 2cf2761e4914..3a5e0b98bfbc 100644
--- a/drivers/leds/blink/leds-bcm63138.c
+++ b/drivers/leds/blink/leds-bcm63138.c
@@ -303,5 +303,6 @@ static struct platform_driver bcm63138_leds_driver = {
module_platform_driver(bcm63138_leds_driver);
MODULE_AUTHOR("Rafał Miłecki");
+MODULE_DESCRIPTION("Broadcom BCM63138 SoC LED driver");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(of, bcm63138_leds_of_match_table);
diff --git a/drivers/leds/flash/leds-as3645a.c b/drivers/leds/flash/leds-as3645a.c
index 12c2609c1137..2c6ef321b7c8 100644
--- a/drivers/leds/flash/leds-as3645a.c
+++ b/drivers/leds/flash/leds-as3645a.c
@@ -743,8 +743,8 @@ static void as3645a_remove(struct i2c_client *client)
}
static const struct i2c_device_id as3645a_id_table[] = {
- { AS_NAME, 0 },
- { },
+ { AS_NAME },
+ { }
};
MODULE_DEVICE_TABLE(i2c, as3645a_id_table);
diff --git a/drivers/leds/flash/leds-mt6360.c b/drivers/leds/flash/leds-mt6360.c
index 1b75b4d36834..4c74f1cf01f0 100644
--- a/drivers/leds/flash/leds-mt6360.c
+++ b/drivers/leds/flash/leds-mt6360.c
@@ -643,14 +643,17 @@ static int mt6360_init_isnk_properties(struct mt6360_led *led,
ret = fwnode_property_read_u32(child, "reg", &reg);
if (ret || reg > MT6360_LED_ISNK3 ||
- priv->leds_active & BIT(reg))
+ priv->leds_active & BIT(reg)) {
+ fwnode_handle_put(child);
return -EINVAL;
+ }
ret = fwnode_property_read_u32(child, "color", &color);
if (ret) {
dev_err(priv->dev,
"led %d, no color specified\n",
led->led_no);
+ fwnode_handle_put(child);
return ret;
}
diff --git a/drivers/leds/flash/leds-rt4505.c b/drivers/leds/flash/leds-rt4505.c
index 1ae5b387f4a5..f16358b8dfc1 100644
--- a/drivers/leds/flash/leds-rt4505.c
+++ b/drivers/leds/flash/leds-rt4505.c
@@ -426,4 +426,5 @@ static struct i2c_driver rt4505_driver = {
module_i2c_driver(rt4505_driver);
MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
+MODULE_DESCRIPTION("Richtek RT4505 LED driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/leds/led-core.c b/drivers/leds/led-core.c
index ef7d1c6767ca..3b4db39f2326 100644
--- a/drivers/leds/led-core.c
+++ b/drivers/leds/led-core.c
@@ -123,15 +123,22 @@ static void led_timer_function(struct timer_list *t)
static void set_brightness_delayed_set_brightness(struct led_classdev *led_cdev,
unsigned int value)
{
- int ret = 0;
+ int ret;
ret = __led_set_brightness(led_cdev, value);
- if (ret == -ENOTSUPP)
+ if (ret == -ENOTSUPP) {
ret = __led_set_brightness_blocking(led_cdev, value);
- if (ret < 0 &&
- /* LED HW might have been unplugged, therefore don't warn */
- !(ret == -ENODEV && (led_cdev->flags & LED_UNREGISTERING) &&
- (led_cdev->flags & LED_HW_PLUGGABLE)))
+ if (ret == -ENOTSUPP)
+ /* No back-end support to set a fixed brightness value */
+ return;
+ }
+
+ /* LED HW might have been unplugged, therefore don't warn */
+ if (ret == -ENODEV && led_cdev->flags & LED_UNREGISTERING &&
+ led_cdev->flags & LED_HW_PLUGGABLE)
+ return;
+
+ if (ret < 0)
dev_err(led_cdev->dev,
"Setting an LED's brightness failed (%d)\n", ret);
}
diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c
index 638aa6591092..78eb20093b2c 100644
--- a/drivers/leds/led-triggers.c
+++ b/drivers/leds/led-triggers.c
@@ -179,9 +179,9 @@ int led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig)
cancel_work_sync(&led_cdev->set_brightness_work);
led_stop_software_blink(led_cdev);
+ device_remove_groups(led_cdev->dev, led_cdev->trigger->groups);
if (led_cdev->trigger->deactivate)
led_cdev->trigger->deactivate(led_cdev);
- device_remove_groups(led_cdev->dev, led_cdev->trigger->groups);
led_cdev->trigger = NULL;
led_cdev->trigger_data = NULL;
led_cdev->activated = false;
@@ -194,6 +194,19 @@ int led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig)
spin_unlock(&trig->leddev_list_lock);
led_cdev->trigger = trig;
+ /*
+ * Some activate() calls use led_trigger_event() to initialize
+ * the brightness of the LED for which the trigger is being set.
+ * Ensure the led_cdev is visible on trig->led_cdevs for this.
+ */
+ synchronize_rcu();
+
+ /*
+ * If "set brightness to 0" is pending in workqueue,
+ * we don't want that to be reordered after ->activate()
+ */
+ flush_work(&led_cdev->set_brightness_work);
+
ret = 0;
if (trig->activate)
ret = trig->activate(led_cdev);
diff --git a/drivers/leds/leds-an30259a.c b/drivers/leds/leds-an30259a.c
index decfca447d8a..a42cc4bc6917 100644
--- a/drivers/leds/leds-an30259a.c
+++ b/drivers/leds/leds-an30259a.c
@@ -331,8 +331,8 @@ static const struct of_device_id an30259a_match_table[] = {
MODULE_DEVICE_TABLE(of, an30259a_match_table);
static const struct i2c_device_id an30259a_id[] = {
- { "an30259a", 0 },
- { /* sentinel */ },
+ { "an30259a" },
+ { /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, an30259a_id);
diff --git a/drivers/leds/leds-bd2802.c b/drivers/leds/leds-bd2802.c
index 0792ea126cea..2a08c5f27608 100644
--- a/drivers/leds/leds-bd2802.c
+++ b/drivers/leds/leds-bd2802.c
@@ -776,7 +776,7 @@ static int bd2802_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(bd2802_pm, bd2802_suspend, bd2802_resume);
static const struct i2c_device_id bd2802_id[] = {
- { "BD2802", 0 },
+ { "BD2802" },
{ }
};
MODULE_DEVICE_TABLE(i2c, bd2802_id);
diff --git a/drivers/leds/leds-blinkm.c b/drivers/leds/leds-blinkm.c
index 2782da1a1930..e40b87aead2d 100644
--- a/drivers/leds/leds-blinkm.c
+++ b/drivers/leds/leds-blinkm.c
@@ -718,7 +718,7 @@ static void blinkm_remove(struct i2c_client *client)
}
static const struct i2c_device_id blinkm_id[] = {
- {"blinkm", 0},
+ { "blinkm" },
{}
};
diff --git a/drivers/leds/leds-is31fl319x.c b/drivers/leds/leds-is31fl319x.c
index 66c65741202e..5e1a4d39a107 100644
--- a/drivers/leds/leds-is31fl319x.c
+++ b/drivers/leds/leds-is31fl319x.c
@@ -140,7 +140,7 @@ static const struct reg_default is31fl3190_reg_defaults[] = {
{ IS31FL3190_PWM(2), 0x00 },
};
-static struct regmap_config is31fl3190_regmap_config = {
+static const struct regmap_config is31fl3190_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = IS31FL3190_RESET,
@@ -178,7 +178,7 @@ static const struct reg_default is31fl3196_reg_defaults[] = {
{ IS31FL3196_PWM(8), 0x00 },
};
-static struct regmap_config is31fl3196_regmap_config = {
+static const struct regmap_config is31fl3196_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = IS31FL3196_REG_CNT,
diff --git a/drivers/leds/leds-lm3530.c b/drivers/leds/leds-lm3530.c
index a2feef8e4ac5..e44a3db106c3 100644
--- a/drivers/leds/leds-lm3530.c
+++ b/drivers/leds/leds-lm3530.c
@@ -478,7 +478,7 @@ static void lm3530_remove(struct i2c_client *client)
}
static const struct i2c_device_id lm3530_id[] = {
- {LM3530_NAME, 0},
+ { LM3530_NAME },
{}
};
MODULE_DEVICE_TABLE(i2c, lm3530_id);
diff --git a/drivers/leds/leds-lm3532.c b/drivers/leds/leds-lm3532.c
index 8c90701dc50d..54b5650877f7 100644
--- a/drivers/leds/leds-lm3532.c
+++ b/drivers/leds/leds-lm3532.c
@@ -726,7 +726,7 @@ static const struct of_device_id of_lm3532_leds_match[] = {
MODULE_DEVICE_TABLE(of, of_lm3532_leds_match);
static const struct i2c_device_id lm3532_id[] = {
- {LM3532_NAME, 0},
+ { LM3532_NAME },
{}
};
MODULE_DEVICE_TABLE(i2c, lm3532_id);
diff --git a/drivers/leds/leds-lm3642.c b/drivers/leds/leds-lm3642.c
index 6eee52e211be..61629d5d6703 100644
--- a/drivers/leds/leds-lm3642.c
+++ b/drivers/leds/leds-lm3642.c
@@ -390,7 +390,7 @@ static void lm3642_remove(struct i2c_client *client)
}
static const struct i2c_device_id lm3642_id[] = {
- {LM3642_NAME, 0},
+ { LM3642_NAME },
{}
};
diff --git a/drivers/leds/leds-lm3697.c b/drivers/leds/leds-lm3697.c
index 380d17a58fe9..99de2a331727 100644
--- a/drivers/leds/leds-lm3697.c
+++ b/drivers/leds/leds-lm3697.c
@@ -360,7 +360,7 @@ static void lm3697_remove(struct i2c_client *client)
}
static const struct i2c_device_id lm3697_id[] = {
- { "lm3697", 0 },
+ { "lm3697" },
{ }
};
MODULE_DEVICE_TABLE(i2c, lm3697_id);
diff --git a/drivers/leds/leds-lp3944.c b/drivers/leds/leds-lp3944.c
index 8ea746c499d1..ccfeee49ea78 100644
--- a/drivers/leds/leds-lp3944.c
+++ b/drivers/leds/leds-lp3944.c
@@ -417,7 +417,7 @@ static void lp3944_remove(struct i2c_client *client)
/* lp3944 i2c driver struct */
static const struct i2c_device_id lp3944_id[] = {
- {"lp3944", 0},
+ { "lp3944" },
{}
};
diff --git a/drivers/leds/leds-lp3952.c b/drivers/leds/leds-lp3952.c
index ff7bae2447dd..17219a582704 100644
--- a/drivers/leds/leds-lp3952.c
+++ b/drivers/leds/leds-lp3952.c
@@ -266,7 +266,7 @@ static int lp3952_probe(struct i2c_client *client)
}
static const struct i2c_device_id lp3952_id[] = {
- {LP3952_NAME, 0},
+ { LP3952_NAME },
{}
};
MODULE_DEVICE_TABLE(i2c, lp3952_id);
diff --git a/drivers/leds/leds-lp5521.c b/drivers/leds/leds-lp5521.c
index f9c8b568b652..d242c12e7569 100644
--- a/drivers/leds/leds-lp5521.c
+++ b/drivers/leds/leds-lp5521.c
@@ -591,7 +591,7 @@ static void lp5521_remove(struct i2c_client *client)
}
static const struct i2c_device_id lp5521_id[] = {
- { "lp5521", 0 }, /* Three channel chip */
+ { "lp5521" }, /* Three channel chip */
{ }
};
MODULE_DEVICE_TABLE(i2c, lp5521_id);
diff --git a/drivers/leds/leds-lp5562.c b/drivers/leds/leds-lp5562.c
index 39db9aeb67c5..e545ca8bd1f6 100644
--- a/drivers/leds/leds-lp5562.c
+++ b/drivers/leds/leds-lp5562.c
@@ -584,7 +584,7 @@ static void lp5562_remove(struct i2c_client *client)
}
static const struct i2c_device_id lp5562_id[] = {
- { "lp5562", 0 },
+ { "lp5562" },
{ }
};
MODULE_DEVICE_TABLE(i2c, lp5562_id);
diff --git a/drivers/leds/leds-lp8501.c b/drivers/leds/leds-lp8501.c
index ac50aa88939a..68b5c7ae31b9 100644
--- a/drivers/leds/leds-lp8501.c
+++ b/drivers/leds/leds-lp8501.c
@@ -375,7 +375,7 @@ static void lp8501_remove(struct i2c_client *client)
}
static const struct i2c_device_id lp8501_id[] = {
- { "lp8501", 0 },
+ { "lp8501" },
{ }
};
MODULE_DEVICE_TABLE(i2c, lp8501_id);
diff --git a/drivers/leds/leds-lp8860.c b/drivers/leds/leds-lp8860.c
index 19b621012e58..7a136fd81720 100644
--- a/drivers/leds/leds-lp8860.c
+++ b/drivers/leds/leds-lp8860.c
@@ -459,7 +459,7 @@ static void lp8860_remove(struct i2c_client *client)
}
static const struct i2c_device_id lp8860_id[] = {
- { "lp8860", 0 },
+ { "lp8860" },
{ }
};
MODULE_DEVICE_TABLE(i2c, lp8860_id);
diff --git a/drivers/leds/leds-powernv.c b/drivers/leds/leds-powernv.c
index 4f01acb75727..49ab8c9a3f29 100644
--- a/drivers/leds/leds-powernv.c
+++ b/drivers/leds/leds-powernv.c
@@ -246,29 +246,25 @@ static int powernv_led_classdev(struct platform_device *pdev,
const char *cur = NULL;
int rc = -1;
struct property *p;
- struct device_node *np;
struct powernv_led_data *powernv_led;
struct device *dev = &pdev->dev;
- for_each_available_child_of_node(led_node, np) {
+ for_each_available_child_of_node_scoped(led_node, np) {
p = of_find_property(np, "led-types", NULL);
while ((cur = of_prop_next_string(p, cur)) != NULL) {
powernv_led = devm_kzalloc(dev, sizeof(*powernv_led),
GFP_KERNEL);
- if (!powernv_led) {
- of_node_put(np);
+ if (!powernv_led)
return -ENOMEM;
- }
powernv_led->common = powernv_led_common;
powernv_led->loc_code = (char *)np->name;
rc = powernv_led_create(dev, powernv_led, cur);
- if (rc) {
- of_node_put(np);
+ if (rc)
return rc;
- }
+
} /* while end */
}
@@ -278,12 +274,11 @@ static int powernv_led_classdev(struct platform_device *pdev,
/* Platform driver probe */
static int powernv_led_probe(struct platform_device *pdev)
{
- struct device_node *led_node;
struct powernv_led_common *powernv_led_common;
struct device *dev = &pdev->dev;
- int rc;
+ struct device_node *led_node
+ __free(device_node) = of_find_node_by_path("/ibm,opal/leds");
- led_node = of_find_node_by_path("/ibm,opal/leds");
if (!led_node) {
dev_err(dev, "%s: LED parent device node not found\n",
__func__);
@@ -292,20 +287,15 @@ static int powernv_led_probe(struct platform_device *pdev)
powernv_led_common = devm_kzalloc(dev, sizeof(*powernv_led_common),
GFP_KERNEL);
- if (!powernv_led_common) {
- rc = -ENOMEM;
- goto out;
- }
+ if (!powernv_led_common)
+ return -ENOMEM;
mutex_init(&powernv_led_common->lock);
powernv_led_common->max_led_type = cpu_to_be64(OPAL_SLOT_LED_TYPE_MAX);
platform_set_drvdata(pdev, powernv_led_common);
- rc = powernv_led_classdev(pdev, led_node, powernv_led_common);
-out:
- of_node_put(led_node);
- return rc;
+ return powernv_led_classdev(pdev, led_node, powernv_led_common);
}
/* Platform driver remove */
diff --git a/drivers/leds/leds-spi-byte.c b/drivers/leds/leds-spi-byte.c
index 96296db5f410..d24d0ddf347c 100644
--- a/drivers/leds/leds-spi-byte.c
+++ b/drivers/leds/leds-spi-byte.c
@@ -29,10 +29,11 @@
*/
#include <linux/leds.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/spi/spi.h>
#include <linux/mutex.h>
+#include <linux/property.h>
+#include <linux/spi/spi.h>
#include <uapi/linux/uleds.h>
struct spi_byte_chipdef {
@@ -55,13 +56,6 @@ static const struct spi_byte_chipdef ubnt_acb_spi_led_cdef = {
.max_value = 0x3F,
};
-static const struct of_device_id spi_byte_dt_ids[] = {
- { .compatible = "ubnt,acb-spi-led", .data = &ubnt_acb_spi_led_cdef },
- {},
-};
-
-MODULE_DEVICE_TABLE(of, spi_byte_dt_ids);
-
static int spi_byte_brightness_set_blocking(struct led_classdev *dev,
enum led_brightness brightness)
{
@@ -80,73 +74,60 @@ static int spi_byte_brightness_set_blocking(struct led_classdev *dev,
static int spi_byte_probe(struct spi_device *spi)
{
- struct device_node *child;
+ struct fwnode_handle *child __free(fwnode_handle) = NULL;
struct device *dev = &spi->dev;
struct spi_byte_led *led;
struct led_init_data init_data = {};
- const char *state;
+ enum led_default_state state;
int ret;
- if (of_get_available_child_count(dev_of_node(dev)) != 1) {
+ if (device_get_child_node_count(dev) != 1) {
dev_err(dev, "Device must have exactly one LED sub-node.");
return -EINVAL;
}
- child = of_get_next_available_child(dev_of_node(dev), NULL);
led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
if (!led)
return -ENOMEM;
+ ret = devm_mutex_init(dev, &led->mutex);
+ if (ret)
+ return ret;
+
led->spi = spi;
- mutex_init(&led->mutex);
led->cdef = device_get_match_data(dev);
led->ldev.brightness = LED_OFF;
led->ldev.max_brightness = led->cdef->max_value - led->cdef->off_value;
led->ldev.brightness_set_blocking = spi_byte_brightness_set_blocking;
- state = of_get_property(child, "default-state", NULL);
- if (state) {
- if (!strcmp(state, "on")) {
- led->ldev.brightness = led->ldev.max_brightness;
- } else if (strcmp(state, "off")) {
- /* all other cases except "off" */
- dev_err(dev, "default-state can only be 'on' or 'off'");
- return -EINVAL;
- }
- }
+ child = device_get_next_child_node(dev, NULL);
+
+ state = led_init_default_state_get(child);
+ if (state == LEDS_DEFSTATE_ON)
+ led->ldev.brightness = led->ldev.max_brightness;
spi_byte_brightness_set_blocking(&led->ldev,
led->ldev.brightness);
- init_data.fwnode = of_fwnode_handle(child);
+ init_data.fwnode = child;
init_data.devicename = "leds-spi-byte";
init_data.default_label = ":";
- ret = devm_led_classdev_register_ext(&spi->dev, &led->ldev, &init_data);
- if (ret) {
- mutex_destroy(&led->mutex);
- return ret;
- }
- spi_set_drvdata(spi, led);
-
- return 0;
+ return devm_led_classdev_register_ext(dev, &led->ldev, &init_data);
}
-static void spi_byte_remove(struct spi_device *spi)
-{
- struct spi_byte_led *led = spi_get_drvdata(spi);
-
- mutex_destroy(&led->mutex);
-}
+static const struct of_device_id spi_byte_dt_ids[] = {
+ { .compatible = "ubnt,acb-spi-led", .data = &ubnt_acb_spi_led_cdef },
+ {}
+};
+MODULE_DEVICE_TABLE(of, spi_byte_dt_ids);
static struct spi_driver spi_byte_driver = {
.probe = spi_byte_probe,
- .remove = spi_byte_remove,
.driver = {
.name = KBUILD_MODNAME,
.of_match_table = spi_byte_dt_ids,
},
};
-
module_spi_driver(spi_byte_driver);
MODULE_AUTHOR("Christian Mauderer <oss@c-mauderer.de>");
diff --git a/drivers/leds/leds-ss4200.c b/drivers/leds/leds-ss4200.c
index fcaa34706b6c..2ef9fc7371bd 100644
--- a/drivers/leds/leds-ss4200.c
+++ b/drivers/leds/leds-ss4200.c
@@ -356,8 +356,10 @@ static int ich7_lpc_probe(struct pci_dev *dev,
nas_gpio_pci_dev = dev;
status = pci_read_config_dword(dev, PMBASE, &g_pm_io_base);
- if (status)
+ if (status) {
+ status = pcibios_err_to_errno(status);
goto out;
+ }
g_pm_io_base &= 0x00000ff80;
status = pci_read_config_dword(dev, GPIO_CTRL, &gc);
@@ -369,8 +371,9 @@ static int ich7_lpc_probe(struct pci_dev *dev,
}
status = pci_read_config_dword(dev, GPIO_BASE, &nas_gpio_io_base);
- if (0 > status) {
+ if (status) {
dev_info(&dev->dev, "Unable to read GPIOBASE.\n");
+ status = pcibios_err_to_errno(status);
goto out;
}
dev_dbg(&dev->dev, ": GPIOBASE = 0x%08x\n", nas_gpio_io_base);
diff --git a/drivers/leds/leds-tlc591xx.c b/drivers/leds/leds-tlc591xx.c
index 945e831ef4ac..6605e08a042a 100644
--- a/drivers/leds/leds-tlc591xx.c
+++ b/drivers/leds/leds-tlc591xx.c
@@ -146,7 +146,7 @@ MODULE_DEVICE_TABLE(of, of_tlc591xx_leds_match);
static int
tlc591xx_probe(struct i2c_client *client)
{
- struct device_node *np, *child;
+ struct device_node *np;
struct device *dev = &client->dev;
const struct tlc591xx *tlc591xx;
struct tlc591xx_priv *priv;
@@ -182,22 +182,20 @@ tlc591xx_probe(struct i2c_client *client)
if (err < 0)
return err;
- for_each_available_child_of_node(np, child) {
+ for_each_available_child_of_node_scoped(np, child) {
struct tlc591xx_led *led;
struct led_init_data init_data = {};
init_data.fwnode = of_fwnode_handle(child);
err = of_property_read_u32(child, "reg", &reg);
- if (err) {
- of_node_put(child);
+ if (err)
return err;
- }
+
if (reg < 0 || reg >= tlc591xx->max_leds ||
- priv->leds[reg].active) {
- of_node_put(child);
+ priv->leds[reg].active)
return -EINVAL;
- }
+
led = &priv->leds[reg];
led->active = true;
@@ -207,12 +205,10 @@ tlc591xx_probe(struct i2c_client *client)
led->ldev.max_brightness = TLC591XX_MAX_BRIGHTNESS;
err = devm_led_classdev_register_ext(dev, &led->ldev,
&init_data);
- if (err < 0) {
- of_node_put(child);
+ if (err < 0)
return dev_err_probe(dev, err,
"couldn't register LED %s\n",
led->ldev.name);
- }
}
return 0;
}
diff --git a/drivers/leds/leds-turris-omnia.c b/drivers/leds/leds-turris-omnia.c
index b443f8c989fa..39f740be058f 100644
--- a/drivers/leds/leds-turris-omnia.c
+++ b/drivers/leds/leds-turris-omnia.c
@@ -534,7 +534,7 @@ static const struct of_device_id of_omnia_leds_match[] = {
};
static const struct i2c_device_id omnia_id[] = {
- { "omnia", 0 },
+ { "omnia" },
{ }
};
MODULE_DEVICE_TABLE(i2c, omnia_id);
diff --git a/drivers/leds/rgb/leds-ncp5623.c b/drivers/leds/rgb/leds-ncp5623.c
index 2be4ff918516..f18156683375 100644
--- a/drivers/leds/rgb/leds-ncp5623.c
+++ b/drivers/leds/rgb/leds-ncp5623.c
@@ -183,16 +183,12 @@ static int ncp5623_probe(struct i2c_client *client)
fwnode_for_each_available_child_node(mc_node, led_node) {
ret = fwnode_property_read_u32(led_node, "color", &color_index);
- if (ret) {
- fwnode_handle_put(led_node);
- goto release_mc_node;
- }
+ if (ret)
+ goto release_led_node;
ret = fwnode_property_read_u32(led_node, "reg", &reg);
- if (ret) {
- fwnode_handle_put(led_node);
- goto release_mc_node;
- }
+ if (ret)
+ goto release_led_node;
subled_info[ncp->mc_dev.num_colors].channel = reg;
subled_info[ncp->mc_dev.num_colors++].color_index = color_index;
@@ -223,6 +219,10 @@ release_mc_node:
fwnode_handle_put(mc_node);
return ret;
+
+release_led_node:
+ fwnode_handle_put(led_node);
+ goto release_mc_node;
}
static void ncp5623_remove(struct i2c_client *client)
diff --git a/drivers/leds/rgb/leds-qcom-lpg.c b/drivers/leds/rgb/leds-qcom-lpg.c
index 9467c796bd04..e74b2ceed1c2 100644
--- a/drivers/leds/rgb/leds-qcom-lpg.c
+++ b/drivers/leds/rgb/leds-qcom-lpg.c
@@ -2,7 +2,7 @@
/*
* Copyright (c) 2017-2022 Linaro Ltd
* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
- * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2023-2024, Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/bits.h>
#include <linux/bitfield.h>
@@ -254,6 +254,9 @@ static int lpg_clear_pbs_trigger(struct lpg *lpg, unsigned int lut_mask)
u8 val = 0;
int rc;
+ if (!lpg->lpg_chan_sdam)
+ return 0;
+
lpg->pbs_en_bitmap &= (~lut_mask);
if (!lpg->pbs_en_bitmap) {
rc = nvmem_device_write(lpg->lpg_chan_sdam, SDAM_REG_PBS_SEQ_EN, 1, &val);
@@ -276,6 +279,9 @@ static int lpg_set_pbs_trigger(struct lpg *lpg, unsigned int lut_mask)
u8 val = PBS_SW_TRIG_BIT;
int rc;
+ if (!lpg->lpg_chan_sdam)
+ return 0;
+
if (!lpg->pbs_en_bitmap) {
rc = nvmem_device_write(lpg->lpg_chan_sdam, SDAM_REG_PBS_SEQ_EN, 1, &val);
if (rc < 0)
diff --git a/drivers/leds/simple/simatic-ipc-leds-gpio-apollolake.c b/drivers/leds/simple/simatic-ipc-leds-gpio-apollolake.c
index 4183ee71fcce..726c186391af 100644
--- a/drivers/leds/simple/simatic-ipc-leds-gpio-apollolake.c
+++ b/drivers/leds/simple/simatic-ipc-leds-gpio-apollolake.c
@@ -60,6 +60,7 @@ static struct platform_driver simatic_ipc_led_gpio_apollolake_driver = {
};
module_platform_driver(simatic_ipc_led_gpio_apollolake_driver);
+MODULE_DESCRIPTION("LED driver for Siemens Simatic IPCs based on Intel Apollo Lake GPIO");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:" KBUILD_MODNAME);
MODULE_SOFTDEP("pre: simatic-ipc-leds-gpio-core platform:apollolake-pinctrl");
diff --git a/drivers/leds/simple/simatic-ipc-leds-gpio-core.c b/drivers/leds/simple/simatic-ipc-leds-gpio-core.c
index 85003fd7f1aa..9bc5f361a06b 100644
--- a/drivers/leds/simple/simatic-ipc-leds-gpio-core.c
+++ b/drivers/leds/simple/simatic-ipc-leds-gpio-core.c
@@ -102,6 +102,7 @@ out:
}
EXPORT_SYMBOL_GPL(simatic_ipc_leds_gpio_probe);
+MODULE_DESCRIPTION("Siemens SIMATIC IPC core driver for GPIO based LEDs");
MODULE_LICENSE("GPL v2");
MODULE_SOFTDEP("pre: platform:leds-gpio");
MODULE_AUTHOR("Henning Schild <henning.schild@siemens.com>");
diff --git a/drivers/leds/simple/simatic-ipc-leds-gpio-elkhartlake.c b/drivers/leds/simple/simatic-ipc-leds-gpio-elkhartlake.c
index 4a53d4dbf52f..3fec96c549c1 100644
--- a/drivers/leds/simple/simatic-ipc-leds-gpio-elkhartlake.c
+++ b/drivers/leds/simple/simatic-ipc-leds-gpio-elkhartlake.c
@@ -50,6 +50,7 @@ static struct platform_driver simatic_ipc_led_gpio_elkhartlake_driver = {
};
module_platform_driver(simatic_ipc_led_gpio_elkhartlake_driver);
+MODULE_DESCRIPTION("LED driver for Siemens Simatic IPCs based on Intel Elkhart Lake GPIO");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:" KBUILD_MODNAME);
MODULE_SOFTDEP("pre: simatic-ipc-leds-gpio-core platform:elkhartlake-pinctrl");
diff --git a/drivers/leds/simple/simatic-ipc-leds-gpio-f7188x.c b/drivers/leds/simple/simatic-ipc-leds-gpio-f7188x.c
index 7a5018639aaf..a1f10952513c 100644
--- a/drivers/leds/simple/simatic-ipc-leds-gpio-f7188x.c
+++ b/drivers/leds/simple/simatic-ipc-leds-gpio-f7188x.c
@@ -100,6 +100,7 @@ static struct platform_driver simatic_ipc_led_gpio_driver = {
};
module_platform_driver(simatic_ipc_led_gpio_driver);
+MODULE_DESCRIPTION("LED driver for Siemens Simatic IPCs based on Nuvoton GPIO");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:" KBUILD_MODNAME);
MODULE_SOFTDEP("pre: simatic-ipc-leds-gpio-core gpio_f7188x");
diff --git a/drivers/leds/simple/simatic-ipc-leds.c b/drivers/leds/simple/simatic-ipc-leds.c
index 2124f6d09930..348679f0d1b7 100644
--- a/drivers/leds/simple/simatic-ipc-leds.c
+++ b/drivers/leds/simple/simatic-ipc-leds.c
@@ -128,6 +128,7 @@ static struct platform_driver simatic_ipc_led_driver = {
};
module_platform_driver(simatic_ipc_led_driver);
+MODULE_DESCRIPTION("LED driver for Siemens Simatic IPCs");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:" KBUILD_MODNAME);
MODULE_AUTHOR("Henning Schild <henning.schild@siemens.com>");
diff --git a/drivers/leds/trigger/Kconfig b/drivers/leds/trigger/Kconfig
index 31576952e181..c11282a74b5a 100644
--- a/drivers/leds/trigger/Kconfig
+++ b/drivers/leds/trigger/Kconfig
@@ -145,4 +145,20 @@ config LEDS_TRIGGER_TTY
When build as a module this driver will be called ledtrig-tty.
+config LEDS_TRIGGER_INPUT_EVENTS
+ tristate "LED Input events trigger"
+ depends on INPUT
+ help
+ Turn LEDs on when there is input (/dev/input/event*) activity and turn
+ them back off again after there has been no activity for 5 seconds.
+
+ This is primarily intended to control LEDs which are a backlight for
+ capacitive touch-buttons, such as e.g. the menu / home / back buttons
+ found on the bottom bezel of many older smartphones and tablets.
+
+ This can also be used to turn on the keyboard backlight LED on
+ input events and turn the keyboard backlight off again when idle.
+
+ When build as a module this driver will be called ledtrig-input-events.
+
endif # LEDS_TRIGGERS
diff --git a/drivers/leds/trigger/Makefile b/drivers/leds/trigger/Makefile
index 242f6c4e3453..3b3628889f68 100644
--- a/drivers/leds/trigger/Makefile
+++ b/drivers/leds/trigger/Makefile
@@ -15,3 +15,4 @@ obj-$(CONFIG_LEDS_TRIGGER_PANIC) += ledtrig-panic.o
obj-$(CONFIG_LEDS_TRIGGER_NETDEV) += ledtrig-netdev.o
obj-$(CONFIG_LEDS_TRIGGER_PATTERN) += ledtrig-pattern.o
obj-$(CONFIG_LEDS_TRIGGER_TTY) += ledtrig-tty.o
+obj-$(CONFIG_LEDS_TRIGGER_INPUT_EVENTS) += ledtrig-input-events.o
diff --git a/drivers/leds/trigger/ledtrig-input-events.c b/drivers/leds/trigger/ledtrig-input-events.c
new file mode 100644
index 000000000000..1de0176799f9
--- /dev/null
+++ b/drivers/leds/trigger/ledtrig-input-events.c
@@ -0,0 +1,233 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Input Events LED trigger
+ *
+ * Copyright (C) 2024 Hans de Goede <hansg@kernel.org>
+ * Partially based on Atsushi Nemoto's ledtrig-heartbeat.c.
+ */
+
+#include <linux/input.h>
+#include <linux/jiffies.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include "../leds.h"
+
+#define DEFAULT_LED_OFF_DELAY_MS 5000
+
+struct input_events_data {
+ struct input_handler handler;
+ struct delayed_work work;
+ spinlock_t lock;
+ struct led_classdev *led_cdev;
+ int led_cdev_saved_flags;
+ /* To avoid repeatedly setting the brightness while there are events */
+ bool led_on;
+ unsigned long led_off_time;
+ unsigned long led_off_delay;
+};
+
+static void led_input_events_work(struct work_struct *work)
+{
+ struct input_events_data *data =
+ container_of(work, struct input_events_data, work.work);
+
+ spin_lock_irq(&data->lock);
+
+ /*
+ * This time_after_eq() check avoids a race where this work starts
+ * running before a new event pushed led_off_time back.
+ */
+ if (time_after_eq(jiffies, data->led_off_time)) {
+ led_set_brightness_nosleep(data->led_cdev, LED_OFF);
+ data->led_on = false;
+ }
+
+ spin_unlock_irq(&data->lock);
+}
+
+static ssize_t delay_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct input_events_data *input_events_data = led_trigger_get_drvdata(dev);
+
+ return sysfs_emit(buf, "%lu\n", input_events_data->led_off_delay);
+}
+
+static ssize_t delay_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct input_events_data *input_events_data = led_trigger_get_drvdata(dev);
+ unsigned long delay;
+ int ret;
+
+ ret = kstrtoul(buf, 0, &delay);
+ if (ret)
+ return ret;
+
+ /* Clamp between 0.5 and 1000 seconds */
+ delay = clamp_val(delay, 500UL, 1000000UL);
+ input_events_data->led_off_delay = msecs_to_jiffies(delay);
+
+ return size;
+}
+
+static DEVICE_ATTR_RW(delay);
+
+static struct attribute *input_events_led_attrs[] = {
+ &dev_attr_delay.attr,
+ NULL
+};
+ATTRIBUTE_GROUPS(input_events_led);
+
+static void input_events_event(struct input_handle *handle, unsigned int type,
+ unsigned int code, int val)
+{
+ struct input_events_data *data =
+ container_of(handle->handler, struct input_events_data, handler);
+ unsigned long led_off_delay = READ_ONCE(data->led_off_delay);
+ struct led_classdev *led_cdev = data->led_cdev;
+ unsigned long flags;
+
+ if (test_and_clear_bit(LED_BLINK_BRIGHTNESS_CHANGE, &led_cdev->work_flags))
+ led_cdev->blink_brightness = led_cdev->new_blink_brightness;
+
+ spin_lock_irqsave(&data->lock, flags);
+
+ if (!data->led_on) {
+ led_set_brightness_nosleep(led_cdev, led_cdev->blink_brightness);
+ data->led_on = true;
+ }
+ data->led_off_time = jiffies + led_off_delay;
+
+ spin_unlock_irqrestore(&data->lock, flags);
+
+ mod_delayed_work(system_wq, &data->work, led_off_delay);
+}
+
+static int input_events_connect(struct input_handler *handler, struct input_dev *dev,
+ const struct input_device_id *id)
+{
+ struct input_handle *handle;
+ int ret;
+
+ handle = kzalloc(sizeof(*handle), GFP_KERNEL);
+ if (!handle)
+ return -ENOMEM;
+
+ handle->dev = dev;
+ handle->handler = handler;
+ handle->name = "input-events";
+
+ ret = input_register_handle(handle);
+ if (ret)
+ goto err_free_handle;
+
+ ret = input_open_device(handle);
+ if (ret)
+ goto err_unregister_handle;
+
+ return 0;
+
+err_unregister_handle:
+ input_unregister_handle(handle);
+err_free_handle:
+ kfree(handle);
+ return ret;
+}
+
+static void input_events_disconnect(struct input_handle *handle)
+{
+ input_close_device(handle);
+ input_unregister_handle(handle);
+ kfree(handle);
+}
+
+static const struct input_device_id input_events_ids[] = {
+ {
+ .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
+ .evbit = { BIT_MASK(EV_KEY) },
+ },
+ {
+ .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
+ .evbit = { BIT_MASK(EV_REL) },
+ },
+ {
+ .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
+ .evbit = { BIT_MASK(EV_ABS) },
+ },
+ { }
+};
+
+static int input_events_activate(struct led_classdev *led_cdev)
+{
+ struct input_events_data *data;
+ int ret;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->handler.name = "input-events";
+ data->handler.event = input_events_event;
+ data->handler.connect = input_events_connect;
+ data->handler.disconnect = input_events_disconnect;
+ data->handler.id_table = input_events_ids;
+
+ INIT_DELAYED_WORK(&data->work, led_input_events_work);
+ spin_lock_init(&data->lock);
+
+ data->led_cdev = led_cdev;
+ data->led_cdev_saved_flags = led_cdev->flags;
+ data->led_off_delay = msecs_to_jiffies(DEFAULT_LED_OFF_DELAY_MS);
+
+ /*
+ * Use led_cdev->blink_brightness + LED_BLINK_SW flag so that sysfs
+ * brightness writes will change led_cdev->new_blink_brightness for
+ * configuring the on state brightness (like ledtrig-heartbeat).
+ */
+ if (!led_cdev->blink_brightness)
+ led_cdev->blink_brightness = led_cdev->max_brightness;
+
+ /* Start with LED off */
+ led_set_brightness_nosleep(data->led_cdev, LED_OFF);
+
+ ret = input_register_handler(&data->handler);
+ if (ret) {
+ kfree(data);
+ return ret;
+ }
+
+ set_bit(LED_BLINK_SW, &led_cdev->work_flags);
+
+ /* Turn LED off during suspend, original flags are restored on deactivate() */
+ led_cdev->flags |= LED_CORE_SUSPENDRESUME;
+
+ led_set_trigger_data(led_cdev, data);
+ return 0;
+}
+
+static void input_events_deactivate(struct led_classdev *led_cdev)
+{
+ struct input_events_data *data = led_get_trigger_data(led_cdev);
+
+ led_cdev->flags = data->led_cdev_saved_flags;
+ clear_bit(LED_BLINK_SW, &led_cdev->work_flags);
+ input_unregister_handler(&data->handler);
+ cancel_delayed_work_sync(&data->work);
+ kfree(data);
+}
+
+static struct led_trigger input_events_led_trigger = {
+ .name = "input-events",
+ .activate = input_events_activate,
+ .deactivate = input_events_deactivate,
+ .groups = input_events_led_groups,
+};
+module_led_trigger(input_events_led_trigger);
+
+MODULE_AUTHOR("Hans de Goede <hansg@kernel.org>");
+MODULE_DESCRIPTION("Input Events LED trigger");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("ledtrig:input-events");
diff --git a/drivers/leds/trigger/ledtrig-timer.c b/drivers/leds/trigger/ledtrig-timer.c
index b4688d1d9d2b..1d213c999d40 100644
--- a/drivers/leds/trigger/ledtrig-timer.c
+++ b/drivers/leds/trigger/ledtrig-timer.c
@@ -110,11 +110,6 @@ static int timer_trig_activate(struct led_classdev *led_cdev)
led_cdev->flags &= ~LED_INIT_DEFAULT_TRIGGER;
}
- /*
- * If "set brightness to 0" is pending in workqueue, we don't
- * want that to be reordered after blink_set()
- */
- flush_work(&led_cdev->set_brightness_work);
led_blink_set(led_cdev, &led_cdev->blink_delay_on,
&led_cdev->blink_delay_off);