summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/testing/sysfs-class-led-trigger-netdev39
-rw-r--r--Documentation/ABI/testing/sysfs-class-led-trigger-tty56
-rw-r--r--Documentation/devicetree/bindings/leds/allwinner,sun50i-a100-ledc.yaml137
-rw-r--r--Documentation/devicetree/bindings/leds/awinic,aw200xx.yaml95
-rw-r--r--Documentation/devicetree/bindings/leds/common.yaml2
-rw-r--r--Documentation/devicetree/bindings/leds/qcom,spmi-flash-led.yaml4
-rw-r--r--drivers/leds/Kconfig35
-rw-r--r--drivers/leds/Makefile2
-rw-r--r--drivers/leds/led-triggers.c13
-rw-r--r--drivers/leds/leds-aw200xx.c98
-rw-r--r--drivers/leds/leds-gpio.c2
-rw-r--r--drivers/leds/leds-max5970.c111
-rw-r--r--drivers/leds/leds-sun50i-a100.c584
-rw-r--r--drivers/leds/leds-syscon.c3
-rw-r--r--drivers/leds/leds-tca6507.c30
-rw-r--r--drivers/leds/rgb/Kconfig2
-rw-r--r--drivers/leds/rgb/leds-qcom-lpg.c63
-rw-r--r--drivers/leds/trigger/ledtrig-gpio.c26
-rw-r--r--drivers/leds/trigger/ledtrig-netdev.c47
-rw-r--r--drivers/leds/trigger/ledtrig-panic.c5
-rw-r--r--drivers/leds/trigger/ledtrig-tty.c247
-rw-r--r--drivers/tty/tty_io.c28
-rw-r--r--include/linux/leds.h20
-rw-r--r--include/linux/tty.h1
24 files changed, 1449 insertions, 201 deletions
diff --git a/Documentation/ABI/testing/sysfs-class-led-trigger-netdev b/Documentation/ABI/testing/sysfs-class-led-trigger-netdev
index f6d9d72ce77b..a6c307c4befa 100644
--- a/Documentation/ABI/testing/sysfs-class-led-trigger-netdev
+++ b/Documentation/ABI/testing/sysfs-class-led-trigger-netdev
@@ -114,6 +114,45 @@ Description:
speed of 1000Mbps of the named network device.
Setting this value also immediately changes the LED state.
+What: /sys/class/leds/<led>/link_2500
+Date: Nov 2023
+KernelVersion: 6.8
+Contact: linux-leds@vger.kernel.org
+Description:
+ Signal the link speed state of 2500Mbps of the named network device.
+
+ If set to 0 (default), the LED's normal state is off.
+
+ If set to 1, the LED's normal state reflects the link state
+ speed of 2500Mbps of the named network device.
+ Setting this value also immediately changes the LED state.
+
+What: /sys/class/leds/<led>/link_5000
+Date: Nov 2023
+KernelVersion: 6.8
+Contact: linux-leds@vger.kernel.org
+Description:
+ Signal the link speed state of 5000Mbps of the named network device.
+
+ If set to 0 (default), the LED's normal state is off.
+
+ If set to 1, the LED's normal state reflects the link state
+ speed of 5000Mbps of the named network device.
+ Setting this value also immediately changes the LED state.
+
+What: /sys/class/leds/<led>/link_10000
+Date: Nov 2023
+KernelVersion: 6.8
+Contact: linux-leds@vger.kernel.org
+Description:
+ Signal the link speed state of 10000Mbps of the named network device.
+
+ If set to 0 (default), the LED's normal state is off.
+
+ If set to 1, the LED's normal state reflects the link state
+ speed of 10000Mbps of the named network device.
+ Setting this value also immediately changes the LED state.
+
What: /sys/class/leds/<led>/half_duplex
Date: Jun 2023
KernelVersion: 6.5
diff --git a/Documentation/ABI/testing/sysfs-class-led-trigger-tty b/Documentation/ABI/testing/sysfs-class-led-trigger-tty
index 2bf6b24e781b..30cef9ac0f49 100644
--- a/Documentation/ABI/testing/sysfs-class-led-trigger-tty
+++ b/Documentation/ABI/testing/sysfs-class-led-trigger-tty
@@ -4,3 +4,59 @@ KernelVersion: 5.10
Contact: linux-leds@vger.kernel.org
Description:
Specifies the tty device name of the triggering tty
+
+What: /sys/class/leds/<led>/rx
+Date: February 2024
+KernelVersion: 6.8
+Description:
+ Signal reception (rx) of data on the named tty device.
+ If set to 0, the LED will not blink on reception.
+ If set to 1 (default), the LED will blink on reception.
+
+What: /sys/class/leds/<led>/tx
+Date: February 2024
+KernelVersion: 6.8
+Description:
+ Signal transmission (tx) of data on the named tty device.
+ If set to 0, the LED will not blink on transmission.
+ If set to 1 (default), the LED will blink on transmission.
+
+What: /sys/class/leds/<led>/cts
+Date: February 2024
+KernelVersion: 6.8
+Description:
+ CTS = Clear To Send
+ DCE is ready to accept data from the DTE.
+ If the line state is detected, the LED is switched on.
+ If set to 0 (default), the LED will not evaluate CTS.
+ If set to 1, the LED will evaluate CTS.
+
+What: /sys/class/leds/<led>/dsr
+Date: February 2024
+KernelVersion: 6.8
+Description:
+ DSR = Data Set Ready
+ DCE is ready to receive and send data.
+ If the line state is detected, the LED is switched on.
+ If set to 0 (default), the LED will not evaluate DSR.
+ If set to 1, the LED will evaluate DSR.
+
+What: /sys/class/leds/<led>/dcd
+Date: February 2024
+KernelVersion: 6.8
+Description:
+ DCD = Data Carrier Detect
+ DTE is receiving a carrier from the DCE.
+ If the line state is detected, the LED is switched on.
+ If set to 0 (default), the LED will not evaluate CAR (DCD).
+ If set to 1, the LED will evaluate CAR (DCD).
+
+What: /sys/class/leds/<led>/rng
+Date: February 2024
+KernelVersion: 6.8
+Description:
+ RNG = Ring Indicator
+ DCE has detected an incoming ring signal on the telephone
+ line. If the line state is detected, the LED is switched on.
+ If set to 0 (default), the LED will not evaluate RNG.
+ If set to 1, the LED will evaluate RNG.
diff --git a/Documentation/devicetree/bindings/leds/allwinner,sun50i-a100-ledc.yaml b/Documentation/devicetree/bindings/leds/allwinner,sun50i-a100-ledc.yaml
new file mode 100644
index 000000000000..760cb336dccb
--- /dev/null
+++ b/Documentation/devicetree/bindings/leds/allwinner,sun50i-a100-ledc.yaml
@@ -0,0 +1,137 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/leds/allwinner,sun50i-a100-ledc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Allwinner A100 LED Controller
+
+maintainers:
+ - Samuel Holland <samuel@sholland.org>
+
+description:
+ The LED controller found in Allwinner sunxi SoCs uses a one-wire serial
+ interface to drive up to 1024 RGB LEDs.
+
+properties:
+ compatible:
+ oneOf:
+ - const: allwinner,sun50i-a100-ledc
+ - items:
+ - enum:
+ - allwinner,sun20i-d1-ledc
+ - allwinner,sun50i-r329-ledc
+ - const: allwinner,sun50i-a100-ledc
+
+ reg:
+ maxItems: 1
+
+ "#address-cells":
+ const: 1
+
+ "#size-cells":
+ const: 0
+
+ interrupts:
+ maxItems: 1
+
+ clocks:
+ items:
+ - description: Bus clock
+ - description: Module clock
+
+ clock-names:
+ items:
+ - const: bus
+ - const: mod
+
+ resets:
+ maxItems: 1
+
+ dmas:
+ maxItems: 1
+ description: TX DMA channel
+
+ dma-names:
+ const: tx
+
+ allwinner,pixel-format:
+ description: Pixel format (subpixel transmission order), default is "grb"
+ enum:
+ - bgr
+ - brg
+ - gbr
+ - grb
+ - rbg
+ - rgb
+
+ allwinner,t0h-ns:
+ default: 336
+ description: Length of high pulse when transmitting a "0" bit
+
+ allwinner,t0l-ns:
+ default: 840
+ description: Length of low pulse when transmitting a "0" bit
+
+ allwinner,t1h-ns:
+ default: 882
+ description: Length of high pulse when transmitting a "1" bit
+
+ allwinner,t1l-ns:
+ default: 294
+ description: Length of low pulse when transmitting a "1" bit
+
+ allwinner,treset-ns:
+ default: 300000
+ description: Minimum delay between transmission frames
+
+patternProperties:
+ "^multi-led@[0-9a-f]+$":
+ type: object
+ $ref: leds-class-multicolor.yaml#
+ unevaluatedProperties: false
+ properties:
+ reg:
+ minimum: 0
+ maximum: 1023
+ description: Index of the LED in the series (must be contiguous)
+
+ required:
+ - reg
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - clocks
+ - clock-names
+ - resets
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/irq.h>
+ #include <dt-bindings/leds/common.h>
+
+ ledc: led-controller@2008000 {
+ compatible = "allwinner,sun20i-d1-ledc",
+ "allwinner,sun50i-a100-ledc";
+ reg = <0x2008000 0x400>;
+ interrupts = <36 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu 12>, <&ccu 34>;
+ clock-names = "bus", "mod";
+ resets = <&ccu 12>;
+ dmas = <&dma 42>;
+ dma-names = "tx";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ multi-led@0 {
+ reg = <0x0>;
+ color = <LED_COLOR_ID_RGB>;
+ function = LED_FUNCTION_INDICATOR;
+ };
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/leds/awinic,aw200xx.yaml b/Documentation/devicetree/bindings/leds/awinic,aw200xx.yaml
index feb5febaf361..54d6d1f08e24 100644
--- a/Documentation/devicetree/bindings/leds/awinic,aw200xx.yaml
+++ b/Documentation/devicetree/bindings/leds/awinic,aw200xx.yaml
@@ -10,15 +10,19 @@ maintainers:
- Martin Kurbanov <mmkurbanov@sberdevices.ru>
description: |
- This controller is present on AW20036/AW20054/AW20072.
- It is a 3x12/6x9/6x12 matrix LED programmed via
- an I2C interface, up to 36/54/72 LEDs or 12/18/24 RGBs,
- 3 pattern controllers for auto breathing or group dimming control.
+ It is a matrix LED driver programmed via an I2C interface. Devices have
+ a set of individually controlled leds and support 3 pattern controllers
+ for auto breathing or group dimming control. Supported devices:
+ - AW20036 (3x12) 36 LEDs
+ - AW20054 (6x9) 54 LEDs
+ - AW20072 (6x12) 72 LEDs
+ - AW20108 (9x12) 108 LEDs
For more product information please see the link below:
aw20036 - https://www.awinic.com/en/productDetail/AW20036QNR#tech-docs
aw20054 - https://www.awinic.com/en/productDetail/AW20054QNR#tech-docs
aw20072 - https://www.awinic.com/en/productDetail/AW20072QNR#tech-docs
+ aw20108 - https://www.awinic.com/en/productDetail/AW20108QNR#tech-docs
properties:
compatible:
@@ -26,6 +30,7 @@ properties:
- awinic,aw20036
- awinic,aw20054
- awinic,aw20072
+ - awinic,aw20108
reg:
maxItems: 1
@@ -36,13 +41,11 @@ properties:
"#size-cells":
const: 0
- awinic,display-rows:
- $ref: /schemas/types.yaml#/definitions/uint32
- description:
- Leds matrix size
+ enable-gpios:
+ maxItems: 1
patternProperties:
- "^led@[0-9a-f]$":
+ "^led@[0-9a-f]+$":
type: object
$ref: common.yaml#
unevaluatedProperties: false
@@ -60,16 +63,11 @@ patternProperties:
since the chip has a single global setting.
The maximum output current of each LED is calculated by the
following formula:
- IMAXled = 160000 * (592 / 600.5) * (1 / display-rows)
+ IMAXled = 160000 * (592 / 600.5) * (1 / max-current-switch-number)
And the minimum output current formula:
- IMINled = 3300 * (592 / 600.5) * (1 / display-rows)
-
-required:
- - compatible
- - reg
- - "#address-cells"
- - "#size-cells"
- - awinic,display-rows
+ IMINled = 3300 * (592 / 600.5) * (1 / max-current-switch-number)
+ where max-current-switch-number is determinated by led configuration
+ and depends on how leds are physically connected to the led driver.
allOf:
- if:
@@ -78,18 +76,67 @@ allOf:
contains:
const: awinic,aw20036
then:
+ patternProperties:
+ "^led@[0-9a-f]+$":
+ properties:
+ reg:
+ items:
+ minimum: 0
+ maximum: 36
+
+ - if:
properties:
- awinic,display-rows:
- enum: [1, 2, 3]
- else:
+ compatible:
+ contains:
+ const: awinic,aw20054
+ then:
+ patternProperties:
+ "^led@[0-9a-f]+$":
+ properties:
+ reg:
+ items:
+ minimum: 0
+ maximum: 54
+
+ - if:
properties:
- awinic,display-rows:
- enum: [1, 2, 3, 4, 5, 6, 7]
+ compatible:
+ contains:
+ const: awinic,aw20072
+ then:
+ patternProperties:
+ "^led@[0-9a-f]+$":
+ properties:
+ reg:
+ items:
+ minimum: 0
+ maximum: 72
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: awinic,aw20108
+ then:
+ patternProperties:
+ "^led@[0-9a-f]+$":
+ properties:
+ reg:
+ items:
+ minimum: 0
+ maximum: 108
+
+required:
+ - compatible
+ - reg
+ - "#address-cells"
+ - "#size-cells"
additionalProperties: false
examples:
- |
+ #include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/leds/common.h>
i2c {
@@ -101,7 +148,7 @@ examples:
reg = <0x3a>;
#address-cells = <1>;
#size-cells = <0>;
- awinic,display-rows = <3>;
+ enable-gpios = <&gpio 3 GPIO_ACTIVE_HIGH>;
led@0 {
reg = <0x0>;
diff --git a/Documentation/devicetree/bindings/leds/common.yaml b/Documentation/devicetree/bindings/leds/common.yaml
index c8d0ba5f2327..55a8d1385e21 100644
--- a/Documentation/devicetree/bindings/leds/common.yaml
+++ b/Documentation/devicetree/bindings/leds/common.yaml
@@ -167,7 +167,7 @@ properties:
Note that this flag is mainly used for PWM-LEDs, where it is not possible
to map brightness to current. Drivers for other controllers should use
led-max-microamp.
- $ref: /schemas/types.yaml#definitions/uint32
+ $ref: /schemas/types.yaml#/definitions/uint32
panic-indicator:
description:
diff --git a/Documentation/devicetree/bindings/leds/qcom,spmi-flash-led.yaml b/Documentation/devicetree/bindings/leds/qcom,spmi-flash-led.yaml
index a8736fd5a539..1ba607685f5f 100644
--- a/Documentation/devicetree/bindings/leds/qcom,spmi-flash-led.yaml
+++ b/Documentation/devicetree/bindings/leds/qcom,spmi-flash-led.yaml
@@ -89,9 +89,11 @@ additionalProperties: false
examples:
- |
#include <dt-bindings/leds/common.h>
- spmi {
+
+ pmic {
#address-cells = <1>;
#size-cells = <0>;
+
led-controller@ee00 {
compatible = "qcom,pm8350c-flash-led", "qcom,spmi-flash-led";
reg = <0xee00>;
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 6292fddcc55c..d721b254e1e4 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -95,14 +95,18 @@ config LEDS_ARIEL
Say Y to if your machine is a Dell Wyse 3020 thin client.
config LEDS_AW200XX
- tristate "LED support for Awinic AW20036/AW20054/AW20072"
+ tristate "LED support for Awinic AW20036/AW20054/AW20072/AW20108"
depends on LEDS_CLASS
depends on I2C
help
- This option enables support for the AW20036/AW20054/AW20072 LED driver.
- It is a 3x12/6x9/6x12 matrix LED driver programmed via
- an I2C interface, up to 36/54/72 LEDs or 12/18/24 RGBs,
- 3 pattern controllers for auto breathing or group dimming control.
+ This option enables support for the Awinic AW200XX LED controllers.
+ It is a matrix LED driver programmed via an I2C interface. Devices have
+ a set of individually controlled LEDs and support 3 pattern controllers
+ for auto breathing or group dimming control. Supported devices:
+ - AW20036 (3x12) 36 LEDs
+ - AW20054 (6x9) 54 LEDs
+ - AW20072 (6x12) 72 LEDs
+ - AW20108 (9x12) 108 LEDs
To compile this driver as a module, choose M here: the module
will be called leds-aw200xx.
@@ -110,6 +114,7 @@ config LEDS_AW200XX
config LEDS_AW2013
tristate "LED support for Awinic AW2013"
depends on LEDS_CLASS && I2C && OF
+ select REGMAP_I2C
help
This option enables support for the AW2013 3-channel
LED driver.
@@ -298,6 +303,15 @@ config LEDS_COBALT_RAQ
help
This option enables support for the Cobalt Raq series LEDs.
+config LEDS_SUN50I_A100
+ tristate "LED support for Allwinner A100 RGB LED controller"
+ depends on LEDS_CLASS_MULTICOLOR
+ depends on ARCH_SUNXI || COMPILE_TEST
+ help
+ This option enables support for the RGB LED controller found
+ in some Allwinner sunxi SoCs, including A100, R329, and D1.
+ It uses a one-wire interface to control up to 1024 LEDs.
+
config LEDS_SUNFIRE
tristate "LED support for SunFire servers."
depends on LEDS_CLASS
@@ -638,6 +652,17 @@ config LEDS_ADP5520
To compile this driver as a module, choose M here: the module will
be called leds-adp5520.
+config LEDS_MAX5970
+ tristate "LED Support for Maxim 5970"
+ depends on LEDS_CLASS
+ depends on MFD_MAX5970
+ help
+ This option enables support for the Maxim MAX5970 & MAX5978 smart
+ switch indication LEDs via the I2C bus.
+
+ To compile this driver as a module, choose M here: the module will
+ be called leds-max5970.
+
config LEDS_MC13783
tristate "LED Support for MC13XXX PMIC"
depends on LEDS_CLASS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index d7348e8bc019..ce07dc295ff0 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -56,6 +56,7 @@ obj-$(CONFIG_LEDS_LP8501) += leds-lp8501.o
obj-$(CONFIG_LEDS_LP8788) += leds-lp8788.o
obj-$(CONFIG_LEDS_LP8860) += leds-lp8860.o
obj-$(CONFIG_LEDS_LT3593) += leds-lt3593.o
+obj-$(CONFIG_LEDS_MAX5970) += leds-max5970.o
obj-$(CONFIG_LEDS_MAX77650) += leds-max77650.o
obj-$(CONFIG_LEDS_MAX8997) += leds-max8997.o
obj-$(CONFIG_LEDS_MC13783) += leds-mc13783.o
@@ -78,6 +79,7 @@ obj-$(CONFIG_LEDS_POWERNV) += leds-powernv.o
obj-$(CONFIG_LEDS_PWM) += leds-pwm.o
obj-$(CONFIG_LEDS_REGULATOR) += leds-regulator.o
obj-$(CONFIG_LEDS_SC27XX_BLTC) += leds-sc27xx-bltc.o
+obj-$(CONFIG_LEDS_SUN50I_A100) += leds-sun50i-a100.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/led-triggers.c b/drivers/leds/led-triggers.c
index 6a5e1f41f9a4..bd59a14a4a90 100644
--- a/drivers/leds/led-triggers.c
+++ b/drivers/leds/led-triggers.c
@@ -269,19 +269,6 @@ void led_trigger_set_default(struct led_classdev *led_cdev)
}
EXPORT_SYMBOL_GPL(led_trigger_set_default);
-void led_trigger_rename_static(const char *name, struct led_trigger *trig)
-{
- /* new name must be on a temporary string to prevent races */
- BUG_ON(name == trig->name);
-
- down_write(&triggers_list_lock);
- /* this assumes that trig->name was originaly allocated to
- * non constant storage */
- strcpy((char *)trig->name, name);
- up_write(&triggers_list_lock);
-}
-EXPORT_SYMBOL_GPL(led_trigger_rename_static);
-
/* LED Trigger Interface */
int led_trigger_register(struct led_trigger *trig)
diff --git a/drivers/leds/leds-aw200xx.c b/drivers/leds/leds-aw200xx.c
index 14ca236ce29e..f584a7f98fc5 100644
--- a/drivers/leds/leds-aw200xx.c
+++ b/drivers/leds/leds-aw200xx.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * Awinic AW20036/AW20054/AW20072 LED driver
+ * Awinic AW20036/AW20054/AW20072/AW20108 LED driver
*
* Copyright (c) 2023, SberDevices. All Rights Reserved.
*
@@ -10,6 +10,7 @@
#include <linux/bitfield.h>
#include <linux/bits.h>
#include <linux/container_of.h>
+#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/leds.h>
#include <linux/mod_devicetable.h>
@@ -74,6 +75,10 @@
#define AW200XX_LED2REG(x, columns) \
((x) + (((x) / (columns)) * (AW200XX_DSIZE_COLUMNS_MAX - (columns))))
+/* DIM current configuration register on page 1 */
+#define AW200XX_REG_DIM_PAGE1(x, columns) \
+ AW200XX_REG(AW200XX_PAGE1, AW200XX_LED2REG(x, columns))
+
/*
* DIM current configuration register (page 4).
* The even address for current DIM configuration.
@@ -82,6 +87,8 @@
#define AW200XX_REG_DIM(x, columns) \
AW200XX_REG(AW200XX_PAGE4, AW200XX_LED2REG(x, columns) * 2)
#define AW200XX_REG_DIM2FADE(x) ((x) + 1)
+#define AW200XX_REG_FADE2DIM(fade) \
+ DIV_ROUND_UP((fade) * AW200XX_DIM_MAX, AW200XX_FADE_MAX)
/*
* Duty ratio of display scan (see p.15 of datasheet for formula):
@@ -112,6 +119,7 @@ struct aw200xx {
struct mutex mutex;
u32 num_leds;
u32 display_rows;
+ struct gpio_desc *hwen;
struct aw200xx_led leds[] __counted_by(num_leds);
};
@@ -153,7 +161,8 @@ static ssize_t dim_store(struct device *dev, struct device_attribute *devattr,
if (dim >= 0) {
ret = regmap_write(chip->regmap,
- AW200XX_REG_DIM(led->num, columns), dim);
+ AW200XX_REG_DIM_PAGE1(led->num, columns),
+ dim);
if (ret)
goto out_unlock;
}
@@ -188,9 +197,7 @@ static int aw200xx_brightness_set(struct led_classdev *cdev,
dim = led->dim;
if (dim < 0)
- dim = max_t(int,
- brightness / (AW200XX_FADE_MAX / AW200XX_DIM_MAX),
- 1);
+ dim = AW200XX_REG_FADE2DIM(brightness);
ret = regmap_write(chip->regmap, reg, dim);
if (ret)
@@ -314,6 +321,9 @@ static int aw200xx_chip_reset(const struct aw200xx *const chip)
if (ret)
return ret;
+ /* According to the datasheet software reset takes at least 1ms */
+ fsleep(1000);
+
regcache_mark_dirty(chip->regmap);
return regmap_write(chip->regmap, AW200XX_REG_FCD, AW200XX_FCD_CLEAR);
}
@@ -353,6 +363,50 @@ static int aw200xx_chip_check(const struct aw200xx *const chip)
return 0;
}
+static void aw200xx_enable(const struct aw200xx *const chip)
+{
+ gpiod_set_value_cansleep(chip->hwen, 1);
+
+ /*
+ * After HWEN pin set high the chip begins to load the OTP information,
+ * which takes 200us to complete. About 200us wait time is needed for
+ * internal oscillator startup and display SRAM initialization. After
+ * display SRAM initialization, the registers in page1 to page5 can be
+ * configured via i2c interface.
+ */
+ fsleep(400);
+}
+
+static void aw200xx_disable(const struct aw200xx *const chip)
+{
+ return gpiod_set_value_cansleep(chip->hwen, 0);
+}
+
+static int aw200xx_probe_get_display_rows(struct device *dev,
+ struct aw200xx *chip)
+{
+ struct fwnode_handle *child;
+ u32 max_source = 0;
+
+ device_for_each_child_node(dev, child) {
+ u32 source;
+ int ret;
+
+ ret = fwnode_property_read_u32(child, "reg", &source);
+ if (ret || source >= chip->cdef->channels)
+ continue;
+
+ max_source = max(max_source, source);
+ }
+
+ if (max_source == 0)
+ return -EINVAL;
+
+ chip->display_rows = max_source / chip->cdef->display_size_columns + 1;
+
+ return 0;
+}
+
static int aw200xx_probe_fw(struct device *dev, struct aw200xx *chip)
{
struct fwnode_handle *child;
@@ -360,18 +414,10 @@ static int aw200xx_probe_fw(struct device *dev, struct aw200xx *chip)
int ret;
int i;
- ret = device_property_read_u32(dev, "awinic,display-rows",
- &chip->display_rows);
+ ret = aw200xx_probe_get_display_rows(dev, chip);
if (ret)
return dev_err_probe(dev, ret,
- "Failed to read 'display-rows' property\n");
-
- if (!chip->display_rows ||
- chip->display_rows > chip->cdef->display_size_rows_max) {
- return dev_err_probe(dev, -EINVAL,
- "Invalid leds display size %u\n",
- chip->display_rows);
- }
+ "No valid led definitions found\n");
current_max = aw200xx_imax_from_global(chip, AW200XX_IMAX_MAX_uA);
current_min = aw200xx_imax_from_global(chip, AW200XX_IMAX_MIN_uA);
@@ -416,6 +462,7 @@ static int aw200xx_probe_fw(struct device *dev, struct aw200xx *chip)
led->num = source;
led->chip = chip;
led->cdev.brightness_set_blocking = aw200xx_brightness_set;
+ led->cdev.max_brightness = AW200XX_FADE_MAX;
led->cdev.groups = dim_groups;
init_data.fwnode = child;
@@ -480,6 +527,7 @@ static const struct regmap_config aw200xx_regmap_config = {
.rd_table = &aw200xx_readable_table,
.wr_table = &aw200xx_writeable_table,
.cache_type = REGCACHE_MAPLE,
+ .disable_locking = true,
};
static int aw200xx_probe(struct i2c_client *client)
@@ -512,6 +560,14 @@ static int aw200xx_probe(struct i2c_client *client)
if (IS_ERR(chip->regmap))
return PTR_ERR(chip->regmap);
+ chip->hwen = devm_gpiod_get_optional(&client->dev, "enable",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(chip->hwen))
+ return dev_err_probe(&client->dev, PTR_ERR(chip->hwen),
+ "Cannot get enable GPIO");
+
+ aw200xx_enable(chip);
+
ret = aw200xx_chip_check(chip);
if (ret)
return ret;
@@ -532,6 +588,9 @@ static int aw200xx_probe(struct i2c_client *client)
ret = aw200xx_chip_init(chip);
out_unlock:
+ if (ret)
+ aw200xx_disable(chip);
+
mutex_unlock(&chip->mutex);
return ret;
}
@@ -541,6 +600,7 @@ static void aw200xx_remove(struct i2c_client *client)
struct aw200xx *chip = i2c_get_clientdata(client);
aw200xx_chip_reset(chip);
+ aw200xx_disable(chip);
mutex_destroy(&chip->mutex);
}
@@ -562,10 +622,17 @@ static const struct aw200xx_chipdef aw20072_cdef = {
.display_size_columns = 12,
};
+static const struct aw200xx_chipdef aw20108_cdef = {
+ .channels = 108,
+ .display_size_rows_max = 9,
+ .display_size_columns = 12,
+};
+
static const struct i2c_device_id aw200xx_id[] = {
{ "aw20036" },
{ "aw20054" },
{ "aw20072" },
+ { "aw20108" },
{}
};
MODULE_DEVICE_TABLE(i2c, aw200xx_id);
@@ -574,6 +641,7 @@ static const struct of_device_id aw200xx_match_table[] = {
{ .compatible = "awinic,aw20036", .data = &aw20036_cdef, },
{ .compatible = "awinic,aw20054", .data = &aw20054_cdef, },
{ .compatible = "awinic,aw20072", .data = &aw20072_cdef, },
+ { .compatible = "awinic,aw20108", .data = &aw20108_cdef, },
{}
};
MODULE_DEVICE_TABLE(of, aw200xx_match_table);
diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c
index 710c319ad312..83fcd7b6afff 100644
--- a/drivers/leds/leds-gpio.c
+++ b/drivers/leds/leds-gpio.c
@@ -172,6 +172,8 @@ static struct gpio_leds_priv *gpio_leds_create(struct device *dev)
led.gpiod = devm_fwnode_gpiod_get(dev, child, NULL, GPIOD_ASIS,
NULL);
if (IS_ERR(led.gpiod)) {
+ dev_err_probe(dev, PTR_ERR(led.gpiod), "Failed to get GPIO '%pfw'\n",
+ child);
fwnode_handle_put(child);
return ERR_CAST(led.gpiod);
}
diff --git a/drivers/leds/leds-max5970.c b/drivers/leds/leds-max5970.c
new file mode 100644
index 000000000000..56a584311581
--- /dev/null
+++ b/drivers/leds/leds-max5970.c
@@ -0,0 +1,111 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Device driver for leds in MAX5970 and MAX5978 IC
+ *
+ * Copyright (c) 2022 9elements GmbH
+ *
+ * Author: Patrick Rudolph <patrick.rudolph@9elements.com>
+ */
+
+#include <linux/bits.h>
+#include <linux/container_of.h>
+#include <linux/device.h>
+#include <linux/leds.h>
+#include <linux/mfd/max5970.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+
+#define ldev_to_maxled(c) container_of(c, struct max5970_led, cdev)
+
+struct max5970_led {
+ struct device *dev;
+ struct regmap *regmap;
+ struct led_classdev cdev;
+ unsigned int index;
+};
+
+static int max5970_led_set_brightness(struct led_classdev *cdev,
+ enum led_brightness brightness)
+{
+ struct max5970_led *ddata = ldev_to_maxled(cdev);
+ int ret, val;
+
+ /* Set/clear corresponding bit for given led index */
+ val = !brightness ? BIT(ddata->index) : 0;
+
+ ret = regmap_update_bits(ddata->regmap, MAX5970_REG_LED_FLASH, BIT(ddata->index), val);
+ if (ret < 0)
+ dev_err(cdev->dev, "failed to set brightness %d", ret);
+
+ return ret;
+}
+
+static int max5970_led_probe(struct platform_device *pdev)
+{
+ struct fwnode_handle *led_node, *child;
+ struct device *dev = &pdev->dev;
+ struct regmap *regmap;
+ struct max5970_led *ddata;
+ int ret = -ENODEV;
+
+ regmap = dev_get_regmap(dev->parent, NULL);
+ if (!regmap)
+ return -ENODEV;
+
+ led_node = device_get_named_child_node(dev->parent, "leds");
+ if (!led_node)
+ return -ENODEV;
+
+ fwnode_for_each_available_child_node(led_node, child) {
+ u32 reg;
+
+ if (fwnode_property_read_u32(child, "reg", &reg))
+ continue;
+
+ if (reg >= MAX5970_NUM_LEDS) {
+ dev_err_probe(dev, -EINVAL, "invalid LED (%u >= %d)\n", reg, MAX5970_NUM_LEDS);
+ continue;
+ }
+
+ ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
+ if (!ddata) {
+ fwnode_handle_put(child);
+ return -ENOMEM;
+ }
+
+ ddata->index = reg;
+ ddata->regmap = regmap;
+ ddata->dev = dev;
+
+ if (fwnode_property_read_string(child, "label", &ddata->cdev.name))
+ ddata->cdev.name = fwnode_get_name(child);
+
+ ddata->cdev.max_brightness = 1;
+ ddata->cdev.brightness_set_blocking = max5970_led_set_brightness;
+ ddata->cdev.default_trigger = "none";
+
+ ret = devm_led_classdev_register(dev, &ddata->cdev);
+ if (ret < 0) {
+ fwnode_handle_put(child);
+ return dev_err_probe(dev, ret, "Failed to initialize LED %u\n", reg);
<