Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'leds-next-6.8' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/leds

Pull LED updates from Lee Jones:
"New Drivers:
- Add support for Allwinner A100 RGB LED controller
- Add support for Maxim 5970 Dual Hot-swap controller

New Device Support:
- Add support for AW20108 to Awinic LED driver

New Functionality:
- Extend support for Net speeds to include; 2.5G, 5G and 10G
- Allow tx/rx and cts/dsr/dcd/rng TTY LEDS to be turned on and off
via sysfs if required
- Add support for hardware control in AW200xx

Fix-ups:
- Use safer methods for string handling
- Improve error handling; return proper error values, simplify,
avoid duplicates, etc
- Replace Mutex use with the Completion mechanism
- Fix include lists; alphabetise, remove unused, explicitly add used
- Use generic platform device properties
- Use/convert to new/better APIs/helpers/MACROs instead of
hand-rolling implementations
- Device Tree binding adaptions/conversions/creation
- Continue work to remove superfluous platform .remove() call-backs
- Remove superfluous/defunct code
- Trivial; whitespace, unused variables, spelling, clean-ups, etc
- Avoid unnecessary duplicate locks

Bug Fixes:
- Repair Kconfig based dependency lists
- Ensure unused dynamically allocated data is freed after use
- Fix support for brightness control
- Add missing sufficient delays during reset to ensure correct
operation
- Avoid division-by-zero issues"

* tag 'leds-next-6.8' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/leds: (45 commits)
leds: trigger: netdev: Add core support for hw not supporting fallback to LED sw control
leds: trigger: panic: Don't register panic notifier if creating the trigger failed
leds: sun50i-a100: Convert to be agnostic to property provider
leds: max5970: Add missing headers
leds: max5970: Make use of dev_err_probe()
leds: max5970: Make use of device properties
leds: max5970: Remove unused variable
leds: rgb: Drop obsolete dependency on COMPILE_TEST
leds: sun50i-a100: Avoid division-by-zero warning
leds: trigger: Remove unused function led_trigger_rename_static()
leds: qcom-lpg: Introduce a wrapper for getting driver data from a pwm chip
leds: gpio: Add kernel log if devm_fwnode_gpiod_get() fails
dt-bindings: leds: qcom,spmi-flash-led: Fix example node name
dt-bindings: leds: aw200xx: Fix led pattern and add reg constraints
dt-bindings: leds: awinic,aw200xx: Add AW20108 device
leds: aw200xx: Add support for aw20108 device
leds: aw200xx: Improve autodim calculation method
leds: aw200xx: Enable disable_locking flag in regmap config
leds: aw200xx: Add delay after software reset
dt-bindings: leds: aw200xx: Remove property "awinic,display-rows"
...

