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

Merge tag 'leds-5.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/pavel/linux-leds

Pull LED updates from Pavel Machek:
"Okay, so... this one is interesting. RGB LEDs are very common, and we
need to have some kind of support for them. Multicolor is for
arbitrary set of LEDs in one package, RGB is for LEDs that can produce
full range of colors. We do not have real multicolor LED that is not
RGB in the pipeline, so that one is disabled for now.

You can expect this saga to continue with next pull requests"

* tag 'leds-5.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/pavel/linux-leds: (37 commits)
MAINTAINERS: Remove myself as LED subsystem maintainer
leds: disallow /sys/class/leds/*:multi:* for now
leds: add RGB color option, as that is different from multicolor.
Make LEDS_LP55XX_COMMON depend on I2C to fix build errors:
Documentation: ABI: leds-turris-omnia: document sysfs attribute
leds: initial support for Turris Omnia LEDs
dt-bindings: leds: add cznic,turris-omnia-leds binding
leds: pattern trigger -- check pattern for validity
leds: Replace HTTP links with HTTPS ones
leds: trigger: add support for LED-private device triggers
leds: lp5521: Add multicolor framework multicolor brightness support
leds: lp5523: Update the lp5523 code to add multicolor brightness function
leds: lp55xx: Add multicolor framework support to lp55xx
leds: lp55xx: Convert LED class registration to devm_*
dt-bindings: leds: Convert leds-lp55xx to yaml
leds: multicolor: Introduce a multicolor class definition
leds: Add multicolor ID to the color ID list
dt: bindings: Add multicolor class dt bindings documention
leds: lp5523: Fix various formatting issues in the code
leds: lp55xx: Fix file permissions to use DEVICE_ATTR macros
...

+1644 -457
+14
Documentation/ABI/testing/sysfs-class-led-driver-turris-omnia
··· 1 + What: /sys/class/leds/<led>/device/brightness 2 + Date: July 2020 3 + KernelVersion: 5.9 4 + Contact: Marek Behún <marek.behun@nic.cz> 5 + Description: (RW) On the front panel of the Turris Omnia router there is also 6 + a button which can be used to control the intensity of all the 7 + LEDs at once, so that if they are too bright, user can dim them. 8 + 9 + The microcontroller cycles between 8 levels of this global 10 + brightness (from 100% to 0%), but this setting can have any 11 + integer value between 0 and 100. It is therefore convenient to be 12 + able to change this setting from software. 13 + 14 + Format: %i
+35
Documentation/ABI/testing/sysfs-class-led-multicolor
··· 1 + What: /sys/class/leds/<led>/brightness 2 + Date: March 2020 3 + KernelVersion: 5.9 4 + Contact: Dan Murphy <dmurphy@ti.com> 5 + Description: read/write 6 + Writing to this file will update all LEDs within the group to a 7 + calculated percentage of what each color LED intensity is set 8 + to. The percentage is calculated for each grouped LED via the 9 + equation below: 10 + 11 + led_brightness = brightness * multi_intensity/max_brightness 12 + 13 + For additional details please refer to 14 + Documentation/leds/leds-class-multicolor.rst. 15 + 16 + The value of the LED is from 0 to 17 + /sys/class/leds/<led>/max_brightness. 18 + 19 + What: /sys/class/leds/<led>/multi_index 20 + Date: March 2020 21 + KernelVersion: 5.9 22 + Contact: Dan Murphy <dmurphy@ti.com> 23 + Description: read 24 + The multi_index array, when read, will output the LED colors 25 + as an array of strings as they are indexed in the 26 + multi_intensity file. 27 + 28 + What: /sys/class/leds/<led>/multi_intensity 29 + Date: March 2020 30 + KernelVersion: 5.9 31 + Contact: Dan Murphy <dmurphy@ti.com> 32 + Description: read/write 33 + This file contains array of integers. Order of components is 34 + described by the multi_index array. The maximum intensity should 35 + not exceed /sys/class/leds/<led>/max_brightness.
+90
Documentation/devicetree/bindings/leds/cznic,turris-omnia-leds.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/cznic,turris-omnia-leds.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: CZ.NIC's Turris Omnia LEDs driver 8 + 9 + maintainers: 10 + - Marek Behún <marek.behun@nic.cz> 11 + 12 + description: 13 + This module adds support for the RGB LEDs found on the front panel of the 14 + Turris Omnia router. There are 12 RGB LEDs that are controlled by a 15 + microcontroller that communicates via the I2C bus. Each LED is described 16 + as a subnode of this I2C device. 17 + 18 + properties: 19 + compatible: 20 + const: cznic,turris-omnia-leds 21 + 22 + reg: 23 + description: I2C slave address of the microcontroller. 24 + maxItems: 1 25 + 26 + "#address-cells": 27 + const: 1 28 + 29 + "#size-cells": 30 + const: 0 31 + 32 + patternProperties: 33 + "^multi-led[0-9a-f]$": 34 + type: object 35 + allOf: 36 + - $ref: leds-class-multicolor.yaml# 37 + description: 38 + This node represents one of the RGB LED devices on Turris Omnia. 39 + No subnodes need to be added for subchannels since this controller only 40 + supports RGB LEDs. 41 + 42 + properties: 43 + reg: 44 + minimum: 0 45 + maximum: 11 46 + description: 47 + This property identifies one of the LEDs on the front panel of the 48 + Turris Omnia router. 49 + 50 + required: 51 + - reg 52 + 53 + additionalProperties: false 54 + 55 + examples: 56 + - | 57 + 58 + #include <dt-bindings/leds/common.h> 59 + 60 + i2c0 { 61 + #address-cells = <1>; 62 + #size-cells = <0>; 63 + 64 + led-controller@2b { 65 + compatible = "cznic,turris-omnia-leds"; 66 + reg = <0x2b>; 67 + #address-cells = <1>; 68 + #size-cells = <0>; 69 + 70 + multi-led@0 { 71 + /* 72 + * No subnodes are needed, this controller only supports RGB 73 + * LEDs. 74 + */ 75 + reg = <0>; 76 + color = <LED_COLOR_ID_MULTI>; 77 + function = LED_FUNCTION_POWER; 78 + linux,default-trigger = "heartbeat"; 79 + }; 80 + 81 + multi-led@a { 82 + reg = <0xa>; 83 + color = <LED_COLOR_ID_MULTI>; 84 + function = LED_FUNCTION_INDICATOR; 85 + function-enumerator = <1>; 86 + }; 87 + }; 88 + }; 89 + 90 + ...
+37
Documentation/devicetree/bindings/leds/leds-class-multicolor.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/leds-class-multicolor.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Common properties for the multicolor LED class. 8 + 9 + maintainers: 10 + - Dan Murphy <dmurphy@ti.com> 11 + 12 + description: | 13 + Bindings for multi color LEDs show how to describe current outputs of 14 + either integrated multi-color LED elements (like RGB, RGBW, RGBWA-UV 15 + etc.) or standalone LEDs, to achieve logically grouped multi-color LED 16 + modules. This is achieved by adding multi-led nodes layer to the 17 + monochrome LED bindings. 18 + The nodes and properties defined in this document are unique to the multicolor 19 + LED class. Common LED nodes and properties are inherited from the common.txt 20 + within this documentation directory. 21 + 22 + patternProperties: 23 + "^multi-led@([0-9a-f])$": 24 + type: object 25 + description: Represents the LEDs that are to be grouped. 26 + properties: 27 + color: 28 + const: 8 # LED_COLOR_ID_MULTI 29 + description: | 30 + For multicolor LED support this property should be defined as 31 + LED_COLOR_ID_MULTI which can be found in include/linux/leds/common.h. 32 + 33 + $ref: "common.yaml#" 34 + 35 + required: 36 + - color 37 + ...
+1 -1
Documentation/devicetree/bindings/leds/leds-lm3532.txt
··· 102 102 }; 103 103 104 104 For more product information please see the links below: 105 - http://www.ti.com/product/LM3532 105 + https://www.ti.com/product/LM3532
+2 -2
Documentation/devicetree/bindings/leds/leds-lm3601x.txt
··· 47 47 } 48 48 49 49 For more product information please see the links below: 50 - http://www.ti.com/product/LM36010 51 - http://www.ti.com/product/LM36011 50 + https://www.ti.com/product/LM36010 51 + https://www.ti.com/product/LM36011
+1 -1
Documentation/devicetree/bindings/leds/leds-lm36274.txt
··· 82 82 }; 83 83 84 84 For more product information please see the link below: 85 - http://www.ti.com/lit/ds/symlink/lm36274.pdf 85 + https://www.ti.com/lit/ds/symlink/lm36274.pdf
+1 -1
Documentation/devicetree/bindings/leds/leds-lm3692x.txt
··· 62 62 } 63 63 64 64 For more product information please see the link below: 65 - http://www.ti.com/lit/ds/snvsa29/snvsa29.pdf 65 + https://www.ti.com/lit/ds/snvsa29/snvsa29.pdf
+1 -1
Documentation/devicetree/bindings/leds/leds-lm3697.txt
··· 70 70 } 71 71 72 72 For more product information please see the link below: 73 - http://www.ti.com/lit/ds/symlink/lm3697.pdf 73 + https://www.ti.com/lit/ds/symlink/lm3697.pdf
-228
Documentation/devicetree/bindings/leds/leds-lp55xx.txt
··· 1 - Binding for TI/National Semiconductor LP55xx Led Drivers 2 - 3 - Required properties: 4 - - compatible: one of 5 - national,lp5521 6 - national,lp5523 7 - ti,lp55231 8 - ti,lp5562 9 - ti,lp8501 10 - 11 - - reg: I2C slave address 12 - - clock-mode: Input clock mode, (0: automode, 1: internal, 2: external) 13 - 14 - Each child has own specific current settings 15 - - led-cur: Current setting at each led channel (mA x10, 0 if led is not connected) 16 - - max-cur: Maximun current at each led channel. 17 - 18 - Optional properties: 19 - - enable-gpio: GPIO attached to the chip's enable pin 20 - - label: Used for naming LEDs 21 - - pwr-sel: LP8501 specific property. Power selection for output channels. 22 - 0: D1~9 are connected to VDD 23 - 1: D1~6 with VDD, D7~9 with VOUT 24 - 2: D1~6 with VOUT, D7~9 with VDD 25 - 3: D1~9 are connected to VOUT 26 - 27 - Alternatively, each child can have a specific channel name and trigger: 28 - - chan-name (optional): name of channel 29 - - linux,default-trigger (optional): see 30 - Documentation/devicetree/bindings/leds/common.txt 31 - 32 - example 1) LP5521 33 - 3 LED channels, external clock used. Channel names are 'lp5521_pri:channel0', 34 - 'lp5521_pri:channel1' and 'lp5521_pri:channel2', with a heartbeat trigger 35 - on channel 0. 36 - 37 - lp5521@32 { 38 - compatible = "national,lp5521"; 39 - reg = <0x32>; 40 - label = "lp5521_pri"; 41 - clock-mode = /bits/ 8 <2>; 42 - 43 - chan0 { 44 - led-cur = /bits/ 8 <0x2f>; 45 - max-cur = /bits/ 8 <0x5f>; 46 - linux,default-trigger = "heartbeat"; 47 - }; 48 - 49 - chan1 { 50 - led-cur = /bits/ 8 <0x2f>; 51 - max-cur = /bits/ 8 <0x5f>; 52 - }; 53 - 54 - chan2 { 55 - led-cur = /bits/ 8 <0x2f>; 56 - max-cur = /bits/ 8 <0x5f>; 57 - }; 58 - }; 59 - 60 - example 2) LP5523 61 - 9 LED channels with specific name. Internal clock used. 62 - The I2C slave address is configurable with ASEL1 and ASEL0 pins. 63 - Available addresses are 32/33/34/35h. 64 - 65 - ASEL1 ASEL0 Address 66 - ------------------------- 67 - GND GND 32h 68 - GND VEN 33h 69 - VEN GND 34h 70 - VEN VEN 35h 71 - 72 - lp5523@32 { 73 - compatible = "national,lp5523"; 74 - reg = <0x32>; 75 - clock-mode = /bits/ 8 <1>; 76 - 77 - chan0 { 78 - chan-name = "d1"; 79 - led-cur = /bits/ 8 <0x14>; 80 - max-cur = /bits/ 8 <0x20>; 81 - }; 82 - 83 - chan1 { 84 - chan-name = "d2"; 85 - led-cur = /bits/ 8 <0x14>; 86 - max-cur = /bits/ 8 <0x20>; 87 - }; 88 - 89 - chan2 { 90 - chan-name = "d3"; 91 - led-cur = /bits/ 8 <0x14>; 92 - max-cur = /bits/ 8 <0x20>; 93 - }; 94 - 95 - chan3 { 96 - chan-name = "d4"; 97 - led-cur = /bits/ 8 <0x14>; 98 - max-cur = /bits/ 8 <0x20>; 99 - }; 100 - 101 - chan4 { 102 - chan-name = "d5"; 103 - led-cur = /bits/ 8 <0x14>; 104 - max-cur = /bits/ 8 <0x20>; 105 - }; 106 - 107 - chan5 { 108 - chan-name = "d6"; 109 - led-cur = /bits/ 8 <0x14>; 110 - max-cur = /bits/ 8 <0x20>; 111 - }; 112 - 113 - chan6 { 114 - chan-name = "d7"; 115 - led-cur = /bits/ 8 <0x14>; 116 - max-cur = /bits/ 8 <0x20>; 117 - }; 118 - 119 - chan7 { 120 - chan-name = "d8"; 121 - led-cur = /bits/ 8 <0x14>; 122 - max-cur = /bits/ 8 <0x20>; 123 - }; 124 - 125 - chan8 { 126 - chan-name = "d9"; 127 - led-cur = /bits/ 8 <0x14>; 128 - max-cur = /bits/ 8 <0x20>; 129 - }; 130 - }; 131 - 132 - example 3) LP5562 133 - 4 channels are defined. 134 - 135 - lp5562@30 { 136 - compatible = "ti,lp5562"; 137 - reg = <0x30>; 138 - clock-mode = /bits/8 <2>; 139 - 140 - chan0 { 141 - chan-name = "R"; 142 - led-cur = /bits/ 8 <0x20>; 143 - max-cur = /bits/ 8 <0x60>; 144 - }; 145 - 146 - chan1 { 147 - chan-name = "G"; 148 - led-cur = /bits/ 8 <0x20>; 149 - max-cur = /bits/ 8 <0x60>; 150 - }; 151 - 152 - chan2 { 153 - chan-name = "B"; 154 - led-cur = /bits/ 8 <0x20>; 155 - max-cur = /bits/ 8 <0x60>; 156 - }; 157 - 158 - chan3 { 159 - chan-name = "W"; 160 - led-cur = /bits/ 8 <0x20>; 161 - max-cur = /bits/ 8 <0x60>; 162 - }; 163 - }; 164 - 165 - example 4) LP8501 166 - 9 channels are defined. The 'pwr-sel' is LP8501 specific property. 167 - Others are same as LP5523. 168 - 169 - lp8501@32 { 170 - compatible = "ti,lp8501"; 171 - reg = <0x32>; 172 - clock-mode = /bits/ 8 <2>; 173 - pwr-sel = /bits/ 8 <3>; /* D1~9 connected to VOUT */ 174 - 175 - chan0 { 176 - chan-name = "d1"; 177 - led-cur = /bits/ 8 <0x14>; 178 - max-cur = /bits/ 8 <0x20>; 179 - }; 180 - 181 - chan1 { 182 - chan-name = "d2"; 183 - led-cur = /bits/ 8 <0x14>; 184 - max-cur = /bits/ 8 <0x20>; 185 - }; 186 - 187 - chan2 { 188 - chan-name = "d3"; 189 - led-cur = /bits/ 8 <0x14>; 190 - max-cur = /bits/ 8 <0x20>; 191 - }; 192 - 193 - chan3 { 194 - chan-name = "d4"; 195 - led-cur = /bits/ 8 <0x14>; 196 - max-cur = /bits/ 8 <0x20>; 197 - }; 198 - 199 - chan4 { 200 - chan-name = "d5"; 201 - led-cur = /bits/ 8 <0x14>; 202 - max-cur = /bits/ 8 <0x20>; 203 - }; 204 - 205 - chan5 { 206 - chan-name = "d6"; 207 - led-cur = /bits/ 8 <0x14>; 208 - max-cur = /bits/ 8 <0x20>; 209 - }; 210 - 211 - chan6 { 212 - chan-name = "d7"; 213 - led-cur = /bits/ 8 <0x14>; 214 - max-cur = /bits/ 8 <0x20>; 215 - }; 216 - 217 - chan7 { 218 - chan-name = "d8"; 219 - led-cur = /bits/ 8 <0x14>; 220 - max-cur = /bits/ 8 <0x20>; 221 - }; 222 - 223 - chan8 { 224 - chan-name = "d9"; 225 - led-cur = /bits/ 8 <0x14>; 226 - max-cur = /bits/ 8 <0x20>; 227 - }; 228 - };
+220
Documentation/devicetree/bindings/leds/leds-lp55xx.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/leds-lp55xx.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: TI/National Semiconductor LP55xx and LP8501 LED Drivers 8 + 9 + maintainers: 10 + - Jacek Anaszewski <jacek.anaszewski@gmail.com> 11 + - Pavel Machek <pavel@ucw.cz> 12 + 13 + description: | 14 + Bindings for the TI/National Semiconductor LP55xx and LP8501 multi channel 15 + LED Drivers. 16 + 17 + For more product information please see the link below: 18 + https://www.ti.com/lit/gpn/lp5521 19 + https://www.ti.com/lit/gpn/lp5523 20 + https://www.ti.com/lit/gpn/lp55231 21 + https://www.ti.com/lit/gpn/lp5562 22 + https://www.ti.com/lit/gpn/lp8501 23 + 24 + properties: 25 + compatible: 26 + enum: 27 + - national,lp5521 28 + - national,lp5523 29 + - ti,lp55231 30 + - ti,lp5562 31 + - ti,lp8501 32 + 33 + reg: 34 + maxItems: 1 35 + description: I2C slave address 36 + 37 + clock-mode: 38 + $ref: /schemas/types.yaml#definitions/uint8 39 + description: | 40 + Input clock mode 41 + enum: 42 + - 0 # automode 43 + - 1 # internal 44 + - 2 # external 45 + 46 + enable-gpio: 47 + maxItems: 1 48 + description: | 49 + GPIO attached to the chip's enable pin 50 + 51 + pwr-sel: 52 + $ref: /schemas/types.yaml#definitions/uint8 53 + description: | 54 + LP8501 specific property. Power selection for output channels. 55 + enum: 56 + - 0 # D1~9 are connected to VDD 57 + - 1 # D1~6 with VDD, D7~9 with VOUT 58 + - 2 # D1~6 with VOUT, D7~9 with VDD 59 + - 3 # D1~9 are connected to VOUT 60 + 61 + patternProperties: 62 + "(^led@[0-9a-f]$|led)": 63 + type: object 64 + $ref: common.yaml# 65 + properties: 66 + led-cur: 67 + $ref: /schemas/types.yaml#definitions/uint8 68 + description: | 69 + Current setting at each LED channel (mA x10, 0 if LED is not connected) 70 + minimum: 0 71 + maximum: 255 72 + 73 + max-cur: 74 + $ref: /schemas/types.yaml#definitions/uint8 75 + description: Maximun current at each LED channel. 76 + 77 + reg: 78 + description: | 79 + Output channel for the LED. This is zero based channel identifier and 80 + the data sheet is a one based channel identifier. 81 + reg value to output to LED output number 82 + enum: 83 + - 0 # LED output D1 84 + - 1 # LED output D2 85 + - 2 # LED output D3 86 + - 3 # LED output D4 87 + - 4 # LED output D5 88 + - 5 # LED output D6 89 + - 6 # LED output D7 90 + - 7 # LED output D8 91 + - 8 # LED output D9 92 + 93 + chan-name: 94 + $ref: /schemas/types.yaml#definitions/string 95 + description: name of channel 96 + 97 + required: 98 + - compatible 99 + - reg 100 + 101 + examples: 102 + - | 103 + #include <dt-bindings/leds/common.h> 104 + 105 + i2c { 106 + #address-cells = <1>; 107 + #size-cells = <0>; 108 + 109 + led-controller@32 { 110 + #address-cells = <1>; 111 + #size-cells = <0>; 112 + compatible = "ti,lp8501"; 113 + reg = <0x32>; 114 + clock-mode = /bits/ 8 <2>; 115 + pwr-sel = /bits/ 8 <3>; /* D1~9 connected to VOUT */ 116 + 117 + led@0 { 118 + reg = <0>; 119 + chan-name = "d1"; 120 + led-cur = /bits/ 8 <0x14>; 121 + max-cur = /bits/ 8 <0x20>; 122 + }; 123 + 124 + led@1 { 125 + reg = <1>; 126 + chan-name = "d2"; 127 + led-cur = /bits/ 8 <0x14>; 128 + max-cur = /bits/ 8 <0x20>; 129 + }; 130 + 131 + led@2 { 132 + reg = <2>; 133 + chan-name = "d3"; 134 + led-cur = /bits/ 8 <0x14>; 135 + max-cur = /bits/ 8 <0x20>; 136 + }; 137 + 138 + led@3 { 139 + reg = <3>; 140 + chan-name = "d4"; 141 + led-cur = /bits/ 8 <0x14>; 142 + max-cur = /bits/ 8 <0x20>; 143 + }; 144 + 145 + led@4 { 146 + reg = <4>; 147 + chan-name = "d5"; 148 + led-cur = /bits/ 8 <0x14>; 149 + max-cur = /bits/ 8 <0x20>; 150 + }; 151 + 152 + led@5 { 153 + reg = <5>; 154 + chan-name = "d6"; 155 + led-cur = /bits/ 8 <0x14>; 156 + max-cur = /bits/ 8 <0x20>; 157 + }; 158 + 159 + led@6 { 160 + reg = <6>; 161 + chan-name = "d7"; 162 + led-cur = /bits/ 8 <0x14>; 163 + max-cur = /bits/ 8 <0x20>; 164 + }; 165 + 166 + led@7 { 167 + reg = <7>; 168 + chan-name = "d8"; 169 + led-cur = /bits/ 8 <0x14>; 170 + max-cur = /bits/ 8 <0x20>; 171 + }; 172 + 173 + led@8 { 174 + reg = <8>; 175 + chan-name = "d9"; 176 + led-cur = /bits/ 8 <0x14>; 177 + max-cur = /bits/ 8 <0x20>; 178 + }; 179 + }; 180 + 181 + led-controller@33 { 182 + #address-cells = <1>; 183 + #size-cells = <0>; 184 + compatible = "national,lp5523"; 185 + reg = <0x33>; 186 + clock-mode = /bits/ 8 <0>; 187 + 188 + multi-led@2 { 189 + #address-cells = <1>; 190 + #size-cells = <0>; 191 + reg = <0x2>; 192 + color = <LED_COLOR_ID_MULTI>; 193 + function = LED_FUNCTION_STANDBY; 194 + linux,default-trigger = "heartbeat"; 195 + 196 + led@0 { 197 + led-cur = /bits/ 8 <50>; 198 + max-cur = /bits/ 8 <100>; 199 + reg = <0x0>; 200 + color = <LED_COLOR_ID_GREEN>; 201 + }; 202 + 203 + led@1 { 204 + led-cur = /bits/ 8 <50>; 205 + max-cur = /bits/ 8 <100>; 206 + reg = <0x1>; 207 + color = <LED_COLOR_ID_BLUE>; 208 + }; 209 + 210 + led@6 { 211 + led-cur = /bits/ 8 <50>; 212 + max-cur = /bits/ 8 <100>; 213 + reg = <0x6>; 214 + color = <LED_COLOR_ID_RED>; 215 + }; 216 + }; 217 + }; 218 + }; 219 + 220 + ...
+1 -1
Documentation/devicetree/bindings/leds/leds-lp8860.txt
··· 47 47 } 48 48 49 49 For more product information please see the link below: 50 - http://www.ti.com/product/lp8860-q1 50 + https://www.ti.com/product/lp8860-q1
+3 -3
Documentation/devicetree/bindings/leds/leds-pca955x.txt
··· 26 26 from 0 to 15 for the pca9552 27 27 from 0 to 3 for the pca9553 28 28 - type: (optional) either 29 - PCA9532_TYPE_NONE 30 - PCA9532_TYPE_LED 31 - PCA9532_TYPE_GPIO 29 + PCA955X_TYPE_NONE 30 + PCA955X_TYPE_LED 31 + PCA955X_TYPE_GPIO 32 32 see dt-bindings/leds/leds-pca955x.h (default to LED) 33 33 - label : (optional) 34 34 see Documentation/devicetree/bindings/leds/common.txt
+1
Documentation/leds/index.rst
··· 9 9 10 10 leds-class 11 11 leds-class-flash 12 + leds-class-multicolor 12 13 ledtrig-oneshot 13 14 ledtrig-transient 14 15 ledtrig-usbport
+86
Documentation/leds/leds-class-multicolor.rst
··· 1 + .. SPDX-License-Identifier: GPL-2.0 2 + 3 + ==================================== 4 + Multicolor LED handling under Linux 5 + ==================================== 6 + 7 + Description 8 + =========== 9 + The multicolor class groups monochrome LEDs and allows controlling two 10 + aspects of the final combined color: hue and lightness. The former is 11 + controlled via the multi_intensity array file and the latter is controlled 12 + via brightness file. 13 + 14 + Multicolor Class Control 15 + ======================== 16 + The multicolor class presents files that groups the colors as indexes in an 17 + array. These files are children under the LED parent node created by the 18 + led_class framework. The led_class framework is documented in led-class.rst 19 + within this documentation directory. 20 + 21 + Each colored LED will be indexed under the multi_* files. The order of the 22 + colors will be arbitrary. The multi_index file can be read to determine the 23 + color name to indexed value. 24 + 25 + The multi_index file is an array that contains the string list of the colors as 26 + they are defined in each multi_* array file. 27 + 28 + The multi_intensity is an array that can be read or written to for the 29 + individual color intensities. All elements within this array must be written in 30 + order for the color LED intensities to be updated. 31 + 32 + Directory Layout Example 33 + ======================== 34 + root:/sys/class/leds/multicolor:status# ls -lR 35 + -rw-r--r-- 1 root root 4096 Oct 19 16:16 brightness 36 + -r--r--r-- 1 root root 4096 Oct 19 16:16 max_brightness 37 + -r--r--r-- 1 root root 4096 Oct 19 16:16 multi_index 38 + -rw-r--r-- 1 root root 4096 Oct 19 16:16 multi_intensity 39 + 40 + Multicolor Class Brightness Control 41 + =================================== 42 + The brightness level for each LED is calculated based on the color LED 43 + intensity setting divided by the global max_brightness setting multiplied by 44 + the requested brightness. 45 + 46 + led_brightness = brightness * multi_intensity/max_brightness 47 + 48 + Example: 49 + A user first writes the multi_intensity file with the brightness levels 50 + for each LED that are necessary to achieve a certain color output from a 51 + multicolor LED group. 52 + 53 + cat /sys/class/leds/multicolor:status/multi_index 54 + green blue red 55 + 56 + echo 43 226 138 > /sys/class/leds/multicolor:status/multi_intensity 57 + 58 + red - 59 + intensity = 138 60 + max_brightness = 255 61 + green - 62 + intensity = 43 63 + max_brightness = 255 64 + blue - 65 + intensity = 226 66 + max_brightness = 255 67 + 68 + The user can control the brightness of that multicolor LED group by writing the 69 + global 'brightness' control. Assuming a max_brightness of 255 the user 70 + may want to dim the LED color group to half. The user would write a value of 71 + 128 to the global brightness file then the values written to each LED will be 72 + adjusted base on this value. 73 + 74 + cat /sys/class/leds/multicolor:status/max_brightness 75 + 255 76 + echo 128 > /sys/class/leds/multicolor:status/brightness 77 + 78 + adjusted_red_value = 128 * 138/255 = 69 79 + adjusted_green_value = 128 * 43/255 = 21 80 + adjusted_blue_value = 128 * 226/255 = 113 81 + 82 + Reading the global brightness file will return the current brightness value of 83 + the color LED group. 84 + 85 + cat /sys/class/leds/multicolor:status/brightness 86 + 128
-2
MAINTAINERS
··· 9743 9743 F: scripts/leaking_addresses.pl 9744 9744 9745 9745 LED SUBSYSTEM 9746 - M: Jacek Anaszewski <jacek.anaszewski@gmail.com> 9747 9746 M: Pavel Machek <pavel@ucw.cz> 9748 9747 R: Dan Murphy <dmurphy@ti.com> 9749 9748 L: linux-leds@vger.kernel.org 9750 9749 S: Maintained 9751 - T: git git://git.kernel.org/pub/scm/linux/kernel/git/j.anaszewski/linux-leds.git 9752 9750 T: git git://git.kernel.org/pub/scm/linux/kernel/git/pavel/linux-leds.git 9753 9751 F: Documentation/devicetree/bindings/leds/ 9754 9752 F: drivers/leds/
+28 -5
drivers/leds/Kconfig
··· 30 30 for the flash related features of a LED device. It can be built 31 31 as a module. 32 32 33 + config LEDS_CLASS_MULTICOLOR 34 + tristate "LED Multicolor Class Support" 35 + depends on LEDS_CLASS 36 + help 37 + This option enables the multicolor LED sysfs class in /sys/class/leds. 38 + It wraps LED class and adds multicolor LED specific sysfs attributes 39 + and kernel internal API to it. You'll need this to provide support 40 + for multicolor LEDs that are grouped together. This class is not 41 + intended for single color LEDs. It can be built as a module. 42 + 33 43 config LEDS_BRIGHTNESS_HW_CHANGED 34 44 bool "LED Class brightness_hw_changed attribute support" 35 45 depends on LEDS_CLASS ··· 175 165 176 166 To compile this driver as a module, choose M here: the module 177 167 will be called leds-el15203000. 168 + 169 + config LEDS_TURRIS_OMNIA 170 + tristate "LED support for CZ.NIC's Turris Omnia" 171 + depends on LEDS_CLASS_MULTICOLOR 172 + depends on I2C 173 + depends on MACH_ARMADA_38X || COMPILE_TEST 174 + depends on OF 175 + help 176 + This option enables basic support for the LEDs found on the front 177 + side of CZ.NIC's Turris Omnia router. There are 12 RGB LEDs on the 178 + front panel. 178 179 179 180 config LEDS_LM3530 180 181 tristate "LCD Backlight driver for LM3530" ··· 397 376 398 377 config LEDS_LP55XX_COMMON 399 378 tristate "Common Driver for TI/National LP5521/5523/55231/5562/8501" 400 - depends on LEDS_LP5521 || LEDS_LP5523 || LEDS_LP5562 || LEDS_LP8501 379 + depends on LEDS_CLASS_MULTICOLOR || !LEDS_CLASS_MULTICOLOR 380 + depends on OF 381 + depends on I2C 401 382 select FW_LOADER 402 383 select FW_LOADER_USER_HELPER 403 384 help ··· 409 386 config LEDS_LP5521 410 387 tristate "LED Support for N.S. LP5521 LED driver chip" 411 388 depends on LEDS_CLASS && I2C 412 - select LEDS_LP55XX_COMMON 389 + depends on LEDS_LP55XX_COMMON 413 390 help 414 391 If you say yes here you get support for the National Semiconductor 415 392 LP5521 LED driver. It is 3 channel chip with programmable engines. ··· 419 396 config LEDS_LP5523 420 397 tristate "LED Support for TI/National LP5523/55231 LED driver chip" 421 398 depends on LEDS_CLASS && I2C 422 - select LEDS_LP55XX_COMMON 399 + depends on LEDS_LP55XX_COMMON 423 400 help 424 401 If you say yes here you get support for TI/National Semiconductor 425 402 LP5523/55231 LED driver. ··· 430 407 config LEDS_LP5562 431 408 tristate "LED Support for TI LP5562 LED driver chip" 432 409 depends on LEDS_CLASS && I2C 433 - select LEDS_LP55XX_COMMON 410 + depends on LEDS_LP55XX_COMMON 434 411 help 435 412 If you say yes here you get support for TI LP5562 LED driver. 436 413 It is 4 channels chip with programmable engines. ··· 440 417 config LEDS_LP8501 441 418 tristate "LED Support for TI LP8501 LED driver chip" 442 419 depends on LEDS_CLASS && I2C 443 - select LEDS_LP55XX_COMMON 420 + depends on LEDS_LP55XX_COMMON 444 421 help 445 422 If you say yes here you get support for TI LP8501 LED driver. 446 423 It is 9 channel chip with programmable engines.
+2
drivers/leds/Makefile
··· 4 4 obj-$(CONFIG_NEW_LEDS) += led-core.o 5 5 obj-$(CONFIG_LEDS_CLASS) += led-class.o 6 6 obj-$(CONFIG_LEDS_CLASS_FLASH) += led-class-flash.o 7 + obj-$(CONFIG_LEDS_CLASS_MULTICOLOR) += led-class-multicolor.o 7 8 obj-$(CONFIG_LEDS_TRIGGERS) += led-triggers.o 8 9 9 10 # LED Platform Drivers (keep this sorted, M-| sort) ··· 87 86 obj-$(CONFIG_LEDS_TI_LMU_COMMON) += leds-ti-lmu-common.o 88 87 obj-$(CONFIG_LEDS_TLC591XX) += leds-tlc591xx.o 89 88 obj-$(CONFIG_LEDS_TPS6105X) += leds-tps6105x.o 89 + obj-$(CONFIG_LEDS_TURRIS_OMNIA) += leds-turris-omnia.o 90 90 obj-$(CONFIG_LEDS_WM831X_STATUS) += leds-wm831x-status.o 91 91 obj-$(CONFIG_LEDS_WM8350) += leds-wm8350.o 92 92 obj-$(CONFIG_LEDS_WRAP) += leds-wrap.o
+203
drivers/leds/led-class-multicolor.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // LED Multicolor class interface 3 + // Copyright (C) 2019-20 Texas Instruments Incorporated - http://www.ti.com/ 4 + // Author: Dan Murphy <dmurphy@ti.com> 5 + 6 + #include <linux/device.h> 7 + #include <linux/init.h> 8 + #include <linux/led-class-multicolor.h> 9 + #include <linux/module.h> 10 + #include <linux/slab.h> 11 + #include <linux/uaccess.h> 12 + 13 + #include "leds.h" 14 + 15 + int led_mc_calc_color_components(struct led_classdev_mc *mcled_cdev, 16 + enum led_brightness brightness) 17 + { 18 + struct led_classdev *led_cdev = &mcled_cdev->led_cdev; 19 + int i; 20 + 21 + for (i = 0; i < mcled_cdev->num_colors; i++) 22 + mcled_cdev->subled_info[i].brightness = brightness * 23 + mcled_cdev->subled_info[i].intensity / 24 + led_cdev->max_brightness; 25 + 26 + return 0; 27 + } 28 + EXPORT_SYMBOL_GPL(led_mc_calc_color_components); 29 + 30 + static ssize_t multi_intensity_store(struct device *dev, 31 + struct device_attribute *intensity_attr, 32 + const char *buf, size_t size) 33 + { 34 + struct led_classdev *led_cdev = dev_get_drvdata(dev); 35 + struct led_classdev_mc *mcled_cdev = lcdev_to_mccdev(led_cdev); 36 + int nrchars, offset = 0; 37 + int intensity_value[LED_COLOR_ID_MAX]; 38 + int i; 39 + ssize_t ret; 40 + 41 + mutex_lock(&led_cdev->led_access); 42 + 43 + for (i = 0; i < mcled_cdev->num_colors; i++) { 44 + ret = sscanf(buf + offset, "%i%n", 45 + &intensity_value[i], &nrchars); 46 + if (ret != 1) { 47 + ret = -EINVAL; 48 + goto err_out; 49 + } 50 + offset += nrchars; 51 + } 52 + 53 + offset++; 54 + if (offset < size) { 55 + ret = -EINVAL; 56 + goto err_out; 57 + } 58 + 59 + for (i = 0; i < mcled_cdev->num_colors; i++) 60 + mcled_cdev->subled_info[i].intensity = intensity_value[i]; 61 + 62 + led_set_brightness(led_cdev, led_cdev->brightness); 63 + ret = size; 64 + err_out: 65 + mutex_unlock(&led_cdev->led_access); 66 + return ret; 67 + } 68 + 69 + static ssize_t multi_intensity_show(struct device *dev, 70 + struct device_attribute *intensity_attr, 71 + char *buf) 72 + { 73 + struct led_classdev *led_cdev = dev_get_drvdata(dev); 74 + struct led_classdev_mc *mcled_cdev = lcdev_to_mccdev(led_cdev); 75 + int len = 0; 76 + int i; 77 + 78 + for (i = 0; i < mcled_cdev->num_colors; i++) { 79 + len += sprintf(buf + len, "%d", 80 + mcled_cdev->subled_info[i].intensity); 81 + if (i < mcled_cdev->num_colors - 1) 82 + len += sprintf(buf + len, " "); 83 + } 84 + 85 + buf[len++] = '\n'; 86 + return len; 87 + } 88 + static DEVICE_ATTR_RW(multi_intensity); 89 + 90 + static ssize_t multi_index_show(struct device *dev, 91 + struct device_attribute *multi_index_attr, 92 + char *buf) 93 + { 94 + struct led_classdev *led_cdev = dev_get_drvdata(dev); 95 + struct led_classdev_mc *mcled_cdev = lcdev_to_mccdev(led_cdev); 96 + int len = 0; 97 + int index; 98 + int i; 99 + 100 + for (i = 0; i < mcled_cdev->num_colors; i++) { 101 + index = mcled_cdev->subled_info[i].color_index; 102 + len += sprintf(buf + len, "%s", led_colors[index]); 103 + if (i < mcled_cdev->num_colors - 1) 104 + len += sprintf(buf + len, " "); 105 + } 106 + 107 + buf[len++] = '\n'; 108 + return len; 109 + } 110 + static DEVICE_ATTR_RO(multi_index); 111 + 112 + static struct attribute *led_multicolor_attrs[] = { 113 + &dev_attr_multi_intensity.attr, 114 + &dev_attr_multi_index.attr, 115 + NULL, 116 + }; 117 + ATTRIBUTE_GROUPS(led_multicolor); 118 + 119 + int led_classdev_multicolor_register_ext(struct device *parent, 120 + struct led_classdev_mc *mcled_cdev, 121 + struct led_init_data *init_data) 122 + { 123 + struct led_classdev *led_cdev; 124 + 125 + if (!mcled_cdev) 126 + return -EINVAL; 127 + 128 + if (mcled_cdev->num_colors <= 0) 129 + return -EINVAL; 130 + 131 + if (mcled_cdev->num_colors > LED_COLOR_ID_MAX) 132 + return -EINVAL; 133 + 134 + led_cdev = &mcled_cdev->led_cdev; 135 + mcled_cdev->led_cdev.groups = led_multicolor_groups; 136 + 137 + return led_classdev_register_ext(parent, led_cdev, init_data); 138 + } 139 + EXPORT_SYMBOL_GPL(led_classdev_multicolor_register_ext); 140 + 141 + void led_classdev_multicolor_unregister(struct led_classdev_mc *mcled_cdev) 142 + { 143 + if (!mcled_cdev) 144 + return; 145 + 146 + led_classdev_unregister(&mcled_cdev->led_cdev); 147 + } 148 + EXPORT_SYMBOL_GPL(led_classdev_multicolor_unregister); 149 + 150 + static void devm_led_classdev_multicolor_release(struct device *dev, void *res) 151 + { 152 + led_classdev_multicolor_unregister(*(struct led_classdev_mc **)res); 153 + } 154 + 155 + int devm_led_classdev_multicolor_register_ext(struct device *parent, 156 + struct led_classdev_mc *mcled_cdev, 157 + struct led_init_data *init_data) 158 + { 159 + struct led_classdev_mc **dr; 160 + int ret; 161 + 162 + dr = devres_alloc(devm_led_classdev_multicolor_release, 163 + sizeof(*dr), GFP_KERNEL); 164 + if (!dr) 165 + return -ENOMEM; 166 + 167 + ret = led_classdev_multicolor_register_ext(parent, mcled_cdev, 168 + init_data); 169 + if (ret) { 170 + devres_free(dr); 171 + return ret; 172 + } 173 + 174 + *dr = mcled_cdev; 175 + devres_add(parent, dr); 176 + 177 + return 0; 178 + } 179 + EXPORT_SYMBOL_GPL(devm_led_classdev_multicolor_register_ext); 180 + 181 + static int devm_led_classdev_multicolor_match(struct device *dev, 182 + void *res, void *data) 183 + { 184 + struct led_classdev_mc **p = res; 185 + 186 + if (WARN_ON(!p || !*p)) 187 + return 0; 188 + 189 + return *p == data; 190 + } 191 + 192 + void devm_led_classdev_multicolor_unregister(struct device *dev, 193 + struct led_classdev_mc *mcled_cdev) 194 + { 195 + WARN_ON(devres_release(dev, 196 + devm_led_classdev_multicolor_release, 197 + devm_led_classdev_multicolor_match, mcled_cdev)); 198 + } 199 + EXPORT_SYMBOL_GPL(devm_led_classdev_multicolor_unregister); 200 + 201 + MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>"); 202 + MODULE_DESCRIPTION("Multicolor LED class interface"); 203 + MODULE_LICENSE("GPL v2");
+1
drivers/leds/led-class.c
··· 173 173 { 174 174 led_cdev->flags |= LED_SUSPENDED; 175 175 led_set_brightness_nopm(led_cdev, 0); 176 + flush_work(&led_cdev->set_brightness_work); 176 177 } 177 178 EXPORT_SYMBOL_GPL(led_classdev_suspend); 178 179
+6
drivers/leds/led-core.c
··· 34 34 [LED_COLOR_ID_VIOLET] = "violet", 35 35 [LED_COLOR_ID_YELLOW] = "yellow", 36 36 [LED_COLOR_ID_IR] = "ir", 37 + [LED_COLOR_ID_MULTI] = "multicolor", 38 + [LED_COLOR_ID_RGB] = "rgb", 37 39 }; 38 40 EXPORT_SYMBOL_GPL(led_colors); 39 41 ··· 424 422 struct led_properties props = {}; 425 423 struct fwnode_handle *fwnode = init_data->fwnode; 426 424 const char *devicename = init_data->devicename; 425 + 426 + /* We want to label LEDs that can produce full range of colors 427 + * as RGB, not multicolor */ 428 + BUG_ON(props.color == LED_COLOR_ID_MULTI); 427 429 428 430 if (!led_classdev_name) 429 431 return -EINVAL;
+21 -7
drivers/leds/led-triggers.c
··· 27 27 28 28 /* Used by LED Class */ 29 29 30 + static inline bool 31 + trigger_relevant(struct led_classdev *led_cdev, struct led_trigger *trig) 32 + { 33 + return !trig->trigger_type || trig->trigger_type == led_cdev->trigger_type; 34 + } 35 + 30 36 ssize_t led_trigger_write(struct file *filp, struct kobject *kobj, 31 37 struct bin_attribute *bin_attr, char *buf, 32 38 loff_t pos, size_t count) ··· 56 50 57 51 down_read(&triggers_list_lock); 58 52 list_for_each_entry(trig, &trigger_list, next_trig) { 59 - if (sysfs_streq(buf, trig->name)) { 53 + if (sysfs_streq(buf, trig->name) && trigger_relevant(led_cdev, trig)) { 60 54 down_write(&led_cdev->trigger_lock); 61 55 led_trigger_set(led_cdev, trig); 62 56 up_write(&led_cdev->trigger_lock); ··· 99 93 led_cdev->trigger ? "none" : "[none]"); 100 94 101 95 list_for_each_entry(trig, &trigger_list, next_trig) { 102 - bool hit = led_cdev->trigger && 103 - !strcmp(led_cdev->trigger->name, trig->name); 96 + bool hit; 97 + 98 + if (!trigger_relevant(led_cdev, trig)) 99 + continue; 100 + 101 + hit = led_cdev->trigger && !strcmp(led_cdev->trigger->name, trig->name); 104 102 105 103 len += led_trigger_snprintf(buf + len, size - len, 106 104 " %s%s%s", hit ? "[" : "", ··· 253 243 down_read(&triggers_list_lock); 254 244 down_write(&led_cdev->trigger_lock); 255 245 list_for_each_entry(trig, &trigger_list, next_trig) { 256 - if (!strcmp(led_cdev->default_trigger, trig->name)) { 246 + if (!strcmp(led_cdev->default_trigger, trig->name) && 247 + trigger_relevant(led_cdev, trig)) { 257 248 led_cdev->flags |= LED_INIT_DEFAULT_TRIGGER; 258 249 led_trigger_set(led_cdev, trig); 259 250 break; ··· 291 280 down_write(&triggers_list_lock); 292 281 /* Make sure the trigger's name isn't already in use */ 293 282 list_for_each_entry(_trig, &trigger_list, next_trig) { 294 - if (!strcmp(_trig->name, trig->name)) { 283 + if (!strcmp(_trig->name, trig->name) && 284 + (trig->trigger_type == _trig->trigger_type || 285 + !trig->trigger_type || !_trig->trigger_type)) { 295 286 up_write(&triggers_list_lock); 296 287 return -EEXIST; 297 288 } ··· 307 294 list_for_each_entry(led_cdev, &leds_list, node) { 308 295 down_write(&led_cdev->trigger_lock); 309 296 if (!led_cdev->trigger && led_cdev->default_trigger && 310 - !strcmp(led_cdev->default_trigger, trig->name)) { 297 + !strcmp(led_cdev->default_trigger, trig->name) && 298 + trigger_relevant(led_cdev, trig)) { 311 299 led_cdev->flags |= LED_INIT_DEFAULT_TRIGGER; 312 300 led_trigger_set(led_cdev, trig); 313 301 } ··· 372 358 } 373 359 EXPORT_SYMBOL_GPL(devm_led_trigger_register); 374 360 375 - /* Simple LED Tigger Interface */ 361 + /* Simple LED Trigger Interface */ 376 362 377 363 void led_trigger_event(struct led_trigger *trig, 378 364 enum led_brightness brightness)
+13 -1
drivers/leds/leds-88pm860x.c
··· 203 203 data->cdev.brightness_set_blocking = pm860x_led_set; 204 204 mutex_init(&data->lock); 205 205 206 - ret = devm_led_classdev_register(chip->dev, &data->cdev); 206 + ret = led_classdev_register(chip->dev, &data->cdev); 207 207 if (ret < 0) { 208 208 dev_err(&pdev->dev, "Failed to register LED: %d\n", ret); 209 209 return ret; 210 210 } 211 211 pm860x_led_set(&data->cdev, 0); 212 + 213 + platform_set_drvdata(pdev, data); 214 + 212 215 return 0; 213 216 } 214 217 218 + static int pm860x_led_remove(struct platform_device *pdev) 219 + { 220 + struct pm860x_led *data = platform_get_drvdata(pdev); 221 + 222 + led_classdev_unregister(&data->cdev); 223 + 224 + return 0; 225 + } 215 226 216 227 static struct platform_driver pm860x_led_driver = { 217 228 .driver = { 218 229 .name = "88pm860x-led", 219 230 }, 220 231 .probe = pm860x_led_probe, 232 + .remove = pm860x_led_remove, 221 233 }; 222 234 223 235 module_platform_driver(pm860x_led_driver);
+75 -22
drivers/leds/leds-bcm6328.c
··· 24 24 25 25 #define BCM6328_LED_MAX_COUNT 24 26 26 #define BCM6328_LED_DEF_DELAY 500 27 - #define BCM6328_LED_INTERVAL_MS 20 28 27 29 - #define BCM6328_LED_INTV_MASK 0x3f 30 - #define BCM6328_LED_FAST_INTV_SHIFT 6 31 - #define BCM6328_LED_FAST_INTV_MASK (BCM6328_LED_INTV_MASK << \ 32 - BCM6328_LED_FAST_INTV_SHIFT) 28 + #define BCM6328_LED_BLINK_DELAYS 2 29 + #define BCM6328_LED_BLINK_MS 20 30 + 31 + #define BCM6328_LED_BLINK_MASK 0x3f 32 + #define BCM6328_LED_BLINK1_SHIFT 0 33 + #define BCM6328_LED_BLINK1_MASK (BCM6328_LED_BLINK_MASK << \ 34 + BCM6328_LED_BLINK1_SHIFT) 35 + #define BCM6328_LED_BLINK2_SHIFT 6 36 + #define BCM6328_LED_BLINK2_MASK (BCM6328_LED_BLINK_MASK << \ 37 + BCM6328_LED_BLINK2_SHIFT) 33 38 #define BCM6328_SERIAL_LED_EN BIT(12) 34 39 #define BCM6328_SERIAL_LED_MUX BIT(13) 35 40 #define BCM6328_SERIAL_LED_CLK_NPOL BIT(14) ··· 50 45 51 46 #define BCM6328_LED_MODE_MASK 3 52 47 #define BCM6328_LED_MODE_ON 0 53 - #define BCM6328_LED_MODE_FAST 1 54 - #define BCM6328_LED_MODE_BLINK 2 48 + #define BCM6328_LED_MODE_BLINK1 1 49 + #define BCM6328_LED_MODE_BLINK2 2 55 50 #define BCM6328_LED_MODE_OFF 3 56 51 #define BCM6328_LED_SHIFT(X) ((X) << 1) 57 52 ··· 132 127 unsigned long flags; 133 128 134 129 spin_lock_irqsave(led->lock, flags); 135 - *(led->blink_leds) &= ~BIT(led->pin); 130 + 131 + /* Remove LED from cached HW blinking intervals */ 132 + led->blink_leds[0] &= ~BIT(led->pin); 133 + led->blink_leds[1] &= ~BIT(led->pin); 134 + 135 + /* Set LED on/off */ 136 136 if ((led->active_low && value == LED_OFF) || 137 137 (!led->active_low && value != LED_OFF)) 138 138 bcm6328_led_mode(led, BCM6328_LED_MODE_ON); 139 139 else 140 140 bcm6328_led_mode(led, BCM6328_LED_MODE_OFF); 141 + 141 142 spin_unlock_irqrestore(led->lock, flags); 142 143 } 143 144 ··· 151 140 { 152 141 unsigned long bcm6328_delay; 153 142 154 - bcm6328_delay = delay + BCM6328_LED_INTERVAL_MS / 2; 155 - bcm6328_delay = bcm6328_delay / BCM6328_LED_INTERVAL_MS; 143 + bcm6328_delay = delay + BCM6328_LED_BLINK_MS / 2; 144 + bcm6328_delay = bcm6328_delay / BCM6328_LED_BLINK_MS; 156 145 if (bcm6328_delay == 0) 157 146 bcm6328_delay = 1; 158 147 ··· 179 168 return -EINVAL; 180 169 } 181 170 182 - if (delay > BCM6328_LED_INTV_MASK) { 171 + if (delay > BCM6328_LED_BLINK_MASK) { 183 172 dev_dbg(led_cdev->dev, 184 173 "fallback to soft blinking (delay > %ums)\n", 185 - BCM6328_LED_INTV_MASK * BCM6328_LED_INTERVAL_MS); 174 + BCM6328_LED_BLINK_MASK * BCM6328_LED_BLINK_MS); 186 175 return -EINVAL; 187 176 } 188 177 189 178 spin_lock_irqsave(led->lock, flags); 190 - if (*(led->blink_leds) == 0 || 191 - *(led->blink_leds) == BIT(led->pin) || 192 - *(led->blink_delay) == delay) { 179 + /* 180 + * Check if any of the two configurable HW blinking intervals is 181 + * available: 182 + * 1. No LEDs assigned to the HW blinking interval. 183 + * 2. Only this LED is assigned to the HW blinking interval. 184 + * 3. LEDs with the same delay assigned. 185 + */ 186 + if (led->blink_leds[0] == 0 || 187 + led->blink_leds[0] == BIT(led->pin) || 188 + led->blink_delay[0] == delay) { 193 189 unsigned long val; 194 190 195 - *(led->blink_leds) |= BIT(led->pin); 196 - *(led->blink_delay) = delay; 191 + /* Add LED to the first HW blinking interval cache */ 192 + led->blink_leds[0] |= BIT(led->pin); 197 193 194 + /* Remove LED from the second HW blinking interval cache */ 195 + led->blink_leds[1] &= ~BIT(led->pin); 196 + 197 + /* Cache first HW blinking interval delay */ 198 + led->blink_delay[0] = delay; 199 + 200 + /* Update the delay for the first HW blinking interval */ 198 201 val = bcm6328_led_read(led->mem + BCM6328_REG_INIT); 199 - val &= ~BCM6328_LED_FAST_INTV_MASK; 200 - val |= (delay << BCM6328_LED_FAST_INTV_SHIFT); 202 + val &= ~BCM6328_LED_BLINK1_MASK; 203 + val |= (delay << BCM6328_LED_BLINK1_SHIFT); 201 204 bcm6328_led_write(led->mem + BCM6328_REG_INIT, val); 202 205 203 - bcm6328_led_mode(led, BCM6328_LED_MODE_BLINK); 206 + /* Set the LED to first HW blinking interval */ 207 + bcm6328_led_mode(led, BCM6328_LED_MODE_BLINK1); 208 + 209 + rc = 0; 210 + } else if (led->blink_leds[1] == 0 || 211 + led->blink_leds[1] == BIT(led->pin) || 212 + led->blink_delay[1] == delay) { 213 + unsigned long val; 214 + 215 + /* Remove LED from the first HW blinking interval */ 216 + led->blink_leds[0] &= ~BIT(led->pin); 217 + 218 + /* Add LED to the second HW blinking interval */ 219 + led->blink_leds[1] |= BIT(led->pin); 220 + 221 + /* Cache second HW blinking interval delay */ 222 + led->blink_delay[1] = delay; 223 + 224 + /* Update the delay for the second HW blinking interval */ 225 + val = bcm6328_led_read(led->mem + BCM6328_REG_INIT); 226 + val &= ~BCM6328_LED_BLINK2_MASK; 227 + val |= (delay << BCM6328_LED_BLINK2_SHIFT); 228 + bcm6328_led_write(led->mem + BCM6328_REG_INIT, val); 229 + 230 + /* Set the LED to second HW blinking interval */ 231 + bcm6328_led_mode(led, BCM6328_LED_MODE_BLINK2); 232 + 204 233 rc = 0; 205 234 } else { 206 235 dev_dbg(led_cdev->dev, ··· 409 358 if (!lock) 410 359 return -ENOMEM; 411 360 412 - blink_leds = devm_kzalloc(dev, sizeof(*blink_leds), GFP_KERNEL); 361 + blink_leds = devm_kcalloc(dev, BCM6328_LED_BLINK_DELAYS, 362 + sizeof(*blink_leds), GFP_KERNEL); 413 363 if (!blink_leds) 414 364 return -ENOMEM; 415 365 416 - blink_delay = devm_kzalloc(dev, sizeof(*blink_delay), GFP_KERNEL); 366 + blink_delay = devm_kcalloc(dev, BCM6328_LED_BLINK_DELAYS, 367 + sizeof(*blink_delay), GFP_KERNEL); 417 368 if (!blink_delay) 418 369 return -ENOMEM; 419 370
+13 -1
drivers/leds/leds-da903x.c
··· 110 110 led->flags = pdata->flags; 111 111 led->master = pdev->dev.parent; 112 112 113 - ret = devm_led_classdev_register(led->master, &led->cdev); 113 + ret = led_classdev_register(led->master, &led->cdev); 114 114 if (ret) { 115 115 dev_err(&pdev->dev, "failed to register LED %d\n", id); 116 116 return ret; 117 117 } 118 + 119 + platform_set_drvdata(pdev, led); 120 + 121 + return 0; 122 + } 123 + 124 + static int da903x_led_remove(struct platform_device *pdev) 125 + { 126 + struct da903x_led *led = platform_get_drvdata(pdev); 127 + 128 + led_classdev_unregister(&led->cdev); 118 129 119 130 return 0; 120 131 } ··· 135 124 .name = "da903x-led", 136 125 }, 137 126 .probe = da903x_led_probe, 127 + .remove = da903x_led_remove, 138 128 }; 139 129 140 130 module_platform_driver(da903x_led_driver);
+4 -11
drivers/leds/leds-gpio.c
··· 125 125 struct gpio_led_data leds[]; 126 126 }; 127 127 128 - static inline int sizeof_gpio_leds_priv(int num_leds) 129 - { 130 - return sizeof(struct gpio_leds_priv) + 131 - (sizeof(struct gpio_led_data) * num_leds); 132 - } 133 - 134 128 static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev) 135 129 { 136 130 struct device *dev = &pdev->dev; ··· 136 142 if (!count) 137 143 return ERR_PTR(-ENODEV); 138 144 139 - priv = devm_kzalloc(dev, sizeof_gpio_leds_priv(count), GFP_KERNEL); 145 + priv = devm_kzalloc(dev, struct_size(priv, leds, count), GFP_KERNEL); 140 146 if (!priv) 141 147 return ERR_PTR(-ENOMEM); 142 148 ··· 214 220 * device, this will hit the board file, if any and get 215 221 * the GPIO from there. 216 222 */ 217 - gpiod = devm_gpiod_get_index(dev, NULL, idx, flags); 223 + gpiod = devm_gpiod_get_index(dev, NULL, idx, GPIOD_OUT_LOW); 218 224 if (!IS_ERR(gpiod)) { 219 225 gpiod_set_consumer_name(gpiod, template->name); 220 226 return gpiod; ··· 254 260 int i, ret = 0; 255 261 256 262 if (pdata && pdata->num_leds) { 257 - priv = devm_kzalloc(&pdev->dev, 258 - sizeof_gpio_leds_priv(pdata->num_leds), 259 - GFP_KERNEL); 263 + priv = devm_kzalloc(&pdev->dev, struct_size(priv, leds, pdata->num_leds), 264 + GFP_KERNEL); 260 265 if (!priv) 261 266 return -ENOMEM; 262 267
+2 -2
drivers/leds/leds-lm3532.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 2 // TI LM3532 LED driver 3 - // Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/ 4 - // http://www.ti.com/lit/ds/symlink/lm3532.pdf 3 + // Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com/ 4 + // https://www.ti.com/lit/ds/symlink/lm3532.pdf 5 5 6 6 #include <linux/i2c.h> 7 7 #include <linux/leds.h>
+9 -3
drivers/leds/leds-lm3533.c
··· 694 694 695 695 platform_set_drvdata(pdev, led); 696 696 697 - ret = devm_led_classdev_register(pdev->dev.parent, &led->cdev); 697 + ret = led_classdev_register(pdev->dev.parent, &led->cdev); 698 698 if (ret) { 699 699 dev_err(&pdev->dev, "failed to register LED %d\n", pdev->id); 700 700 return ret; ··· 704 704 705 705 ret = lm3533_led_setup(led, pdata); 706 706 if (ret) 707 - return ret; 707 + goto err_deregister; 708 708 709 709 ret = lm3533_ctrlbank_enable(&led->cb); 710 710 if (ret) 711 - return ret; 711 + goto err_deregister; 712 712 713 713 return 0; 714 + 715 + err_deregister: 716 + led_classdev_unregister(&led->cdev); 717 + 718 + return ret; 714 719 } 715 720 716 721 static int lm3533_led_remove(struct platform_device *pdev) ··· 725 720 dev_dbg(&pdev->dev, "%s\n", __func__); 726 721 727 722 lm3533_ctrlbank_disable(&led->cb); 723 + led_classdev_unregister(&led->cdev); 728 724 729 725 return 0; 730 726 }
+7 -9
drivers/leds/leds-lm355x.c
··· 164 164 /* input and output pins configuration */ 165 165 switch (chip->type) { 166 166 case CHIP_LM3554: 167 - reg_val = pdata->pin_tx2 | pdata->ntc_pin; 167 + reg_val = (u32)pdata->pin_tx2 | (u32)pdata->ntc_pin; 168 168 ret = regmap_update_bits(chip->regmap, 0xE0, 0x28, reg_val); 169 169 if (ret < 0) 170 170 goto out; 171 - reg_val = pdata->pass_mode; 171 + reg_val = (u32)pdata->pass_mode; 172 172 ret = regmap_update_bits(chip->regmap, 0xA0, 0x04, reg_val); 173 173 if (ret < 0) 174 174 goto out; 175 175 break; 176 176 177 177 case CHIP_LM3556: 178 - reg_val = pdata->pin_tx2 | pdata->ntc_pin | pdata->pass_mode; 178 + reg_val = (u32)pdata->pin_tx2 | (u32)pdata->ntc_pin | 179 + (u32)pdata->pass_mode; 179 180 ret = regmap_update_bits(chip->regmap, 0x0A, 0xC4, reg_val); 180 181 if (ret < 0) 181 182 goto out; ··· 453 452 chip->cdev_flash.max_brightness = 16; 454 453 chip->cdev_flash.brightness_set_blocking = lm355x_strobe_brightness_set; 455 454 chip->cdev_flash.default_trigger = "flash"; 456 - err = led_classdev_register((struct device *) 457 - &client->dev, &chip->cdev_flash); 455 + err = led_classdev_register(&client->dev, &chip->cdev_flash); 458 456 if (err < 0) 459 457 goto err_out; 460 458 /* torch */ ··· 461 461 chip->cdev_torch.max_brightness = 8; 462 462 chip->cdev_torch.brightness_set_blocking = lm355x_torch_brightness_set; 463 463 chip->cdev_torch.default_trigger = "torch"; 464 - err = led_classdev_register((struct device *) 465 - &client->dev, &chip->cdev_torch); 464 + err = led_classdev_register(&client->dev, &chip->cdev_torch); 466 465 if (err < 0) 467 466 goto err_create_torch_file; 468 467 /* indicator */ ··· 475 476 /* indicator pattern control only for LM3556 */ 476 477 if (id->driver_data == CHIP_LM3556) 477 478 chip->cdev_indicator.groups = lm355x_indicator_groups; 478 - err = led_classdev_register((struct device *) 479 - &client->dev, &chip->cdev_indicator); 479 + err = led_classdev_register(&client->dev, &chip->cdev_indicator); 480 480 if (err < 0) 481 481 goto err_create_indicator_file; 482 482
+1 -1
drivers/leds/leds-lm3601x.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 2 // Flash and torch driver for Texas Instruments LM3601X LED 3 3 // Flash driver chip family 4 - // Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ 4 + // Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/ 5 5 6 6 #include <linux/delay.h> 7 7 #include <linux/i2c.h>
+13 -4
drivers/leds/leds-lm36274.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 2 // TI LM36274 LED chip family driver 3 - // Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/ 3 + // Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com/ 4 4 5 5 #include <linux/bitops.h> 6 6 #include <linux/device.h> ··· 133 133 lm36274_data->pdev = pdev; 134 134 lm36274_data->dev = lmu->dev; 135 135 lm36274_data->regmap = lmu->regmap; 136 - dev_set_drvdata(&pdev->dev, lm36274_data); 136 + platform_set_drvdata(pdev, lm36274_data); 137 137 138 138 ret = lm36274_parse_dt(lm36274_data); 139 139 if (ret) { ··· 147 147 return ret; 148 148 } 149 149 150 - return devm_led_classdev_register(lm36274_data->dev, 151 - &lm36274_data->led_dev); 150 + return led_classdev_register(lm36274_data->dev, &lm36274_data->led_dev); 151 + } 152 + 153 + static int lm36274_remove(struct platform_device *pdev) 154 + { 155 + struct lm36274 *lm36274_data = platform_get_drvdata(pdev); 156 + 157 + led_classdev_unregister(&lm36274_data->led_dev); 158 + 159 + return 0; 152 160 } 153 161 154 162 static const struct of_device_id of_lm36274_leds_match[] = { ··· 167 159 168 160 static struct platform_driver lm36274_driver = { 169 161 .probe = lm36274_probe, 162 + .remove = lm36274_remove, 170 163 .driver = { 171 164 .name = "lm36274-leds", 172 165 },
+3 -6
drivers/leds/leds-lm3642.c
··· 340 340 chip->cdev_flash.brightness_set_blocking = lm3642_strobe_brightness_set; 341 341 chip->cdev_flash.default_trigger = "flash"; 342 342 chip->cdev_flash.groups = lm3642_flash_groups, 343 - err = led_classdev_register((struct device *) 344 - &client->dev, &chip->cdev_flash); 343 + err = led_classdev_register(&client->dev, &chip->cdev_flash); 345 344 if (err < 0) { 346 345 dev_err(chip->dev, "failed to register flash\n"); 347 346 goto err_out; ··· 352 353 chip->cdev_torch.brightness_set_blocking = lm3642_torch_brightness_set; 353 354 chip->cdev_torch.default_trigger = "torch"; 354 355 chip->cdev_torch.groups = lm3642_torch_groups, 355 - err = led_classdev_register((struct device *) 356 - &client->dev, &chip->cdev_torch); 356 + err = led_classdev_register(&client->dev, &chip->cdev_torch); 357 357 if (err < 0) { 358 358 dev_err(chip->dev, "failed to register torch\n"); 359 359 goto err_create_torch_file; ··· 363 365 chip->cdev_indicator.max_brightness = 8; 364 366 chip->cdev_indicator.brightness_set_blocking = 365 367 lm3642_indicator_brightness_set; 366 - err = led_classdev_register((struct device *) 367 - &client->dev, &chip->cdev_indicator); 368 + err = led_classdev_register(&client->dev, &chip->cdev_indicator); 368 369 if (err < 0) { 369 370 dev_err(chip->dev, "failed to register indicator\n"); 370 371 goto err_create_indicator_file;
+1 -1
drivers/leds/leds-lm3692x.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 2 // TI LM3692x LED chip family driver 3 - // Copyright (C) 2017-18 Texas Instruments Incorporated - http://www.ti.com/ 3 + // Copyright (C) 2017-18 Texas Instruments Incorporated - https://www.ti.com/ 4 4 5 5 #include <linux/gpio/consumer.h> 6 6 #include <linux/i2c.h>
+1 -1
drivers/leds/leds-lm3697.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 2 // TI LM3697 LED chip family driver 3 - // Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ 3 + // Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/ 4 4 5 5 #include <linux/gpio/consumer.h> 6 6 #include <linux/i2c.h>
+31 -12
drivers/leds/leds-lp5521.c
··· 349 349 return 0; 350 350 } 351 351 352 + static int lp5521_multicolor_brightness(struct lp55xx_led *led) 353 + { 354 + struct lp55xx_chip *chip = led->chip; 355 + int ret; 356 + int i; 357 + 358 + mutex_lock(&chip->lock); 359 + for (i = 0; i < led->mc_cdev.num_colors; i++) { 360 + ret = lp55xx_write(chip, 361 + LP5521_REG_LED_PWM_BASE + 362 + led->mc_cdev.subled_info[i].channel, 363 + led->mc_cdev.subled_info[i].brightness); 364 + if (ret) 365 + break; 366 + } 367 + mutex_unlock(&chip->lock); 368 + return ret; 369 + } 370 + 352 371 static int lp5521_led_brightness(struct lp55xx_led *led) 353 372 { 354 373 struct lp55xx_chip *chip = led->chip; ··· 509 490 .max_channel = LP5521_MAX_LEDS, 510 491 .post_init_device = lp5521_post_init_device, 511 492 .brightness_fn = lp5521_led_brightness, 493 + .multicolor_brightness_fn = lp5521_multicolor_brightness, 512 494 .set_led_current = lp5521_set_led_current, 513 495 .firmware_cb = lp5521_firmware_loaded, 514 496 .run_engine = lp5521_run_engine, ··· 525 505 struct lp55xx_platform_data *pdata = dev_get_platdata(&client->dev); 526 506 struct device_node *np = client->dev.of_node; 527 507 508 + chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); 509 + if (!chip) 510 + return -ENOMEM; 511 + 512 + chip->cfg = &lp5521_cfg; 513 + 528 514 if (!pdata) { 529 515 if (np) { 530 - pdata = lp55xx_of_populate_pdata(&client->dev, np); 516 + pdata = lp55xx_of_populate_pdata(&client->dev, np, 517 + chip); 531 518 if (IS_ERR(pdata)) 532 519 return PTR_ERR(pdata); 533 520 } else { ··· 543 516 } 544 517 } 545 518 546 - chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); 547 - if (!chip) 548 - return -ENOMEM; 549 - 550 519 led = devm_kcalloc(&client->dev, 551 520 pdata->num_channels, sizeof(*led), GFP_KERNEL); 552 521 if (!led) ··· 550 527 551 528 chip->cl = client; 552 529 chip->pdata = pdata; 553 - chip->cfg = &lp5521_cfg; 554 530 555 531 mutex_init(&chip->lock); 556 532 ··· 563 541 564 542 ret = lp55xx_register_leds(led, chip); 565 543 if (ret) 566 - goto err_register_leds; 544 + goto err_out; 567 545 568 546 ret = lp55xx_register_sysfs(chip); 569 547 if (ret) { 570 548 dev_err(&client->dev, "registering sysfs failed\n"); 571 - goto err_register_sysfs; 549 + goto err_out; 572 550 } 573 551 574 552 return 0; 575 553 576 - err_register_sysfs: 577 - lp55xx_unregister_leds(led, chip); 578 - err_register_leds: 554 + err_out: 579 555 lp55xx_deinit_device(chip); 580 556 err_init: 581 557 return ret; ··· 586 566 587 567 lp5521_stop_all_engines(chip); 588 568 lp55xx_unregister_sysfs(chip); 589 - lp55xx_unregister_leds(led, chip); 590 569 lp55xx_deinit_device(chip); 591 570 592 571 return 0;
+41 -21
drivers/leds/leds-lp5523.c
··· 23 23 24 24 #define LP5523_PROGRAM_LENGTH 32 /* bytes */ 25 25 /* Memory is used like this: 26 - 0x00 engine 1 program 27 - 0x10 engine 2 program 28 - 0x20 engine 3 program 29 - 0x30 engine 1 muxing info 30 - 0x40 engine 2 muxing info 31 - 0x50 engine 3 muxing info 32 - */ 26 + * 0x00 engine 1 program 27 + * 0x10 engine 2 program 28 + * 0x20 engine 3 program 29 + * 0x30 engine 1 muxing info 30 + * 0x40 engine 2 muxing info 31 + * 0x50 engine 3 muxing info 32 + */ 33 33 #define LP5523_MAX_LEDS 9 34 34 35 35 /* Registers */ ··· 326 326 const u8 *data, size_t size) 327 327 { 328 328 u8 pattern[LP5523_PROGRAM_LENGTH] = {0}; 329 - unsigned cmd; 329 + unsigned int cmd; 330 330 char c[3]; 331 331 int nrchars; 332 332 int ret; ··· 468 468 static void lp5523_mux_to_array(u16 led_mux, char *array) 469 469 { 470 470 int i, pos = 0; 471 + 471 472 for (i = 0; i < LP5523_MAX_LEDS; i++) 472 473 pos += sprintf(array + pos, "%x", LED_ACTIVE(led_mux, i)); 473 474 ··· 507 506 if (ret) 508 507 return ret; 509 508 510 - ret = lp55xx_write(chip, LP5523_REG_PROG_MEM , (u8)(mux >> 8)); 509 + ret = lp55xx_write(chip, LP5523_REG_PROG_MEM, (u8)(mux >> 8)); 511 510 if (ret) 512 511 return ret; 513 512 ··· 792 791 return ret; 793 792 } 794 793 794 + static int lp5523_multicolor_brightness(struct lp55xx_led *led) 795 + { 796 + struct lp55xx_chip *chip = led->chip; 797 + int ret; 798 + int i; 799 + 800 + mutex_lock(&chip->lock); 801 + for (i = 0; i < led->mc_cdev.num_colors; i++) { 802 + ret = lp55xx_write(chip, 803 + LP5523_REG_LED_PWM_BASE + 804 + led->mc_cdev.subled_info[i].channel, 805 + led->mc_cdev.subled_info[i].brightness); 806 + if (ret) 807 + break; 808 + } 809 + mutex_unlock(&chip->lock); 810 + return ret; 811 + } 812 + 795 813 static int lp5523_led_brightness(struct lp55xx_led *led) 796 814 { 797 815 struct lp55xx_chip *chip = led->chip; ··· 877 857 .max_channel = LP5523_MAX_LEDS, 878 858 .post_init_device = lp5523_post_init_device, 879 859 .brightness_fn = lp5523_led_brightness, 860 + .multicolor_brightness_fn = lp5523_multicolor_brightness, 880 861 .set_led_current = lp5523_set_led_current, 881 862 .firmware_cb = lp5523_firmware_loaded, 882 863 .run_engine = lp5523_run_engine, ··· 893 872 struct lp55xx_platform_data *pdata = dev_get_platdata(&client->dev); 894 873 struct device_node *np = client->dev.of_node; 895 874 875 + chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); 876 + if (!chip) 877 + return -ENOMEM; 878 + 879 + chip->cfg = &lp5523_cfg; 880 + 896 881 if (!pdata) { 897 882 if (np) { 898 - pdata = lp55xx_of_populate_pdata(&client->dev, np); 883 + pdata = lp55xx_of_populate_pdata(&client->dev, np, 884 + chip); 899 885 if (IS_ERR(pdata)) 900 886 return PTR_ERR(pdata); 901 887 } else { ··· 911 883 } 912 884 } 913 885 914 - chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); 915 - if (!chip) 916 - return -ENOMEM; 917 - 918 886 led = devm_kcalloc(&client->dev, 919 887 pdata->num_channels, sizeof(*led), GFP_KERNEL); 920 888 if (!led) ··· 918 894 919 895 chip->cl = client; 920 896 chip->pdata = pdata; 921 - chip->cfg = &lp5523_cfg; 922 897 923 898 mutex_init(&chip->lock); 924 899 ··· 931 908 932 909 ret = lp55xx_register_leds(led, chip); 933 910 if (ret) 934 - goto err_register_leds; 911 + goto err_out; 935 912 936 913 ret = lp55xx_register_sysfs(chip); 937 914 if (ret) { 938 915 dev_err(&client->dev, "registering sysfs failed\n"); 939 - goto err_register_sysfs; 916 + goto err_out; 940 917 } 941 918 942 919 return 0; 943 920 944 - err_register_sysfs: 945 - lp55xx_unregister_leds(led, chip); 946 - err_register_leds: 921 + err_out: 947 922 lp55xx_deinit_device(chip); 948 923 err_init: 949 924 return ret; ··· 954 933 955 934 lp5523_stop_all_engines(chip); 956 935 lp55xx_unregister_sysfs(chip); 957 - lp55xx_unregister_leds(led, chip); 958 936 lp55xx_deinit_device(chip); 959 937 960 938 return 0;
+11 -11
drivers/leds/leds-lp5562.c
··· 520 520 struct lp55xx_platform_data *pdata = dev_get_platdata(&client->dev); 521 521 struct device_node *np = client->dev.of_node; 522 522 523 + chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); 524 + if (!chip) 525 + return -ENOMEM; 526 + 527 + chip->cfg = &lp5562_cfg; 528 + 523 529 if (!pdata) { 524 530 if (np) { 525 - pdata = lp55xx_of_populate_pdata(&client->dev, np); 531 + pdata = lp55xx_of_populate_pdata(&client->dev, np, 532 + chip); 526 533 if (IS_ERR(pdata)) 527 534 return PTR_ERR(pdata); 528 535 } else { ··· 538 531 } 539 532 } 540 533 541 - chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); 542 - if (!chip) 543 - return -ENOMEM; 544 534 545 535 led = devm_kcalloc(&client->dev, 546 536 pdata->num_channels, sizeof(*led), GFP_KERNEL); ··· 546 542 547 543 chip->cl = client; 548 544 chip->pdata = pdata; 549 - chip->cfg = &lp5562_cfg; 550 545 551 546 mutex_init(&chip->lock); 552 547 ··· 557 554 558 555 ret = lp55xx_register_leds(led, chip); 559 556 if (ret) 560 - goto err_register_leds; 557 + goto err_out; 561 558 562 559 ret = lp55xx_register_sysfs(chip); 563 560 if (ret) { 564 561 dev_err(&client->dev, "registering sysfs failed\n"); 565 - goto err_register_sysfs; 562 + goto err_out; 566 563 } 567 564 568 565 return 0; 569 566 570 - err_register_sysfs: 571 - lp55xx_unregister_leds(led, chip); 572 - err_register_leds: 567 + err_out: 573 568 lp55xx_deinit_device(chip); 574 569 err_init: 575 570 return ret; ··· 581 580 lp5562_stop_engine(chip); 582 581 583 582 lp55xx_unregister_sysfs(chip); 584 - lp55xx_unregister_leds(led, chip); 585 583 lp55xx_deinit_device(chip); 586 584 587 585 return 0;
+180 -67
drivers/leds/leds-lp55xx-common.c
··· 17 17 #include <linux/module.h> 18 18 #include <linux/platform_data/leds-lp55xx.h> 19 19 #include <linux/slab.h> 20 - #include <linux/gpio.h> 21 - #include <linux/of_gpio.h> 20 + #include <linux/gpio/consumer.h> 22 21 23 22 #include "leds-lp55xx-common.h" 24 23 ··· 32 33 static struct lp55xx_led *dev_to_lp55xx_led(struct device *dev) 33 34 { 34 35 return cdev_to_lp55xx_led(dev_get_drvdata(dev)); 36 + } 37 + 38 + static struct lp55xx_led *mcled_cdev_to_led(struct led_classdev_mc *mc_cdev) 39 + { 40 + return container_of(mc_cdev, struct lp55xx_led, mc_cdev); 35 41 } 36 42 37 43 static void lp55xx_reset_device(struct lp55xx_chip *chip) ··· 82 78 return cfg->post_init_device(chip); 83 79 } 84 80 85 - static ssize_t lp55xx_show_current(struct device *dev, 81 + static ssize_t led_current_show(struct device *dev, 86 82 struct device_attribute *attr, 87 83 char *buf) 88 84 { ··· 91 87 return scnprintf(buf, PAGE_SIZE, "%d\n", led->led_current); 92 88 } 93 89 94 - static ssize_t lp55xx_store_current(struct device *dev, 90 + static ssize_t led_current_store(struct device *dev, 95 91 struct device_attribute *attr, 96 92 const char *buf, size_t len) 97 93 { ··· 115 111 return len; 116 112 } 117 113 118 - static ssize_t lp55xx_show_max_current(struct device *dev, 114 + static ssize_t max_current_show(struct device *dev, 119 115 struct device_attribute *attr, 120 116 char *buf) 121 117 { ··· 124 120 return scnprintf(buf, PAGE_SIZE, "%d\n", led->max_current); 125 121 } 126 122 127 - static DEVICE_ATTR(led_current, S_IRUGO | S_IWUSR, lp55xx_show_current, 128 - lp55xx_store_current); 129 - static DEVICE_ATTR(max_current, S_IRUGO , lp55xx_show_max_current, NULL); 123 + static DEVICE_ATTR_RW(led_current); 124 + static DEVICE_ATTR_RO(max_current); 130 125 131 126 static struct attribute *lp55xx_led_attrs[] = { 132 127 &dev_attr_led_current.attr, ··· 133 130 NULL, 134 131 }; 135 132 ATTRIBUTE_GROUPS(lp55xx_led); 133 + 134 + static int lp55xx_set_mc_brightness(struct led_classdev *cdev, 135 + enum led_brightness brightness) 136 + { 137 + struct led_classdev_mc *mc_dev = lcdev_to_mccdev(cdev); 138 + struct lp55xx_led *led = mcled_cdev_to_led(mc_dev); 139 + struct lp55xx_device_config *cfg = led->chip->cfg; 140 + 141 + led_mc_calc_color_components(&led->mc_cdev, brightness); 142 + return cfg->multicolor_brightness_fn(led); 143 + 144 + } 136 145 137 146 static int lp55xx_set_brightness(struct led_classdev *cdev, 138 147 enum led_brightness brightness) ··· 162 147 struct lp55xx_platform_data *pdata = chip->pdata; 163 148 struct lp55xx_device_config *cfg = chip->cfg; 164 149 struct device *dev = &chip->cl->dev; 165 - char name[32]; 166 - int ret; 167 150 int max_channel = cfg->max_channel; 151 + struct mc_subled *mc_led_info; 152 + struct led_classdev *led_cdev; 153 + char name[32]; 154 + int i, j = 0; 155 + int ret; 168 156 169 157 if (chan >= max_channel) { 170 158 dev_err(dev, "invalid channel: %d / %d\n", chan, max_channel); ··· 177 159 if (pdata->led_config[chan].led_current == 0) 178 160 return 0; 179 161 180 - led->led_current = pdata->led_config[chan].led_current; 181 - led->max_current = pdata->led_config[chan].max_current; 182 - led->chan_nr = pdata->led_config[chan].chan_nr; 183 - led->cdev.default_trigger = pdata->led_config[chan].default_trigger; 184 - 185 - if (led->chan_nr >= max_channel) { 186 - dev_err(dev, "Use channel numbers between 0 and %d\n", 187 - max_channel - 1); 188 - return -EINVAL; 189 - } 190 - 191 - led->cdev.brightness_set_blocking = lp55xx_set_brightness; 192 - led->cdev.groups = lp55xx_led_groups; 193 - 194 162 if (pdata->led_config[chan].name) { 195 163 led->cdev.name = pdata->led_config[chan].name; 196 164 } else { ··· 185 181 led->cdev.name = name; 186 182 } 187 183 188 - ret = led_classdev_register(dev, &led->cdev); 184 + if (pdata->led_config[chan].num_colors > 1) { 185 + mc_led_info = devm_kcalloc(dev, 186 + pdata->led_config[chan].num_colors, 187 + sizeof(*mc_led_info), GFP_KERNEL); 188 + if (!mc_led_info) 189 + return -ENOMEM; 190 + 191 + led_cdev = &led->mc_cdev.led_cdev; 192 + led_cdev->name = led->cdev.name; 193 + led_cdev->brightness_set_blocking = lp55xx_set_mc_brightness; 194 + led->mc_cdev.num_colors = pdata->led_config[chan].num_colors; 195 + for (i = 0; i < led->mc_cdev.num_colors; i++) { 196 + mc_led_info[i].color_index = 197 + pdata->led_config[chan].color_id[i]; 198 + mc_led_info[i].channel = 199 + pdata->led_config[chan].output_num[i]; 200 + j++; 201 + } 202 + 203 + led->mc_cdev.subled_info = mc_led_info; 204 + } else { 205 + led->cdev.brightness_set_blocking = lp55xx_set_brightness; 206 + } 207 + 208 + led->cdev.groups = lp55xx_led_groups; 209 + led->cdev.default_trigger = pdata->led_config[chan].default_trigger; 210 + led->led_current = pdata->led_config[chan].led_current; 211 + led->max_current = pdata->led_config[chan].max_current; 212 + led->chan_nr = pdata->led_config[chan].chan_nr; 213 + 214 + if (led->chan_nr >= max_channel) { 215 + dev_err(dev, "Use channel numbers between 0 and %d\n", 216 + max_channel - 1); 217 + return -EINVAL; 218 + } 219 + 220 + if (pdata->led_config[chan].num_colors > 1) 221 + ret = devm_led_classdev_multicolor_register(dev, &led->mc_cdev); 222 + else 223 + ret = devm_led_classdev_register(dev, &led->cdev); 224 + 189 225 if (ret) { 190 226 dev_err(dev, "led register err: %d\n", ret); 191 227 return ret; ··· 269 225 GFP_KERNEL, chip, lp55xx_firmware_loaded); 270 226 } 271 227 272 - static ssize_t lp55xx_show_engine_select(struct device *dev, 228 + static ssize_t select_engine_show(struct device *dev, 273 229 struct device_attribute *attr, 274 230 char *buf) 275 231 { ··· 279 235 return sprintf(buf, "%d\n", chip->engine_idx); 280 236 } 281 237 282 - static ssize_t lp55xx_store_engine_select(struct device *dev, 238 + static ssize_t select_engine_store(struct device *dev, 283 239 struct device_attribute *attr, 284 240 const char *buf, size_t len) 285 241 { ··· 321 277 chip->cfg->run_engine(chip, start); 322 278 } 323 279 324 - static ssize_t lp55xx_store_engine_run(struct device *dev, 280 + static ssize_t run_engine_store(struct device *dev, 325 281 struct device_attribute *attr, 326 282 const char *buf, size_t len) 327 283 { ··· 346 302 return len; 347 303 } 348 304 349 - static DEVICE_ATTR(select_engine, S_IRUGO | S_IWUSR, 350 - lp55xx_show_engine_select, lp55xx_store_engine_select); 351 - static DEVICE_ATTR(run_engine, S_IWUSR, NULL, lp55xx_store_engine_run); 305 + static DEVICE_ATTR_RW(select_engine); 306 + static DEVICE_ATTR_WO(run_engine); 352 307 353 308 static struct attribute *lp55xx_engine_attributes[] = { 354 309 &dev_attr_select_engine.attr, ··· 438 395 if (!pdata || !cfg) 439 396 return -EINVAL; 440 397 441 - if (gpio_is_valid(pdata->enable_gpio)) { 442 - ret = devm_gpio_request_one(dev, pdata->enable_gpio, 443 - GPIOF_DIR_OUT, "lp5523_enable"); 444 - if (ret < 0) { 445 - dev_err(dev, "could not acquire enable gpio (err=%d)\n", 446 - ret); 447 - goto err; 448 - } 449 - 450 - gpio_set_value(pdata->enable_gpio, 0); 398 + if (pdata->enable_gpiod) { 399 + gpiod_set_consumer_name(pdata->enable_gpiod, "LP55xx enable"); 400 + gpiod_set_value(pdata->enable_gpiod, 0); 451 401 usleep_range(1000, 2000); /* Keep enable down at least 1ms */ 452 - gpio_set_value(pdata->enable_gpio, 1); 402 + gpiod_set_value(pdata->enable_gpiod, 1); 453 403 usleep_range(1000, 2000); /* 500us abs min. */ 454 404 } 455 405 ··· 483 447 if (chip->clk) 484 448 clk_disable_unprepare(chip->clk); 485 449 486 - if (gpio_is_valid(pdata->enable_gpio)) 487 - gpio_set_value(pdata->enable_gpio, 0); 450 + if (pdata->enable_gpiod) 451 + gpiod_set_value(pdata->enable_gpiod, 0); 488 452 } 489 453 EXPORT_SYMBOL_GPL(lp55xx_deinit_device); 490 454 ··· 526 490 return 0; 527 491 528 492 err_init_led: 529 - lp55xx_unregister_leds(led, chip); 530 493 return ret; 531 494 } 532 495 EXPORT_SYMBOL_GPL(lp55xx_register_leds); 533 - 534 - void lp55xx_unregister_leds(struct lp55xx_led *led, struct lp55xx_chip *chip) 535 - { 536 - int i; 537 - struct lp55xx_led *each; 538 - 539 - for (i = 0; i < chip->num_leds; i++) { 540 - each = led + i; 541 - led_classdev_unregister(&each->cdev); 542 - } 543 - } 544 - EXPORT_SYMBOL_GPL(lp55xx_unregister_leds); 545 496 546 497 int lp55xx_register_sysfs(struct lp55xx_chip *chip) 547 498 { ··· 561 538 } 562 539 EXPORT_SYMBOL_GPL(lp55xx_unregister_sysfs); 563 540 541 + static int lp55xx_parse_common_child(struct device_node *np, 542 + struct lp55xx_led_config *cfg, 543 + int led_number, int *chan_nr) 544 + { 545 + int ret; 546 + 547 + of_property_read_string(np, "chan-name", 548 + &cfg[led_number].name); 549 + of_property_read_u8(np, "led-cur", 550 + &cfg[led_number].led_current); 551 + of_property_read_u8(np, "max-cur", 552 + &cfg[led_number].max_current); 553 + 554 + ret = of_property_read_u32(np, "reg", chan_nr); 555 + if (ret) 556 + return ret; 557 + 558 + if (*chan_nr < 0 || *chan_nr > cfg->max_channel) 559 + return -EINVAL; 560 + 561 + return 0; 562 + } 563 + 564 + static int lp55xx_parse_multi_led_child(struct device_node *child, 565 + struct lp55xx_led_config *cfg, 566 + int child_number, int color_number) 567 + { 568 + int chan_nr, color_id, ret; 569 + 570 + ret = lp55xx_parse_common_child(child, cfg, child_number, &chan_nr); 571 + if (ret) 572 + return ret; 573 + 574 + ret = of_property_read_u32(child, "color", &color_id); 575 + if (ret) 576 + return ret; 577 + 578 + cfg[child_number].color_id[color_number] = color_id; 579 + cfg[child_number].output_num[color_number] = chan_nr; 580 + 581 + return 0; 582 + } 583 + 584 + static int lp55xx_parse_multi_led(struct device_node *np, 585 + struct lp55xx_led_config *cfg, 586 + int child_number) 587 + { 588 + struct device_node *child; 589 + int num_colors = 0, ret; 590 + 591 + for_each_child_of_node(np, child) { 592 + ret = lp55xx_parse_multi_led_child(child, cfg, child_number, 593 + num_colors); 594 + if (ret) 595 + return ret; 596 + num_colors++; 597 + } 598 + 599 + cfg[child_number].num_colors = num_colors; 600 + 601 + return 0; 602 + } 603 + 604 + static int lp55xx_parse_logical_led(struct device_node *np, 605 + struct lp55xx_led_config *cfg, 606 + int child_number) 607 + { 608 + int led_color, ret; 609 + int chan_nr = 0; 610 + 611 + cfg[child_number].default_trigger = 612 + of_get_property(np, "linux,default-trigger", NULL); 613 + 614 + ret = of_property_read_u32(np, "color", &led_color); 615 + if (ret) 616 + return ret; 617 + 618 + if (led_color == LED_COLOR_ID_RGB) 619 + return lp55xx_parse_multi_led(np, cfg, child_number); 620 + 621 + ret = lp55xx_parse_common_child(np, cfg, child_number, &chan_nr); 622 + if (ret < 0) 623 + return ret; 624 + 625 + cfg[child_number].chan_nr = chan_nr; 626 + 627 + return ret; 628 + } 629 + 564 630 struct lp55xx_platform_data *lp55xx_of_populate_pdata(struct device *dev, 565 - struct device_node *np) 631 + struct device_node *np, 632 + struct lp55xx_chip *chip) 566 633 { 567 634 struct device_node *child; 568 635 struct lp55xx_platform_data *pdata; 569 636 struct lp55xx_led_config *cfg; 570 637 int num_channels; 571 638 int i = 0; 639 + int ret; 572 640 573 641 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); 574 642 if (!pdata) ··· 677 563 678 564 pdata->led_config = &cfg[0]; 679 565 pdata->num_channels = num_channels; 566 + cfg->max_channel = chip->cfg->max_channel; 680 567 681 568 for_each_child_of_node(np, child) { 682 - cfg[i].chan_nr = i; 683 - 684 - of_property_read_string(child, "chan-name", &cfg[i].name); 685 - of_property_read_u8(child, "led-cur", &cfg[i].led_current); 686 - of_property_read_u8(child, "max-cur", &cfg[i].max_current); 687 - cfg[i].default_trigger = 688 - of_get_property(child, "linux,default-trigger", NULL); 689 - 569 + ret = lp55xx_parse_logical_led(child, cfg, i); 570 + if (ret) 571 + return ERR_PTR(-EINVAL); 690 572 i++; 691 573 } 692 574 693 575 of_property_read_string(np, "label", &pdata->label); 694 576 of_property_read_u8(np, "clock-mode", &pdata->clock_mode); 695 577 696 - pdata->enable_gpio = of_get_named_gpio(np, "enable-gpio", 0); 578 + pdata->enable_gpiod = devm_gpiod_get_optional(dev, "enable", 579 + GPIOD_ASIS); 580 + if (IS_ERR(pdata->enable_gpiod)) 581 + return ERR_CAST(pdata->enable_gpiod); 697 582 698 583 /* LP8501 specific */ 699 584 of_property_read_u8(np, "pwr-sel", (u8 *)&pdata->pwr_sel);
+12 -4
drivers/leds/leds-lp55xx-common.h
··· 12 12 #ifndef _LEDS_LP55XX_COMMON_H 13 13 #define _LEDS_LP55XX_COMMON_H 14 14 15 + #include <linux/led-class-multicolor.h> 16 + 15 17 enum lp55xx_engine_index { 16 18 LP55XX_ENGINE_INVALID, 17 19 LP55XX_ENGINE_1, ··· 95 93 * @max_channel : Maximum number of channels 96 94 * @post_init_device : Chip specific initialization code 97 95 * @brightness_fn : Brightness function 96 + * @multicolor_brightness_fn : Multicolor brightness function 98 97 * @set_led_current : LED current set function 99 98 * @firmware_cb : Call function when the firmware is loaded 100 99 * @run_engine : Run internal engine for pattern ··· 109 106 /* define if the device has specific initialization process */ 110 107 int (*post_init_device) (struct lp55xx_chip *chip); 111 108 112 - /* access brightness register */ 109 + /* set LED brightness */ 113 110 int (*brightness_fn)(struct lp55xx_led *led); 111 + 112 + /* set multicolor LED brightness */ 113 + int (*multicolor_brightness_fn)(struct lp55xx_led *led); 114 114 115 115 /* current setting function */ 116 116 void (*set_led_current) (struct lp55xx_led *led, u8 led_current); ··· 165 159 * struct lp55xx_led 166 160 * @chan_nr : Channel number 167 161 * @cdev : LED class device 162 + * @mc_cdev : Multi color class device 163 + * @color_components: Multi color LED map information 168 164 * @led_current : Current setting at each led channel 169 165 * @max_current : Maximun current at each led channel 170 166 * @brightness : Brightness value ··· 175 167 struct lp55xx_led { 176 168 int chan_nr; 177 169 struct led_classdev cdev; 170 + struct led_classdev_mc mc_cdev; 178 171 u8 led_current; 179 172 u8 max_current; 180 173 u8 brightness; ··· 198 189 /* common LED class device functions */ 199 190 extern int lp55xx_register_leds(struct lp55xx_led *led, 200 191 struct lp55xx_chip *chip); 201 - extern void lp55xx_unregister_leds(struct lp55xx_led *led, 202 - struct lp55xx_chip *chip); 203 192 204 193 /* common device attributes functions */ 205 194 extern int lp55xx_register_sysfs(struct lp55xx_chip *chip); ··· 205 198 206 199 /* common device tree population function */ 207 200 extern struct lp55xx_platform_data 208 - *lp55xx_of_populate_pdata(struct device *dev, struct device_node *np); 201 + *lp55xx_of_populate_pdata(struct device *dev, struct device_node *np, 202 + struct lp55xx_chip *chip); 209 203 210 204 #endif /* _LEDS_LP55XX_COMMON_H */
+11 -12
drivers/leds/leds-lp8501.c
··· 308 308 struct lp55xx_platform_data *pdata = dev_get_platdata(&client->dev); 309 309 struct device_node *np = client->dev.of_node; 310 310 311 + chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); 312 + if (!chip) 313 + return -ENOMEM; 314 + 315 + chip->cfg = &lp8501_cfg; 316 + 311 317 if (!pdata) { 312 318 if (np) { 313 - pdata = lp55xx_of_populate_pdata(&client->dev, np); 319 + pdata = lp55xx_of_populate_pdata(&client->dev, np, 320 + chip); 314 321 if (IS_ERR(pdata)) 315 322 return PTR_ERR(pdata); 316 323 } else { ··· 326 319 } 327 320 } 328 321 329 - chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); 330 - if (!chip) 331 - return -ENOMEM; 332 - 333 322 led = devm_kcalloc(&client->dev, 334 323 pdata->num_channels, sizeof(*led), GFP_KERNEL); 335 324 if (!led) ··· 333 330 334 331 chip->cl = client; 335 332 chip->pdata = pdata; 336 - chip->cfg = &lp8501_cfg; 337 333 338 334 mutex_init(&chip->lock); 339 335 ··· 346 344 347 345 ret = lp55xx_register_leds(led, chip); 348 346 if (ret) 349 - goto err_register_leds; 347 + goto err_out; 350 348 351 349 ret = lp55xx_register_sysfs(chip); 352 350 if (ret) { 353 351 dev_err(&client->dev, "registering sysfs failed\n"); 354 - goto err_register_sysfs; 352 + goto err_out; 355 353 } 356 354 357 355 return 0; 358 356 359 - err_register_sysfs: 360 - lp55xx_unregister_leds(led, chip); 361 - err_register_leds: 357 + err_out: 362 358 lp55xx_deinit_device(chip); 363 359 err_init: 364 360 return ret; ··· 369 369 370 370 lp8501_stop_engine(chip); 371 371 lp55xx_unregister_sysfs(chip); 372 - lp55xx_unregister_leds(led, chip); 373 372 lp55xx_deinit_device(chip); 374 373 375 374 return 0;
+1 -8
drivers/leds/leds-ns2.c
··· 348 348 struct ns2_led_data leds_data[]; 349 349 }; 350 350 351 - static inline int sizeof_ns2_led_priv(int num_leds) 352 - { 353 - return sizeof(struct ns2_led_priv) + 354 - (sizeof(struct ns2_led_data) * num_leds); 355 - } 356 - 357 351 static int ns2_led_probe(struct platform_device *pdev) 358 352 { 359 353 struct ns2_led_platform_data *pdata = dev_get_platdata(&pdev->dev); ··· 372 378 return -EINVAL; 373 379 #endif /* CONFIG_OF_GPIO */ 374 380 375 - priv = devm_kzalloc(&pdev->dev, 376 - sizeof_ns2_led_priv(pdata->num_leds), GFP_KERNEL); 381 + priv = devm_kzalloc(&pdev->dev, struct_size(priv, leds_data, pdata->num_leds), GFP_KERNEL); 377 382 if (!priv) 378 383 return -ENOMEM; 379 384 priv->num_leds = pdata->num_leds;
+1 -1
drivers/leds/leds-pca955x.c
··· 40 40 #include <linux/ctype.h> 41 41 #include <linux/delay.h> 42 42 #include <linux/err.h> 43 - #include <linux/gpio.h> 43 + #include <linux/gpio/driver.h> 44 44 #include <linux/i2c.h> 45 45 #include <linux/leds.h> 46 46 #include <linux/module.h>
+295
drivers/leds/leds-turris-omnia.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * CZ.NIC's Turris Omnia LEDs driver 4 + * 5 + * 2020 by Marek Behun <marek.behun@nic.cz> 6 + */ 7 + 8 + #include <linux/i2c.h> 9 + #include <linux/led-class-multicolor.h> 10 + #include <linux/module.h> 11 + #include <linux/mutex.h> 12 + #include <linux/of.h> 13 + #include "leds.h" 14 + 15 + #define OMNIA_BOARD_LEDS 12 16 + #define OMNIA_LED_NUM_CHANNELS 3 17 + 18 + #define CMD_LED_MODE 3 19 + #define CMD_LED_MODE_LED(l) ((l) & 0x0f) 20 + #define CMD_LED_MODE_USER 0x10 21 + 22 + #define CMD_LED_STATE 4 23 + #define CMD_LED_STATE_LED(l) ((l) & 0x0f) 24 + #define CMD_LED_STATE_ON 0x10 25 + 26 + #define CMD_LED_COLOR 5 27 + #define CMD_LED_SET_BRIGHTNESS 7 28 + #define CMD_LED_GET_BRIGHTNESS 8 29 + 30 + #define OMNIA_CMD 0 31 + 32 + #define OMNIA_CMD_LED_COLOR_LED 1 33 + #define OMNIA_CMD_LED_COLOR_R 2 34 + #define OMNIA_CMD_LED_COLOR_G 3 35 + #define OMNIA_CMD_LED_COLOR_B 4 36 + #define OMNIA_CMD_LED_COLOR_LEN 5 37 + 38 + struct omnia_led { 39 + struct led_classdev_mc mc_cdev; 40 + struct mc_subled subled_info[OMNIA_LED_NUM_CHANNELS]; 41 + int reg; 42 + }; 43 + 44 + #define to_omnia_led(l) container_of(l, struct omnia_led, mc_cdev) 45 + 46 + struct omnia_leds { 47 + struct i2c_client *client; 48 + struct mutex lock; 49 + struct omnia_led leds[]; 50 + }; 51 + 52 + static int omnia_led_brightness_set_blocking(struct led_classdev *cdev, 53 + enum led_brightness brightness) 54 + { 55 + struct led_classdev_mc *mc_cdev = lcdev_to_mccdev(cdev); 56 + struct omnia_leds *leds = dev_get_drvdata(cdev->dev->parent); 57 + struct omnia_led *led = to_omnia_led(mc_cdev); 58 + u8 buf[OMNIA_CMD_LED_COLOR_LEN], state; 59 + int ret; 60 + 61 + mutex_lock(&leds->lock); 62 + 63 + led_mc_calc_color_components(&led->mc_cdev, brightness); 64 + 65 + buf[OMNIA_CMD] = CMD_LED_COLOR; 66 + buf[OMNIA_CMD_LED_COLOR_LED] = led->reg; 67 + buf[OMNIA_CMD_LED_COLOR_R] = mc_cdev->subled_info[0].brightness; 68 + buf[OMNIA_CMD_LED_COLOR_G] = mc_cdev->subled_info[1].brightness; 69 + buf[OMNIA_CMD_LED_COLOR_B] = mc_cdev->subled_info[2].brightness; 70 + 71 + state = CMD_LED_STATE_LED(led->reg); 72 + if (buf[OMNIA_CMD_LED_COLOR_R] || buf[OMNIA_CMD_LED_COLOR_G] || buf[OMNIA_CMD_LED_COLOR_B]) 73 + state |= CMD_LED_STATE_ON; 74 + 75 + ret = i2c_smbus_write_byte_data(leds->client, CMD_LED_STATE, state); 76 + if (ret >= 0 && (state & CMD_LED_STATE_ON)) 77 + ret = i2c_master_send(leds->client, buf, 5); 78 + 79 + mutex_unlock(&leds->lock); 80 + 81 + return ret; 82 + } 83 + 84 + static int omnia_led_register(struct i2c_client *client, struct omnia_led *led, 85 + struct device_node *np) 86 + { 87 + struct led_init_data init_data = {}; 88 + struct device *dev = &client->dev; 89 + struct led_classdev *cdev; 90 + int ret, color; 91 + 92 + ret = of_property_read_u32(np, "reg", &led->reg); 93 + if (ret || led->reg >= OMNIA_BOARD_LEDS) { 94 + dev_warn(dev, 95 + "Node %pOF: must contain 'reg' property with values between 0 and %i\n", 96 + np, OMNIA_BOARD_LEDS - 1); 97 + return 0; 98 + } 99 + 100 + ret = of_property_read_u32(np, "color", &color); 101 + if (ret || color != LED_COLOR_ID_MULTI) { 102 + dev_warn(dev, 103 + "Node %pOF: must contain 'color' property with value LED_COLOR_ID_MULTI\n", 104 + np); 105 + return 0; 106 + } 107 + 108 + led->subled_info[0].color_index = LED_COLOR_ID_RED; 109 + led->subled_info[0].channel = 0; 110 + led->subled_info[1].color_index = LED_COLOR_ID_GREEN; 111 + led->subled_info[1].channel = 1; 112 + led->subled_info[2].color_index = LED_COLOR_ID_BLUE; 113 + led->subled_info[2].channel = 2; 114 + 115 + led->mc_cdev.subled_info = led->subled_info; 116 + led->mc_cdev.num_colors = OMNIA_LED_NUM_CHANNELS; 117 + 118 + init_data.fwnode = &np->fwnode; 119 + 120 + cdev = &led->mc_cdev.led_cdev; 121 + cdev->max_brightness = 255; 122 + cdev->brightness_set_blocking = omnia_led_brightness_set_blocking; 123 + 124 + of_property_read_string(np, "linux,default-trigger", &cdev->default_trigger); 125 + 126 + /* put the LED into software mode */ 127 + ret = i2c_smbus_write_byte_data(client, CMD_LED_MODE, 128 + CMD_LED_MODE_LED(led->reg) | 129 + CMD_LED_MODE_USER); 130 + if (ret < 0) { 131 + dev_err(dev, "Cannot set LED %pOF to software mode: %i\n", np, ret); 132 + return ret; 133 + } 134 + 135 + /* disable the LED */ 136 + ret = i2c_smbus_write_byte_data(client, CMD_LED_STATE, CMD_LED_STATE_LED(led->reg)); 137 + if (ret < 0) { 138 + dev_err(dev, "Cannot set LED %pOF brightness: %i\n", np, ret); 139 + return ret; 140 + } 141 + 142 + ret = devm_led_classdev_multicolor_register_ext(dev, &led->mc_cdev, &init_data); 143 + if (ret < 0) { 144 + dev_err(dev, "Cannot register LED %pOF: %i\n", np, ret); 145 + return ret; 146 + } 147 + 148 + return 1; 149 + } 150 + 151 + /* 152 + * On the front panel of the Turris Omnia router there is also a button which 153 + * can be used to control the intensity of all the LEDs at once, so that if they 154 + * are too bright, user can dim them. 155 + * The microcontroller cycles between 8 levels of this global brightness (from 156 + * 100% to 0%), but this setting can have any integer value between 0 and 100. 157 + * It is therefore convenient to be able to change this setting from software. 158 + * We expose this setting via a sysfs attribute file called "brightness". This 159 + * file lives in the device directory of the LED controller, not an individual 160 + * LED, so it should not confuse users. 161 + */ 162 + static ssize_t brightness_show(struct device *dev, struct device_attribute *a, char *buf) 163 + { 164 + struct i2c_client *client = to_i2c_client(dev); 165 + struct omnia_leds *leds = i2c_get_clientdata(client); 166 + int ret; 167 + 168 + mutex_lock(&leds->lock); 169 + ret = i2c_smbus_read_byte_data(client, CMD_LED_GET_BRIGHTNESS); 170 + mutex_unlock(&leds->lock); 171 + 172 + if (ret < 0) 173 + return ret; 174 + 175 + return sprintf(buf, "%d\n", ret); 176 + } 177 + 178 + static ssize_t brightness_store(struct device *dev, struct device_attribute *a, const char *buf, 179 + size_t count) 180 + { 181 + struct i2c_client *client = to_i2c_client(dev); 182 + struct omnia_leds *leds = i2c_get_clientdata(client); 183 + unsigned int brightness; 184 + int ret; 185 + 186 + if (sscanf(buf, "%u", &brightness) != 1) 187 + return -EINVAL; 188 + 189 + if (brightness > 100) 190 + return -EINVAL; 191 + 192 + mutex_lock(&leds->lock); 193 + ret = i2c_smbus_write_byte_data(client, CMD_LED_SET_BRIGHTNESS, (u8) brightness); 194 + mutex_unlock(&leds->lock); 195 + 196 + if (ret < 0) 197 + return ret; 198 + 199 + return count; 200 + } 201 + static DEVICE_ATTR_RW(brightness); 202 + 203 + static struct attribute *omnia_led_controller_attrs[] = { 204 + &dev_attr_brightness.attr, 205 + NULL, 206 + }; 207 + ATTRIBUTE_GROUPS(omnia_led_controller); 208 + 209 + static int omnia_leds_probe(struct i2c_client *client, 210 + const struct i2c_device_id *id) 211 + { 212 + struct device *dev = &client->dev; 213 + struct device_node *np = dev->of_node, *child; 214 + struct omnia_leds *leds; 215 + struct omnia_led *led; 216 + int ret, count; 217 + 218 + count = of_get_available_child_count(np); 219 + if (!count) { 220 + dev_err(dev, "LEDs are not defined in device tree!\n"); 221 + return -ENODEV; 222 + } else if (count > OMNIA_BOARD_LEDS) { 223 + dev_err(dev, "Too many LEDs defined in device tree!\n"); 224 + return -EINVAL; 225 + } 226 + 227 + leds = devm_kzalloc(dev, struct_size(leds, leds, count), GFP_KERNEL); 228 + if (!leds) 229 + return -ENOMEM; 230 + 231 + leds->client = client; 232 + i2c_set_clientdata(client, leds); 233 + 234 + mutex_init(&leds->lock); 235 + 236 + led = &leds->leds[0]; 237 + for_each_available_child_of_node(np, child) { 238 + ret = omnia_led_register(client, led, child); 239 + if (ret < 0) 240 + return ret; 241 + 242 + led += ret; 243 + } 244 + 245 + if (devm_device_add_groups(dev, omnia_led_controller_groups)) 246 + dev_warn(dev, "Could not add attribute group!\n"); 247 + 248 + return 0; 249 + } 250 + 251 + static int omnia_leds_remove(struct i2c_client *client) 252 + { 253 + u8 buf[OMNIA_CMD_LED_COLOR_LEN]; 254 + 255 + /* put all LEDs into default (HW triggered) mode */ 256 + i2c_smbus_write_byte_data(client, CMD_LED_MODE, 257 + CMD_LED_MODE_LED(OMNIA_BOARD_LEDS)); 258 + 259 + /* set all LEDs color to [255, 255, 255] */ 260 + buf[OMNIA_CMD] = CMD_LED_COLOR; 261 + buf[OMNIA_CMD_LED_COLOR_LED] = OMNIA_BOARD_LEDS; 262 + buf[OMNIA_CMD_LED_COLOR_R] = 255; 263 + buf[OMNIA_CMD_LED_COLOR_G] = 255; 264 + buf[OMNIA_CMD_LED_COLOR_B] = 255; 265 + 266 + i2c_master_send(client, buf, 5); 267 + 268 + return 0; 269 + } 270 + 271 + static const struct of_device_id of_omnia_leds_match[] = { 272 + { .compatible = "cznic,turris-omnia-leds", }, 273 + {}, 274 + }; 275 + 276 + static const struct i2c_device_id omnia_id[] = { 277 + { "omnia", 0 }, 278 + { } 279 + }; 280 + 281 + static struct i2c_driver omnia_leds_driver = { 282 + .probe = omnia_leds_probe, 283 + .remove = omnia_leds_remove, 284 + .id_table = omnia_id, 285 + .driver = { 286 + .name = "leds-turris-omnia", 287 + .of_match_table = of_omnia_leds_match, 288 + }, 289 + }; 290 + 291 + module_i2c_driver(omnia_leds_driver); 292 + 293 + MODULE_AUTHOR("Marek Behun <marek.behun@nic.cz>"); 294 + MODULE_DESCRIPTION("CZ.NIC's Turris Omnia LEDs"); 295 + MODULE_LICENSE("GPL v2");
+13 -1
drivers/leds/leds-wm831x-status.c
··· 269 269 drvdata->cdev.blink_set = wm831x_status_blink_set; 270 270 drvdata->cdev.groups = wm831x_status_groups; 271 271 272 - ret = devm_led_classdev_register(wm831x->dev, &drvdata->cdev); 272 + ret = led_classdev_register(wm831x->dev, &drvdata->cdev); 273 273 if (ret < 0) { 274 274 dev_err(&pdev->dev, "Failed to register LED: %d\n", ret); 275 275 return ret; 276 276 } 277 + 278 + platform_set_drvdata(pdev, drvdata); 279 + 280 + return 0; 281 + } 282 + 283 + static int wm831x_status_remove(struct platform_device *pdev) 284 + { 285 + struct wm831x_status *drvdata = platform_get_drvdata(pdev); 286 + 287 + led_classdev_unregister(&drvdata->cdev); 277 288 278 289 return 0; 279 290 } ··· 294 283 .name = "wm831x-status", 295 284 }, 296 285 .probe = wm831x_status_probe, 286 + .remove = wm831x_status_remove, 297 287 }; 298 288 299 289 module_platform_driver(wm831x_status_driver);
+2 -1
drivers/leds/trigger/ledtrig-gpio.c
··· 99 99 gpio_data->inverted = inverted; 100 100 101 101 /* After inverting, we need to update the LED. */ 102 - gpio_trig_irq(0, led); 102 + if (gpio_is_valid(gpio_data->gpio)) 103 + gpio_trig_irq(0, led); 103 104 104 105 return n; 105 106 }
+4 -2
drivers/leds/trigger/ledtrig-pattern.c
··· 227 227 228 228 while (offset < count - 1 && data->npatterns < MAX_PATTERNS) { 229 229 cr = 0; 230 - ccount = sscanf(buf + offset, "%d %u %n", 230 + ccount = sscanf(buf + offset, "%u %u %n", 231 231 &data->patterns[data->npatterns].brightness, 232 232 &data->patterns[data->npatterns].delta_t, &cr); 233 - if (ccount != 2) { 233 + 234 + if (ccount != 2 || 235 + data->patterns[data->npatterns].brightness > data->led_cdev->max_brightness) { 234 236 data->npatterns = 0; 235 237 return -EINVAL; 236 238 }
+4 -1
include/dt-bindings/leds/common.h
··· 30 30 #define LED_COLOR_ID_VIOLET 5 31 31 #define LED_COLOR_ID_YELLOW 6 32 32 #define LED_COLOR_ID_IR 7 33 - #define LED_COLOR_ID_MAX 8 33 + #define LED_COLOR_ID_MULTI 8 /* For multicolor LEDs */ 34 + #define LED_COLOR_ID_RGB 9 /* For multicolor LEDs that can do arbitrary color, 35 + so this would include RGBW and similar */ 36 + #define LED_COLOR_ID_MAX 10 34 37 35 38 /* Standard LED functions */ 36 39 /* Keyboard LEDs, usually it would be input4::capslock etc. */
+121
include/linux/led-class-multicolor.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* LED Multicolor class interface 3 + * Copyright (C) 2019-20 Texas Instruments Incorporated - http://www.ti.com/ 4 + */ 5 + 6 + #ifndef _LINUX_MULTICOLOR_LEDS_H_INCLUDED 7 + #define _LINUX_MULTICOLOR_LEDS_H_INCLUDED 8 + 9 + #include <linux/leds.h> 10 + #include <dt-bindings/leds/common.h> 11 + 12 + struct mc_subled { 13 + unsigned int color_index; 14 + unsigned int brightness; 15 + unsigned int intensity; 16 + unsigned int channel; 17 + }; 18 + 19 + struct led_classdev_mc { 20 + /* led class device */ 21 + struct led_classdev led_cdev; 22 + unsigned int num_colors; 23 + 24 + struct mc_subled *subled_info; 25 + }; 26 + 27 + static inline struct led_classdev_mc *lcdev_to_mccdev( 28 + struct led_classdev *led_cdev) 29 + { 30 + return container_of(led_cdev, struct led_classdev_mc, led_cdev); 31 + } 32 + 33 + #if IS_ENABLED(CONFIG_LEDS_CLASS_MULTICOLOR) 34 + /** 35 + * led_classdev_multicolor_register_ext - register a new object of led_classdev 36 + * class with support for multicolor LEDs 37 + * @parent: the multicolor LED to register 38 + * @mcled_cdev: the led_classdev_mc structure for this device 39 + * @init_data: the LED class multicolor device initialization data 40 + * 41 + * Returns: 0 on success or negative error value on failure 42 + */ 43 + int led_classdev_multicolor_register_ext(struct device *parent, 44 + struct led_classdev_mc *mcled_cdev, 45 + struct led_init_data *init_data); 46 + 47 + static inline int led_classdev_multicolor_register(struct device *parent, 48 + struct led_classdev_mc *mcled_cdev) 49 + { 50 + return led_classdev_multicolor_register_ext(parent, mcled_cdev, NULL); 51 + } 52 + 53 + /** 54 + * led_classdev_multicolor_unregister - unregisters an object of led_classdev 55 + * class with support for multicolor LEDs 56 + * @mcled_cdev: the multicolor LED to unregister 57 + * 58 + * Unregister a previously registered via led_classdev_multicolor_register 59 + * object 60 + */ 61 + void led_classdev_multicolor_unregister(struct led_classdev_mc *mcled_cdev); 62 + 63 + /* Calculate brightness for the monochrome LED cluster */ 64 + int led_mc_calc_color_components(struct led_classdev_mc *mcled_cdev, 65 + enum led_brightness brightness); 66 + 67 + int devm_led_classdev_multicolor_register_ext(struct device *parent, 68 + struct led_classdev_mc *mcled_cdev, 69 + struct led_init_data *init_data); 70 + 71 + static inline int devm_led_classdev_multicolor_register(struct device *parent, 72 + struct led_classdev_mc *mcled_cdev) 73 + { 74 + return devm_led_classdev_multicolor_register_ext(parent, mcled_cdev, 75 + NULL); 76 + } 77 + 78 + void devm_led_classdev_multicolor_unregister(struct device *parent, 79 + struct led_classdev_mc *mcled_cdev); 80 + #else 81 + 82 + static inline int led_classdev_multicolor_register_ext(struct device *parent, 83 + struct led_classdev_mc *mcled_cdev, 84 + struct led_init_data *init_data) 85 + { 86 + return -EINVAL; 87 + } 88 + 89 + static inline int led_classdev_multicolor_register(struct device *parent, 90 + struct led_classdev_mc *mcled_cdev) 91 + { 92 + return led_classdev_multicolor_register_ext(parent, mcled_cdev, NULL); 93 + } 94 + 95 + static inline void led_classdev_multicolor_unregister(struct led_classdev_mc *mcled_cdev) {}; 96 + static inline int led_mc_calc_color_components(struct led_classdev_mc *mcled_cdev, 97 + enum led_brightness brightness) 98 + { 99 + return -EINVAL; 100 + } 101 + 102 + static inline int devm_led_classdev_multicolor_register_ext(struct device *parent, 103 + struct led_classdev_mc *mcled_cdev, 104 + struct led_init_data *init_data) 105 + { 106 + return -EINVAL; 107 + } 108 + 109 + static inline int devm_led_classdev_multicolor_register(struct device *parent, 110 + struct led_classdev_mc *mcled_cdev) 111 + { 112 + return devm_led_classdev_multicolor_register_ext(parent, mcled_cdev, 113 + NULL); 114 + } 115 + 116 + static inline void devm_led_classdev_multicolor_unregister(struct device *parent, 117 + struct led_classdev_mc *mcled_cdev) 118 + {}; 119 + 120 + #endif /* IS_ENABLED(CONFIG_LEDS_CLASS_MULTICOLOR) */ 121 + #endif /* _LINUX_MULTICOLOR_LEDS_H_INCLUDED */
+10
include/linux/leds.h
··· 57 57 bool devname_mandatory; 58 58 }; 59 59 60 + struct led_hw_trigger_type { 61 + int dummy; 62 + }; 63 + 60 64 struct led_classdev { 61 65 const char *name; 62 66 enum led_brightness brightness; ··· 145 141 void *trigger_data; 146 142 /* true if activated - deactivate routine uses it to do cleanup */ 147 143 bool activated; 144 + 145 + /* LEDs that have private triggers have this set */ 146 + struct led_hw_trigger_type *trigger_type; 148 147 #endif 149 148 150 149 #ifdef CONFIG_LEDS_BRIGHTNESS_HW_CHANGED ··· 351 344 const char *name; 352 345 int (*activate)(struct led_classdev *led_cdev); 353 346 void (*deactivate)(struct led_classdev *led_cdev); 347 + 348 + /* LED-private triggers have this set */ 349 + struct led_hw_trigger_type *trigger_type; 354 350 355 351 /* LEDs under control by this trigger (for simple triggers) */ 356 352 rwlock_t leddev_list_lock;
+11 -2
include/linux/platform_data/leds-lp55xx.h
··· 12 12 #ifndef _LEDS_LP55XX_H 13 13 #define _LEDS_LP55XX_H 14 14 15 + #include <linux/gpio/consumer.h> 16 + #include <linux/led-class-multicolor.h> 17 + 15 18 /* Clock configuration */ 16 19 #define LP55XX_CLOCK_AUTO 0 17 20 #define LP55XX_CLOCK_INT 1 18 21 #define LP55XX_CLOCK_EXT 2 22 + 23 + #define LP55XX_MAX_GROUPED_CHAN 4 19 24 20 25 struct lp55xx_led_config { 21 26 const char *name; ··· 28 23 u8 chan_nr; 29 24 u8 led_current; /* mA x10, 0 if led is not connected */ 30 25 u8 max_current; 26 + int num_colors; 27 + unsigned int max_channel; 28 + int color_id[LED_COLOR_ID_MAX]; 29 + int output_num[LED_COLOR_ID_MAX]; 31 30 }; 32 31 33 32 struct lp55xx_predef_pattern { ··· 58 49 * @clock_mode : Input clock mode. LP55XX_CLOCK_AUTO or _INT or _EXT 59 50 * @setup_resources : Platform specific function before enabling the chip 60 51 * @release_resources : Platform specific function after disabling the chip 61 - * @enable : EN pin control by platform side 52 + * @enable_gpiod : enable GPIO descriptor 62 53 * @patterns : Predefined pattern data for RGB channels 63 54 * @num_patterns : Number of patterns 64 55 * @update_config : Value of CONFIG register ··· 74 65 u8 clock_mode; 75 66 76 67 /* optional enable GPIO */ 77 - int enable_gpio; 68 + struct gpio_desc *enable_gpiod; 78 69 79 70 /* Predefined pattern data */ 80 71 struct lp55xx_predef_pattern *patterns;