aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2021-08-31 14:41:41 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2021-08-31 14:41:41 -0700
commita998a62be9cdb509491731ffe81575aa09943a32 (patch)
tree12f89fd74e0bbdae12fdd159ba5a2c4ecfeeeefa
parente7c1bbcf0c315c56cd970642214aa1df3d8cf61d (diff)
parent239f32b4f161c1584cd4b386d6ab8766432a6ede (diff)
downloadlinux-a998a62be9cdb509491731ffe81575aa09943a32.tar.gz
Merge tag 'leds-5.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/pavel/linux-leds
Pull LED updates from Pavel Machek: "Usual driver changes, some documentation that should hopefully get LED names standartized, and many fixes" * tag 'leds-5.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/pavel/linux-leds: (32 commits) leds: pca955x: Switch to i2c probe_new leds: pca955x: Let the core process the fwnode leds: pca955x: Implement the default-state property leds: pca955x: Add brightness_get function leds: pca955x: Clean up code formatting leds: leds-core: Implement the retain-state-shutdown property dt-bindings: leds: Add retain-state-shutdown boolean Documentation: leds: standartizing LED names leds: trigger: remove reference to obsolete CONFIG_IDE_GD_ATA leds: lp50xx: Fix chip name in KConfig leds: pwm: add support for default-state device property leds: move default_state read from fwnode to core leds: flash: Remove redundant initialization of variable ret leds: lgm-sso: Propagate error codes from callee to caller leds: trigger: audio: Add an activate callback to ensure the initial brightness is set leds: rt8515: Put fwnode in any case during ->probe() leds: lt3593: Put fwnode in any case during ->probe() leds: lm3697: Make error handling more robust leds: lm3697: Update header block to reflect reality leds: lm3692x: Correct headers (of*.h -> mod_devicetable.h) ...
-rw-r--r--Documentation/devicetree/bindings/leds/common.yaml6
-rw-r--r--Documentation/leds/well-known-leds.txt58
-rw-r--r--MAINTAINERS2
-rw-r--r--drivers/leds/Kconfig59
-rw-r--r--drivers/leds/Makefile6
-rw-r--r--drivers/leds/blink/leds-lgm-sso.c39
-rw-r--r--drivers/leds/flash/Kconfig53
-rw-r--r--drivers/leds/flash/Makefile6
-rw-r--r--drivers/leds/flash/leds-aat1290.c (renamed from drivers/leds/leds-aat1290.c)0
-rw-r--r--drivers/leds/flash/leds-as3645a.c (renamed from drivers/leds/leds-as3645a.c)0
-rw-r--r--drivers/leds/flash/leds-ktd2692.c (renamed from drivers/leds/leds-ktd2692.c)0
-rw-r--r--drivers/leds/flash/leds-lm3601x.c (renamed from drivers/leds/leds-lm3601x.c)0
-rw-r--r--drivers/leds/flash/leds-max77693.c (renamed from drivers/leds/leds-max77693.c)0
-rw-r--r--drivers/leds/flash/leds-rt8515.c4
-rw-r--r--drivers/leds/flash/leds-sgm3140.c (renamed from drivers/leds/leds-sgm3140.c)0
-rw-r--r--drivers/leds/led-class-flash.c6
-rw-r--r--drivers/leds/led-class.c10
-rw-r--r--drivers/leds/led-core.c15
-rw-r--r--drivers/leds/leds-el15203000.c3
-rw-r--r--drivers/leds/leds-gpio.c12
-rw-r--r--drivers/leds/leds-is31fl32xx.c1
-rw-r--r--drivers/leds/leds-lm3692x.c3
-rw-r--r--drivers/leds/leds-lm3697.c16
-rw-r--r--drivers/leds/leds-lt3593.c5
-rw-r--r--drivers/leds/leds-pca955x.c232
-rw-r--r--drivers/leds/leds-pwm.c49
-rw-r--r--drivers/leds/leds.h1
-rw-r--r--drivers/leds/trigger/Kconfig2
-rw-r--r--drivers/leds/trigger/ledtrig-audio.c37
-rw-r--r--include/linux/leds.h12
30 files changed, 441 insertions, 196 deletions
diff --git a/Documentation/devicetree/bindings/leds/common.yaml b/Documentation/devicetree/bindings/leds/common.yaml
index b1f363747a628..697102707703a 100644
--- a/Documentation/devicetree/bindings/leds/common.yaml
+++ b/Documentation/devicetree/bindings/leds/common.yaml
@@ -128,6 +128,12 @@ properties:
as a panic indicator.
type: boolean
+ retain-state-shutdown:
+ description:
+ This property specifies that the LED should not be turned off or changed
+ when the system shuts down.
+ type: boolean
+
trigger-sources:
description: |
List of devices which should be used as a source triggering this LED
diff --git a/Documentation/leds/well-known-leds.txt b/Documentation/leds/well-known-leds.txt
new file mode 100644
index 0000000000000..4a8b9dc4bf526
--- /dev/null
+++ b/Documentation/leds/well-known-leds.txt
@@ -0,0 +1,58 @@
+-*- org -*-
+
+It is somehow important to provide consistent interface to the
+userland. LED devices have one problem there, and that is naming of
+directories in /sys/class/leds. It would be nice if userland would
+just know right "name" for given LED function, but situation got more
+complex.
+
+Anyway, if backwards compatibility is not an issue, new code should
+use one of the "good" names from this list, and you should extend the
+list where applicable.
+
+Legacy names are listed, too; in case you are writing application that
+wants to use particular feature, you should probe for good name, first,
+but then try the legacy ones, too.
+
+Notice there's a list of functions in include/dt-bindings/leds/common.h .
+
+* Keyboards
+
+Good: "input*:*:capslock"
+Good: "input*:*:scrolllock"
+Good: "input*:*:numlock"
+Legacy: "shift-key-light" (Motorola Droid 4, capslock)
+
+Set of common keyboard LEDs, going back to PC AT or so.
+
+Legacy: "tpacpi::thinklight" (IBM/Lenovo Thinkpads)
+Legacy: "lp5523:kb{1,2,3,4,5,6}" (Nokia N900)
+
+Frontlight/backlight of main keyboard.
+
+Legacy: "button-backlight" (Motorola Droid 4)
+
+Some phones have touch buttons below screen; it is different from main
+keyboard. And this is their backlight.
+
+* Sound subsystem
+
+Good: "platform:*:mute"
+Good: "platform:*:micmute"
+
+LEDs on notebook body, indicating that sound input / output is muted.
+
+* System notification
+
+Legacy: "status-led:{red,green,blue}" (Motorola Droid 4)
+Legacy: "lp5523:{r,g,b}" (Nokia N900)
+
+Phones usually have multi-color status LED.
+
+* Power management
+
+Good: "platform:*:charging" (allwinner sun50i)
+
+* Screen
+
+Good: ":backlight" (Motorola Droid 4)
diff --git a/MAINTAINERS b/MAINTAINERS
index 142e27504f4df..19d783ea85c6a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2849,7 +2849,7 @@ AS3645A LED FLASH CONTROLLER DRIVER
M: Sakari Ailus <sakari.ailus@iki.fi>
L: linux-leds@vger.kernel.org
S: Maintained
-F: drivers/leds/leds-as3645a.c
+F: drivers/leds/flash/leds-as3645a.c
ASAHI KASEI AK7375 LENS VOICE COIL DRIVER
M: Tianshu Qiu <tian.shu.qiu@intel.com>
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index bdf16180f5ffe..ed800f5da7d88 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -59,16 +59,6 @@ config LEDS_88PM860X
This option enables support for on-chip LED drivers found on Marvell
Semiconductor 88PM8606 PMIC.
-config LEDS_AAT1290
- tristate "LED support for the AAT1290"
- depends on LEDS_CLASS_FLASH
- depends on V4L2_FLASH_LED_CLASS || !V4L2_FLASH_LED_CLASS
- depends on GPIOLIB || COMPILE_TEST
- depends on OF
- depends on PINCTRL
- help
- This option enables support for the LEDs on the AAT1290.
-
config LEDS_AN30259A
tristate "LED support for Panasonic AN30259A"
depends on LEDS_CLASS && I2C && OF
@@ -104,15 +94,6 @@ config LEDS_ARIEL
Say Y to if your machine is a Dell Wyse 3020 thin client.
-config LEDS_AS3645A
- tristate "AS3645A and LM3555 LED flash controllers support"
- depends on I2C && LEDS_CLASS_FLASH
- depends on V4L2_FLASH_LED_CLASS || !V4L2_FLASH_LED_CLASS
- help
- Enable LED flash class support for AS3645A LED flash
- controller. V4L2 flash API is provided as well if
- CONFIG_V4L2_FLASH_API is enabled.
-
config LEDS_AW2013
tristate "LED support for Awinic AW2013"
depends on LEDS_CLASS && I2C && OF
@@ -239,15 +220,6 @@ config LEDS_LM3692X
This option enables support for the TI LM3692x family
of white LED string drivers used for backlighting.
-config LEDS_LM3601X
- tristate "LED support for LM3601x Chips"
- depends on LEDS_CLASS && I2C
- depends on LEDS_CLASS_FLASH
- select REGMAP_I2C
- help
- This option enables support for the TI LM3601x family
- of flash, torch and indicator classes.
-
config LEDS_LOCOMO
tristate "LED Support for Locomo device"
depends on LEDS_CLASS
@@ -397,7 +369,7 @@ config LEDS_LP3952
module will be called leds-lp3952.
config LEDS_LP50XX
- tristate "LED Support for TI LP5036/30/24/18/12/9 LED driver chip"
+ tristate "LED Support for TI LP5036/30/24/18/12/09 LED driver chip"
depends on LEDS_CLASS && REGMAP_I2C
depends on LEDS_CLASS_MULTICOLOR || !LEDS_CLASS_MULTICOLOR
help
@@ -699,17 +671,6 @@ config LEDS_MAX77650
help
LEDs driver for MAX77650 family of PMICs from Maxim Integrated.
-config LEDS_MAX77693
- tristate "LED support for MAX77693 Flash"
- depends on LEDS_CLASS_FLASH
- depends on V4L2_FLASH_LED_CLASS || !V4L2_FLASH_LED_CLASS
- depends on MFD_MAX77693
- depends on OF
- help
- This option enables support for the flash part of the MAX77693
- multifunction device. It has build in control for two leds in flash
- and torch mode.
-
config LEDS_MAX8997
tristate "LED support for MAX8997 PMIC"
depends on LEDS_CLASS && MFD_MAX8997
@@ -741,16 +702,6 @@ config LEDS_MENF21BMC
This driver can also be built as a module. If so the module
will be called leds-menf21bmc.
-config LEDS_KTD2692
- tristate "LED support for KTD2692 flash LED controller"
- depends on LEDS_CLASS_FLASH && OF
- depends on GPIOLIB || COMPILE_TEST
- help
- This option enables support for KTD2692 LED flash connected
- through ExpressWire interface.
-
- Say Y to enable this driver.
-
config LEDS_IS31FL319X
tristate "LED Support for ISSI IS31FL319x I2C LED controller family"
depends on LEDS_CLASS && I2C && OF
@@ -913,14 +864,6 @@ config LEDS_IP30
To compile this driver as a module, choose M here: the module
will be called leds-ip30.
-config LEDS_SGM3140
- tristate "LED support for the SGM3140"
- depends on LEDS_CLASS_FLASH
- depends on V4L2_FLASH_LED_CLASS || !V4L2_FLASH_LED_CLASS
- help
- This option enables support for the SGM3140 500mA Buck/Boost Charge
- Pump LED Driver.
-
config LEDS_ACER_A500
tristate "Power button LED support for Acer Iconia Tab A500"
depends on LEDS_CLASS && MFD_ACER_A500_EC
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 7e604d3028c80..c636ec069612d 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -9,13 +9,11 @@ obj-$(CONFIG_LEDS_TRIGGERS) += led-triggers.o
# LED Platform Drivers (keep this sorted, M-| sort)
obj-$(CONFIG_LEDS_88PM860X) += leds-88pm860x.o
-obj-$(CONFIG_LEDS_AAT1290) += leds-aat1290.o
obj-$(CONFIG_LEDS_ACER_A500) += leds-acer-a500.o
obj-$(CONFIG_LEDS_ADP5520) += leds-adp5520.o
obj-$(CONFIG_LEDS_AN30259A) += leds-an30259a.o
obj-$(CONFIG_LEDS_APU) += leds-apu.o
obj-$(CONFIG_LEDS_ARIEL) += leds-ariel.o
-obj-$(CONFIG_LEDS_AS3645A) += leds-as3645a.o
obj-$(CONFIG_LEDS_ASIC3) += leds-asic3.o
obj-$(CONFIG_LEDS_AW2013) += leds-aw2013.o
obj-$(CONFIG_LEDS_BCM6328) += leds-bcm6328.o
@@ -37,12 +35,10 @@ obj-$(CONFIG_LEDS_IP30) += leds-ip30.o
obj-$(CONFIG_LEDS_IPAQ_MICRO) += leds-ipaq-micro.o
obj-$(CONFIG_LEDS_IS31FL319X) += leds-is31fl319x.o
obj-$(CONFIG_LEDS_IS31FL32XX) += leds-is31fl32xx.o
-obj-$(CONFIG_LEDS_KTD2692) += leds-ktd2692.o
obj-$(CONFIG_LEDS_LM3530) += leds-lm3530.o
obj-$(CONFIG_LEDS_LM3532) += leds-lm3532.o
obj-$(CONFIG_LEDS_LM3533) += leds-lm3533.o
obj-$(CONFIG_LEDS_LM355x) += leds-lm355x.o
-obj-$(CONFIG_LEDS_LM3601X) += leds-lm3601x.o
obj-$(CONFIG_LEDS_LM36274) += leds-lm36274.o
obj-$(CONFIG_LEDS_LM3642) += leds-lm3642.o
obj-$(CONFIG_LEDS_LM3692X) += leds-lm3692x.o
@@ -60,7 +56,6 @@ obj-$(CONFIG_LEDS_LP8788) += leds-lp8788.o
obj-$(CONFIG_LEDS_LP8860) += leds-lp8860.o
obj-$(CONFIG_LEDS_LT3593) += leds-lt3593.o
obj-$(CONFIG_LEDS_MAX77650) += leds-max77650.o
-obj-$(CONFIG_LEDS_MAX77693) += leds-max77693.o
obj-$(CONFIG_LEDS_MAX8997) += leds-max8997.o
obj-$(CONFIG_LEDS_MC13783) += leds-mc13783.o
obj-$(CONFIG_LEDS_MENF21BMC) += leds-menf21bmc.o
@@ -82,7 +77,6 @@ obj-$(CONFIG_LEDS_PWM) += leds-pwm.o
obj-$(CONFIG_LEDS_REGULATOR) += leds-regulator.o
obj-$(CONFIG_LEDS_S3C24XX) += leds-s3c24xx.o
obj-$(CONFIG_LEDS_SC27XX_BLTC) += leds-sc27xx-bltc.o
-obj-$(CONFIG_LEDS_SGM3140) += leds-sgm3140.o
obj-$(CONFIG_LEDS_SUNFIRE) += leds-sunfire.o
obj-$(CONFIG_LEDS_SYSCON) += leds-syscon.o
obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o
diff --git a/drivers/leds/blink/leds-lgm-sso.c b/drivers/leds/blink/leds-lgm-sso.c
index 7eb2f44f16be5..fd8b7573285ad 100644
--- a/drivers/leds/blink/leds-lgm-sso.c
+++ b/drivers/leds/blink/leds-lgm-sso.c
@@ -611,9 +611,6 @@ static void sso_led_shutdown(struct sso_led *led)
if (led->desc.hw_trig)
regmap_update_bits(priv->mmap, SSO_CON3, BIT(led->desc.pin), 0);
- if (led->gpiod)
- devm_gpiod_put(priv->dev, led->gpiod);
-
led->priv = NULL;
}
@@ -624,15 +621,16 @@ __sso_led_dt_parse(struct sso_led_priv *priv, struct fwnode_handle *fw_ssoled)
struct device *dev = priv->dev;
struct sso_led_desc *desc;
struct sso_led *led;
- struct list_head *p;
const char *tmp;
u32 prop;
int ret;
fwnode_for_each_child_node(fw_ssoled, fwnode_child) {
led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
- if (!led)
- return -ENOMEM;
+ if (!led) {
+ ret = -ENOMEM;
+ goto __dt_err;
+ }
INIT_LIST_HEAD(&led->list);
led->priv = priv;
@@ -642,7 +640,7 @@ __sso_led_dt_parse(struct sso_led_priv *priv, struct fwnode_handle *fw_ssoled)
fwnode_child,
GPIOD_ASIS, NULL);
if (IS_ERR(led->gpiod)) {
- dev_err(dev, "led: get gpio fail!\n");
+ ret = dev_err_probe(dev, PTR_ERR(led->gpiod), "led: get gpio fail!\n");
goto __dt_err;
}
@@ -662,8 +660,11 @@ __sso_led_dt_parse(struct sso_led_priv *priv, struct fwnode_handle *fw_ssoled)
desc->panic_indicator = 1;
ret = fwnode_property_read_u32(fwnode_child, "reg", &prop);
- if (ret != 0 || prop >= SSO_LED_MAX_NUM) {
+ if (ret)
+ goto __dt_err;
+ if (prop >= SSO_LED_MAX_NUM) {
dev_err(dev, "invalid LED pin:%u\n", prop);
+ ret = -EINVAL;
goto __dt_err;
}
desc->pin = prop;
@@ -699,21 +700,20 @@ __sso_led_dt_parse(struct sso_led_priv *priv, struct fwnode_handle *fw_ssoled)
desc->brightness = LED_FULL;
}
- if (sso_create_led(priv, led, fwnode_child))
+ ret = sso_create_led(priv, led, fwnode_child);
+ if (ret)
goto __dt_err;
}
- fwnode_handle_put(fw_ssoled);
return 0;
+
__dt_err:
- fwnode_handle_put(fw_ssoled);
+ fwnode_handle_put(fwnode_child);
/* unregister leds */
- list_for_each(p, &priv->led_list) {
- led = list_entry(p, struct sso_led, list);
+ list_for_each_entry(led, &priv->led_list, list)
sso_led_shutdown(led);
- }
- return -EINVAL;
+ return ret;
}
static int sso_led_dt_parse(struct sso_led_priv *priv)
@@ -731,6 +731,7 @@ static int sso_led_dt_parse(struct sso_led_priv *priv)
fw_ssoled = fwnode_get_named_child_node(fwnode, "ssoled");
if (fw_ssoled) {
ret = __sso_led_dt_parse(priv, fw_ssoled);
+ fwnode_handle_put(fw_ssoled);
if (ret)
return ret;
}
@@ -841,14 +842,12 @@ static int intel_sso_led_probe(struct platform_device *pdev)
static int intel_sso_led_remove(struct platform_device *pdev)
{
struct sso_led_priv *priv;
- struct list_head *pos, *n;
- struct sso_led *led;
+ struct sso_led *led, *n;
priv = platform_get_drvdata(pdev);
- list_for_each_safe(pos, n, &priv->led_list) {
- list_del(pos);
- led = list_entry(pos, struct sso_led, list);
+ list_for_each_entry_safe(led, n, &priv->led_list, list) {
+ list_del(&led->list);
sso_led_shutdown(led);
}
diff --git a/drivers/leds/flash/Kconfig b/drivers/leds/flash/Kconfig
index 3f49f3edbffb5..b230f3d65eb00 100644
--- a/drivers/leds/flash/Kconfig
+++ b/drivers/leds/flash/Kconfig
@@ -2,6 +2,52 @@
if LEDS_CLASS_FLASH
+config LEDS_AAT1290
+ tristate "LED support for the AAT1290"
+ depends on V4L2_FLASH_LED_CLASS || !V4L2_FLASH_LED_CLASS
+ depends on GPIOLIB || COMPILE_TEST
+ depends on OF
+ depends on PINCTRL
+ help
+ This option enables support for the LEDs on the AAT1290.
+
+config LEDS_AS3645A
+ tristate "AS3645A and LM3555 LED flash controllers support"
+ depends on I2C
+ depends on V4L2_FLASH_LED_CLASS || !V4L2_FLASH_LED_CLASS
+ help
+ Enable LED flash class support for AS3645A LED flash
+ controller. V4L2 flash API is provided as well if
+ CONFIG_V4L2_FLASH_API is enabled.
+
+config LEDS_KTD2692
+ tristate "LED support for Kinetic KTD2692 flash LED controller"
+ depends on OF
+ depends on GPIOLIB || COMPILE_TEST
+ help
+ This option enables support for Kinetic KTD2692 LED flash connected
+ through ExpressWire interface.
+
+ Say Y to enable this driver.
+
+config LEDS_LM3601X
+ tristate "LED support for LM3601x Chips"
+ depends on LEDS_CLASS && I2C
+ select REGMAP_I2C
+ help
+ This option enables support for the TI LM3601x family
+ of flash, torch and indicator classes.
+
+config LEDS_MAX77693
+ tristate "LED support for MAX77693 Flash"
+ depends on V4L2_FLASH_LED_CLASS || !V4L2_FLASH_LED_CLASS
+ depends on MFD_MAX77693
+ depends on OF
+ help
+ This option enables support for the flash part of the MAX77693
+ multifunction device. It has build in control for two leds in flash
+ and torch mode.
+
config LEDS_RT4505
tristate "LED support for RT4505 flashlight controller"
depends on I2C && OF
@@ -24,4 +70,11 @@ config LEDS_RT8515
To compile this driver as a module, choose M here: the module
will be called leds-rt8515.
+config LEDS_SGM3140
+ tristate "LED support for the SGM3140"
+ depends on V4L2_FLASH_LED_CLASS || !V4L2_FLASH_LED_CLASS
+ help
+ This option enables support for the SGM3140 500mA Buck/Boost Charge
+ Pump LED Driver.
+
endif # LEDS_CLASS_FLASH
diff --git a/drivers/leds/flash/Makefile b/drivers/leds/flash/Makefile
index 09aee561f7697..ebea42f9c37e4 100644
--- a/drivers/leds/flash/Makefile
+++ b/drivers/leds/flash/Makefile
@@ -1,4 +1,10 @@
# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_LEDS_AAT1290) += leds-aat1290.o
+obj-$(CONFIG_LEDS_AS3645A) += leds-as3645a.o
+obj-$(CONFIG_LEDS_KTD2692) += leds-ktd2692.o
+obj-$(CONFIG_LEDS_LM3601X) += leds-lm3601x.o
+obj-$(CONFIG_LEDS_MAX77693) += leds-max77693.o
obj-$(CONFIG_LEDS_RT4505) += leds-rt4505.o
obj-$(CONFIG_LEDS_RT8515) += leds-rt8515.o
+obj-$(CONFIG_LEDS_SGM3140) += leds-sgm3140.o
diff --git a/drivers/leds/leds-aat1290.c b/drivers/leds/flash/leds-aat1290.c
index 589484b22c796..589484b22c796 100644
--- a/drivers/leds/leds-aat1290.c
+++ b/drivers/leds/flash/leds-aat1290.c
diff --git a/drivers/leds/leds-as3645a.c b/drivers/leds/flash/leds-as3645a.c
index aa3f82be0a9c9..aa3f82be0a9c9 100644
--- a/drivers/leds/leds-as3645a.c
+++ b/drivers/leds/flash/leds-as3645a.c
diff --git a/drivers/leds/leds-ktd2692.c b/drivers/leds/flash/leds-ktd2692.c
index f341da1503a49..f341da1503a49 100644
--- a/drivers/leds/leds-ktd2692.c
+++ b/drivers/leds/flash/leds-ktd2692.c
diff --git a/drivers/leds/leds-lm3601x.c b/drivers/leds/flash/leds-lm3601x.c
index d0e1d4814042e..d0e1d4814042e 100644
--- a/drivers/leds/leds-lm3601x.c
+++ b/drivers/leds/flash/leds-lm3601x.c
diff --git a/drivers/leds/leds-max77693.c b/drivers/leds/flash/leds-max77693.c
index 5c1faeb55a314..5c1faeb55a314 100644
--- a/drivers/leds/leds-max77693.c
+++ b/drivers/leds/flash/leds-max77693.c
diff --git a/drivers/leds/flash/leds-rt8515.c b/drivers/leds/flash/leds-rt8515.c
index 590bfa180d104..44904fdee3cc0 100644
--- a/drivers/leds/flash/leds-rt8515.c
+++ b/drivers/leds/flash/leds-rt8515.c
@@ -343,8 +343,9 @@ static int rt8515_probe(struct platform_device *pdev)
ret = devm_led_classdev_flash_register_ext(dev, fled, &init_data);
if (ret) {
- dev_err(dev, "can't register LED %s\n", led->name);
+ fwnode_handle_put(child);
mutex_destroy(&rt->lock);
+ dev_err(dev, "can't register LED %s\n", led->name);
return ret;
}
@@ -362,6 +363,7 @@ static int rt8515_probe(struct platform_device *pdev)
*/
}
+ fwnode_handle_put(child);
return 0;
}
diff --git a/drivers/leds/leds-sgm3140.c b/drivers/leds/flash/leds-sgm3140.c
index f4f831570f11c..f4f831570f11c 100644
--- a/drivers/leds/leds-sgm3140.c
+++ b/drivers/leds/flash/leds-sgm3140.c
diff --git a/drivers/leds/led-class-flash.c b/drivers/leds/led-class-flash.c
index 6eeb9effcf653..185e17055317c 100644
--- a/drivers/leds/led-class-flash.c
+++ b/drivers/leds/led-class-flash.c
@@ -92,14 +92,12 @@ static ssize_t flash_strobe_store(struct device *dev,
struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
unsigned long state;
- ssize_t ret = -EINVAL;
+ ssize_t ret = -EBUSY;
mutex_lock(&led_cdev->led_access);
- if (led_sysfs_is_disabled(led_cdev)) {
- ret = -EBUSY;
+ if (led_sysfs_is_disabled(led_cdev))
goto unlock;
- }
ret = kstrtoul(buf, 10, &state);
if (ret)
diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
index f704391d57a85..f4bb02f6e0428 100644
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -350,10 +350,15 @@ int led_classdev_register_ext(struct device *parent,
if (ret < 0)
return ret;
- if (init_data->fwnode)
+ if (init_data->fwnode) {
fwnode_property_read_string(init_data->fwnode,
"linux,default-trigger",
&led_cdev->default_trigger);
+
+ if (fwnode_property_present(init_data->fwnode,
+ "retain-state-shutdown"))
+ led_cdev->flags |= LED_RETAIN_AT_SHUTDOWN;
+ }
} else {
proposed_name = led_cdev->name;
}
@@ -444,7 +449,8 @@ void led_classdev_unregister(struct led_classdev *led_cdev)
/* Stop blinking */
led_stop_software_blink(led_cdev);
- led_set_brightness(led_cdev, LED_OFF);
+ if (!(led_cdev->flags & LED_RETAIN_AT_SHUTDOWN))
+ led_set_brightness(led_cdev, LED_OFF);
flush_work(&led_cdev->set_brightness_work);
diff --git a/drivers/leds/led-core.c b/drivers/leds/led-core.c
index 8eb8054ef9c61..4a97cb7457888 100644
--- a/drivers/leds/led-core.c
+++ b/drivers/leds/led-core.c
@@ -477,3 +477,18 @@ int led_compose_name(struct device *dev, struct led_init_data *init_data,
return 0;
}
EXPORT_SYMBOL_GPL(led_compose_name);
+
+enum led_default_state led_init_default_state_get(struct fwnode_handle *fwnode)
+{
+ const char *state = NULL;
+
+ if (!fwnode_property_read_string(fwnode, "default-state", &state)) {
+ if (!strcmp(state, "keep"))
+ return LEDS_DEFSTATE_KEEP;
+ if (!strcmp(state, "on"))
+ return LEDS_DEFSTATE_ON;
+ }
+
+ return LEDS_DEFSTATE_OFF;
+}
+EXPORT_SYMBOL_GPL(led_init_default_state_get);
diff --git a/drivers/leds/leds-el15203000.c b/drivers/leds/leds-el15203000.c
index 76b455e87574b..f9eb59a255705 100644
--- a/drivers/leds/leds-el15203000.c
+++ b/drivers/leds/leds-el15203000.c
@@ -4,8 +4,9 @@
#include <linux/delay.h>
#include <linux/leds.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/property.h>
#include <linux/spi/spi.h>
/*
diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c
index b5d5e22d2d1ea..092eb59a7d325 100644
--- a/drivers/leds/leds-gpio.c
+++ b/drivers/leds/leds-gpio.c
@@ -16,6 +16,7 @@
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/slab.h>
+#include "leds.h"
struct gpio_led_data {
struct led_classdev cdev;
@@ -144,7 +145,6 @@ static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev)
device_for_each_child_node(dev, child) {
struct gpio_led_data *led_dat = &priv->leds[priv->num_leds];
struct gpio_led led = {};
- const char *state = NULL;
/*
* Acquire gpiod from DT with uninitialized label, which
@@ -161,15 +161,7 @@ static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev)
led_dat->gpiod = led.gpiod;
- if (!fwnode_property_read_string(child, "default-state",
- &state)) {
- if (!strcmp(state, "keep"))
- led.default_state = LEDS_GPIO_DEFSTATE_KEEP;
- else if (!strcmp(state, "on"))
- led.default_state = LEDS_GPIO_DEFSTATE_ON;
- else
- led.default_state = LEDS_GPIO_DEFSTATE_OFF;
- }
+ led.default_state = led_init_default_state_get(child);
if (fwnode_property_present(child, "retain-state-suspended"))
led.retain_state_suspended = 1;
diff --git a/drivers/leds/leds-is31fl32xx.c b/drivers/leds/leds-is31fl32xx.c
index 3b55af9a8c585..22c092a4394ab 100644
--- a/drivers/leds/leds-is31fl32xx.c
+++ b/drivers/leds/leds-is31fl32xx.c
@@ -386,6 +386,7 @@ static int is31fl32xx_parse_dt(struct device *dev,
dev_err(dev,
"Node %pOF 'reg' conflicts with another LED\n",
child);
+ ret = -EINVAL;
goto err;
}
diff --git a/drivers/leds/leds-lm3692x.c b/drivers/leds/leds-lm3692x.c
index a02756d7ed8f4..afe6fb297855f 100644
--- a/drivers/leds/leds-lm3692x.c
+++ b/drivers/leds/leds-lm3692x.c
@@ -7,10 +7,9 @@
#include <linux/init.h>
#include <linux/leds.h>
#include <linux/log2.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/mutex.h>
-#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
diff --git a/drivers/leds/leds-lm3697.c b/drivers/leds/leds-lm3697.c
index 970a4f34791b4..a8c9322558cc5 100644
--- a/drivers/leds/leds-lm3697.c
+++ b/drivers/leds/leds-lm3697.c
@@ -2,11 +2,16 @@
// TI LM3697 LED chip family driver
// Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/
+#include <linux/bits.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
-#include <linux/of.h>
-#include <linux/of_gpio.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
+#include <linux/types.h>
+
#include <linux/leds-ti-lmu-common.h>
#define LM3697_REV 0x0
@@ -221,14 +226,12 @@ static int lm3697_probe_dt(struct lm3697 *priv)
ret = fwnode_property_read_u32(child, "reg", &control_bank);
if (ret) {
dev_err(dev, "reg property missing\n");
- fwnode_handle_put(child);
goto child_out;
}
if (control_bank > LM3697_CONTROL_B) {
dev_err(dev, "reg property is invalid\n");
ret = -EINVAL;
- fwnode_handle_put(child);
goto child_out;
}
@@ -259,7 +262,6 @@ static int lm3697_probe_dt(struct lm3697 *priv)
led->num_leds);
if (ret) {
dev_err(dev, "led-sources property missing\n");
- fwnode_handle_put(child);
goto child_out;
}
@@ -284,14 +286,16 @@ static int lm3697_probe_dt(struct lm3697 *priv)
&init_data);
if (ret) {
dev_err(dev, "led register err: %d\n", ret);
- fwnode_handle_put(child);
goto child_out;
}
i++;
}
+ return ret;
+
child_out:
+ fwnode_handle_put(child);
return ret;
}
diff --git a/drivers/leds/leds-lt3593.c b/drivers/leds/leds-lt3593.c
index 3bb52d3165d90..d0160fde0f94c 100644
--- a/drivers/leds/leds-lt3593.c
+++ b/drivers/leds/leds-lt3593.c
@@ -97,10 +97,9 @@ static int lt3593_led_probe(struct platform_device *pdev)
init_data.default_label = ":";
ret = devm_led_classdev_register_ext(dev, &led_data->cdev, &init_data);
- if (ret < 0) {
- fwnode_handle_put(child);
+ fwnode_handle_put(child);
+ if (ret < 0)
return ret;
- }
platform_set_drvdata(pdev, led_data);
diff --git a/drivers/leds/leds-pca955x.c b/drivers/leds/leds-pca955x.c
index 7087ca4592fc9..a6b5699aeae4f 100644
--- a/drivers/leds/leds-pca955x.c
+++ b/drivers/leds/leds-pca955x.c
@@ -127,9 +127,9 @@ struct pca955x_led {
struct pca955x *pca955x;
struct led_classdev led_cdev;
int led_num; /* 0 .. 15 potentially */
- char name[32];
u32 type;
- const char *default_trigger;
+ int default_state;
+ struct fwnode_handle *fwnode;
};
struct pca955x_platform_data {
@@ -166,11 +166,10 @@ static inline u8 pca955x_ledsel(u8 oldval, int led_num, int state)
static int pca955x_write_psc(struct i2c_client *client, int n, u8 val)
{
struct pca955x *pca955x = i2c_get_clientdata(client);
+ u8 cmd = pca95xx_num_input_regs(pca955x->chipdef->bits) + (2 * n);
int ret;
- ret = i2c_smbus_write_byte_data(client,
- pca95xx_num_input_regs(pca955x->chipdef->bits) + 2*n,
- val);
+ ret = i2c_smbus_write_byte_data(client, cmd, val);
if (ret < 0)
dev_err(&client->dev, "%s: reg 0x%x, val 0x%x, err %d\n",
__func__, n, val, ret);
@@ -187,11 +186,10 @@ static int pca955x_write_psc(struct i2c_client *client, int n, u8 val)
static int pca955x_write_pwm(struct i2c_client *client, int n, u8 val)
{
struct pca955x *pca955x = i2c_get_clientdata(client);
+ u8 cmd = pca95xx_num_input_regs(pca955x->chipdef->bits) + 1 + (2 * n);
int ret;
- ret = i2c_smbus_write_byte_data(client,
- pca95xx_num_input_regs(pca955x->chipdef->bits) + 1 + 2*n,
- val);
+ ret = i2c_smbus_write_byte_data(client, cmd, val);
if (ret < 0)
dev_err(&client->dev, "%s: reg 0x%x, val 0x%x, err %d\n",
__func__, n, val, ret);
@@ -205,11 +203,10 @@ static int pca955x_write_pwm(struct i2c_client *client, int n, u8 val)
static int pca955x_write_ls(struct i2c_client *client, int n, u8 val)
{
struct pca955x *pca955x = i2c_get_clientdata(client);
+ u8 cmd = pca95xx_num_input_regs(pca955x->chipdef->bits) + 4 + n;
int ret;
- ret = i2c_smbus_write_byte_data(client,
- pca95xx_num_input_regs(pca955x->chipdef->bits) + 4 + n,
- val);
+ ret = i2c_smbus_write_byte_data(client, cmd, val);
if (ret < 0)
dev_err(&client->dev, "%s: reg 0x%x, val 0x%x, err %d\n",
__func__, n, val, ret);
@@ -223,10 +220,10 @@ static int pca955x_write_ls(struct i2c_client *client, int n, u8 val)
static int pca955x_read_ls(struct i2c_client *client, int n, u8 *val)
{
struct pca955x *pca955x = i2c_get_clientdata(client);
+ u8 cmd = pca95xx_num_input_regs(pca955x->chipdef->bits) + 4 + n;
int ret;
- ret = i2c_smbus_read_byte_data(client,
- pca95xx_num_input_regs(pca955x->chipdef->bits) + 4 + n);
+ ret = i2c_smbus_read_byte_data(client, cmd);
if (ret < 0) {
dev_err(&client->dev, "%s: reg 0x%x, err %d\n",
__func__, n, ret);
@@ -236,6 +233,57 @@ static int pca955x_read_ls(struct i2c_client *client, int n, u8 *val)
return 0;
}
+static int pca955x_read_pwm(struct i2c_client *client, int n, u8 *val)
+{
+ struct pca955x *pca955x = i2c_get_clientdata(client);
+ u8 cmd = pca95xx_num_input_regs(pca955x->chipdef->bits) + 1 + (2 * n);
+ int ret;
+
+ ret = i2c_smbus_read_byte_data(client, cmd);
+ if (ret < 0) {
+ dev_err(&client->dev, "%s: reg 0x%x, err %d\n",
+ __func__, n, ret);
+ return ret;
+ }
+ *val = (u8)ret;
+ return 0;
+}
+
+static enum led_brightness pca955x_led_get(struct led_classdev *led_cdev)
+{
+ struct pca955x_led *pca955x_led = container_of(led_cdev,
+ struct pca955x_led,
+ led_cdev);
+ struct pca955x *pca955x = pca955x_led->pca955x;
+ u8 ls, pwm;
+ int ret;
+
+ ret = pca955x_read_ls(pca955x->client, pca955x_led->led_num / 4, &ls);
+ if (ret)
+ return ret;
+
+ ls = (ls >> ((pca955x_led->led_num % 4) << 1)) & 0x3;
+ switch (ls) {
+ case PCA955X_LS_LED_ON:
+ ret = LED_FULL;
+ break;
+ case PCA955X_LS_LED_OFF:
+ ret = LED_OFF;
+ break;
+ case PCA955X_LS_BLINK0:
+ ret = LED_HALF;
+ break;
+ case PCA955X_LS_BLINK1:
+ ret = pca955x_read_pwm(pca955x->client, 1, &pwm);
+ if (ret)
+ return ret;
+ ret = 255 - pwm;
+ break;
+ }
+
+ return ret;
+}
+
static int pca955x_led_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
@@ -371,6 +419,7 @@ static struct pca955x_platform_data *
pca955x_get_pdata(struct i2c_client *client, struct pca955x_chipdef *chip)
{
struct pca955x_platform_data *pdata;
+ struct pca955x_led *led;
struct fwnode_handle *child;
int count;
@@ -389,7 +438,7 @@ pca955x_get_pdata(struct i2c_client *client, struct pca955x_chipdef *chip)
return ERR_PTR(-ENOMEM);
device_for_each_child_node(&client->dev, child) {
- const char *name;
+ const char *state;
u32 reg;
int res;
@@ -397,17 +446,22 @@ pca955x_get_pdata(struct i2c_client *client, struct pca955x_chipdef *chip)
if ((res != 0) || (reg >= chip->bits))
continue;
- res = fwnode_property_read_string(child, "label", &name);
- if ((res != 0) && is_of_node(child))
- name = to_of_node(child)->name;
-
- snprintf(pdata->leds[reg].name, sizeof(pdata->leds[reg].name),
- "%s", name);
-
- pdata->leds[reg].type = PCA955X_TYPE_LED;
- fwnode_property_read_u32(child, "type", &pdata->leds[reg].type);
- fwnode_property_read_string(child, "linux,default-trigger",
- &pdata->leds[reg].default_trigger);
+ led = &pdata->leds[reg];
+ led->type = PCA955X_TYPE_LED;
+ led->fwnode = child;
+ fwnode_property_read_u32(child, "type", &led->type);
+
+ if (!fwnode_property_read_string(child, "default-state",
+ &state)) {
+ if (!strcmp(state, "keep"))
+ led->default_state = LEDS_GPIO_DEFSTATE_KEEP;
+ else if (!strcmp(state, "on"))
+ led->default_state = LEDS_GPIO_DEFSTATE_ON;
+ else
+ led->default_state = LEDS_GPIO_DEFSTATE_OFF;
+ } else {
+ led->default_state = LEDS_GPIO_DEFSTATE_OFF;
+ }
}
pdata->num_leds = chip->bits;
@@ -425,18 +479,38 @@ static const struct of_device_id of_pca955x_match[] = {
};
MODULE_DEVICE_TABLE(of, of_pca955x_match);
-static int pca955x_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int pca955x_probe(struct i2c_client *client)
{
struct pca955x *pca955x;
struct pca955x_led *pca955x_led;
struct pca955x_chipdef *chip;
+ struct led_classdev *led;
+ struct led_init_data init_data;
struct i2c_adapter *adapter;
int i, err;
struct pca955x_platform_data *pdata;
int ngpios = 0;
+ bool set_default_label = false;
+ bool keep_pwm = false;
+ char default_label[8];
+ enum pca955x_type chip_type;
+ const void *md = device_get_match_data(&client->dev);
+
+ if (md) {
+ chip_type = (enum pca955x_type)md;
+ } else {
+ const struct i2c_device_id *id = i2c_match_id(pca955x_id,
+ client);
+
+ if (id) {
+ chip_type = (enum pca955x_type)id->driver_data;
+ } else {
+ dev_err(&client->dev, "unknown chip\n");
+ return -ENODEV;
+ }
+ }
- chip = &pca955x_chipdefs[id->driver_data];
+ chip = &pca955x_chipdefs[chip_type];
adapter = client->adapter;
pdata = dev_get_platdata(&client->dev);
if (!pdata) {
@@ -449,13 +523,13 @@ static int pca955x_probe(struct i2c_client *client,
if ((client->addr & ~((1 << chip->slv_addr_shift) - 1)) !=
chip->slv_addr) {
dev_err(&client->dev, "invalid slave address %02x\n",
- client->addr);
+ client->addr);
return -ENODEV;
}
dev_info(&client->dev, "leds-pca955x: Using %s %d-bit LED driver at "
- "slave address 0x%02x\n",
- client->name, chip->bits, client->addr);
+ "slave address 0x%02x\n", client->name, chip->bits,
+ client->addr);
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -EIO;
@@ -471,8 +545,8 @@ static int pca955x_probe(struct i2c_client *client,
if (!pca955x)
return -ENOMEM;
- pca955x->leds = devm_kcalloc(&client->dev,
- chip->bits, sizeof(*pca955x_led), GFP_KERNEL);
+ pca955x->leds = devm_kcalloc(&client->dev, chip->bits,
+ sizeof(*pca955x_led), GFP_KERNEL);
if (!pca955x->leds)
return -ENOMEM;
@@ -482,6 +556,9 @@ static int pca955x_probe(struct i2c_client *client,
pca955x->client = client;
pca955x->chipdef = chip;
+ init_data.devname_mandatory = false;
+ init_data.devicename = "pca955x";
+
for (i = 0; i < chip->bits; i++) {
pca955x_led = &pca955x->leds[i];
pca955x_led->led_num = i;
@@ -495,35 +572,60 @@ static int pca955x_probe(struct i2c_client *client,
ngpios++;
break;
case PCA955X_TYPE_LED:
- /*
- * Platform data can specify LED names and
- * default triggers
- */
- if (pdata->leds[i].name[0] == '\0')
- snprintf(pdata->leds[i].name,
- sizeof(pdata->leds[i].name), "%d", i);
-
- snprintf(pca955x_led->name,
- sizeof(pca955x_led->name), "pca955x:%s",
- pdata->leds[i].name);
-
- if (pdata->leds[i].default_trigger)
- pca955x_led->led_cdev.default_trigger =
- pdata->leds[i].default_trigger;
-
- pca955x_led->led_cdev.name = pca955x_led->name;
- pca955x_led->led_cdev.brightness_set_blocking =
- pca955x_led_set;
-
- err = devm_led_classdev_register(&client->dev,
- &pca955x_led->led_cdev);
+ led = &pca955x_led->led_cdev;
+ led->brightness_set_blocking = pca955x_led_set;
+ led->brightness_get = pca955x_led_get;
+
+ if (pdata->leds[i].default_state ==
+ LEDS_GPIO_DEFSTATE_OFF) {
+ err = pca955x_led_set(led, LED_OFF);
+ if (err)
+ return err;
+ } else if (pdata->leds[i].default_state ==
+ LEDS_GPIO_DEFSTATE_ON) {
+ err = pca955x_led_set(led, LED_FULL);
+ if (err)
+ return err;
+ }
+
+ init_data.fwnode = pdata->leds[i].fwnode;
+
+ if (is_of_node(init_data.fwnode)) {
+ if (to_of_node(init_data.fwnode)->name[0] ==
+ '\0')
+ set_default_label = true;
+ else
+ set_default_label = false;
+ } else {
+ set_default_label = true;
+ }
+
+ if (set_default_label) {
+ snprintf(default_label, sizeof(default_label),
+ "%d", i);
+ init_data.default_label = default_label;
+ } else {
+ init_data.default_label = NULL;
+ }
+
+ err = devm_led_classdev_register_ext(&client->dev, led,
+ &init_data);
if (err)
return err;
- /* Turn off LED */
- err = pca955x_led_set(&pca955x_led->led_cdev, LED_OFF);
- if (err)
- return err;
+ /*
+ * For default-state == "keep", let the core update the
+ * brightness from the hardware, then check the
+ * brightness to see if it's using PWM1. If so, PWM1
+ * should not be written below.
+ */
+ if (pdata->leds[i].default_state ==
+ LEDS_GPIO_DEFSTATE_KEEP) {
+ if (led->brightness != LED_FULL &&
+ led->brightness != LED_OFF &&
+ led->brightness != LED_HALF)
+ keep_pwm = true;
+ }
}
}
@@ -532,10 +634,12 @@ static int pca955x_probe(struct i2c_client *client,
if (err)
return err;
- /* PWM1 is used for variable brightness, default to OFF */
- err = pca955x_write_pwm(client, 1, 0);
- if (err)
- return err;
+ if (!keep_pwm) {
+ /* PWM1 is used for variable brightness, default to OFF */
+ err = pca955x_write_pwm(client, 1, 0);
+ if (err)
+ return err;
+ }
/* Set to fast frequency so we do not see flashing */
err = pca955x_write_psc(client, 0, 0);
@@ -581,7 +685,7 @@ static struct i2c_driver pca955x_driver = {
.name = "leds-pca955x",
.of_match_table = of_pca955x_match,
},
- .probe = pca955x_probe,
+ .probe_new = pca955x_probe,
.id_table = pca955x_id,
};
diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c
index d71e9fa5c8dec..6832180c1c54f 100644
--- a/drivers/leds/leds-pwm.c
+++ b/drivers/leds/leds-pwm.c
@@ -17,10 +17,12 @@
#include <linux/err.h>
#include <linux/pwm.h>
#include <linux/slab.h>
+#include "leds.h"
struct led_pwm {
const char *name;
u8 active_low;
+ u8 default_state;
unsigned int max_brightness;
};
@@ -77,7 +79,38 @@ static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv,
led_data->cdev.brightness_set_blocking = led_pwm_set;
- pwm_init_state(led_data->pwm, &led_data->pwmstate);
+ /* init PWM state */
+ switch (led->default_state) {
+ case LEDS_DEFSTATE_KEEP:
+ pwm_get_state(led_data->pwm, &led_data->pwmstate);
+ if (led_data->pwmstate.period)
+ break;
+ led->default_state = LEDS_DEFSTATE_OFF;
+ dev_warn(dev,
+ "failed to read period for %s, default to off",
+ led->name);
+ fallthrough;
+ default:
+ pwm_init_state(led_data->pwm, &led_data->pwmstate);
+ break;
+ }
+
+ /* set brightness */
+ switch (led->default_state) {
+ case LEDS_DEFSTATE_ON:
+ led_data->cdev.brightness = led->max_brightness;
+ break;
+ case LEDS_DEFSTATE_KEEP:
+ {
+ uint64_t brightness;
+
+ brightness = led->max_brightness;
+ brightness *= led_data->pwmstate.duty_cycle;
+ do_div(brightness, led_data->pwmstate.period);
+ led_data->cdev.brightness = brightness;
+ }
+ break;
+ }
ret = devm_led_classdev_register_ext(dev, &led_data->cdev, &init_data);
if (ret) {
@@ -86,11 +119,13 @@ static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv,
return ret;
}
- ret = led_pwm_set(&led_data->cdev, led_data->cdev.brightness);
- if (ret) {
- dev_err(dev, "failed to set led PWM value for %s: %d",
- led->name, ret);
- return ret;
+ if (led->default_state != LEDS_DEFSTATE_KEEP) {
+ ret = led_pwm_set(&led_data->cdev, led_data->cdev.brightness);
+ if (ret) {
+ dev_err(dev, "failed to set led PWM value for %s: %d",
+ led->name, ret);
+ return ret;
+ }
}
priv->num_leds++;
@@ -120,6 +155,8 @@ static int led_pwm_create_fwnode(struct device *dev, struct led_pwm_priv *priv)
fwnode_property_read_u32(fwnode, "max-brightness",
&led.max_brightness);
+ led.default_state = led_init_default_state_get(fwnode);
+
ret = led_pwm_add(dev, priv, &led, fwnode);
if (ret)
goto err_child_out;
diff --git a/drivers/leds/leds.h b/drivers/leds/leds.h
index 345062ccabdaa..aa64757a4d894 100644
--- a/drivers/leds/leds.h
+++ b/drivers/leds/leds.h
@@ -27,6 +27,7 @@ ssize_t led_trigger_read(struct file *filp, struct kobject *kobj,
ssize_t led_trigger_write(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr, char *buf,
loff_t pos, size_t count);
+enum led_default_state led_init_default_state_get(struct fwnode_handle *fwnode);
extern struct rw_semaphore leds_list_lock;
extern struct list_head leds_list;
diff --git a/drivers/leds/trigger/Kconfig b/drivers/leds/trigger/Kconfig
index b77a01bd27f47..1f1d572880859 100644
--- a/drivers/leds/trigger/Kconfig
+++ b/drivers/leds/trigger/Kconfig
@@ -34,7 +34,7 @@ config LEDS_TRIGGER_ONESHOT
config LEDS_TRIGGER_DISK
bool "LED Disk Trigger"
- depends on IDE_GD_ATA || ATA
+ depends on ATA
help
This allows LEDs to be controlled by disk activity.
If unsure, say Y.
diff --git a/drivers/leds/trigger/ledtrig-audio.c b/drivers/leds/trigger/ledtrig-audio.c
index f76621e88482d..c6b437e6369b8 100644
--- a/drivers/leds/trigger/ledtrig-audio.c
+++ b/drivers/leds/trigger/ledtrig-audio.c
@@ -6,10 +6,33 @@
#include <linux/kernel.h>
#include <linux/leds.h>
#include <linux/module.h>
+#include "../leds.h"
-static struct led_trigger *ledtrig_audio[NUM_AUDIO_LEDS];
static enum led_brightness audio_state[NUM_AUDIO_LEDS];
+static int ledtrig_audio_mute_activate(struct led_classdev *led_cdev)
+{
+ led_set_brightness_nosleep(led_cdev, audio_state[LED_AUDIO_MUTE]);
+ return 0;
+}
+
+static int ledtrig_audio_micmute_activate(struct led_classdev *led_cdev)
+{
+ led_set_brightness_nosleep(led_cdev, audio_state[LED_AUDIO_MICMUTE]);
+ return 0;
+}
+
+static struct led_trigger ledtrig_audio[NUM_AUDIO_LEDS] = {
+ [LED_AUDIO_MUTE] = {
+ .name = "audio-mute",
+ .activate = ledtrig_audio_mute_activate,
+ },
+ [LED_AUDIO_MICMUTE] = {
+ .name = "audio-micmute",
+ .activate = ledtrig_audio_micmute_activate,
+ },
+};
+
enum led_brightness ledtrig_audio_get(enum led_audio type)
{
return audio_state[type];
@@ -19,24 +42,22 @@ EXPORT_SYMBOL_GPL(ledtrig_audio_get);
void ledtrig_audio_set(enum led_audio type, enum led_brightness state)
{
audio_state[type] = state;
- led_trigger_event(ledtrig_audio[type], state);
+ led_trigger_event(&ledtrig_audio[type], state);
}
EXPORT_SYMBOL_GPL(ledtrig_audio_set);
static int __init ledtrig_audio_init(void)
{
- led_trigger_register_simple("audio-mute",
- &ledtrig_audio[LED_AUDIO_MUTE]);
- led_trigger_register_simple("audio-micmute",
- &ledtrig_audio[LED_AUDIO_MICMUTE]);
+ led_trigger_register(&ledtrig_audio[LED_AUDIO_MUTE]);
+ led_trigger_register(&ledtrig_audio[LED_AUDIO_MICMUTE]);
return 0;
}
module_init(ledtrig_audio_init);
static void __exit ledtrig_audio_exit(void)
{
- led_trigger_unregister_simple(ledtrig_audio[LED_AUDIO_MUTE]);
- led_trigger_unregister_simple(ledtrig_audio[LED_AUDIO_MICMUTE]);
+ led_trigger_unregister(&ledtrig_audio[LED_AUDIO_MUTE]);
+ led_trigger_unregister(&ledtrig_audio[LED_AUDIO_MICMUTE]);
}
module_exit(ledtrig_audio_exit);
diff --git a/include/linux/leds.h b/include/linux/leds.h
index 329fd914cf243..a0b730be40ad2 100644
--- a/include/linux/leds.h
+++ b/include/linux/leds.h
@@ -33,6 +33,12 @@ enum led_brightness {
LED_FULL = 255,
};
+enum led_default_state {
+ LEDS_DEFSTATE_OFF = 0,
+ LEDS_DEFSTATE_ON = 1,
+ LEDS_DEFSTATE_KEEP = 2,
+};
+
struct led_init_data {
/* device fwnode handle */
struct fwnode_handle *fwnode;
@@ -520,9 +526,9 @@ struct gpio_led {
/* default_state should be one of LEDS_GPIO_DEFSTATE_(ON|OFF|KEEP) */
struct gpio_desc *gpiod;
};
-#define LEDS_GPIO_DEFSTATE_OFF 0
-#define LEDS_GPIO_DEFSTATE_ON 1
-#define LEDS_GPIO_DEFSTATE_KEEP 2
+#define LEDS_GPIO_DEFSTATE_OFF LEDS_DEFSTATE_OFF
+#define LEDS_GPIO_DEFSTATE_ON LEDS_DEFSTATE_ON
+#define LEDS_GPIO_DEFSTATE_KEEP LEDS_DEFSTATE_KEEP
struct gpio_led_platform_data {
int num_leds;