+1449 -201
+39
Documentation/ABI/testing/sysfs-class-led-trigger-netdev
··· 114 114 speed of 1000Mbps of the named network device. 115 115 Setting this value also immediately changes the LED state. 116 116 117 + What: /sys/class/leds/<led>/link_2500 118 + Date: Nov 2023 119 + KernelVersion: 6.8 120 + Contact: linux-leds@vger.kernel.org 121 + Description: 122 + Signal the link speed state of 2500Mbps of the named network device. 123 + 124 + If set to 0 (default), the LED's normal state is off. 125 + 126 + If set to 1, the LED's normal state reflects the link state 127 + speed of 2500Mbps of the named network device. 128 + Setting this value also immediately changes the LED state. 129 + 130 + What: /sys/class/leds/<led>/link_5000 131 + Date: Nov 2023 132 + KernelVersion: 6.8 133 + Contact: linux-leds@vger.kernel.org 134 + Description: 135 + Signal the link speed state of 5000Mbps of the named network device. 136 + 137 + If set to 0 (default), the LED's normal state is off. 138 + 139 + If set to 1, the LED's normal state reflects the link state 140 + speed of 5000Mbps of the named network device. 141 + Setting this value also immediately changes the LED state. 142 + 143 + What: /sys/class/leds/<led>/link_10000 144 + Date: Nov 2023 145 + KernelVersion: 6.8 146 + Contact: linux-leds@vger.kernel.org 147 + Description: 148 + Signal the link speed state of 10000Mbps of the named network device. 149 + 150 + If set to 0 (default), the LED's normal state is off. 151 + 152 + If set to 1, the LED's normal state reflects the link state 153 + speed of 10000Mbps of the named network device. 154 + Setting this value also immediately changes the LED state. 155 + 117 156 What: /sys/class/leds/<led>/half_duplex 118 157 Date: Jun 2023 119 158 KernelVersion: 6.5
+56
Documentation/ABI/testing/sysfs-class-led-trigger-tty
··· 4 4 Contact: linux-leds@vger.kernel.org 5 5 Description: 6 6 Specifies the tty device name of the triggering tty 7 + 8 + What: /sys/class/leds/<led>/rx 9 + Date: February 2024 10 + KernelVersion: 6.8 11 + Description: 12 + Signal reception (rx) of data on the named tty device. 13 + If set to 0, the LED will not blink on reception. 14 + If set to 1 (default), the LED will blink on reception. 15 + 16 + What: /sys/class/leds/<led>/tx 17 + Date: February 2024 18 + KernelVersion: 6.8 19 + Description: 20 + Signal transmission (tx) of data on the named tty device. 21 + If set to 0, the LED will not blink on transmission. 22 + If set to 1 (default), the LED will blink on transmission. 23 + 24 + What: /sys/class/leds/<led>/cts 25 + Date: February 2024 26 + KernelVersion: 6.8 27 + Description: 28 + CTS = Clear To Send 29 + DCE is ready to accept data from the DTE. 30 + If the line state is detected, the LED is switched on. 31 + If set to 0 (default), the LED will not evaluate CTS. 32 + If set to 1, the LED will evaluate CTS. 33 + 34 + What: /sys/class/leds/<led>/dsr 35 + Date: February 2024 36 + KernelVersion: 6.8 37 + Description: 38 + DSR = Data Set Ready 39 + DCE is ready to receive and send data. 40 + If the line state is detected, the LED is switched on. 41 + If set to 0 (default), the LED will not evaluate DSR. 42 + If set to 1, the LED will evaluate DSR. 43 + 44 + What: /sys/class/leds/<led>/dcd 45 + Date: February 2024 46 + KernelVersion: 6.8 47 + Description: 48 + DCD = Data Carrier Detect 49 + DTE is receiving a carrier from the DCE. 50 + If the line state is detected, the LED is switched on. 51 + If set to 0 (default), the LED will not evaluate CAR (DCD). 52 + If set to 1, the LED will evaluate CAR (DCD). 53 + 54 + What: /sys/class/leds/<led>/rng 55 + Date: February 2024 56 + KernelVersion: 6.8 57 + Description: 58 + RNG = Ring Indicator 59 + DCE has detected an incoming ring signal on the telephone 60 + line. If the line state is detected, the LED is switched on. 61 + If set to 0 (default), the LED will not evaluate RNG. 62 + If set to 1, the LED will evaluate RNG.
+137
Documentation/devicetree/bindings/leds/allwinner,sun50i-a100-ledc.yaml
··· 1 + # SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/leds/allwinner,sun50i-a100-ledc.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Allwinner A100 LED Controller 8 + 9 + maintainers: 10 + - Samuel Holland <samuel@sholland.org> 11 + 12 + description: 13 + The LED controller found in Allwinner sunxi SoCs uses a one-wire serial 14 + interface to drive up to 1024 RGB LEDs. 15 + 16 + properties: 17 + compatible: 18 + oneOf: 19 + - const: allwinner,sun50i-a100-ledc 20 + - items: 21 + - enum: 22 + - allwinner,sun20i-d1-ledc 23 + - allwinner,sun50i-r329-ledc 24 + - const: allwinner,sun50i-a100-ledc 25 + 26 + reg: 27 + maxItems: 1 28 + 29 + "#address-cells": 30 + const: 1 31 + 32 + "#size-cells": 33 + const: 0 34 + 35 + interrupts: 36 + maxItems: 1 37 + 38 + clocks: 39 + items: 40 + - description: Bus clock 41 + - description: Module clock 42 + 43 + clock-names: 44 + items: 45 + - const: bus 46 + - const: mod 47 + 48 + resets: 49 + maxItems: 1 50 + 51 + dmas: 52 + maxItems: 1 53 + description: TX DMA channel 54 + 55 + dma-names: 56 + const: tx 57 + 58 + allwinner,pixel-format: 59 + description: Pixel format (subpixel transmission order), default is "grb" 60 + enum: 61 + - bgr 62 + - brg 63 + - gbr 64 + - grb 65 + - rbg 66 + - rgb 67 + 68 + allwinner,t0h-ns: 69 + default: 336 70 + description: Length of high pulse when transmitting a "0" bit 71 + 72 + allwinner,t0l-ns: 73 + default: 840 74 + description: Length of low pulse when transmitting a "0" bit 75 + 76 + allwinner,t1h-ns: 77 + default: 882 78 + description: Length of high pulse when transmitting a "1" bit 79 + 80 + allwinner,t1l-ns: 81 + default: 294 82 + description: Length of low pulse when transmitting a "1" bit 83 + 84 + allwinner,treset-ns: 85 + default: 300000 86 + description: Minimum delay between transmission frames 87 + 88 + patternProperties: 89 + "^multi-led@[0-9a-f]+$": 90 + type: object 91 + $ref: leds-class-multicolor.yaml# 92 + unevaluatedProperties: false 93 + properties: 94 + reg: 95 + minimum: 0 96 + maximum: 1023 97 + description: Index of the LED in the series (must be contiguous) 98 + 99 + required: 100 + - reg 101 + 102 + required: 103 + - compatible 104 + - reg 105 + - interrupts 106 + - clocks 107 + - clock-names 108 + - resets 109 + 110 + additionalProperties: false 111 + 112 + examples: 113 + - | 114 + #include <dt-bindings/interrupt-controller/irq.h> 115 + #include <dt-bindings/leds/common.h> 116 + 117 + ledc: led-controller@2008000 { 118 + compatible = "allwinner,sun20i-d1-ledc", 119 + "allwinner,sun50i-a100-ledc"; 120 + reg = <0x2008000 0x400>; 121 + interrupts = <36 IRQ_TYPE_LEVEL_HIGH>; 122 + clocks = <&ccu 12>, <&ccu 34>; 123 + clock-names = "bus", "mod"; 124 + resets = <&ccu 12>; 125 + dmas = <&dma 42>; 126 + dma-names = "tx"; 127 + #address-cells = <1>; 128 + #size-cells = <0>; 129 + 130 + multi-led@0 { 131 + reg = <0x0>; 132 + color = <LED_COLOR_ID_RGB>; 133 + function = LED_FUNCTION_INDICATOR; 134 + }; 135 + }; 136 + 137 + ...
+71 -24
Documentation/devicetree/bindings/leds/awinic,aw200xx.yaml
··· 10 10 - Martin Kurbanov <mmkurbanov@sberdevices.ru> 11 11 12 12 description: | 13 - This controller is present on AW20036/AW20054/AW20072. 14 - It is a 3x12/6x9/6x12 matrix LED programmed via 15 - an I2C interface, up to 36/54/72 LEDs or 12/18/24 RGBs, 16 - 3 pattern controllers for auto breathing or group dimming control. 13 + It is a matrix LED driver programmed via an I2C interface. Devices have 14 + a set of individually controlled leds and support 3 pattern controllers 15 + for auto breathing or group dimming control. Supported devices: 16 + - AW20036 (3x12) 36 LEDs 17 + - AW20054 (6x9) 54 LEDs 18 + - AW20072 (6x12) 72 LEDs 19 + - AW20108 (9x12) 108 LEDs 17 20 18 21 For more product information please see the link below: 19 22 aw20036 - https://www.awinic.com/en/productDetail/AW20036QNR#tech-docs 20 23 aw20054 - https://www.awinic.com/en/productDetail/AW20054QNR#tech-docs 21 24 aw20072 - https://www.awinic.com/en/productDetail/AW20072QNR#tech-docs 25 + aw20108 - https://www.awinic.com/en/productDetail/AW20108QNR#tech-docs 22 26 23 27 properties: 24 28 compatible: ··· 30 26 - awinic,aw20036 31 27 - awinic,aw20054 32 28 - awinic,aw20072 29 + - awinic,aw20108 33 30 34 31 reg: 35 32 maxItems: 1 ··· 41 36 "#size-cells": 42 37 const: 0 43 38 44 - awinic,display-rows: 45 - $ref: /schemas/types.yaml#/definitions/uint32 46 - description: 47 - Leds matrix size 39 + enable-gpios: 40 + maxItems: 1 48 41 49 42 patternProperties: 50 - "^led@[0-9a-f]$": 43 + "^led@[0-9a-f]+$": 51 44 type: object 52 45 $ref: common.yaml# 53 46 unevaluatedProperties: false ··· 63 60 since the chip has a single global setting. 64 61 The maximum output current of each LED is calculated by the 65 62 following formula: 66 - IMAXled = 160000 * (592 / 600.5) * (1 / display-rows) 63 + IMAXled = 160000 * (592 / 600.5) * (1 / max-current-switch-number) 67 64 And the minimum output current formula: 68 - IMINled = 3300 * (592 / 600.5) * (1 / display-rows) 69 - 70 - required: 71 - - compatible 72 - - reg 73 - - "#address-cells" 74 - - "#size-cells" 75 - - awinic,display-rows 65 + IMINled = 3300 * (592 / 600.5) * (1 / max-current-switch-number) 66 + where max-current-switch-number is determinated by led configuration 67 + and depends on how leds are physically connected to the led driver. 76 68 77 69 allOf: 78 70 - if: ··· 76 78 contains: 77 79 const: awinic,aw20036 78 80 then: 81 + patternProperties: 82 + "^led@[0-9a-f]+$": 83 + properties: 84 + reg: 85 + items: 86 + minimum: 0 87 + maximum: 36 88 + 89 + - if: 79 90 properties: 80 - awinic,display-rows: 81 - enum: [1, 2, 3] 82 - else: 91 + compatible: 92 + contains: 93 + const: awinic,aw20054 94 + then: 95 + patternProperties: 96 + "^led@[0-9a-f]+$": 97 + properties: 98 + reg: 99 + items: 100 + minimum: 0 101 + maximum: 54 102 + 103 + - if: 83 104 properties: 84 - awinic,display-rows: 85 - enum: [1, 2, 3, 4, 5, 6, 7] 105 + compatible: 106 + contains: 107 + const: awinic,aw20072 108 + then: 109 + patternProperties: 110 + "^led@[0-9a-f]+$": 111 + properties: 112 + reg: 113 + items: 114 + minimum: 0 115 + maximum: 72 116 + 117 + - if: 118 + properties: 119 + compatible: 120 + contains: 121 + const: awinic,aw20108 122 + then: 123 + patternProperties: 124 + "^led@[0-9a-f]+$": 125 + properties: 126 + reg: 127 + items: 128 + minimum: 0 129 + maximum: 108 130 + 131 + required: 132 + - compatible 133 + - reg 134 + - "#address-cells" 135 + - "#size-cells" 86 136 87 137 additionalProperties: false 88 138 89 139 examples: 90 140 - | 141 + #include <dt-bindings/gpio/gpio.h> 91 142 #include <dt-bindings/leds/common.h> 92 143 93 144 i2c { ··· 148 101 reg = <0x3a>; 149 102 #address-cells = <1>; 150 103 #size-cells = <0>; 151 - awinic,display-rows = <3>; 104 + enable-gpios = <&gpio 3 GPIO_ACTIVE_HIGH>; 152 105 153 106 led@0 { 154 107 reg = <0x0>;
+1 -1
Documentation/devicetree/bindings/leds/common.yaml
··· 167 167 Note that this flag is mainly used for PWM-LEDs, where it is not possible 168 168 to map brightness to current. Drivers for other controllers should use 169 169 led-max-microamp. 170 - $ref: /schemas/types.yaml#definitions/uint32 170 + $ref: /schemas/types.yaml#/definitions/uint32 171 171 172 172 panic-indicator: 173 173 description:
+3 -1
Documentation/devicetree/bindings/leds/qcom,spmi-flash-led.yaml
··· 89 89 examples: 90 90 - | 91 91 #include <dt-bindings/leds/common.h> 92 - spmi { 92 + 93 + pmic { 93 94 #address-cells = <1>; 94 95 #size-cells = <0>; 96 + 95 97 led-controller@ee00 { 96 98 compatible = "qcom,pm8350c-flash-led", "qcom,spmi-flash-led"; 97 99 reg = <0xee00>;
+30 -5
drivers/leds/Kconfig
··· 95 95 Say Y to if your machine is a Dell Wyse 3020 thin client. 96 96 97 97 config LEDS_AW200XX 98 - tristate "LED support for Awinic AW20036/AW20054/AW20072" 98 + tristate "LED support for Awinic AW20036/AW20054/AW20072/AW20108" 99 99 depends on LEDS_CLASS 100 100 depends on I2C 101 101 help 102 - This option enables support for the AW20036/AW20054/AW20072 LED driver. 103 - It is a 3x12/6x9/6x12 matrix LED driver programmed via 104 - an I2C interface, up to 36/54/72 LEDs or 12/18/24 RGBs, 105 - 3 pattern controllers for auto breathing or group dimming control. 102 + This option enables support for the Awinic AW200XX LED controllers. 103 + It is a matrix LED driver programmed via an I2C interface. Devices have 104 + a set of individually controlled LEDs and support 3 pattern controllers 105 + for auto breathing or group dimming control. Supported devices: 106 + - AW20036 (3x12) 36 LEDs 107 + - AW20054 (6x9) 54 LEDs 108 + - AW20072 (6x12) 72 LEDs 109 + - AW20108 (9x12) 108 LEDs 106 110 107 111 To compile this driver as a module, choose M here: the module 108 112 will be called leds-aw200xx. ··· 114 110 config LEDS_AW2013 115 111 tristate "LED support for Awinic AW2013" 116 112 depends on LEDS_CLASS && I2C && OF 113 + select REGMAP_I2C 117 114 help 118 115 This option enables support for the AW2013 3-channel 119 116 LED driver. ··· 302 297 select LEDS_TRIGGERS 303 298 help 304 299 This option enables support for the Cobalt Raq series LEDs. 300 + 301 + config LEDS_SUN50I_A100 302 + tristate "LED support for Allwinner A100 RGB LED controller" 303 + depends on LEDS_CLASS_MULTICOLOR 304 + depends on ARCH_SUNXI || COMPILE_TEST 305 + help 306 + This option enables support for the RGB LED controller found 307 + in some Allwinner sunxi SoCs, including A100, R329, and D1. 308 + It uses a one-wire interface to control up to 1024 LEDs. 305 309 306 310 config LEDS_SUNFIRE 307 311 tristate "LED support for SunFire servers." ··· 651 637 652 638 To compile this driver as a module, choose M here: the module will 653 639 be called leds-adp5520. 640 + 641 + config LEDS_MAX5970 642 + tristate "LED Support for Maxim 5970" 643 + depends on LEDS_CLASS 644 + depends on MFD_MAX5970 645 + help 646 + This option enables support for the Maxim MAX5970 & MAX5978 smart 647 + switch indication LEDs via the I2C bus. 648 + 649 + To compile this driver as a module, choose M here: the module will 650 + be called leds-max5970. 654 651 655 652 config LEDS_MC13783 656 653 tristate "LED Support for MC13XXX PMIC"
+2
drivers/leds/Makefile
··· 56 56 obj-$(CONFIG_LEDS_LP8788) += leds-lp8788.o 57 57 obj-$(CONFIG_LEDS_LP8860) += leds-lp8860.o 58 58 obj-$(CONFIG_LEDS_LT3593) += leds-lt3593.o 59 + obj-$(CONFIG_LEDS_MAX5970) += leds-max5970.o 59 60 obj-$(CONFIG_LEDS_MAX77650) += leds-max77650.o 60 61 obj-$(CONFIG_LEDS_MAX8997) += leds-max8997.o 61 62 obj-$(CONFIG_LEDS_MC13783) += leds-mc13783.o ··· 79 78 obj-$(CONFIG_LEDS_PWM) += leds-pwm.o 80 79 obj-$(CONFIG_LEDS_REGULATOR) += leds-regulator.o 81 80 obj-$(CONFIG_LEDS_SC27XX_BLTC) += leds-sc27xx-bltc.o 81 + obj-$(CONFIG_LEDS_SUN50I_A100) += leds-sun50i-a100.o 82 82 obj-$(CONFIG_LEDS_SUNFIRE) += leds-sunfire.o 83 83 obj-$(CONFIG_LEDS_SYSCON) += leds-syscon.o 84 84 obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o
-13
drivers/leds/led-triggers.c
··· 269 269 } 270 270 EXPORT_SYMBOL_GPL(led_trigger_set_default); 271 271 272 - void led_trigger_rename_static(const char *name, struct led_trigger *trig) 273 - { 274 - /* new name must be on a temporary string to prevent races */ 275 - BUG_ON(name == trig->name); 276 - 277 - down_write(&triggers_list_lock); 278 - /* this assumes that trig->name was originaly allocated to 279 - * non constant storage */ 280 - strcpy((char *)trig->name, name); 281 - up_write(&triggers_list_lock); 282 - } 283 - EXPORT_SYMBOL_GPL(led_trigger_rename_static); 284 - 285 272 /* LED Trigger Interface */ 286 273 287 274 int led_trigger_register(struct led_trigger *trig)
+83 -15
drivers/leds/leds-aw200xx.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 2 /* 3 - * Awinic AW20036/AW20054/AW20072 LED driver 3 + * Awinic AW20036/AW20054/AW20072/AW20108 LED driver 4 4 * 5 5 * Copyright (c) 2023, SberDevices. All Rights Reserved. 6 6 * ··· 10 10 #include <linux/bitfield.h> 11 11 #include <linux/bits.h> 12 12 #include <linux/container_of.h> 13 + #include <linux/gpio/consumer.h> 13 14 #include <linux/i2c.h> 14 15 #include <linux/leds.h> 15 16 #include <linux/mod_devicetable.h> ··· 75 74 #define AW200XX_LED2REG(x, columns) \ 76 75 ((x) + (((x) / (columns)) * (AW200XX_DSIZE_COLUMNS_MAX - (columns)))) 77 76 77 + /* DIM current configuration register on page 1 */ 78 + #define AW200XX_REG_DIM_PAGE1(x, columns) \ 79 + AW200XX_REG(AW200XX_PAGE1, AW200XX_LED2REG(x, columns)) 80 + 78 81 /* 79 82 * DIM current configuration register (page 4). 80 83 * The even address for current DIM configuration. ··· 87 82 #define AW200XX_REG_DIM(x, columns) \ 88 83 AW200XX_REG(AW200XX_PAGE4, AW200XX_LED2REG(x, columns) * 2) 89 84 #define AW200XX_REG_DIM2FADE(x) ((x) + 1) 85 + #define AW200XX_REG_FADE2DIM(fade) \ 86 + DIV_ROUND_UP((fade) * AW200XX_DIM_MAX, AW200XX_FADE_MAX) 90 87 91 88 /* 92 89 * Duty ratio of display scan (see p.15 of datasheet for formula): ··· 119 112 struct mutex mutex; 120 113 u32 num_leds; 121 114 u32 display_rows; 115 + struct gpio_desc *hwen; 122 116 struct aw200xx_led leds[] __counted_by(num_leds); 123 117 }; 124 118 ··· 161 153 162 154 if (dim >= 0) { 163 155 ret = regmap_write(chip->regmap, 164 - AW200XX_REG_DIM(led->num, columns), dim); 156 + AW200XX_REG_DIM_PAGE1(led->num, columns), 157 + dim); 165 158 if (ret) 166 159 goto out_unlock; 167 160 } ··· 197 188 198 189 dim = led->dim; 199 190 if (dim < 0) 200 - dim = max_t(int, 201 - brightness / (AW200XX_FADE_MAX / AW200XX_DIM_MAX), 202 - 1); 191 + dim = AW200XX_REG_FADE2DIM(brightness); 203 192 204 193 ret = regmap_write(chip->regmap, reg, dim); 205 194 if (ret) ··· 321 314 if (ret) 322 315 return ret; 323 316 317 + /* According to the datasheet software reset takes at least 1ms */ 318 + fsleep(1000); 319 + 324 320 regcache_mark_dirty(chip->regmap); 325 321 return regmap_write(chip->regmap, AW200XX_REG_FCD, AW200XX_FCD_CLEAR); 326 322 } ··· 363 353 return 0; 364 354 } 365 355 356 + static void aw200xx_enable(const struct aw200xx *const chip) 357 + { 358 + gpiod_set_value_cansleep(chip->hwen, 1); 359 + 360 + /* 361 + * After HWEN pin set high the chip begins to load the OTP information, 362 + * which takes 200us to complete. About 200us wait time is needed for 363 + * internal oscillator startup and display SRAM initialization. After 364 + * display SRAM initialization, the registers in page1 to page5 can be 365 + * configured via i2c interface. 366 + */ 367 + fsleep(400); 368 + } 369 + 370 + static void aw200xx_disable(const struct aw200xx *const chip) 371 + { 372 + return gpiod_set_value_cansleep(chip->hwen, 0); 373 + } 374 + 375 + static int aw200xx_probe_get_display_rows(struct device *dev, 376 + struct aw200xx *chip) 377 + { 378 + struct fwnode_handle *child; 379 + u32 max_source = 0; 380 + 381 + device_for_each_child_node(dev, child) { 382 + u32 source; 383 + int ret; 384 + 385 + ret = fwnode_property_read_u32(child, "reg", &source); 386 + if (ret || source >= chip->cdef->channels) 387 + continue; 388 + 389 + max_source = max(max_source, source); 390 + } 391 + 392 + if (max_source == 0) 393 + return -EINVAL; 394 + 395 + chip->display_rows = max_source / chip->cdef->display_size_columns + 1; 396 + 397 + return 0; 398 + } 399 + 366 400 static int aw200xx_probe_fw(struct device *dev, struct aw200xx *chip) 367 401 { 368 402 struct fwnode_handle *child; ··· 414 360 int ret; 415 361 int i; 416 362 417 - ret = device_property_read_u32(dev, "awinic,display-rows", 418 - &chip->display_rows); 363 + ret = aw200xx_probe_get_display_rows(dev, chip); 419 364 if (ret) 420 365 return dev_err_probe(dev, ret, 421 - "Failed to read 'display-rows' property\n"); 422 - 423 - if (!chip->display_rows || 424 - chip->display_rows > chip->cdef->display_size_rows_max) { 425 - return dev_err_probe(dev, -EINVAL, 426 - "Invalid leds display size %u\n", 427 - chip->display_rows); 428 - } 366 + "No valid led definitions found\n"); 429 367 430 368 current_max = aw200xx_imax_from_global(chip, AW200XX_IMAX_MAX_uA); 431 369 current_min = aw200xx_imax_from_global(chip, AW200XX_IMAX_MIN_uA); ··· 462 416 led->num = source; 463 417 led->chip = chip; 464 418 led->cdev.brightness_set_blocking = aw200xx_brightness_set; 419 + led->cdev.max_brightness = AW200XX_FADE_MAX; 465 420 led->cdev.groups = dim_groups; 466 421 init_data.fwnode = child; 467 422 ··· 527 480 .rd_table = &aw200xx_readable_table, 528 481 .wr_table = &aw200xx_writeable_table, 529 482 .cache_type = REGCACHE_MAPLE, 483 + .disable_locking = true, 530 484 }; 531 485 532 486 static int aw200xx_probe(struct i2c_client *client) ··· 560 512 if (IS_ERR(chip->regmap)) 561 513 return PTR_ERR(chip->regmap); 562 514 515 + chip->hwen = devm_gpiod_get_optional(&client->dev, "enable", 516 + GPIOD_OUT_HIGH); 517 + if (IS_ERR(chip->hwen)) 518 + return dev_err_probe(&client->dev, PTR_ERR(chip->hwen), 519 + "Cannot get enable GPIO"); 520 + 521 + aw200xx_enable(chip); 522 + 563 523 ret = aw200xx_chip_check(chip); 564 524 if (ret) 565 525 return ret; ··· 588 532 ret = aw200xx_chip_init(chip); 589 533 590 534 out_unlock: 535 + if (ret) 536 + aw200xx_disable(chip); 537 + 591 538 mutex_unlock(&chip->mutex); 592 539 return ret; 593 540 } ··· 600 541 struct aw200xx *chip = i2c_get_clientdata(client); 601 542 602 543 aw200xx_chip_reset(chip); 544 + aw200xx_disable(chip); 603 545 mutex_destroy(&chip->mutex); 604 546 } 605 547 ··· 622 562 .display_size_columns = 12, 623 563 }; 624 564 565 + static const struct aw200xx_chipdef aw20108_cdef = { 566 + .channels = 108, 567 + .display_size_rows_max = 9, 568 + .display_size_columns = 12, 569 + }; 570 + 625 571 static const struct i2c_device_id aw200xx_id[] = { 626 572 { "aw20036" }, 627 573 { "aw20054" }, 628 574 { "aw20072" }, 575 + { "aw20108" }, 629 576 {} 630 577 }; 631 578 MODULE_DEVICE_TABLE(i2c, aw200xx_id); ··· 641 574 { .compatible = "awinic,aw20036", .data = &aw20036_cdef, }, 642 575 { .compatible = "awinic,aw20054", .data = &aw20054_cdef, }, 643 576 { .compatible = "awinic,aw20072", .data = &aw20072_cdef, }, 577 + { .compatible = "awinic,aw20108", .data = &aw20108_cdef, }, 644 578 {} 645 579 }; 646 580 MODULE_DEVICE_TABLE(of, aw200xx_match_table);
+2
drivers/leds/leds-gpio.c
··· 172 172 led.gpiod = devm_fwnode_gpiod_get(dev, child, NULL, GPIOD_ASIS, 173 173 NULL); 174 174 if (IS_ERR(led.gpiod)) { 175 + dev_err_probe(dev, PTR_ERR(led.gpiod), "Failed to get GPIO '%pfw'\n", 176 + child); 175 177 fwnode_handle_put(child); 176 178 return ERR_CAST(led.gpiod); 177 179 }
+111
drivers/leds/leds-max5970.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Device driver for leds in MAX5970 and MAX5978 IC 4 + * 5 + * Copyright (c) 2022 9elements GmbH 6 + * 7 + * Author: Patrick Rudolph <patrick.rudolph@9elements.com> 8 + */ 9 + 10 + #include <linux/bits.h> 11 + #include <linux/container_of.h> 12 + #include <linux/device.h> 13 + #include <linux/leds.h> 14 + #include <linux/mfd/max5970.h> 15 + #include <linux/mod_devicetable.h> 16 + #include <linux/module.h> 17 + #include <linux/platform_device.h> 18 + #include <linux/property.h> 19 + #include <linux/regmap.h> 20 + 21 + #define ldev_to_maxled(c) container_of(c, struct max5970_led, cdev) 22 + 23 + struct max5970_led { 24 + struct device *dev; 25 + struct regmap *regmap; 26 + struct led_classdev cdev; 27 + unsigned int index; 28 + }; 29 + 30 + static int max5970_led_set_brightness(struct led_classdev *cdev, 31 + enum led_brightness brightness) 32 + { 33 + struct max5970_led *ddata = ldev_to_maxled(cdev); 34 + int ret, val; 35 + 36 + /* Set/clear corresponding bit for given led index */ 37 + val = !brightness ? BIT(ddata->index) : 0; 38 + 39 + ret = regmap_update_bits(ddata->regmap, MAX5970_REG_LED_FLASH, BIT(ddata->index), val); 40 + if (ret < 0) 41 + dev_err(cdev->dev, "failed to set brightness %d", ret); 42 + 43 + return ret; 44 + } 45 + 46 + static int max5970_led_probe(struct platform_device *pdev) 47 + { 48 + struct fwnode_handle *led_node, *child; 49 + struct device *dev = &pdev->dev; 50 + struct regmap *regmap; 51 + struct max5970_led *ddata; 52 + int ret = -ENODEV; 53 + 54 + regmap = dev_get_regmap(dev->parent, NULL); 55 + if (!regmap) 56 + return -ENODEV; 57 + 58 + led_node = device_get_named_child_node(dev->parent, "leds"); 59 + if (!led_node) 60 + return -ENODEV; 61 + 62 + fwnode_for_each_available_child_node(led_node, child) { 63 + u32 reg; 64 + 65 + if (fwnode_property_read_u32(child, "reg", &reg)) 66 + continue; 67 + 68 + if (reg >= MAX5970_NUM_LEDS) { 69 + dev_err_probe(dev, -EINVAL, "invalid LED (%u >= %d)\n", reg, MAX5970_NUM_LEDS); 70 + continue; 71 + } 72 + 73 + ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL); 74 + if (!ddata) { 75 + fwnode_handle_put(child); 76 + return -ENOMEM; 77 + } 78 + 79 + ddata->index = reg; 80 + ddata->regmap = regmap; 81 + ddata->dev = dev; 82 + 83 + if (fwnode_property_read_string(child, "label", &ddata->cdev.name)) 84 + ddata->cdev.name = fwnode_get_name(child); 85 + 86 + ddata->cdev.max_brightness = 1; 87 + ddata->cdev.brightness_set_blocking = max5970_led_set_brightness; 88 + ddata->cdev.default_trigger = "none"; 89 + 90 + ret = devm_led_classdev_register(dev, &ddata->cdev); 91 + if (ret < 0) { 92 + fwnode_handle_put(child); 93 + return dev_err_probe(dev, ret, "Failed to initialize LED %u\n", reg); 94 + } 95 + } 96 + 97 + return ret; 98 + } 99 + 100 + static struct platform_driver max5970_led_driver = { 101 + .driver = { 102 + .name = "max5970-led", 103 + }, 104 + .probe = max5970_led_probe, 105 + }; 106 + module_platform_driver(max5970_led_driver); 107 + 108 + MODULE_AUTHOR("Patrick Rudolph <patrick.rudolph@9elements.com>"); 109 + MODULE_AUTHOR("Naresh Solanki <Naresh.Solanki@9elements.com>"); 110 + MODULE_DESCRIPTION("MAX5970_hot-swap controller LED driver"); 111 + MODULE_LICENSE("GPL");
+584
drivers/leds/leds-sun50i-a100.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (C) 2021-2023 Samuel Holland <samuel@sholland.org> 4 + * 5 + * Partly based on drivers/leds/leds-turris-omnia.c, which is: 6 + * Copyright (c) 2020 by Marek Behún <kabel@kernel.org> 7 + */ 8 + 9 + #include <linux/bitfield.h> 10 + #include <linux/clk.h> 11 + #include <linux/delay.h> 12 + #include <linux/dma-mapping.h> 13 + #include <linux/dmaengine.h> 14 + #include <linux/interrupt.h> 15 + #include <linux/io.h> 16 + #include <linux/led-class-multicolor.h> 17 + #include <linux/leds.h> 18 + #include <linux/mod_devicetable.h> 19 + #include <linux/module.h> 20 + #include <linux/platform_device.h> 21 + #include <linux/pm.h> 22 + #include <linux/property.h> 23 + #include <linux/reset.h> 24 + #include <linux/spinlock.h> 25 + 26 + #define LEDC_CTRL_REG 0x0000 27 + #define LEDC_CTRL_REG_DATA_LENGTH GENMASK(28, 16) 28 + #define LEDC_CTRL_REG_RGB_MODE GENMASK(8, 6) 29 + #define LEDC_CTRL_REG_LEDC_EN BIT(0) 30 + #define LEDC_T01_TIMING_CTRL_REG 0x0004 31 + #define LEDC_T01_TIMING_CTRL_REG_T1H GENMASK(26, 21) 32 + #define LEDC_T01_TIMING_CTRL_REG_T1L GENMASK(20, 16) 33 + #define LEDC_T01_TIMING_CTRL_REG_T0H GENMASK(10, 6) 34 + #define LEDC_T01_TIMING_CTRL_REG_T0L GENMASK(5, 0) 35 + #define LEDC_RESET_TIMING_CTRL_REG 0x000c 36 + #define LEDC_RESET_TIMING_CTRL_REG_TR GENMASK(28, 16) 37 + #define LEDC_RESET_TIMING_CTRL_REG_LED_NUM GENMASK(9, 0) 38 + #define LEDC_DATA_REG 0x0014 39 + #define LEDC_DMA_CTRL_REG 0x0018 40 + #define LEDC_DMA_CTRL_REG_DMA_EN BIT(5) 41 + #define LEDC_DMA_CTRL_REG_FIFO_TRIG_LEVEL GENMASK(4, 0) 42 + #define LEDC_INT_CTRL_REG 0x001c 43 + #define LEDC_INT_CTRL_REG_GLOBAL_INT_EN BIT(5) 44 + #define LEDC_INT_CTRL_REG_FIFO_CPUREQ_INT_EN BIT(1) 45 + #define LEDC_INT_CTRL_REG_TRANS_FINISH_INT_EN BIT(0) 46 + #define LEDC_INT_STS_REG 0x0020 47 + #define LEDC_INT_STS_REG_FIFO_WLW GENMASK(15, 10) 48 + #define LEDC_INT_STS_REG_FIFO_CPUREQ_INT BIT(1) 49 + #define LEDC_INT_STS_REG_TRANS_FINISH_INT BIT(0) 50 + 51 + #define LEDC_FIFO_DEPTH 32U 52 + #define LEDC_MAX_LEDS 1024 53 + #define LEDC_CHANNELS_PER_LED 3 /* RGB */ 54 + 55 + #define LEDS_TO_BYTES(n) ((n) * sizeof(u32)) 56 + 57 + struct sun50i_a100_ledc_led { 58 + struct led_classdev_mc mc_cdev; 59 + struct mc_subled subled_info[LEDC_CHANNELS_PER_LED]; 60 + u32 addr; 61 + }; 62 + 63 + #define to_ledc_led(mc) container_of(mc, struct sun50i_a100_ledc_led, mc_cdev) 64 + 65 + struct sun50i_a100_ledc_timing { 66 + u32 t0h_ns; 67 + u32 t0l_ns; 68 + u32 t1h_ns; 69 + u32 t1l_ns; 70 + u32 treset_ns; 71 + }; 72 + 73 + struct sun50i_a100_ledc { 74 + struct device *dev; 75 + void __iomem *base; 76 + struct clk *bus_clk; 77 + struct clk *mod_clk; 78 + struct reset_control *reset; 79 + 80 + u32 *buffer; 81 + struct dma_chan *dma_chan; 82 + dma_addr_t dma_handle; 83 + unsigned int pio_length; 84 + unsigned int pio_offset; 85 + 86 + spinlock_t lock; 87 + unsigned int next_length; 88 + bool xfer_active; 89 + 90 + u32 format; 91 + struct sun50i_a100_ledc_timing timing; 92 + 93 + u32 max_addr; 94 + u32 num_leds; 95 + struct sun50i_a100_ledc_led leds[] __counted_by(num_leds); 96 + }; 97 + 98 + static int sun50i_a100_ledc_dma_xfer(struct sun50i_a100_ledc *priv, unsigned int length) 99 + { 100 + struct dma_async_tx_descriptor *desc; 101 + dma_cookie_t cookie; 102 + 103 + desc = dmaengine_prep_slave_single(priv->dma_chan, priv->dma_handle, 104 + LEDS_TO_BYTES(length), DMA_MEM_TO_DEV, 0); 105 + if (!desc) 106 + return -ENOMEM; 107 + 108 + cookie = dmaengine_submit(desc); 109 + if (dma_submit_error(cookie)) 110 + return -EIO; 111 + 112 + dma_async_issue_pending(priv->dma_chan); 113 + 114 + return 0; 115 + } 116 + 117 + static void sun50i_a100_ledc_pio_xfer(struct sun50i_a100_ledc *priv, unsigned int fifo_used) 118 + { 119 + unsigned int burst, length, offset; 120 + u32 control; 121 + 122 + length = priv->pio_length; 123 + offset = priv->pio_offset; 124 + burst = min(length, LEDC_FIFO_DEPTH - fifo_used); 125 + 126 + iowrite32_rep(priv->base + LEDC_DATA_REG, priv->buffer + offset, burst); 127 + 128 + if (burst < length) { 129 + priv->pio_length = length - burst; 130 + priv->pio_offset = offset + burst; 131 + 132 + if (!offset) { 133 + control = readl(priv->base + LEDC_INT_CTRL_REG); 134 + control |= LEDC_INT_CTRL_REG_FIFO_CPUREQ_INT_EN; 135 + writel(control, priv->base + LEDC_INT_CTRL_REG); 136 + } 137 + } else { 138 + /* Disable the request IRQ once all data is written. */ 139 + control = readl(priv->base + LEDC_INT_CTRL_REG); 140 + control &= ~LEDC_INT_CTRL_REG_FIFO_CPUREQ_INT_EN; 141 + writel(control, priv->base + LEDC_INT_CTRL_REG); 142 + } 143 + } 144 + 145 + static void sun50i_a100_ledc_start_xfer(struct sun50i_a100_ledc *priv, unsigned int length) 146 + { 147 + bool use_dma = false; 148 + u32 control; 149 + 150 + if (priv->dma_chan && length > LEDC_FIFO_DEPTH) { 151 + int ret; 152 + 153 + ret = sun50i_a100_ledc_dma_xfer(priv, length); 154 + if (ret) 155 + dev_warn(priv->dev, "Failed to set up DMA (%d), using PIO\n", ret); 156 + else 157 + use_dma = true; 158 + } 159 + 160 + /* The DMA trigger level must be at least the burst length. */ 161 + control = FIELD_PREP(LEDC_DMA_CTRL_REG_DMA_EN, use_dma) | 162 + FIELD_PREP_CONST(LEDC_DMA_CTRL_REG_FIFO_TRIG_LEVEL, LEDC_FIFO_DEPTH / 2); 163 + writel(control, priv->base + LEDC_DMA_CTRL_REG); 164 + 165 + control = readl(priv->base + LEDC_CTRL_REG); 166 + control &= ~LEDC_CTRL_REG_DATA_LENGTH; 167 + control |= FIELD_PREP(LEDC_CTRL_REG_DATA_LENGTH, length) | LEDC_CTRL_REG_LEDC_EN; 168 + writel(control, priv->base + LEDC_CTRL_REG); 169 + 170 + if (!use_dma) { 171 + /* The FIFO is empty when starting a new transfer. */ 172 + unsigned int fifo_used = 0; 173 + 174 + priv->pio_length = length; 175 + priv->pio_offset = 0; 176 + 177 + sun50i_a100_ledc_pio_xfer(priv, fifo_used); 178 + } 179 + } 180 + 181 + static irqreturn_t sun50i_a100_ledc_irq(int irq, void *data) 182 + { 183 + struct sun50i_a100_ledc *priv = data; 184 + u32 status; 185 + 186 + status = readl(priv->base + LEDC_INT_STS_REG); 187 + 188 + if (status & LEDC_INT_STS_REG_TRANS_FINISH_INT) { 189 + unsigned int next_length; 190 + 191 + spin_lock(&priv->lock); 192 + 193 + /* If another transfer is queued, dequeue and start it. */ 194 + next_length = priv->next_length; 195 + if (next_length) 196 + priv->next_length = 0; 197 + else 198 + priv->xfer_active = false; 199 + 200 + spin_unlock(&priv->lock); 201 + 202 + if (next_length) 203 + sun50i_a100_ledc_start_xfer(priv, next_length); 204 + } else if (status & LEDC_INT_STS_REG_FIFO_CPUREQ_INT) { 205 + /* Continue the current transfer. */ 206 + sun50i_a100_ledc_pio_xfer(priv, FIELD_GET(LEDC_INT_STS_REG_FIFO_WLW, status)); 207 + } 208 + 209 + /* Clear the W1C status bits. */ 210 + writel(status, priv->base + LEDC_INT_STS_REG); 211 + 212 + return IRQ_HANDLED; 213 + } 214 + 215 + static void sun50i_a100_ledc_brightness_set(struct led_classdev *cdev, 216 + enum led_brightness brightness) 217 + { 218 + struct sun50i_a100_ledc *priv = dev_get_drvdata(cdev->dev->parent); 219 + struct led_classdev_mc *mc_cdev = lcdev_to_mccdev(cdev); 220 + struct sun50i_a100_ledc_led *led = to_ledc_led(mc_cdev); 221 + unsigned int next_length; 222 + unsigned long flags; 223 + bool xfer_active; 224 + 225 + led_mc_calc_color_components(mc_cdev, brightness); 226 + 227 + priv->buffer[led->addr] = led->subled_info[0].brightness << 16 | 228 + led->subled_info[1].brightness << 8 | 229 + led->subled_info[2].brightness; 230 + 231 + spin_lock_irqsave(&priv->lock, flags); 232 + 233 + /* Start, enqueue, or extend an enqueued transfer, as appropriate. */ 234 + next_length = max(priv->next_length, led->addr + 1); 235 + xfer_active = priv->xfer_active; 236 + if (xfer_active) 237 + priv->next_length = next_length; 238 + else 239 + priv->xfer_active = true; 240 + 241 + spin_unlock_irqrestore(&priv->lock, flags); 242 + 243 + if (!xfer_active) 244 + sun50i_a100_ledc_start_xfer(priv, next_length); 245 + } 246 + 247 + static const char *const sun50i_a100_ledc_formats[] = { 248 + "rgb", "rbg", "grb", "gbr", "brg", "bgr", 249 + }; 250 + 251 + static int sun50i_a100_ledc_parse_format(struct device *dev, 252 + struct sun50i_a100_ledc *priv) 253 + { 254 + const char *format = "grb"; 255 + u32 i; 256 + 257 + device_property_read_string(dev, "allwinner,pixel-format", &format); 258 + 259 + for (i = 0; i < ARRAY_SIZE(sun50i_a100_ledc_formats); i++) { 260 + if (!strcmp(format, sun50i_a100_ledc_formats[i])) { 261 + priv->format = i; 262 + return 0; 263 + } 264 + } 265 + 266 + return dev_err_probe(dev, -EINVAL, "Bad pixel format '%s'\n", format); 267 + } 268 + 269 + static void sun50i_a100_ledc_set_format(struct sun50i_a100_ledc *priv) 270 + { 271 + u32 control; 272 + 273 + control = readl(priv->base + LEDC_CTRL_REG); 274 + control &= ~LEDC_CTRL_REG_RGB_MODE; 275 + control |= FIELD_PREP(LEDC_CTRL_REG_RGB_MODE, priv->format); 276 + writel(control, priv->base + LEDC_CTRL_REG); 277 + } 278 + 279 + static const struct sun50i_a100_ledc_timing sun50i_a100_ledc_default_timing = { 280 + .t0h_ns = 336, 281 + .t0l_ns = 840, 282 + .t1h_ns = 882, 283 + .t1l_ns = 294, 284 + .treset_ns = 300000, 285 + }; 286 + 287 + static int sun50i_a100_ledc_parse_timing(struct device *dev, 288 + struct sun50i_a100_ledc *priv) 289 + { 290 + struct sun50i_a100_ledc_timing *timing = &priv->timing; 291 + 292 + *timing = sun50i_a100_ledc_default_timing; 293 + 294 + device_property_read_u32(dev, "allwinner,t0h-ns", &timing->t0h_ns); 295 + device_property_read_u32(dev, "allwinner,t0l-ns", &timing->t0l_ns); 296 + device_property_read_u32(dev, "allwinner,t1h-ns", &timing->t1h_ns); 297 + device_property_read_u32(dev, "allwinner,t1l-ns", &timing->t1l_ns); 298 + device_property_read_u32(dev, "allwinner,treset-ns", &timing->treset_ns); 299 + 300 + return 0; 301 + } 302 + 303 + static void sun50i_a100_ledc_set_timing(struct sun50i_a100_ledc *priv) 304 + { 305 + const struct sun50i_a100_ledc_timing *timing = &priv->timing; 306 + unsigned long mod_freq = clk_get_rate(priv->mod_clk); 307 + u32 cycle_ns; 308 + u32 control; 309 + 310 + if (!mod_freq) 311 + return; 312 + 313 + cycle_ns = NSEC_PER_SEC / mod_freq; 314 + control = FIELD_PREP(LEDC_T01_TIMING_CTRL_REG_T1H, timing->t1h_ns / cycle_ns) | 315 + FIELD_PREP(LEDC_T01_TIMING_CTRL_REG_T1L, timing->t1l_ns / cycle_ns) | 316 + FIELD_PREP(LEDC_T01_TIMING_CTRL_REG_T0H, timing->t0h_ns / cycle_ns) | 317 + FIELD_PREP(LEDC_T01_TIMING_CTRL_REG_T0L, timing->t0l_ns / cycle_ns); 318 + writel(control, priv->base + LEDC_T01_TIMING_CTRL_REG); 319 + 320 + control = FIELD_PREP(LEDC_RESET_TIMING_CTRL_REG_TR, timing->treset_ns / cycle_ns) | 321 + FIELD_PREP(LEDC_RESET_TIMING_CTRL_REG_LED_NUM, priv->max_addr); 322 + writel(control, priv->base + LEDC_RESET_TIMING_CTRL_REG); 323 + } 324 + 325 + static int sun50i_a100_ledc_resume(struct device *dev) 326 + { 327 + struct sun50i_a100_ledc *priv = dev_get_drvdata(dev); 328 + int ret; 329 + 330 + ret = reset_control_deassert(priv->reset); 331 + if (ret) 332 + return ret; 333 + 334 + ret = clk_prepare_enable(priv->bus_clk); 335 + if (ret) 336 + goto err_assert_reset; 337 + 338 + ret = clk_prepare_enable(priv->mod_clk); 339 + if (ret) 340 + goto err_disable_bus_clk; 341 + 342 + sun50i_a100_ledc_set_format(priv); 343 + sun50i_a100_ledc_set_timing(priv); 344 + 345 + writel(LEDC_INT_CTRL_REG_GLOBAL_INT_EN | LEDC_INT_CTRL_REG_TRANS_FINISH_INT_EN, 346 + priv->base + LEDC_INT_CTRL_REG); 347 + 348 + return 0; 349 + 350 + err_disable_bus_clk: 351 + clk_disable_unprepare(priv->bus_clk); 352 + err_assert_reset: 353 + reset_control_assert(priv->reset); 354 + 355 + return ret; 356 + } 357 + 358 + static int sun50i_a100_ledc_suspend(struct device *dev) 359 + { 360 + struct sun50i_a100_ledc *priv = dev_get_drvdata(dev); 361 + 362 + /* Wait for all transfers to complete. */ 363 + for (;;) { 364 + unsigned long flags; 365 + bool xfer_active; 366 + 367 + spin_lock_irqsave(&priv->lock, flags); 368 + xfer_active = priv->xfer_active; 369 + spin_unlock_irqrestore(&priv->lock, flags); 370 + if (!xfer_active) 371 + break; 372 + 373 + msleep(1); 374 + } 375 + 376 + clk_disable_unprepare(priv->mod_clk); 377 + clk_disable_unprepare(priv->bus_clk); 378 + reset_control_assert(priv->reset); 379 + 380 + return 0; 381 + } 382 + 383 + static void sun50i_a100_ledc_dma_cleanup(void *data) 384 + { 385 + struct sun50i_a100_ledc *priv = data; 386 + 387 + dma_release_channel(priv->dma_chan); 388 + } 389 + 390 + static int sun50i_a100_ledc_probe(struct platform_device *pdev) 391 + { 392 + struct dma_slave_config dma_cfg = {}; 393 + struct led_init_data init_data = {}; 394 + struct sun50i_a100_ledc_led *led; 395 + struct device *dev = &pdev->dev; 396 + struct sun50i_a100_ledc *priv; 397 + struct fwnode_handle *child; 398 + struct resource *mem; 399 + u32 max_addr = 0; 400 + u32 num_leds = 0; 401 + int irq, ret; 402 + 403 + /* 404 + * The maximum LED address must be known in sun50i_a100_ledc_resume() before 405 + * class device registration, so parse and validate the subnodes up front. 406 + */ 407 + device_for_each_child_node(dev, child) { 408 + u32 addr, color; 409 + 410 + ret = fwnode_property_read_u32(child, "reg", &addr); 411 + if (ret || addr >= LEDC_MAX_LEDS) { 412 + fwnode_handle_put(child); 413 + return dev_err_probe(dev, -EINVAL, "'reg' must be between 0 and %d\n", 414 + LEDC_MAX_LEDS - 1); 415 + } 416 + 417 + ret = fwnode_property_read_u32(child, "color", &color); 418 + if (ret || color != LED_COLOR_ID_RGB) { 419 + fwnode_handle_put(child); 420 + return dev_err_probe(dev, -EINVAL, "'color' must be LED_COLOR_ID_RGB\n"); 421 + } 422 + 423 + max_addr = max(max_addr, addr); 424 + num_leds++; 425 + } 426 + 427 + if (!num_leds) 428 + return -ENODEV; 429 + 430 + priv = devm_kzalloc(dev, struct_size(priv, leds, num_leds), GFP_KERNEL); 431 + if (!priv) 432 + return -ENOMEM; 433 + 434 + priv->dev = dev; 435 + priv->max_addr = max_addr; 436 + priv->num_leds = num_leds; 437 + spin_lock_init(&priv->lock); 438 + dev_set_drvdata(dev, priv); 439 + 440 + ret = sun50i_a100_ledc_parse_format(dev, priv); 441 + if (ret) 442 + return ret; 443 + 444 + ret = sun50i_a100_ledc_parse_timing(dev, priv); 445 + if (ret) 446 + return ret; 447 + 448 + priv->base = devm_platform_get_and_ioremap_resource(pdev, 0, &mem); 449 + if (IS_ERR(priv->base)) 450 + return PTR_ERR(priv->base); 451 + 452 + priv->bus_clk = devm_clk_get(dev, "bus"); 453 + if (IS_ERR(priv->bus_clk)) 454 + return PTR_ERR(priv->bus_clk); 455 + 456 + priv->mod_clk = devm_clk_get(dev, "mod"); 457 + if (IS_ERR(priv->mod_clk)) 458 + return PTR_ERR(priv->mod_clk); 459 + 460 + priv->reset = devm_reset_control_get_exclusive(dev, NULL); 461 + if (IS_ERR(priv->reset)) 462 + return PTR_ERR(priv->reset); 463 + 464 + priv->dma_chan = dma_request_chan(dev, "tx"); 465 + if (IS_ERR(priv->dma_chan)) { 466 + if (PTR_ERR(priv->dma_chan) != -ENODEV) 467 + return PTR_ERR(priv->dma_chan); 468 + 469 + priv->dma_chan = NULL; 470 + 471 + priv->buffer = devm_kzalloc(dev, LEDS_TO_BYTES(LEDC_MAX_LEDS), GFP_KERNEL); 472 + if (!priv->buffer) 473 + return -ENOMEM; 474 + } else { 475 + ret = devm_add_action_or_reset(dev, sun50i_a100_ledc_dma_cleanup, priv); 476 + if (ret) 477 + return ret; 478 + 479 + dma_cfg.dst_addr = mem->start + LEDC_DATA_REG; 480 + dma_cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 481 + dma_cfg.dst_maxburst = LEDC_FIFO_DEPTH / 2; 482 + 483 + ret = dmaengine_slave_config(priv->dma_chan, &dma_cfg); 484 + if (ret) 485 + return ret; 486 + 487 + priv->buffer = dmam_alloc_attrs(dmaengine_get_dma_device(priv->dma_chan), 488 + LEDS_TO_BYTES(LEDC_MAX_LEDS), &priv->dma_handle, 489 + GFP_KERNEL, DMA_ATTR_WRITE_COMBINE); 490 + if (!priv->buffer) 491 + return -ENOMEM; 492 + } 493 + 494 + irq = platform_get_irq(pdev, 0); 495 + if (irq < 0) 496 + return irq; 497 + 498 + ret = devm_request_irq(dev, irq, sun50i_a100_ledc_irq, 0, dev_name(dev), priv); 499 + if (ret) 500 + return ret; 501 + 502 + ret = sun50i_a100_ledc_resume(dev); 503 + if (ret) 504 + return ret; 505 + 506 + led = priv->leds; 507 + device_for_each_child_node(dev, child) { 508 + struct led_classdev *cdev; 509 + 510 + /* The node was already validated above. */ 511 + fwnode_property_read_u32(child, "reg", &led->addr); 512 + 513 + led->subled_info[0].color_index = LED_COLOR_ID_RED; 514 + led->subled_info[0].channel = 0; 515 + led->subled_info[1].color_index = LED_COLOR_ID_GREEN; 516 + led->subled_info[1].channel = 1; 517 + led->subled_info[2].color_index = LED_COLOR_ID_BLUE; 518 + led->subled_info[2].channel = 2; 519 + 520 + led->mc_cdev.num_colors = ARRAY_SIZE(led->subled_info); 521 + led->mc_cdev.subled_info = led->subled_info; 522 + 523 + cdev = &led->mc_cdev.led_cdev; 524 + cdev->max_brightness = U8_MAX; 525 + cdev->brightness_set = sun50i_a100_ledc_brightness_set; 526 + 527 + init_data.fwnode = child; 528 + 529 + ret = led_classdev_multicolor_register_ext(dev, &led->mc_cdev, &init_data); 530 + if (ret) { 531 + dev_err_probe(dev, ret, "Failed to register multicolor LED %u", led->addr); 532 + goto err_put_child; 533 + } 534 + 535 + led++; 536 + } 537 + 538 + dev_info(dev, "Registered %u LEDs\n", num_leds); 539 + 540 + return 0; 541 + 542 + err_put_child: 543 + fwnode_handle_put(child); 544 + while (led-- > priv->leds) 545 + led_classdev_multicolor_unregister(&led->mc_cdev); 546 + sun50i_a100_ledc_suspend(&pdev->dev); 547 + 548 + return ret; 549 + } 550 + 551 + static void sun50i_a100_ledc_remove(struct platform_device *pdev) 552 + { 553 + struct sun50i_a100_ledc *priv = platform_get_drvdata(pdev); 554 + 555 + for (u32 i = 0; i < priv->num_leds; i++) 556 + led_classdev_multicolor_unregister(&priv->leds[i].mc_cdev); 557 + sun50i_a100_ledc_suspend(&pdev->dev); 558 + } 559 + 560 + static const struct of_device_id sun50i_a100_ledc_of_match[] = { 561 + { .compatible = "allwinner,sun50i-a100-ledc" }, 562 + {} 563 + }; 564 + MODULE_DEVICE_TABLE(of, sun50i_a100_ledc_of_match); 565 + 566 + static DEFINE_SIMPLE_DEV_PM_OPS(sun50i_a100_ledc_pm, 567 + sun50i_a100_ledc_suspend, 568 + sun50i_a100_ledc_resume); 569 + 570 + static struct platform_driver sun50i_a100_ledc_driver = { 571 + .probe = sun50i_a100_ledc_probe, 572 + .remove_new = sun50i_a100_ledc_remove, 573 + .shutdown = sun50i_a100_ledc_remove, 574 + .driver = { 575 + .name = "sun50i-a100-ledc", 576 + .of_match_table = sun50i_a100_ledc_of_match, 577 + .pm = pm_ptr(&sun50i_a100_ledc_pm), 578 + }, 579 + }; 580 + module_platform_driver(sun50i_a100_ledc_driver); 581 + 582 + MODULE_AUTHOR("Samuel Holland <samuel@sholland.org>"); 583 + MODULE_DESCRIPTION("Allwinner A100 LED controller driver"); 584 + MODULE_LICENSE("GPL");
+2 -1
drivers/leds/leds-syscon.c
··· 81 81 82 82 sled->map = map; 83 83 84 - if (of_property_read_u32(np, "offset", &sled->offset)) 84 + if (of_property_read_u32(np, "reg", &sled->offset) && 85 + of_property_read_u32(np, "offset", &sled->offset)) 85 86 return -EINVAL; 86 87 if (of_property_read_u32(np, "mask", &sled->mask)) 87 88 return -EINVAL;
+4 -26
drivers/leds/leds-tca6507.c
··· 638 638 tca->gpio.direction_output = tca6507_gpio_direction_output; 639 639 tca->gpio.set = tca6507_gpio_set_value; 640 640 tca->gpio.parent = dev; 641 - err = gpiochip_add_data(&tca->gpio, tca); 641 + err = devm_gpiochip_add_data(dev, &tca->gpio, tca); 642 642 if (err) { 643 643 tca->gpio.ngpio = 0; 644 644 return err; 645 645 } 646 646 return 0; 647 - } 648 - 649 - static void tca6507_remove_gpio(struct tca6507_chip *tca) 650 - { 651 - if (tca->gpio.ngpio) 652 - gpiochip_remove(&tca->gpio); 653 647 } 654 648 #else /* CONFIG_GPIOLIB */ 655 649 static int tca6507_probe_gpios(struct device *dev, ··· 651 657 struct tca6507_platform_data *pdata) 652 658 { 653 659 return 0; 654 - } 655 - static void tca6507_remove_gpio(struct tca6507_chip *tca) 656 - { 657 660 } 658 661 #endif /* CONFIG_GPIOLIB */ 659 662 ··· 753 762 l->led_cdev.brightness_set = tca6507_brightness_set; 754 763 l->led_cdev.blink_set = tca6507_blink_set; 755 764 l->bank = -1; 756 - err = led_classdev_register(dev, &l->led_cdev); 765 + err = devm_led_classdev_register(dev, &l->led_cdev); 757 766 if (err < 0) 758 - goto exit; 767 + return err; 759 768 } 760 769 } 761 770 err = tca6507_probe_gpios(dev, tca, pdata); 762 771 if (err) 763 - goto exit; 772 + return err; 764 773 /* set all registers to known state - zero */ 765 774 tca->reg_set = 0x7f; 766 775 schedule_work(&tca->work); 767 776 768 777 return 0; 769 - exit: 770 - while (i--) { 771 - if (tca->leds[i].led_cdev.name) 772 - led_classdev_unregister(&tca->leds[i].led_cdev); 773 - } 774 - return err; 775 778 } 776 779 777 780 static void tca6507_remove(struct i2c_client *client) 778 781 { 779 - int i; 780 782 struct tca6507_chip *tca = i2c_get_clientdata(client); 781 - struct tca6507_led *tca_leds = tca->leds; 782 783 783 - for (i = 0; i < NUM_LEDS; i++) { 784 - if (tca_leds[i].led_cdev.name) 785 - led_classdev_unregister(&tca_leds[i].led_cdev); 786 - } 787 - tca6507_remove_gpio(tca); 788 784 cancel_work_sync(&tca->work); 789 785 } 790 786
+1 -1
drivers/leds/rgb/Kconfig
··· 4 4 5 5 config LEDS_GROUP_MULTICOLOR 6 6 tristate "LEDs group multi-color support" 7 - depends on OF || COMPILE_TEST 7 + depends on OF 8 8 help 9 9 This option enables support for monochrome LEDs that are grouped 10 10 into multicolor LEDs which is useful in the case where LEDs of
+26 -37
drivers/leds/rgb/leds-qcom-lpg.c
··· 552 552 ret = count; 553 553 goto err_malformed; 554 554 } else if (count != lpg->data->num_channels * 2) { 555 - dev_err(lpg->dev, "qcom,dtest needs to be %d items\n", 556 - lpg->data->num_channels * 2); 557 - return -EINVAL; 555 + return dev_err_probe(lpg->dev, -EINVAL, 556 + "qcom,dtest needs to be %d items\n", 557 + lpg->data->num_channels * 2); 558 558 } 559 559 560 560 for (i = 0; i < lpg->data->num_channels; i++) { ··· 574 574 return 0; 575 575 576 576 err_malformed: 577 - dev_err(lpg->dev, "malformed qcom,dtest\n"); 578 - return ret; 577 + return dev_err_probe(lpg->dev, ret, "malformed qcom,dtest\n"); 579 578 } 580 579 581 580 static void lpg_apply_dtest(struct lpg_channel *chan) ··· 976 977 return lpg_pattern_clear(led); 977 978 } 978 979 980 + static inline struct lpg *lpg_pwm_from_chip(struct pwm_chip *chip) 981 + { 982 + return container_of(chip, struct lpg, pwm); 983 + } 984 + 979 985 static int lpg_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) 980 986 { 981 - struct lpg *lpg = container_of(chip, struct lpg, pwm); 987 + struct lpg *lpg = lpg_pwm_from_chip(chip); 982 988 struct lpg_channel *chan = &lpg->channels[pwm->hwpwm]; 983 989 984 990 return chan->in_use ? -EBUSY : 0; ··· 999 995 static int lpg_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, 1000 996 const struct pwm_state *state) 1001 997 { 1002 - struct lpg *lpg = container_of(chip, struct lpg, pwm); 998 + struct lpg *lpg = lpg_pwm_from_chip(chip); 1003 999 struct lpg_channel *chan = &lpg->channels[pwm->hwpwm]; 1004 1000 int ret = 0; 1005 1001 ··· 1030 1026 static int lpg_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, 1031 1027 struct pwm_state *state) 1032 1028 { 1033 - struct lpg *lpg = container_of(chip, struct lpg, pwm); 1029 + struct lpg *lpg = lpg_pwm_from_chip(chip); 1034 1030 struct lpg_channel *chan = &lpg->channels[pwm->hwpwm]; 1035 1031 unsigned int resolution; 1036 1032 unsigned int pre_div; ··· 1099 1095 lpg->pwm.npwm = lpg->num_channels; 1100 1096 lpg->pwm.ops = &lpg_pwm_ops; 1101 1097 1102 - ret = pwmchip_add(&lpg->pwm); 1098 + ret = devm_pwmchip_add(lpg->dev, &lpg->pwm); 1103 1099 if (ret) 1104 - dev_err(lpg->dev, "failed to add PWM chip: ret %d\n", ret); 1100 + dev_err_probe(lpg->dev, ret, "failed to add PWM chip\n"); 1105 1101 1106 1102 return ret; 1107 1103 } ··· 1115 1111 int ret; 1116 1112 1117 1113 ret = of_property_read_u32(np, "reg", &reg); 1118 - if (ret || !reg || reg > lpg->num_channels) { 1119 - dev_err(lpg->dev, "invalid \"reg\" of %pOFn\n", np); 1120 - return -EINVAL; 1121 - } 1114 + if (ret || !reg || reg > lpg->num_channels) 1115 + return dev_err_probe(lpg->dev, -EINVAL, "invalid \"reg\" of %pOFn\n", np); 1122 1116 1123 1117 chan = &lpg->channels[reg - 1]; 1124 1118 chan->in_use = true; 1125 1119 1126 1120 ret = of_property_read_u32(np, "color", &color); 1127 - if (ret < 0 && ret != -EINVAL) { 1128 - dev_err(lpg->dev, "failed to parse \"color\" of %pOF\n", np); 1129 - return ret; 1130 - } 1121 + if (ret < 0 && ret != -EINVAL) 1122 + return dev_err_probe(lpg->dev, ret, 1123 + "failed to parse \"color\" of %pOF\n", np); 1131 1124 1132 1125 chan->color = color; 1133 1126 ··· 1147 1146 int i; 1148 1147 1149 1148 ret = of_property_read_u32(np, "color", &color); 1150 - if (ret < 0 && ret != -EINVAL) { 1151 - dev_err(lpg->dev, "failed to parse \"color\" of %pOF\n", np); 1152 - return ret; 1153 - } 1149 + if (ret < 0 && ret != -EINVAL) 1150 + return dev_err_probe(lpg->dev, ret, 1151 + "failed to parse \"color\" of %pOF\n", np); 1154 1152 1155 1153 if (color == LED_COLOR_ID_RGB) 1156 1154 num_channels = of_get_available_child_count(np); ··· 1226 1226 else 1227 1227 ret = devm_led_classdev_register_ext(lpg->dev, &led->cdev, &init_data); 1228 1228 if (ret) 1229 - dev_err(lpg->dev, "unable to register %s\n", cdev->name); 1229 + dev_err_probe(lpg->dev, ret, "unable to register %s\n", cdev->name); 1230 1230 1231 1231 return ret; 1232 1232 } ··· 1272 1272 1273 1273 if (lpg->triled_has_src_sel) { 1274 1274 ret = of_property_read_u32(np, "qcom,power-source", &lpg->triled_src); 1275 - if (ret || lpg->triled_src == 2 || lpg->triled_src > 3) { 1276 - dev_err(lpg->dev, "invalid power source\n"); 1277 - return -EINVAL; 1278 - } 1275 + if (ret || lpg->triled_src == 2 || lpg->triled_src > 3) 1276 + return dev_err_probe(lpg->dev, -EINVAL, 1277 + "invalid power source\n"); 1279 1278 } 1280 1279 1281 1280 /* Disable automatic trickle charge LED */ ··· 1323 1324 if (!lpg->data) 1324 1325 return -EINVAL; 1325 1326 1326 - platform_set_drvdata(pdev, lpg); 1327 - 1328 1327 lpg->dev = &pdev->dev; 1329 1328 mutex_init(&lpg->lock); 1330 1329 ··· 1358 1361 lpg_apply_dtest(&lpg->channels[i]); 1359 1362 1360 1363 return lpg_add_pwm(lpg); 1361 - } 1362 - 1363 - static void lpg_remove(struct platform_device *pdev) 1364 - { 1365 - struct lpg *lpg = platform_get_drvdata(pdev); 1366 - 1367 - pwmchip_remove(&lpg->pwm); 1368 1364 } 1369 1365 1370 1366 static const struct lpg_data pm8916_pwm_data = { ··· 1519 1529 1520 1530 static struct platform_driver lpg_driver = { 1521 1531 .probe = lpg_probe, 1522 - .remove_new = lpg_remove, 1523 1532 .driver = { 1524 1533 .name = "qcom-spmi-lpg", 1525 1534 .of_match_table = lpg_of_table,
+11 -15
drivers/leds/trigger/ledtrig-gpio.c
··· 41 41 return IRQ_HANDLED; 42 42 } 43 43 44 - static ssize_t gpio_trig_brightness_show(struct device *dev, 44 + static ssize_t desired_brightness_show(struct device *dev, 45 45 struct device_attribute *attr, char *buf) 46 46 { 47 47 struct gpio_trig_data *gpio_data = led_trigger_get_drvdata(dev); 48 48 49 - return sprintf(buf, "%u\n", gpio_data->desired_brightness); 49 + return sysfs_emit(buf, "%u\n", gpio_data->desired_brightness); 50 50 } 51 51 52 - static ssize_t gpio_trig_brightness_store(struct device *dev, 52 + static ssize_t desired_brightness_store(struct device *dev, 53 53 struct device_attribute *attr, const char *buf, size_t n) 54 54 { 55 55 struct gpio_trig_data *gpio_data = led_trigger_get_drvdata(dev); 56 - unsigned desired_brightness; 56 + u8 desired_brightness; 57 57 int ret; 58 58 59 - ret = sscanf(buf, "%u", &desired_brightness); 60 - if (ret < 1 || desired_brightness > 255) { 61 - dev_err(dev, "invalid value\n"); 62 - return -EINVAL; 63 - } 59 + ret = kstrtou8(buf, 10, &desired_brightness); 60 + if (ret) 61 + return ret; 64 62 65 63 gpio_data->desired_brightness = desired_brightness; 66 64 67 65 return n; 68 66 } 69 - static DEVICE_ATTR(desired_brightness, 0644, gpio_trig_brightness_show, 70 - gpio_trig_brightness_store); 67 + static DEVICE_ATTR_RW(desired_brightness); 71 68 72 69 static struct attribute *gpio_trig_attrs[] = { 73 70 &dev_attr_desired_brightness.attr, ··· 86 89 * The generic property "trigger-sources" is followed, 87 90 * and we hope that this is a GPIO. 88 91 */ 89 - gpio_data->gpiod = fwnode_gpiod_get_index(dev->fwnode, 90 - "trigger-sources", 91 - 0, GPIOD_IN, 92 - "led-trigger"); 92 + gpio_data->gpiod = gpiod_get_optional(dev, "trigger-sources", GPIOD_IN); 93 93 if (IS_ERR(gpio_data->gpiod)) { 94 94 ret = PTR_ERR(gpio_data->gpiod); 95 95 kfree(gpio_data); ··· 97 103 kfree(gpio_data); 98 104 return -EINVAL; 99 105 } 106 + 107 + gpiod_set_consumer_name(gpio_data->gpiod, "led-trigger"); 100 108 101 109 gpio_data->led = led; 102 110 led_set_trigger_data(led, gpio_data);
+46 -1
drivers/leds/trigger/ledtrig-netdev.c
··· 38 38 * tx - LED blinks on transmitted data 39 39 * rx - LED blinks on receive data 40 40 * 41 + * Note: If the user selects a mode that is not supported by hw, default 42 + * behavior is to fall back to software control of the LED. However not every 43 + * hw supports software control. LED callbacks brightness_set() and 44 + * brightness_set_blocking() are NULL in this case. hw_control_is_supported() 45 + * should use available means supported by hw to inform the user that selected 46 + * mode isn't supported by hw. This could be switching off the LED or any 47 + * hw blink mode. If software control fallback isn't possible, we return 48 + * -EOPNOTSUPP to the user, but still store the selected mode. This is needed 49 + * in case an intermediate unsupported mode is necessary to switch from one 50 + * supported mode to another. 41 51 */ 42 52 43 53 struct led_netdev_data { ··· 107 97 108 98 if (test_bit(TRIGGER_NETDEV_LINK_1000, &trigger_data->mode) && 109 99 trigger_data->link_speed == SPEED_1000) 100 + blink_on = true; 101 + 102 + if (test_bit(TRIGGER_NETDEV_LINK_2500, &trigger_data->mode) && 103 + trigger_data->link_speed == SPEED_2500) 104 + blink_on = true; 105 + 106 + if (test_bit(TRIGGER_NETDEV_LINK_5000, &trigger_data->mode) && 107 + trigger_data->link_speed == SPEED_5000) 108 + blink_on = true; 109 + 110 + if (test_bit(TRIGGER_NETDEV_LINK_10000, &trigger_data->mode) && 111 + trigger_data->link_speed == SPEED_10000) 110 112 blink_on = true; 111 113 112 114 if (test_bit(TRIGGER_NETDEV_HALF_DUPLEX, &trigger_data->mode) && ··· 311 289 case TRIGGER_NETDEV_LINK_10: 312 290 case TRIGGER_NETDEV_LINK_100: 313 291 case TRIGGER_NETDEV_LINK_1000: 292 + case TRIGGER_NETDEV_LINK_2500: 293 + case TRIGGER_NETDEV_LINK_5000: 294 + case TRIGGER_NETDEV_LINK_10000: 314 295 case TRIGGER_NETDEV_HALF_DUPLEX: 315 296 case TRIGGER_NETDEV_FULL_DUPLEX: 316 297 case TRIGGER_NETDEV_TX: ··· 331 306 size_t size, enum led_trigger_netdev_modes attr) 332 307 { 333 308 struct led_netdev_data *trigger_data = led_trigger_get_drvdata(dev); 309 + struct led_classdev *led_cdev = trigger_data->led_cdev; 334 310 unsigned long state, mode = trigger_data->mode; 335 311 int ret; 336 312 int bit; ··· 345 319 case TRIGGER_NETDEV_LINK_10: 346 320 case TRIGGER_NETDEV_LINK_100: 347 321 case TRIGGER_NETDEV_LINK_1000: 322 + case TRIGGER_NETDEV_LINK_2500: 323 + case TRIGGER_NETDEV_LINK_5000: 324 + case TRIGGER_NETDEV_LINK_10000: 348 325 case TRIGGER_NETDEV_HALF_DUPLEX: 349 326 case TRIGGER_NETDEV_FULL_DUPLEX: 350 327 case TRIGGER_NETDEV_TX: ··· 366 337 if (test_bit(TRIGGER_NETDEV_LINK, &mode) && 367 338 (test_bit(TRIGGER_NETDEV_LINK_10, &mode) || 368 339 test_bit(TRIGGER_NETDEV_LINK_100, &mode) || 369 - test_bit(TRIGGER_NETDEV_LINK_1000, &mode))) 340 + test_bit(TRIGGER_NETDEV_LINK_1000, &mode) || 341 + test_bit(TRIGGER_NETDEV_LINK_2500, &mode) || 342 + test_bit(TRIGGER_NETDEV_LINK_5000, &mode) || 343 + test_bit(TRIGGER_NETDEV_LINK_10000, &mode))) 370 344 return -EINVAL; 371 345 372 346 cancel_delayed_work_sync(&trigger_data->work); 373 347 374 348 trigger_data->mode = mode; 375 349 trigger_data->hw_control = can_hw_control(trigger_data); 350 + 351 + if (!led_cdev->brightness_set && !led_cdev->brightness_set_blocking && 352 + !trigger_data->hw_control) 353 + return -EOPNOTSUPP; 376 354 377 355 set_baseline_state(trigger_data); 378 356 ··· 403 367 DEFINE_NETDEV_TRIGGER(link_10, TRIGGER_NETDEV_LINK_10); 404 368 DEFINE_NETDEV_TRIGGER(link_100, TRIGGER_NETDEV_LINK_100); 405 369 DEFINE_NETDEV_TRIGGER(link_1000, TRIGGER_NETDEV_LINK_1000); 370 + DEFINE_NETDEV_TRIGGER(link_2500, TRIGGER_NETDEV_LINK_2500); 371 + DEFINE_NETDEV_TRIGGER(link_5000, TRIGGER_NETDEV_LINK_5000); 372 + DEFINE_NETDEV_TRIGGER(link_10000, TRIGGER_NETDEV_LINK_10000); 406 373 DEFINE_NETDEV_TRIGGER(half_duplex, TRIGGER_NETDEV_HALF_DUPLEX); 407 374 DEFINE_NETDEV_TRIGGER(full_duplex, TRIGGER_NETDEV_FULL_DUPLEX); 408 375 DEFINE_NETDEV_TRIGGER(tx, TRIGGER_NETDEV_TX); ··· 464 425 &dev_attr_link_10.attr, 465 426 &dev_attr_link_100.attr, 466 427 &dev_attr_link_1000.attr, 428 + &dev_attr_link_2500.attr, 429 + &dev_attr_link_5000.attr, 430 + &dev_attr_link_10000.attr, 467 431 &dev_attr_full_duplex.attr, 468 432 &dev_attr_half_duplex.attr, 469 433 &dev_attr_rx.attr, ··· 564 522 test_bit(TRIGGER_NETDEV_LINK_10, &trigger_data->mode) || 565 523 test_bit(TRIGGER_NETDEV_LINK_100, &trigger_data->mode) || 566 524 test_bit(TRIGGER_NETDEV_LINK_1000, &trigger_data->mode) || 525 + test_bit(TRIGGER_NETDEV_LINK_2500, &trigger_data->mode) || 526 + test_bit(TRIGGER_NETDEV_LINK_5000, &trigger_data->mode) || 527 + test_bit(TRIGGER_NETDEV_LINK_10000, &trigger_data->mode) || 567 528 test_bit(TRIGGER_NETDEV_HALF_DUPLEX, &trigger_data->mode) || 568 529 test_bit(TRIGGER_NETDEV_FULL_DUPLEX, &trigger_data->mode); 569 530 interval = jiffies_to_msecs(
+4 -1
drivers/leds/trigger/ledtrig-panic.c
··· 64 64 65 65 static int __init ledtrig_panic_init(void) 66 66 { 67 + led_trigger_register_simple("panic", &trigger); 68 + if (!trigger) 69 + return -ENOMEM; 70 + 67 71 atomic_notifier_chain_register(&panic_notifier_list, 68 72 &led_trigger_panic_nb); 69 73 70 - led_trigger_register_simple("panic", &trigger); 71 74 panic_blink = led_panic_blink; 72 75 return 0; 73 76 }
+210 -37
drivers/leds/trigger/ledtrig-tty.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 2 3 + #include <linux/completion.h> 3 4 #include <linux/delay.h> 4 5 #include <linux/leds.h> 5 6 #include <linux/module.h> ··· 13 12 struct ledtrig_tty_data { 14 13 struct led_classdev *led_cdev; 15 14 struct delayed_work dwork; 16 - struct mutex mutex; 15 + struct completion sysfs; 17 16 const char *ttyname; 18 17 struct tty_struct *tty; 19 18 int rx, tx; 19 + bool mode_rx; 20 + bool mode_tx; 21 + bool mode_cts; 22 + bool mode_dsr; 23 + bool mode_dcd; 24 + bool mode_rng; 20 25 }; 21 26 22 - static void ledtrig_tty_restart(struct ledtrig_tty_data *trigger_data) 27 + /* Indicates which state the LED should now display */ 28 + enum led_trigger_tty_state { 29 + TTY_LED_BLINK, 30 + TTY_LED_ENABLE, 31 + TTY_LED_DISABLE, 32 + }; 33 + 34 + enum led_trigger_tty_modes { 35 + TRIGGER_TTY_RX = 0, 36 + TRIGGER_TTY_TX, 37 + TRIGGER_TTY_CTS, 38 + TRIGGER_TTY_DSR, 39 + TRIGGER_TTY_DCD, 40 + TRIGGER_TTY_RNG, 41 + }; 42 + 43 + static int ledtrig_tty_wait_for_completion(struct device *dev) 23 44 { 24 - schedule_delayed_work(&trigger_data->dwork, 0); 45 + struct ledtrig_tty_data *trigger_data = led_trigger_get_drvdata(dev); 46 + int ret; 47 + 48 + ret = wait_for_completion_timeout(&trigger_data->sysfs, 49 + msecs_to_jiffies(LEDTRIG_TTY_INTERVAL * 20)); 50 + if (ret == 0) 51 + return -ETIMEDOUT; 52 + 53 + return ret; 25 54 } 26 55 27 56 static ssize_t ttyname_show(struct device *dev, ··· 59 28 { 60 29 struct ledtrig_tty_data *trigger_data = led_trigger_get_drvdata(dev); 61 30 ssize_t len = 0; 31 + int completion; 62 32 63 - mutex_lock(&trigger_data->mutex); 33 + reinit_completion(&trigger_data->sysfs); 34 + completion = ledtrig_tty_wait_for_completion(dev); 35 + if (completion < 0) 36 + return completion; 64 37 65 38 if (trigger_data->ttyname) 66 39 len = sprintf(buf, "%s\n", trigger_data->ttyname); 67 - 68 - mutex_unlock(&trigger_data->mutex); 69 40 70 41 return len; 71 42 } ··· 79 46 struct ledtrig_tty_data *trigger_data = led_trigger_get_drvdata(dev); 80 47 char *ttyname; 81 48 ssize_t ret = size; 82 - bool running; 49 + int completion; 83 50 84 51 if (size > 0 && buf[size - 1] == '\n') 85 52 size -= 1; ··· 92 59 ttyname = NULL; 93 60 } 94 61 95 - mutex_lock(&trigger_data->mutex); 96 - 97 - running = trigger_data->ttyname != NULL; 62 + reinit_completion(&trigger_data->sysfs); 63 + completion = ledtrig_tty_wait_for_completion(dev); 64 + if (completion < 0) 65 + return completion; 98 66 99 67 kfree(trigger_data->ttyname); 100 68 tty_kref_put(trigger_data->tty); ··· 103 69 104 70 trigger_data->ttyname = ttyname; 105 71 106 - mutex_unlock(&trigger_data->mutex); 107 - 108 - if (ttyname && !running) 109 - ledtrig_tty_restart(trigger_data); 110 - 111 72 return ret; 112 73 } 113 74 static DEVICE_ATTR_RW(ttyname); 75 + 76 + static ssize_t ledtrig_tty_attr_show(struct device *dev, char *buf, 77 + enum led_trigger_tty_modes attr) 78 + { 79 + struct ledtrig_tty_data *trigger_data = led_trigger_get_drvdata(dev); 80 + bool state; 81 + 82 + switch (attr) { 83 + case TRIGGER_TTY_RX: 84 + state = trigger_data->mode_rx; 85 + break; 86 + case TRIGGER_TTY_TX: 87 + state = trigger_data->mode_tx; 88 + break; 89 + case TRIGGER_TTY_CTS: 90 + state = trigger_data->mode_cts; 91 + break; 92 + case TRIGGER_TTY_DSR: 93 + state = trigger_data->mode_dsr; 94 + break; 95 + case TRIGGER_TTY_DCD: 96 + state = trigger_data->mode_dcd; 97 + break; 98 + case TRIGGER_TTY_RNG: 99 + state = trigger_data->mode_rng; 100 + break; 101 + } 102 + 103 + return sysfs_emit(buf, "%u\n", state); 104 + } 105 + 106 + static ssize_t ledtrig_tty_attr_store(struct device *dev, const char *buf, 107 + size_t size, enum led_trigger_tty_modes attr) 108 + { 109 + struct ledtrig_tty_data *trigger_data = led_trigger_get_drvdata(dev); 110 + bool state; 111 + int ret; 112 + 113 + ret = kstrtobool(buf, &state); 114 + if (ret) 115 + return ret; 116 + 117 + switch (attr) { 118 + case TRIGGER_TTY_RX: 119 + trigger_data->mode_rx = state; 120 + break; 121 + case TRIGGER_TTY_TX: 122 + trigger_data->mode_tx = state; 123 + break; 124 + case TRIGGER_TTY_CTS: 125 + trigger_data->mode_cts = state; 126 + break; 127 + case TRIGGER_TTY_DSR: 128 + trigger_data->mode_dsr = state; 129 + break; 130 + case TRIGGER_TTY_DCD: 131 + trigger_data->mode_dcd = state; 132 + break; 133 + case TRIGGER_TTY_RNG: 134 + trigger_data->mode_rng = state; 135 + break; 136 + } 137 + 138 + return size; 139 + } 140 + 141 + #define DEFINE_TTY_TRIGGER(trigger_name, trigger) \ 142 + static ssize_t trigger_name##_show(struct device *dev, \ 143 + struct device_attribute *attr, char *buf) \ 144 + { \ 145 + return ledtrig_tty_attr_show(dev, buf, trigger); \ 146 + } \ 147 + static ssize_t trigger_name##_store(struct device *dev, \ 148 + struct device_attribute *attr, const char *buf, size_t size) \ 149 + { \ 150 + return ledtrig_tty_attr_store(dev, buf, size, trigger); \ 151 + } \ 152 + static DEVICE_ATTR_RW(trigger_name) 153 + 154 + DEFINE_TTY_TRIGGER(rx, TRIGGER_TTY_RX); 155 + DEFINE_TTY_TRIGGER(tx, TRIGGER_TTY_TX); 156 + DEFINE_TTY_TRIGGER(cts, TRIGGER_TTY_CTS); 157 + DEFINE_TTY_TRIGGER(dsr, TRIGGER_TTY_DSR); 158 + DEFINE_TTY_TRIGGER(dcd, TRIGGER_TTY_DCD); 159 + DEFINE_TTY_TRIGGER(rng, TRIGGER_TTY_RNG); 114 160 115 161 static void ledtrig_tty_work(struct work_struct *work) 116 162 { 117 163 struct ledtrig_tty_data *trigger_data = 118 164 container_of(work, struct ledtrig_tty_data, dwork.work); 119 - struct serial_icounter_struct icount; 165 + enum led_trigger_tty_state state = TTY_LED_DISABLE; 166 + unsigned long interval = LEDTRIG_TTY_INTERVAL; 167 + bool invert = false; 168 + int status; 120 169 int ret; 121 170 122 - mutex_lock(&trigger_data->mutex); 123 - 124 - if (!trigger_data->ttyname) { 125 - /* exit without rescheduling */ 126 - mutex_unlock(&trigger_data->mutex); 127 - return; 128 - } 171 + if (!trigger_data->ttyname) 172 + goto out; 129 173 130 174 /* try to get the tty corresponding to $ttyname */ 131 175 if (!trigger_data->tty) { ··· 227 115 trigger_data->tty = tty; 228 116 } 229 117 230 - ret = tty_get_icount(trigger_data->tty, &icount); 231 - if (ret) { 232 - dev_info(trigger_data->tty->dev, "Failed to get icount, stopped polling\n"); 233 - mutex_unlock(&trigger_data->mutex); 234 - return; 118 + status = tty_get_tiocm(trigger_data->tty); 119 + if (status > 0) { 120 + if (trigger_data->mode_cts) { 121 + if (status & TIOCM_CTS) 122 + state = TTY_LED_ENABLE; 123 + } 124 + 125 + if (trigger_data->mode_dsr) { 126 + if (status & TIOCM_DSR) 127 + state = TTY_LED_ENABLE; 128 + } 129 + 130 + if (trigger_data->mode_dcd) { 131 + if (status & TIOCM_CAR) 132 + state = TTY_LED_ENABLE; 133 + } 134 + 135 + if (trigger_data->mode_rng) { 136 + if (status & TIOCM_RNG) 137 + state = TTY_LED_ENABLE; 138 + } 235 139 } 236 140 237 - if (icount.rx != trigger_data->rx || 238 - icount.tx != trigger_data->tx) { 239 - unsigned long interval = LEDTRIG_TTY_INTERVAL; 141 + /* 142 + * The evaluation of rx/tx must be done after the evaluation 143 + * of TIOCM_*, because rx/tx has priority. 144 + */ 145 + if (trigger_data->mode_rx || trigger_data->mode_tx) { 146 + struct serial_icounter_struct icount; 240 147 241 - led_blink_set_oneshot(trigger_data->led_cdev, &interval, 242 - &interval, 0); 148 + ret = tty_get_icount(trigger_data->tty, &icount); 149 + if (ret) 150 + goto out; 243 151 244 - trigger_data->rx = icount.rx; 245 - trigger_data->tx = icount.tx; 152 + if (trigger_data->mode_tx && (icount.tx != trigger_data->tx)) { 153 + trigger_data->tx = icount.tx; 154 + invert = state == TTY_LED_ENABLE; 155 + state = TTY_LED_BLINK; 156 + } 157 + 158 + if (trigger_data->mode_rx && (icount.rx != trigger_data->rx)) { 159 + trigger_data->rx = icount.rx; 160 + invert = state == TTY_LED_ENABLE; 161 + state = TTY_LED_BLINK; 162 + } 246 163 } 247 164 248 165 out: 249 - mutex_unlock(&trigger_data->mutex); 166 + switch (state) { 167 + case TTY_LED_BLINK: 168 + led_blink_set_oneshot(trigger_data->led_cdev, &interval, 169 + &interval, invert); 170 + break; 171 + case TTY_LED_ENABLE: 172 + led_set_brightness(trigger_data->led_cdev, 173 + trigger_data->led_cdev->blink_brightness); 174 + break; 175 + case TTY_LED_DISABLE: 176 + fallthrough; 177 + default: 178 + led_set_brightness(trigger_data->led_cdev, LED_OFF); 179 + break; 180 + } 181 + 182 + complete_all(&trigger_data->sysfs); 250 183 schedule_delayed_work(&trigger_data->dwork, 251 184 msecs_to_jiffies(LEDTRIG_TTY_INTERVAL * 2)); 252 185 } 253 186 254 187 static struct attribute *ledtrig_tty_attrs[] = { 255 188 &dev_attr_ttyname.attr, 189 + &dev_attr_rx.attr, 190 + &dev_attr_tx.attr, 191 + &dev_attr_cts.attr, 192 + &dev_attr_dsr.attr, 193 + &dev_attr_dcd.attr, 194 + &dev_attr_rng.attr, 256 195 NULL 257 196 }; 258 197 ATTRIBUTE_GROUPS(ledtrig_tty); ··· 316 153 if (!trigger_data) 317 154 return -ENOMEM; 318 155 156 + /* Enable default rx/tx mode */ 157 + trigger_data->mode_rx = true; 158 + trigger_data->mode_tx = true; 159 + 319 160 led_set_trigger_data(led_cdev, trigger_data); 320 161 321 162 INIT_DELAYED_WORK(&trigger_data->dwork, ledtrig_tty_work); 322 163 trigger_data->led_cdev = led_cdev; 323 - mutex_init(&trigger_data->mutex); 164 + init_completion(&trigger_data->sysfs); 165 + 166 + schedule_delayed_work(&trigger_data->dwork, 0); 324 167 325 168 return 0; 326 169 } ··· 336 167 struct ledtrig_tty_data *trigger_data = led_get_trigger_data(led_cdev); 337 168 338 169 cancel_delayed_work_sync(&trigger_data->dwork); 170 + 171 + kfree(trigger_data->ttyname); 172 + tty_kref_put(trigger_data->tty); 173 + trigger_data->tty = NULL; 339 174 340 175 kfree(trigger_data); 341 176 }
+22 -6
drivers/tty/tty_io.c
··· 2499 2499 } 2500 2500 2501 2501 /** 2502 + * tty_get_tiocm - get tiocm status register 2503 + * @tty: tty device 2504 + * 2505 + * Obtain the modem status bits from the tty driver if the feature 2506 + * is supported. 2507 + */ 2508 + int tty_get_tiocm(struct tty_struct *tty) 2509 + { 2510 + int retval = -ENOTTY; 2511 + 2512 + if (tty->ops->tiocmget) 2513 + retval = tty->ops->tiocmget(tty); 2514 + 2515 + return retval; 2516 + } 2517 + EXPORT_SYMBOL_GPL(tty_get_tiocm); 2518 + 2519 + /** 2502 2520 * tty_tiocmget - get modem status 2503 2521 * @tty: tty device 2504 2522 * @p: pointer to result ··· 2528 2510 */ 2529 2511 static int tty_tiocmget(struct tty_struct *tty, int __user *p) 2530 2512 { 2531 - int retval = -ENOTTY; 2513 + int retval; 2532 2514 2533 - if (tty->ops->tiocmget) { 2534 - retval = tty->ops->tiocmget(tty); 2515 + retval = tty_get_tiocm(tty); 2516 + if (retval >= 0) 2517 + retval = put_user(retval, p); 2535 2518 2536 - if (retval >= 0) 2537 - retval = put_user(retval, p); 2538 - } 2539 2519 return retval; 2540 2520 } 2541 2521
+3 -17
include/linux/leds.h
··· 527 527 return led_cdev->trigger_data; 528 528 } 529 529 530 - /** 531 - * led_trigger_rename_static - rename a trigger 532 - * @name: the new trigger name 533 - * @trig: the LED trigger to rename 534 - * 535 - * Change a LED trigger name by copying the string passed in 536 - * name into current trigger name, which MUST be large 537 - * enough for the new string. 538 - * 539 - * Note that name must NOT point to the same string used 540 - * during LED registration, as that could lead to races. 541 - * 542 - * This is meant to be used on triggers with statically 543 - * allocated name. 544 - */ 545 - void led_trigger_rename_static(const char *name, struct led_trigger *trig); 546 - 547 530 #define module_led_trigger(__led_trigger) \ 548 531 module_driver(__led_trigger, led_trigger_register, \ 549 532 led_trigger_unregister) ··· 571 588 TRIGGER_NETDEV_LINK_10, 572 589 TRIGGER_NETDEV_LINK_100, 573 590 TRIGGER_NETDEV_LINK_1000, 591 + TRIGGER_NETDEV_LINK_2500, 592 + TRIGGER_NETDEV_LINK_5000, 593 + TRIGGER_NETDEV_LINK_10000, 574 594 TRIGGER_NETDEV_HALF_DUPLEX, 575 595 TRIGGER_NETDEV_FULL_DUPLEX, 576 596 TRIGGER_NETDEV_TX,
+1
include/linux/tty.h
··· 419 419 int tty_do_resize(struct tty_struct *tty, struct winsize *ws); 420 420 int tty_get_icount(struct tty_struct *tty, 421 421 struct serial_icounter_struct *icount); 422 + int tty_get_tiocm(struct tty_struct *tty); 422 423 int is_current_pgrp_orphaned(void); 423 424 void tty_hangup(struct tty_struct *tty); 424 425 void tty_vhangup(struct tty_struct *tty);