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

Configure Feed

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

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

Pull LED updates from Lee Jones:
"Core Frameworks:
- Add new framework to support Group Multi-Color (GMC) LEDs
- Offer an 'optional' API for non-essential LEDs
- Support obtaining 'max brightness' values from Device Tree
- Provide new led_classdev member 'color' (settable via DT and SYFS)
- Stop TTY Trigger from using the old LED_ON constraints
- Statically allocate leds_class

New Drivers:
- Add support for NXP PCA995x I2C Constant Current LED Driver

New Device Support:
- Add support for Siemens Simatic IPC BX-21 to Simatic IPC

Fix-ups:
- Some dependency / Kconfig tweaking
- Move final probe() functions back over from .probe_new()
- Simplify obtaining resources (memory, device data) using unified
API helpers
- Bunch of Device Tree additions, conversions and adaptions
- Fix trivial styling issues; comments
- Ensure correct includes are present and remove some that are not
required
- Omit the use of redundant casts and if relevant replace with better
ones
- Use purpose-built APIs for various actions; sysfs_emit(),
module_led_trigger()
- Remove a bunch of superfluous locking

Bug Fixes:
- Ensure error codes are correctly propagated back up the call chain
- Fix incorrect error values from being returned (missing '-')
- Ensure get'ed resources are put'ed to prevent leaks
- Use correct class when exporting module resources
- Fixing rounding (or lack there of) issues
- Fix 'always false' LED_COLOR_ID_MULTI BUG() check"

* tag 'leds-next-6.6' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/leds: (40 commits)
leds: aw2013: Enable pull-up supply for interrupt and I2C
dt-bindings: leds: Document pull-up supply for interrupt and I2C
dt-bindings: leds: aw2013: Document interrupt
leds: uleds: Use module_misc_device macro to simplify the code
leds: trigger: netdev: Use module_led_trigger macro to simplify the code
dt-bindings: leds: Fix reference to definition of default-state
leds: turris-omnia: Drop unnecessary mutex locking
leds: turris-omnia: Use sysfs_emit() instead of sprintf()
leds: Make leds_class a static const structure
leds: Remove redundant of_match_ptr()
dt-bindings: leds: Add gpio-line-names to PCA9532 GPIO
leds: trigger: tty: Do not use LED_ON/OFF constants, use led_blink_set_oneshot instead
dt-bindings: leds: rohm,bd71828: Drop select:false
leds: Fix BUG_ON check for LED_COLOR_ID_MULTI that is always false
leds: multicolor: Use rounded division when calculating color components
leds: rgb: Add a multicolor LED driver to group monochromatic LEDs
dt-bindings: leds: Add binding for a multicolor group of LEDs
leds: class: Store the color index in struct led_classdev
leds: Provide devm_of_led_get_optional()
leds: pca995x: Fix MODULE_DEVICE_TABLE for OF
...

+880 -176
+9
Documentation/ABI/testing/sysfs-class-led
··· 59 59 brightness. Reading this file when no hw brightness change 60 60 event has happened will return an ENODATA error. 61 61 62 + What: /sys/class/leds/<led>/color 63 + Date: June 2023 64 + KernelVersion: 6.5 65 + Description: 66 + Color of the LED. 67 + 68 + This is a read-only file. Reading this file returns the color 69 + of the LED as a string (e.g: "red", "green", "multicolor"). 70 + 62 71 What: /sys/class/leds/<led>/trigger 63 72 Date: March 2006 64 73 KernelVersion: 2.6.17
+13 -2
Documentation/devicetree/bindings/leds/common.yaml
··· 83 83 - enum: 84 84 # LED will act as a back-light, controlled by the framebuffer system 85 85 - backlight 86 - # LED will turn on (but for leds-gpio see "default-state" property in 87 - # Documentation/devicetree/bindings/leds/leds-gpio.yaml) 86 + # LED will turn on (see also "default-state" property) 88 87 - default-on 89 88 # LED "double" flashes at a load average based rate 90 89 - heartbeat ··· 156 157 damage in case an excessive current is set. 157 158 For flash LED controllers with configurable current this property is 158 159 mandatory for the LEDs in the non-flash modes (e.g. torch or indicator). 160 + 161 + max-brightness: 162 + description: 163 + Normally, the maximum brightness is determined by the hardware, and this 164 + property is not required. This property is used to set a software limit. 165 + It could happen that an LED is made so bright that it gets damaged or 166 + causes damage due to restrictions in a specific system, such as mounting 167 + conditions. 168 + Note that this flag is mainly used for PWM-LEDs, where it is not possible 169 + to map brightness to current. Drivers for other controllers should use 170 + led-max-microamp. 171 + $ref: /schemas/types.yaml#definitions/uint32 159 172 160 173 panic-indicator: 161 174 description:
-55
Documentation/devicetree/bindings/leds/leds-an30259a.txt
··· 1 - * Panasonic AN30259A 3-channel LED driver 2 - 3 - The AN30259A is a LED controller capable of driving three LEDs independently. It supports 4 - constant current output and sloping current output modes. The chip is connected over I2C. 5 - 6 - Required properties: 7 - - compatible: Must be "panasonic,an30259a". 8 - - reg: I2C slave address. 9 - - #address-cells: Must be 1. 10 - - #size-cells: Must be 0. 11 - 12 - Each LED is represented as a sub-node of the panasonic,an30259a node. 13 - 14 - Required sub-node properties: 15 - - reg: Pin that the LED is connected to. Must be 1, 2, or 3. 16 - 17 - Optional sub-node properties: 18 - - function : 19 - see Documentation/devicetree/bindings/leds/common.txt 20 - - color : 21 - see Documentation/devicetree/bindings/leds/common.txt 22 - - label : 23 - see Documentation/devicetree/bindings/leds/common.txt (deprecated) 24 - - linux,default-trigger : 25 - see Documentation/devicetree/bindings/leds/common.txt 26 - 27 - Example: 28 - 29 - #include <dt-bindings/leds/common.h> 30 - 31 - led-controller@30 { 32 - compatible = "panasonic,an30259a"; 33 - reg = <0x30>; 34 - #address-cells = <1>; 35 - #size-cells = <0>; 36 - 37 - led@1 { 38 - reg = <1>; 39 - linux,default-trigger = "heartbeat"; 40 - function = LED_FUNCTION_INDICATOR; 41 - color = <LED_COLOR_ID_RED>; 42 - }; 43 - 44 - led@2 { 45 - reg = <2>; 46 - function = LED_FUNCTION_INDICATOR; 47 - color = <LED_COLOR_ID_GREEN>; 48 - }; 49 - 50 - led@3 { 51 - reg = <3>; 52 - function = LED_FUNCTION_INDICATOR; 53 - color = <LED_COLOR_ID_BLUE>; 54 - }; 55 - };
+13
Documentation/devicetree/bindings/leds/leds-aw2013.yaml
··· 20 20 reg: 21 21 maxItems: 1 22 22 23 + interrupts: 24 + maxItems: 1 25 + description: Open-drain, low active interrupt pin "INTN". 26 + Used to report completion of operations (power up, LED breath effects). 27 + 23 28 vcc-supply: 24 29 description: Regulator providing power to the "VCC" pin. 30 + 31 + vio-supply: 32 + description: Regulator providing power for pull-up of the I/O lines. 33 + "VIO1" in the typical application circuit example of the datasheet. 34 + Note that this regulator does not directly connect to AW2013, but is 35 + needed for the correct operation of the interrupt and I2C lines. 25 36 26 37 "#address-cells": 27 38 const: 1 ··· 63 52 examples: 64 53 - | 65 54 #include <dt-bindings/gpio/gpio.h> 55 + #include <dt-bindings/interrupt-controller/irq.h> 66 56 #include <dt-bindings/leds/common.h> 67 57 68 58 i2c { ··· 73 61 led-controller@45 { 74 62 compatible = "awinic,aw2013"; 75 63 reg = <0x45>; 64 + interrupts = <42 IRQ_TYPE_LEVEL_LOW>; 76 65 #address-cells = <1>; 77 66 #size-cells = <0>; 78 67
+64
Documentation/devicetree/bindings/leds/leds-group-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-group-multicolor.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Multi-color LED built with monochromatic LEDs 8 + 9 + maintainers: 10 + - Jean-Jacques Hiblot <jjhiblot@traphandler.com> 11 + 12 + description: | 13 + This driver combines several monochromatic LEDs into one multi-color 14 + LED using the multicolor LED class. 15 + 16 + properties: 17 + compatible: 18 + const: leds-group-multicolor 19 + 20 + leds: 21 + description: 22 + An aray of monochromatic leds 23 + $ref: /schemas/types.yaml#/definitions/phandle-array 24 + 25 + required: 26 + - leds 27 + 28 + allOf: 29 + - $ref: leds-class-multicolor.yaml# 30 + 31 + unevaluatedProperties: false 32 + 33 + examples: 34 + - | 35 + #include <dt-bindings/gpio/gpio.h> 36 + #include <dt-bindings/leds/common.h> 37 + 38 + monochromatic-leds { 39 + compatible = "gpio-leds"; 40 + 41 + led0: led-0 { 42 + gpios = <&mcu_pio 0 GPIO_ACTIVE_LOW>; 43 + color = <LED_COLOR_ID_RED>; 44 + }; 45 + 46 + led1: led-1 { 47 + gpios = <&mcu_pio 1 GPIO_ACTIVE_HIGH>; 48 + color = <LED_COLOR_ID_GREEN>; 49 + }; 50 + 51 + led2: led-2 { 52 + gpios = <&mcu_pio 2 GPIO_ACTIVE_HIGH>; 53 + color = <LED_COLOR_ID_BLUE>; 54 + }; 55 + }; 56 + 57 + multi-led { 58 + compatible = "leds-group-multicolor"; 59 + color = <LED_COLOR_ID_RGB>; 60 + function = LED_FUNCTION_INDICATOR; 61 + leds = <&led0>, <&led1>, <&led2>; 62 + }; 63 + 64 + ...
+4
Documentation/devicetree/bindings/leds/nxp,pca953x.yaml
··· 29 29 30 30 gpio-controller: true 31 31 32 + gpio-line-names: 33 + minItems: 1 34 + maxItems: 16 35 + 32 36 '#gpio-cells': 33 37 const: 2 34 38
+81
Documentation/devicetree/bindings/leds/nxp,pca995x.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/nxp,pca995x.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: NXP PCA995x LED controllers 8 + 9 + maintainers: 10 + - Isai Gaspar <isaiezequiel.gaspar@nxp.com> 11 + - Marek Vasut <marex@denx.de> 12 + 13 + description: 14 + The NXP PCA9952/PCA9955B are programmable LED controllers connected via I2C 15 + that can drive 16 separate lines. Each of them can be individually switched 16 + on and off, and brightness can be controlled via individual PWM. 17 + 18 + Datasheets are available at 19 + https://www.nxp.com/docs/en/data-sheet/PCA9952_PCA9955.pdf 20 + https://www.nxp.com/docs/en/data-sheet/PCA9955B.pdf 21 + 22 + properties: 23 + compatible: 24 + enum: 25 + - nxp,pca9952 26 + - nxp,pca9955b 27 + 28 + reg: 29 + maxItems: 1 30 + 31 + "#address-cells": 32 + const: 1 33 + 34 + "#size-cells": 35 + const: 0 36 + 37 + patternProperties: 38 + "^led@[0-9a-f]+$": 39 + type: object 40 + $ref: common.yaml# 41 + unevaluatedProperties: false 42 + 43 + properties: 44 + reg: 45 + minimum: 0 46 + maximum: 15 47 + 48 + required: 49 + - reg 50 + 51 + additionalProperties: false 52 + 53 + examples: 54 + - | 55 + #include <dt-bindings/leds/common.h> 56 + 57 + i2c { 58 + #address-cells = <1>; 59 + #size-cells = <0>; 60 + 61 + led-controller@1 { 62 + compatible = "nxp,pca9955b"; 63 + reg = <0x01>; 64 + #address-cells = <1>; 65 + #size-cells = <0>; 66 + 67 + led@0 { 68 + reg = <0x0>; 69 + color = <LED_COLOR_ID_RED>; 70 + function = LED_FUNCTION_POWER; 71 + }; 72 + 73 + led@2 { 74 + reg = <0x2>; 75 + color = <LED_COLOR_ID_WHITE>; 76 + function = LED_FUNCTION_STATUS; 77 + }; 78 + }; 79 + }; 80 + 81 + ...
+84
Documentation/devicetree/bindings/leds/panasonic,an30259a.yaml
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/leds/panasonic,an30259a.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Panasonic AN30259A 3-channel LED controller 8 + 9 + maintainers: 10 + - Iskren Chernev <me@iskren.info> 11 + 12 + description: 13 + The AN30259A is a LED controller capable of driving three LEDs independently. 14 + It supports constant current output and sloping current output modes. The chip 15 + is connected over I2C. 16 + 17 + properties: 18 + compatible: 19 + const: panasonic,an30259a 20 + 21 + reg: 22 + maxItems: 1 23 + 24 + interrupts: 25 + maxItems: 1 26 + 27 + "#address-cells": 28 + const: 1 29 + 30 + "#size-cells": 31 + const: 0 32 + 33 + patternProperties: 34 + "^led@[1-3]$": 35 + $ref: common.yaml# 36 + unevaluatedProperties: false 37 + 38 + properties: 39 + reg: 40 + enum: [ 1, 2, 3 ] 41 + 42 + required: 43 + - compatible 44 + - reg 45 + - "#address-cells" 46 + - "#size-cells" 47 + 48 + additionalProperties: false 49 + 50 + examples: 51 + - | 52 + #include <dt-bindings/leds/common.h> 53 + 54 + i2c { 55 + #address-cells = <1>; 56 + #size-cells = <0>; 57 + 58 + led-controller@30 { 59 + compatible = "panasonic,an30259a"; 60 + reg = <0x30>; 61 + #address-cells = <1>; 62 + #size-cells = <0>; 63 + 64 + led@1 { 65 + reg = <1>; 66 + linux,default-trigger = "heartbeat"; 67 + function = LED_FUNCTION_INDICATOR; 68 + color = <LED_COLOR_ID_RED>; 69 + }; 70 + 71 + led@2 { 72 + reg = <2>; 73 + function = LED_FUNCTION_INDICATOR; 74 + color = <LED_COLOR_ID_GREEN>; 75 + }; 76 + 77 + led@3 { 78 + reg = <3>; 79 + function = LED_FUNCTION_INDICATOR; 80 + color = <LED_COLOR_ID_BLUE>; 81 + }; 82 + }; 83 + }; 84 + ...
+2 -2
Documentation/devicetree/bindings/leds/rohm,bd2606mvv.yaml
··· 35 35 description: GPIO pin to enable/disable the device. 36 36 37 37 patternProperties: 38 - "^led@[0-6]$": 38 + "^led@[0-5]$": 39 39 type: object 40 40 $ref: common.yaml# 41 41 unevaluatedProperties: false ··· 43 43 properties: 44 44 reg: 45 45 minimum: 0 46 - maximum: 6 46 + maximum: 5 47 47 48 48 required: 49 49 - reg
-2
Documentation/devicetree/bindings/leds/rohm,bd71828-leds.yaml
··· 18 18 19 19 The device has two LED outputs referred as GRNLED and AMBLED in data-sheet. 20 20 21 - select: false 22 - 23 21 properties: 24 22 compatible: 25 23 const: rohm,bd71828-leds
+9
drivers/leds/Kconfig
··· 521 521 LED driver chip accessed via the I2C bus. Supported 522 522 devices include PCA9633 and PCA9634 523 523 524 + config LEDS_PCA995X 525 + tristate "LED Support for PCA995x I2C chips" 526 + depends on LEDS_CLASS 527 + depends on I2C 528 + help 529 + This option enables support for LEDs connected to PCA995x 530 + LED driver chips accessed via the I2C bus. Supported 531 + devices include PCA9955BTW, PCA9952TW and PCA9955TW. 532 + 524 533 config LEDS_WM831X_STATUS 525 534 tristate "LED support for status LEDs on WM831x PMICs" 526 535 depends on LEDS_CLASS
+1
drivers/leds/Makefile
··· 72 72 obj-$(CONFIG_LEDS_PCA9532) += leds-pca9532.o 73 73 obj-$(CONFIG_LEDS_PCA955X) += leds-pca955x.o 74 74 obj-$(CONFIG_LEDS_PCA963X) += leds-pca963x.o 75 + obj-$(CONFIG_LEDS_PCA995X) += leds-pca995x.o 75 76 obj-$(CONFIG_LEDS_PM8058) += leds-pm8058.o 76 77 obj-$(CONFIG_LEDS_POWERNV) += leds-powernv.o 77 78 obj-$(CONFIG_LEDS_PWM) += leds-pwm.o
+2 -2
drivers/leds/blink/Kconfig
··· 1 1 config LEDS_BCM63138 2 2 tristate "LED Support for Broadcom BCM63138 SoC" 3 3 depends on LEDS_CLASS 4 - depends on ARCH_BCM4908 || ARCH_BCM_5301X || BCM63XX || COMPILE_TEST 4 + depends on ARCH_BCMBCA || ARCH_BCM_5301X || BCM63XX || COMPILE_TEST 5 5 depends on HAS_IOMEM 6 6 depends on OF 7 - default ARCH_BCM4908 7 + default ARCH_BCMBCA 8 8 help 9 9 This option enables support for LED controller that is part of 10 10 BCM63138 SoC. The same hardware block is known to be also used
+2
drivers/leds/flash/Kconfig
··· 89 89 the total LED current will be split symmetrically on each channel and 90 90 they will be enabled/disabled at the same time. 91 91 92 + This driver can be built as a module, it will be called "leds-qcom-flash". 93 + 92 94 config LEDS_RT4505 93 95 tristate "LED support for RT4505 flashlight controller" 94 96 depends on I2C && OF
+5
drivers/leds/flash/leds-qcom-flash.c
··· 309 309 struct qcom_flash_led *led = flcdev_to_qcom_fled(fled_cdev); 310 310 int rc; 311 311 312 + rc = set_flash_strobe(led, SW_STROBE, false); 313 + if (rc) 314 + return rc; 315 + 312 316 rc = set_flash_current(led, led->flash_current_ma, FLASH_MODE); 313 317 if (rc) 314 318 return rc; ··· 749 745 return 0; 750 746 751 747 release: 748 + fwnode_handle_put(child); 752 749 while (flash_data->v4l2_flash[flash_data->leds_count] && flash_data->leds_count) 753 750 v4l2_flash_release(flash_data->v4l2_flash[flash_data->leds_count--]); 754 751 return rc;
+5 -3
drivers/leds/led-class-multicolor.c
··· 6 6 #include <linux/device.h> 7 7 #include <linux/init.h> 8 8 #include <linux/led-class-multicolor.h> 9 + #include <linux/math.h> 9 10 #include <linux/module.h> 10 11 #include <linux/slab.h> 11 12 #include <linux/uaccess.h> ··· 20 19 int i; 21 20 22 21 for (i = 0; i < mcled_cdev->num_colors; i++) 23 - mcled_cdev->subled_info[i].brightness = brightness * 24 - mcled_cdev->subled_info[i].intensity / 25 - led_cdev->max_brightness; 22 + mcled_cdev->subled_info[i].brightness = 23 + DIV_ROUND_CLOSEST(brightness * 24 + mcled_cdev->subled_info[i].intensity, 25 + led_cdev->max_brightness); 26 26 27 27 return 0; 28 28 }
+63 -13
drivers/leds/led-class.c
··· 22 22 #include <linux/of.h> 23 23 #include "leds.h" 24 24 25 - static struct class *leds_class; 26 25 static DEFINE_MUTEX(leds_lookup_lock); 27 26 static LIST_HEAD(leds_lookup_list); 28 27 ··· 75 76 } 76 77 static DEVICE_ATTR_RO(max_brightness); 77 78 79 + static ssize_t color_show(struct device *dev, 80 + struct device_attribute *attr, char *buf) 81 + { 82 + const char *color_text = "invalid"; 83 + struct led_classdev *led_cdev = dev_get_drvdata(dev); 84 + 85 + if (led_cdev->color < LED_COLOR_ID_MAX) 86 + color_text = led_colors[led_cdev->color]; 87 + 88 + return sysfs_emit(buf, "%s\n", color_text); 89 + } 90 + static DEVICE_ATTR_RO(color); 91 + 78 92 #ifdef CONFIG_LEDS_TRIGGERS 79 93 static BIN_ATTR(trigger, 0644, led_trigger_read, led_trigger_write, 0); 80 94 static struct bin_attribute *led_trigger_bin_attrs[] = { ··· 102 90 static struct attribute *led_class_attrs[] = { 103 91 &dev_attr_brightness.attr, 104 92 &dev_attr_max_brightness.attr, 93 + &dev_attr_color.attr, 105 94 NULL, 106 95 }; 107 96 ··· 247 234 return led_cdev; 248 235 } 249 236 237 + static const struct class leds_class = { 238 + .name = "leds", 239 + .dev_groups = led_groups, 240 + .pm = &leds_class_dev_pm_ops, 241 + }; 242 + 250 243 /** 251 244 * of_led_get() - request a LED device via the LED framework 252 245 * @np: device node to get the LED device from ··· 270 251 if (!led_node) 271 252 return ERR_PTR(-ENOENT); 272 253 273 - led_dev = class_find_device_by_of_node(leds_class, led_node); 254 + led_dev = class_find_device_by_of_node(&leds_class, led_node); 274 255 of_node_put(led_node); 275 256 put_device(led_dev); 276 257 ··· 365 346 if (!provider) 366 347 return ERR_PTR(-ENOENT); 367 348 368 - led_dev = class_find_device_by_name(leds_class, provider); 349 + led_dev = class_find_device_by_name(&leds_class, provider); 369 350 kfree_const(provider); 370 351 371 352 return led_module_get(led_dev); ··· 421 402 } 422 403 EXPORT_SYMBOL_GPL(led_remove_lookup); 423 404 405 + /** 406 + * devm_of_led_get_optional - Resource-managed request of an optional LED device 407 + * @dev: LED consumer 408 + * @index: index of the LED to obtain in the consumer 409 + * 410 + * The device node of the device is parsed to find the requested LED device. 411 + * The LED device returned from this function is automatically released 412 + * on driver detach. 413 + * 414 + * @return a pointer to a LED device, ERR_PTR(errno) on failure and NULL if the 415 + * led was not found. 416 + */ 417 + struct led_classdev *__must_check devm_of_led_get_optional(struct device *dev, 418 + int index) 419 + { 420 + struct led_classdev *led; 421 + 422 + led = devm_of_led_get(dev, index); 423 + if (IS_ERR(led) && PTR_ERR(led) == -ENOENT) 424 + return NULL; 425 + 426 + return led; 427 + } 428 + EXPORT_SYMBOL_GPL(devm_of_led_get_optional); 429 + 424 430 static int led_classdev_next_name(const char *init_name, char *name, 425 431 size_t len) 426 432 { ··· 456 412 strscpy(name, init_name, len); 457 413 458 414 while ((ret < len) && 459 - (dev = class_find_device_by_name(leds_class, name))) { 415 + (dev = class_find_device_by_name(&leds_class, name))) { 460 416 put_device(dev); 461 417 ret = snprintf(name, len, "%s_%u", init_name, ++i); 462 418 } ··· 501 457 if (fwnode_property_present(init_data->fwnode, 502 458 "retain-state-shutdown")) 503 459 led_cdev->flags |= LED_RETAIN_AT_SHUTDOWN; 460 + 461 + fwnode_property_read_u32(init_data->fwnode, 462 + "max-brightness", 463 + &led_cdev->max_brightness); 464 + 465 + if (fwnode_property_present(init_data->fwnode, "color")) 466 + fwnode_property_read_u32(init_data->fwnode, "color", 467 + &led_cdev->color); 504 468 } 505 469 } else { 506 470 proposed_name = led_cdev->name; ··· 518 466 if (ret < 0) 519 467 return ret; 520 468 469 + if (led_cdev->color >= LED_COLOR_ID_MAX) 470 + dev_warn(parent, "LED %s color identifier out of range\n", final_name); 471 + 521 472 mutex_init(&led_cdev->led_access); 522 473 mutex_lock(&led_cdev->led_access); 523 - led_cdev->dev = device_create_with_groups(leds_class, parent, 0, 524 - led_cdev, led_cdev->groups, "%s", final_name); 474 + led_cdev->dev = device_create_with_groups(&leds_class, parent, 0, 475 + led_cdev, led_cdev->groups, "%s", final_name); 525 476 if (IS_ERR(led_cdev->dev)) { 526 477 mutex_unlock(&led_cdev->led_access); 527 478 return PTR_ERR(led_cdev->dev); ··· 681 626 682 627 static int __init leds_init(void) 683 628 { 684 - leds_class = class_create("leds"); 685 - if (IS_ERR(leds_class)) 686 - return PTR_ERR(leds_class); 687 - leds_class->pm = &leds_class_dev_pm_ops; 688 - leds_class->dev_groups = led_groups; 689 - return 0; 629 + return class_register(&leds_class); 690 630 } 691 631 692 632 static void __exit leds_exit(void) 693 633 { 694 - class_destroy(leds_class); 634 + class_unregister(&leds_class); 695 635 } 696 636 697 637 subsys_initcall(leds_init);
+4 -4
drivers/leds/led-core.c
··· 474 474 struct fwnode_handle *fwnode = init_data->fwnode; 475 475 const char *devicename = init_data->devicename; 476 476 477 - /* We want to label LEDs that can produce full range of colors 478 - * as RGB, not multicolor */ 479 - BUG_ON(props.color == LED_COLOR_ID_MULTI); 480 - 481 477 if (!led_classdev_name) 482 478 return -EINVAL; 483 479 484 480 led_parse_fwnode_props(dev, fwnode, &props); 481 + 482 + /* We want to label LEDs that can produce full range of colors 483 + * as RGB, not multicolor */ 484 + BUG_ON(props.color == LED_COLOR_ID_MULTI); 485 485 486 486 if (props.label) { 487 487 /*
+1 -1
drivers/leds/leds-an30259a.c
··· 344 344 static struct i2c_driver an30259a_driver = { 345 345 .driver = { 346 346 .name = "leds-an30259a", 347 - .of_match_table = of_match_ptr(an30259a_match_table), 347 + .of_match_table = an30259a_match_table, 348 348 }, 349 349 .probe = an30259a_probe, 350 350 .remove = an30259a_remove,
+1 -1
drivers/leds/leds-ariel.c
··· 7 7 8 8 #include <linux/module.h> 9 9 #include <linux/leds.h> 10 + #include <linux/platform_device.h> 10 11 #include <linux/regmap.h> 11 - #include <linux/of_platform.h> 12 12 13 13 enum ec_index { 14 14 EC_BLUE_LED = 0x01,
+2 -2
drivers/leds/leds-aw200xx.c
··· 368 368 369 369 if (!chip->display_rows || 370 370 chip->display_rows > chip->cdef->display_size_rows_max) { 371 - return dev_err_probe(dev, ret, 371 + return dev_err_probe(dev, -EINVAL, 372 372 "Invalid leds display size %u\n", 373 373 chip->display_rows); 374 374 } ··· 583 583 .name = "aw200xx", 584 584 .of_match_table = aw200xx_match_table, 585 585 }, 586 - .probe_new = aw200xx_probe, 586 + .probe = aw200xx_probe, 587 587 .remove = aw200xx_remove, 588 588 .id_table = aw200xx_id, 589 589 };
+23 -15
drivers/leds/leds-aw2013.c
··· 62 62 63 63 struct aw2013 { 64 64 struct mutex mutex; /* held when writing to registers */ 65 - struct regulator *vcc_regulator; 65 + struct regulator_bulk_data regulators[2]; 66 66 struct i2c_client *client; 67 67 struct aw2013_led leds[AW2013_MAX_LEDS]; 68 68 struct regmap *regmap; ··· 106 106 107 107 regmap_write(chip->regmap, AW2013_GCR, 0); 108 108 109 - ret = regulator_disable(chip->vcc_regulator); 109 + ret = regulator_bulk_disable(ARRAY_SIZE(chip->regulators), 110 + chip->regulators); 110 111 if (ret) { 111 112 dev_err(&chip->client->dev, 112 - "Failed to disable regulator: %d\n", ret); 113 + "Failed to disable regulators: %d\n", ret); 113 114 return; 114 115 } 115 116 ··· 124 123 if (chip->enabled) 125 124 return 0; 126 125 127 - ret = regulator_enable(chip->vcc_regulator); 126 + ret = regulator_bulk_enable(ARRAY_SIZE(chip->regulators), 127 + chip->regulators); 128 128 if (ret) { 129 129 dev_err(&chip->client->dev, 130 - "Failed to enable regulator: %d\n", ret); 130 + "Failed to enable regulators: %d\n", ret); 131 131 return ret; 132 132 } 133 133 chip->enabled = true; ··· 350 348 goto error; 351 349 } 352 350 353 - chip->vcc_regulator = devm_regulator_get(&client->dev, "vcc"); 354 - ret = PTR_ERR_OR_ZERO(chip->vcc_regulator); 355 - if (ret) { 351 + chip->regulators[0].supply = "vcc"; 352 + chip->regulators[1].supply = "vio"; 353 + ret = devm_regulator_bulk_get(&client->dev, 354 + ARRAY_SIZE(chip->regulators), 355 + chip->regulators); 356 + if (ret < 0) { 356 357 if (ret != -EPROBE_DEFER) 357 358 dev_err(&client->dev, 358 - "Failed to request regulator: %d\n", ret); 359 + "Failed to request regulators: %d\n", ret); 359 360 goto error; 360 361 } 361 362 362 - ret = regulator_enable(chip->vcc_regulator); 363 + ret = regulator_bulk_enable(ARRAY_SIZE(chip->regulators), 364 + chip->regulators); 363 365 if (ret) { 364 366 dev_err(&client->dev, 365 - "Failed to enable regulator: %d\n", ret); 367 + "Failed to enable regulators: %d\n", ret); 366 368 goto error; 367 369 } 368 370 ··· 388 382 if (ret < 0) 389 383 goto error_reg; 390 384 391 - ret = regulator_disable(chip->vcc_regulator); 385 + ret = regulator_bulk_disable(ARRAY_SIZE(chip->regulators), 386 + chip->regulators); 392 387 if (ret) { 393 388 dev_err(&client->dev, 394 - "Failed to disable regulator: %d\n", ret); 389 + "Failed to disable regulators: %d\n", ret); 395 390 goto error; 396 391 } 397 392 ··· 401 394 return 0; 402 395 403 396 error_reg: 404 - regulator_disable(chip->vcc_regulator); 397 + regulator_bulk_disable(ARRAY_SIZE(chip->regulators), 398 + chip->regulators); 405 399 406 400 error: 407 401 mutex_destroy(&chip->mutex); ··· 428 420 static struct i2c_driver aw2013_driver = { 429 421 .driver = { 430 422 .name = "leds-aw2013", 431 - .of_match_table = of_match_ptr(aw2013_match_table), 423 + .of_match_table = aw2013_match_table, 432 424 }, 433 425 .probe = aw2013_probe, 434 426 .remove = aw2013_remove,
+1 -1
drivers/leds/leds-cpcap.c
··· 7 7 #include <linux/mfd/motorola-cpcap.h> 8 8 #include <linux/module.h> 9 9 #include <linux/mutex.h> 10 - #include <linux/of_device.h> 10 + #include <linux/of.h> 11 11 #include <linux/platform_device.h> 12 12 #include <linux/regmap.h> 13 13 #include <linux/regulator/consumer.h>
+1 -1
drivers/leds/leds-cr0014114.c
··· 4 4 5 5 #include <linux/delay.h> 6 6 #include <linux/leds.h> 7 + #include <linux/mod_devicetable.h> 7 8 #include <linux/module.h> 8 - #include <linux/of_device.h> 9 9 #include <linux/spi/spi.h> 10 10 #include <linux/workqueue.h> 11 11
+1 -7
drivers/leds/leds-ip30.c
··· 27 27 28 28 static int ip30led_create(struct platform_device *pdev, int num) 29 29 { 30 - struct resource *res; 31 30 struct ip30_led *data; 32 - 33 - res = platform_get_resource(pdev, IORESOURCE_MEM, num); 34 - if (!res) 35 - return -EBUSY; 36 31 37 32 data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); 38 33 if (!data) 39 34 return -ENOMEM; 40 35 41 - data->reg = devm_ioremap_resource(&pdev->dev, res); 36 + data->reg = devm_platform_ioremap_resource(pdev, num); 42 37 if (IS_ERR(data->reg)) 43 38 return PTR_ERR(data->reg); 44 - 45 39 46 40 switch (num) { 47 41 case IP30_LED_SYSTEM:
-1
drivers/leds/leds-is31fl32xx.c
··· 15 15 #include <linux/leds.h> 16 16 #include <linux/module.h> 17 17 #include <linux/of.h> 18 - #include <linux/of_device.h> 19 18 20 19 /* Used to indicate a device has no such register */ 21 20 #define IS31FL32XX_REG_NONE 0xFF
+2 -3
drivers/leds/leds-lp5521.c
··· 594 594 }; 595 595 MODULE_DEVICE_TABLE(i2c, lp5521_id); 596 596 597 - #ifdef CONFIG_OF 598 597 static const struct of_device_id of_lp5521_leds_match[] = { 599 598 { .compatible = "national,lp5521", }, 600 599 {}, 601 600 }; 602 601 603 602 MODULE_DEVICE_TABLE(of, of_lp5521_leds_match); 604 - #endif 603 + 605 604 static struct i2c_driver lp5521_driver = { 606 605 .driver = { 607 606 .name = "lp5521", 608 - .of_match_table = of_match_ptr(of_lp5521_leds_match), 607 + .of_match_table = of_lp5521_leds_match, 609 608 }, 610 609 .probe = lp5521_probe, 611 610 .remove = lp5521_remove,
+1 -3
drivers/leds/leds-lp5523.c
··· 972 972 973 973 MODULE_DEVICE_TABLE(i2c, lp5523_id); 974 974 975 - #ifdef CONFIG_OF 976 975 static const struct of_device_id of_lp5523_leds_match[] = { 977 976 { .compatible = "national,lp5523", }, 978 977 { .compatible = "ti,lp55231", }, ··· 979 980 }; 980 981 981 982 MODULE_DEVICE_TABLE(of, of_lp5523_leds_match); 982 - #endif 983 983 984 984 static struct i2c_driver lp5523_driver = { 985 985 .driver = { 986 986 .name = "lp5523x", 987 - .of_match_table = of_match_ptr(of_lp5523_leds_match), 987 + .of_match_table = of_lp5523_leds_match, 988 988 }, 989 989 .probe = lp5523_probe, 990 990 .remove = lp5523_remove,
+1 -3
drivers/leds/leds-lp5562.c
··· 589 589 }; 590 590 MODULE_DEVICE_TABLE(i2c, lp5562_id); 591 591 592 - #ifdef CONFIG_OF 593 592 static const struct of_device_id of_lp5562_leds_match[] = { 594 593 { .compatible = "ti,lp5562", }, 595 594 {}, 596 595 }; 597 596 598 597 MODULE_DEVICE_TABLE(of, of_lp5562_leds_match); 599 - #endif 600 598 601 599 static struct i2c_driver lp5562_driver = { 602 600 .driver = { 603 601 .name = "lp5562", 604 - .of_match_table = of_match_ptr(of_lp5562_leds_match), 602 + .of_match_table = of_lp5562_leds_match, 605 603 }, 606 604 .probe = lp5562_probe, 607 605 .remove = lp5562_remove,
+1 -3
drivers/leds/leds-lp8501.c
··· 380 380 }; 381 381 MODULE_DEVICE_TABLE(i2c, lp8501_id); 382 382 383 - #ifdef CONFIG_OF 384 383 static const struct of_device_id of_lp8501_leds_match[] = { 385 384 { .compatible = "ti,lp8501", }, 386 385 {}, 387 386 }; 388 387 389 388 MODULE_DEVICE_TABLE(of, of_lp8501_leds_match); 390 - #endif 391 389 392 390 static struct i2c_driver lp8501_driver = { 393 391 .driver = { 394 392 .name = "lp8501", 395 - .of_match_table = of_match_ptr(of_lp8501_leds_match), 393 + .of_match_table = of_lp8501_leds_match, 396 394 }, 397 395 .probe = lp8501_probe, 398 396 .remove = lp8501_remove,
-1
drivers/leds/leds-mlxreg.c
··· 8 8 #include <linux/io.h> 9 9 #include <linux/leds.h> 10 10 #include <linux/module.h> 11 - #include <linux/of_device.h> 12 11 #include <linux/platform_data/mlxreg.h> 13 12 #include <linux/platform_device.h> 14 13 #include <linux/regmap.h>
+1 -1
drivers/leds/leds-ns2.c
··· 247 247 if (!count) 248 248 return -ENODEV; 249 249 250 - leds = devm_kzalloc(dev, array_size(sizeof(*leds), count), GFP_KERNEL); 250 + leds = devm_kcalloc(dev, count, sizeof(*leds), GFP_KERNEL); 251 251 if (!leds) 252 252 return -ENOMEM; 253 253
-1
drivers/leds/leds-pca9532.c
··· 18 18 #include <linux/leds-pca9532.h> 19 19 #include <linux/gpio/driver.h> 20 20 #include <linux/of.h> 21 - #include <linux/of_device.h> 22 21 23 22 /* m = num_leds*/ 24 23 #define PCA9532_REG_INPUT(i) ((i) >> 3)
+204
drivers/leds/leds-pca995x.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * LED driver for PCA995x I2C LED drivers 4 + * 5 + * Copyright 2011 bct electronic GmbH 6 + * Copyright 2013 Qtechnology/AS 7 + * Copyright 2022 NXP 8 + * Copyright 2023 Marek Vasut 9 + */ 10 + 11 + #include <linux/i2c.h> 12 + #include <linux/leds.h> 13 + #include <linux/module.h> 14 + #include <linux/mod_devicetable.h> 15 + #include <linux/property.h> 16 + #include <linux/regmap.h> 17 + 18 + /* Register definition */ 19 + #define PCA995X_MODE1 0x00 20 + #define PCA995X_MODE2 0x01 21 + #define PCA995X_LEDOUT0 0x02 22 + #define PCA9955B_PWM0 0x08 23 + #define PCA9952_PWM0 0x0A 24 + #define PCA9952_IREFALL 0x43 25 + #define PCA9955B_IREFALL 0x45 26 + 27 + /* Auto-increment disabled. Normal mode */ 28 + #define PCA995X_MODE1_CFG 0x00 29 + 30 + /* LED select registers determine the source that drives LED outputs */ 31 + #define PCA995X_LED_OFF 0x0 32 + #define PCA995X_LED_ON 0x1 33 + #define PCA995X_LED_PWM_MODE 0x2 34 + #define PCA995X_LDRX_MASK 0x3 35 + #define PCA995X_LDRX_BITS 2 36 + 37 + #define PCA995X_MAX_OUTPUTS 16 38 + #define PCA995X_OUTPUTS_PER_REG 4 39 + 40 + #define PCA995X_IREFALL_FULL_CFG 0xFF 41 + #define PCA995X_IREFALL_HALF_CFG (PCA995X_IREFALL_FULL_CFG / 2) 42 + 43 + #define PCA995X_TYPE_NON_B 0 44 + #define PCA995X_TYPE_B 1 45 + 46 + #define ldev_to_led(c) container_of(c, struct pca995x_led, ldev) 47 + 48 + struct pca995x_led { 49 + unsigned int led_no; 50 + struct led_classdev ldev; 51 + struct pca995x_chip *chip; 52 + }; 53 + 54 + struct pca995x_chip { 55 + struct regmap *regmap; 56 + struct pca995x_led leds[PCA995X_MAX_OUTPUTS]; 57 + int btype; 58 + }; 59 + 60 + static int pca995x_brightness_set(struct led_classdev *led_cdev, 61 + enum led_brightness brightness) 62 + { 63 + struct pca995x_led *led = ldev_to_led(led_cdev); 64 + struct pca995x_chip *chip = led->chip; 65 + u8 ledout_addr, pwmout_addr; 66 + int shift, ret; 67 + 68 + pwmout_addr = (chip->btype ? PCA9955B_PWM0 : PCA9952_PWM0) + led->led_no; 69 + ledout_addr = PCA995X_LEDOUT0 + (led->led_no / PCA995X_OUTPUTS_PER_REG); 70 + shift = PCA995X_LDRX_BITS * (led->led_no % PCA995X_OUTPUTS_PER_REG); 71 + 72 + switch (brightness) { 73 + case LED_FULL: 74 + return regmap_update_bits(chip->regmap, ledout_addr, 75 + PCA995X_LDRX_MASK << shift, 76 + PCA995X_LED_ON << shift); 77 + case LED_OFF: 78 + return regmap_update_bits(chip->regmap, ledout_addr, 79 + PCA995X_LDRX_MASK << shift, 0); 80 + default: 81 + /* Adjust brightness as per user input by changing individual PWM */ 82 + ret = regmap_write(chip->regmap, pwmout_addr, brightness); 83 + if (ret) 84 + return ret; 85 + 86 + /* 87 + * Change LDRx configuration to individual brightness via PWM. 88 + * LED will stop blinking if it's doing so. 89 + */ 90 + return regmap_update_bits(chip->regmap, ledout_addr, 91 + PCA995X_LDRX_MASK << shift, 92 + PCA995X_LED_PWM_MODE << shift); 93 + } 94 + } 95 + 96 + static const struct regmap_config pca995x_regmap = { 97 + .reg_bits = 8, 98 + .val_bits = 8, 99 + .max_register = 0x49, 100 + }; 101 + 102 + static int pca995x_probe(struct i2c_client *client) 103 + { 104 + struct fwnode_handle *led_fwnodes[PCA995X_MAX_OUTPUTS] = { 0 }; 105 + struct fwnode_handle *np, *child; 106 + struct device *dev = &client->dev; 107 + struct pca995x_chip *chip; 108 + struct pca995x_led *led; 109 + int i, btype, reg, ret; 110 + 111 + btype = (unsigned long)device_get_match_data(&client->dev); 112 + 113 + np = dev_fwnode(dev); 114 + if (!np) 115 + return -ENODEV; 116 + 117 + chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); 118 + if (!chip) 119 + return -ENOMEM; 120 + 121 + chip->btype = btype; 122 + chip->regmap = devm_regmap_init_i2c(client, &pca995x_regmap); 123 + if (IS_ERR(chip->regmap)) 124 + return PTR_ERR(chip->regmap); 125 + 126 + i2c_set_clientdata(client, chip); 127 + 128 + fwnode_for_each_available_child_node(np, child) { 129 + ret = fwnode_property_read_u32(child, "reg", &reg); 130 + if (ret) { 131 + fwnode_handle_put(child); 132 + return ret; 133 + } 134 + 135 + if (reg < 0 || reg >= PCA995X_MAX_OUTPUTS || led_fwnodes[reg]) { 136 + fwnode_handle_put(child); 137 + return -EINVAL; 138 + } 139 + 140 + led = &chip->leds[reg]; 141 + led_fwnodes[reg] = child; 142 + led->chip = chip; 143 + led->led_no = reg; 144 + led->ldev.brightness_set_blocking = pca995x_brightness_set; 145 + led->ldev.max_brightness = 255; 146 + } 147 + 148 + for (i = 0; i < PCA995X_MAX_OUTPUTS; i++) { 149 + struct led_init_data init_data = {}; 150 + 151 + if (!led_fwnodes[i]) 152 + continue; 153 + 154 + init_data.fwnode = led_fwnodes[i]; 155 + 156 + ret = devm_led_classdev_register_ext(dev, 157 + &chip->leds[i].ldev, 158 + &init_data); 159 + if (ret < 0) { 160 + fwnode_handle_put(child); 161 + return dev_err_probe(dev, ret, 162 + "Could not register LED %s\n", 163 + chip->leds[i].ldev.name); 164 + } 165 + } 166 + 167 + /* Disable LED all-call address and set normal mode */ 168 + ret = regmap_write(chip->regmap, PCA995X_MODE1, PCA995X_MODE1_CFG); 169 + if (ret) 170 + return ret; 171 + 172 + /* IREF Output current value for all LEDn outputs */ 173 + return regmap_write(chip->regmap, 174 + btype ? PCA9955B_IREFALL : PCA9952_IREFALL, 175 + PCA995X_IREFALL_HALF_CFG); 176 + } 177 + 178 + static const struct i2c_device_id pca995x_id[] = { 179 + { "pca9952", .driver_data = (kernel_ulong_t)PCA995X_TYPE_NON_B }, 180 + { "pca9955b", .driver_data = (kernel_ulong_t)PCA995X_TYPE_B }, 181 + {} 182 + }; 183 + MODULE_DEVICE_TABLE(i2c, pca995x_id); 184 + 185 + static const struct of_device_id pca995x_of_match[] = { 186 + { .compatible = "nxp,pca9952", .data = (void *)PCA995X_TYPE_NON_B }, 187 + { .compatible = "nxp,pca9955b", .data = (void *)PCA995X_TYPE_B }, 188 + {}, 189 + }; 190 + MODULE_DEVICE_TABLE(of, pca995x_of_match); 191 + 192 + static struct i2c_driver pca995x_driver = { 193 + .driver = { 194 + .name = "leds-pca995x", 195 + .of_match_table = pca995x_of_match, 196 + }, 197 + .probe = pca995x_probe, 198 + .id_table = pca995x_id, 199 + }; 200 + module_i2c_driver(pca995x_driver); 201 + 202 + MODULE_AUTHOR("Isai Gaspar <isaiezequiel.gaspar@nxp.com>"); 203 + MODULE_DESCRIPTION("PCA995x LED driver"); 204 + MODULE_LICENSE("GPL");
-1
drivers/leds/leds-pm8058.c
··· 4 4 #include <linux/leds.h> 5 5 #include <linux/module.h> 6 6 #include <linux/of.h> 7 - #include <linux/of_device.h> 8 7 #include <linux/platform_device.h> 9 8 #include <linux/pm.h> 10 9 #include <linux/regmap.h>
+2 -2
drivers/leds/leds-pwm.c
··· 12 12 #include <linux/module.h> 13 13 #include <linux/kernel.h> 14 14 #include <linux/platform_device.h> 15 - #include <linux/of_platform.h> 15 + #include <linux/of.h> 16 16 #include <linux/leds.h> 17 17 #include <linux/err.h> 18 18 #include <linux/pwm.h> ··· 146 146 led.name = to_of_node(fwnode)->name; 147 147 148 148 if (!led.name) { 149 - ret = EINVAL; 149 + ret = -EINVAL; 150 150 goto err_child_out; 151 151 } 152 152
+1 -1
drivers/leds/leds-spi-byte.c
··· 30 30 31 31 #include <linux/leds.h> 32 32 #include <linux/module.h> 33 - #include <linux/of_device.h> 33 + #include <linux/of.h> 34 34 #include <linux/spi/spi.h> 35 35 #include <linux/mutex.h> 36 36 #include <uapi/linux/uleds.h>
+1 -2
drivers/leds/leds-syscon.c
··· 7 7 */ 8 8 #include <linux/io.h> 9 9 #include <linux/init.h> 10 - #include <linux/of_device.h> 11 - #include <linux/of_address.h> 10 + #include <linux/of.h> 12 11 #include <linux/platform_device.h> 13 12 #include <linux/stat.h> 14 13 #include <linux/slab.h>
+1 -1
drivers/leds/leds-ti-lmu-common.c
··· 7 7 8 8 #include <linux/bitops.h> 9 9 #include <linux/err.h> 10 - #include <linux/of_device.h> 10 + #include <linux/property.h> 11 11 12 12 #include <linux/leds-ti-lmu-common.h> 13 13
-1
drivers/leds/leds-tlc591xx.c
··· 8 8 #include <linux/leds.h> 9 9 #include <linux/module.h> 10 10 #include <linux/of.h> 11 - #include <linux/of_device.h> 12 11 #include <linux/regmap.h> 13 12 #include <linux/slab.h> 14 13
+2 -11
drivers/leds/leds-turris-omnia.c
··· 156 156 char *buf) 157 157 { 158 158 struct i2c_client *client = to_i2c_client(dev); 159 - struct omnia_leds *leds = i2c_get_clientdata(client); 160 159 int ret; 161 160 162 - mutex_lock(&leds->lock); 163 161 ret = i2c_smbus_read_byte_data(client, CMD_LED_GET_BRIGHTNESS); 164 - mutex_unlock(&leds->lock); 165 162 166 163 if (ret < 0) 167 164 return ret; 168 165 169 - return sprintf(buf, "%d\n", ret); 166 + return sysfs_emit(buf, "%d\n", ret); 170 167 } 171 168 172 169 static ssize_t brightness_store(struct device *dev, struct device_attribute *a, 173 170 const char *buf, size_t count) 174 171 { 175 172 struct i2c_client *client = to_i2c_client(dev); 176 - struct omnia_leds *leds = i2c_get_clientdata(client); 177 173 unsigned long brightness; 178 174 int ret; 179 175 ··· 179 183 if (brightness > 100) 180 184 return -EINVAL; 181 185 182 - mutex_lock(&leds->lock); 183 186 ret = i2c_smbus_write_byte_data(client, CMD_LED_SET_BRIGHTNESS, 184 187 (u8)brightness); 185 - mutex_unlock(&leds->lock); 186 188 187 - if (ret < 0) 188 - return ret; 189 - 190 - return count; 189 + return ret < 0 ? ret : count; 191 190 } 192 191 static DEVICE_ATTR_RW(brightness); 193 192
+12
drivers/leds/rgb/Kconfig
··· 2 2 3 3 if LEDS_CLASS_MULTICOLOR 4 4 5 + config LEDS_GROUP_MULTICOLOR 6 + tristate "LEDs group multi-color support" 7 + depends on OF || COMPILE_TEST 8 + help 9 + This option enables support for monochrome LEDs that are grouped 10 + into multicolor LEDs which is useful in the case where LEDs of 11 + different colors are physically grouped in a single multi-color LED 12 + and driven by a controller that doesn't have multi-color support. 13 + 14 + To compile this driver as a module, choose M here: the module 15 + will be called leds-group-multicolor. 16 + 5 17 config LEDS_PWM_MULTICOLOR 6 18 tristate "PWM driven multi-color LED Support" 7 19 depends on PWM
+1
drivers/leds/rgb/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0 2 2 3 + obj-$(CONFIG_LEDS_GROUP_MULTICOLOR) += leds-group-multicolor.o 3 4 obj-$(CONFIG_LEDS_PWM_MULTICOLOR) += leds-pwm-multicolor.o 4 5 obj-$(CONFIG_LEDS_QCOM_LPG) += leds-qcom-lpg.o 5 6 obj-$(CONFIG_LEDS_MT6370_RGB) += leds-mt6370-rgb.o
+169
drivers/leds/rgb/leds-group-multicolor.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Multi-color LED built with monochromatic LED devices 4 + * 5 + * This driver groups several monochromatic LED devices in a single multicolor LED device. 6 + * 7 + * Compared to handling this grouping in user-space, the benefits are: 8 + * - The state of the monochromatic LED relative to each other is always consistent. 9 + * - The sysfs interface of the LEDs can be used for the group as a whole. 10 + * 11 + * Copyright 2023 Jean-Jacques Hiblot <jjhiblot@traphandler.com> 12 + */ 13 + 14 + #include <linux/err.h> 15 + #include <linux/leds.h> 16 + #include <linux/led-class-multicolor.h> 17 + #include <linux/math.h> 18 + #include <linux/module.h> 19 + #include <linux/mod_devicetable.h> 20 + #include <linux/platform_device.h> 21 + #include <linux/property.h> 22 + 23 + struct leds_multicolor { 24 + struct led_classdev_mc mc_cdev; 25 + struct led_classdev **monochromatics; 26 + }; 27 + 28 + static int leds_gmc_set(struct led_classdev *cdev, enum led_brightness brightness) 29 + { 30 + struct led_classdev_mc *mc_cdev = lcdev_to_mccdev(cdev); 31 + struct leds_multicolor *priv = container_of(mc_cdev, struct leds_multicolor, mc_cdev); 32 + const unsigned int group_max_brightness = mc_cdev->led_cdev.max_brightness; 33 + int i; 34 + 35 + for (i = 0; i < mc_cdev->num_colors; i++) { 36 + struct led_classdev *mono = priv->monochromatics[i]; 37 + const unsigned int mono_max_brightness = mono->max_brightness; 38 + unsigned int intensity = mc_cdev->subled_info[i].intensity; 39 + int mono_brightness; 40 + 41 + /* 42 + * Scale the brightness according to relative intensity of the 43 + * color AND the max brightness of the monochromatic LED. 44 + */ 45 + mono_brightness = DIV_ROUND_CLOSEST(brightness * intensity * mono_max_brightness, 46 + group_max_brightness * group_max_brightness); 47 + 48 + led_set_brightness(mono, mono_brightness); 49 + } 50 + 51 + return 0; 52 + } 53 + 54 + static void restore_sysfs_write_access(void *data) 55 + { 56 + struct led_classdev *led_cdev = data; 57 + 58 + /* Restore the write acccess to the LED */ 59 + mutex_lock(&led_cdev->led_access); 60 + led_sysfs_enable(led_cdev); 61 + mutex_unlock(&led_cdev->led_access); 62 + } 63 + 64 + static int leds_gmc_probe(struct platform_device *pdev) 65 + { 66 + struct device *dev = &pdev->dev; 67 + struct led_init_data init_data = {}; 68 + struct led_classdev *cdev; 69 + struct mc_subled *subled; 70 + struct leds_multicolor *priv; 71 + unsigned int max_brightness = 0; 72 + int i, ret, count = 0; 73 + 74 + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 75 + if (!priv) 76 + return -ENOMEM; 77 + 78 + for (;;) { 79 + struct led_classdev *led_cdev; 80 + 81 + led_cdev = devm_of_led_get_optional(dev, count); 82 + if (IS_ERR(led_cdev)) 83 + return dev_err_probe(dev, PTR_ERR(led_cdev), "Unable to get LED #%d", 84 + count); 85 + if (!led_cdev) 86 + break; 87 + 88 + priv->monochromatics = devm_krealloc_array(dev, priv->monochromatics, 89 + count + 1, sizeof(*priv->monochromatics), 90 + GFP_KERNEL); 91 + if (!priv->monochromatics) 92 + return -ENOMEM; 93 + 94 + priv->monochromatics[count] = led_cdev; 95 + 96 + max_brightness = max(max_brightness, led_cdev->max_brightness); 97 + 98 + count++; 99 + } 100 + 101 + subled = devm_kcalloc(dev, count, sizeof(*subled), GFP_KERNEL); 102 + if (!subled) 103 + return -ENOMEM; 104 + priv->mc_cdev.subled_info = subled; 105 + 106 + for (i = 0; i < count; i++) { 107 + struct led_classdev *led_cdev = priv->monochromatics[i]; 108 + 109 + subled[i].color_index = led_cdev->color; 110 + 111 + /* Configure the LED intensity to its maximum */ 112 + subled[i].intensity = max_brightness; 113 + } 114 + 115 + /* Initialise the multicolor's LED class device */ 116 + cdev = &priv->mc_cdev.led_cdev; 117 + cdev->flags = LED_CORE_SUSPENDRESUME; 118 + cdev->brightness_set_blocking = leds_gmc_set; 119 + cdev->max_brightness = max_brightness; 120 + cdev->color = LED_COLOR_ID_MULTI; 121 + priv->mc_cdev.num_colors = count; 122 + 123 + init_data.fwnode = dev_fwnode(dev); 124 + ret = devm_led_classdev_multicolor_register_ext(dev, &priv->mc_cdev, &init_data); 125 + if (ret) 126 + return dev_err_probe(dev, ret, "failed to register multicolor LED for %s.\n", 127 + cdev->name); 128 + 129 + ret = leds_gmc_set(cdev, cdev->brightness); 130 + if (ret) 131 + return dev_err_probe(dev, ret, "failed to set LED value for %s.", cdev->name); 132 + 133 + for (i = 0; i < count; i++) { 134 + struct led_classdev *led_cdev = priv->monochromatics[i]; 135 + 136 + /* 137 + * Make the individual LED sysfs interface read-only to prevent the user 138 + * to change the brightness of the individual LEDs of the group. 139 + */ 140 + mutex_lock(&led_cdev->led_access); 141 + led_sysfs_disable(led_cdev); 142 + mutex_unlock(&led_cdev->led_access); 143 + 144 + /* Restore the write access to the LED sysfs when the group is destroyed */ 145 + devm_add_action_or_reset(dev, restore_sysfs_write_access, led_cdev); 146 + } 147 + 148 + return 0; 149 + } 150 + 151 + static const struct of_device_id of_leds_group_multicolor_match[] = { 152 + { .compatible = "leds-group-multicolor" }, 153 + {} 154 + }; 155 + MODULE_DEVICE_TABLE(of, of_leds_group_multicolor_match); 156 + 157 + static struct platform_driver leds_group_multicolor_driver = { 158 + .probe = leds_gmc_probe, 159 + .driver = { 160 + .name = "leds_group_multicolor", 161 + .of_match_table = of_leds_group_multicolor_match, 162 + } 163 + }; 164 + module_platform_driver(leds_group_multicolor_driver); 165 + 166 + MODULE_AUTHOR("Jean-Jacques Hiblot <jjhiblot@traphandler.com>"); 167 + MODULE_DESCRIPTION("LEDs group multicolor driver"); 168 + MODULE_LICENSE("GPL"); 169 + MODULE_ALIAS("platform:leds-group-multicolor");
-2
drivers/leds/rgb/leds-qcom-lpg.c
··· 9 9 #include <linux/led-class-multicolor.h> 10 10 #include <linux/module.h> 11 11 #include <linux/of.h> 12 - #include <linux/of_device.h> 13 12 #include <linux/platform_device.h> 14 13 #include <linux/pwm.h> 15 14 #include <linux/regmap.h> ··· 1092 1093 { 1093 1094 int ret; 1094 1095 1095 - lpg->pwm.base = -1; 1096 1096 lpg->pwm.dev = lpg->dev; 1097 1097 lpg->pwm.npwm = lpg->num_channels; 1098 1098 lpg->pwm.ops = &lpg_pwm_ops;
+14
drivers/leds/simple/Kconfig
··· 1 1 # SPDX-License-Identifier: GPL-2.0-only 2 2 config LEDS_SIEMENS_SIMATIC_IPC 3 3 tristate "LED driver for Siemens Simatic IPCs" 4 + depends on LEDS_CLASS 4 5 depends on SIEMENS_SIMATIC_IPC 5 6 default y 6 7 help ··· 36 35 37 36 To compile this driver as a module, choose M here: the module 38 37 will be called simatic-ipc-leds-gpio-f7188x. 38 + 39 + config LEDS_SIEMENS_SIMATIC_IPC_ELKHARTLAKE 40 + tristate "LED driver for Siemens Simatic IPCs based on Intel Elkhart Lake GPIO" 41 + depends on LEDS_GPIO 42 + depends on PINCTRL_ELKHARTLAKE 43 + depends on SIEMENS_SIMATIC_IPC 44 + default LEDS_SIEMENS_SIMATIC_IPC 45 + help 46 + This option enables support for the LEDs of several Industrial PCs 47 + from Siemens based on Elkhart Lake GPIO i.e. BX-21A. 48 + 49 + To compile this driver as a module, choose M here: the module 50 + will be called simatic-ipc-leds-gpio-elkhartlake.
+1
drivers/leds/simple/Makefile
··· 2 2 obj-$(CONFIG_LEDS_SIEMENS_SIMATIC_IPC) += simatic-ipc-leds.o 3 3 obj-$(CONFIG_LEDS_SIEMENS_SIMATIC_IPC_APOLLOLAKE) += simatic-ipc-leds-gpio-core.o simatic-ipc-leds-gpio-apollolake.o 4 4 obj-$(CONFIG_LEDS_SIEMENS_SIMATIC_IPC_F7188X) += simatic-ipc-leds-gpio-core.o simatic-ipc-leds-gpio-f7188x.o 5 + obj-$(CONFIG_LEDS_SIEMENS_SIMATIC_IPC_ELKHARTLAKE) += simatic-ipc-leds-gpio-core.o simatic-ipc-leds-gpio-elkhartlake.o
+4
drivers/leds/simple/simatic-ipc-leds-gpio-core.c
··· 57 57 switch (plat->devmode) { 58 58 case SIMATIC_IPC_DEVICE_127E: 59 59 case SIMATIC_IPC_DEVICE_227G: 60 + case SIMATIC_IPC_DEVICE_BX_21A: 60 61 break; 61 62 default: 62 63 return -ENODEV; ··· 72 71 err = PTR_ERR(simatic_leds_pdev); 73 72 goto out; 74 73 } 74 + 75 + if (!table_extra) 76 + return 0; 75 77 76 78 table_extra->dev_id = dev_name(dev); 77 79 gpiod_add_lookup_table(table_extra);
+57
drivers/leds/simple/simatic-ipc-leds-gpio-elkhartlake.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Siemens SIMATIC IPC driver for GPIO based LEDs 4 + * 5 + * Copyright (c) Siemens AG, 2023 6 + * 7 + * Author: 8 + * Henning Schild <henning.schild@siemens.com> 9 + */ 10 + 11 + #include <linux/gpio/machine.h> 12 + #include <linux/gpio/consumer.h> 13 + #include <linux/leds.h> 14 + #include <linux/module.h> 15 + #include <linux/platform_device.h> 16 + #include <linux/platform_data/x86/simatic-ipc-base.h> 17 + 18 + #include "simatic-ipc-leds-gpio.h" 19 + 20 + static struct gpiod_lookup_table simatic_ipc_led_gpio_table = { 21 + .dev_id = "leds-gpio", 22 + .table = { 23 + GPIO_LOOKUP_IDX("INTC1020:04", 72, NULL, 0, GPIO_ACTIVE_HIGH), 24 + GPIO_LOOKUP_IDX("INTC1020:04", 77, NULL, 1, GPIO_ACTIVE_HIGH), 25 + GPIO_LOOKUP_IDX("INTC1020:04", 78, NULL, 2, GPIO_ACTIVE_HIGH), 26 + GPIO_LOOKUP_IDX("INTC1020:04", 58, NULL, 3, GPIO_ACTIVE_HIGH), 27 + GPIO_LOOKUP_IDX("INTC1020:04", 60, NULL, 4, GPIO_ACTIVE_HIGH), 28 + GPIO_LOOKUP_IDX("INTC1020:04", 62, NULL, 5, GPIO_ACTIVE_HIGH), 29 + {} /* Terminating entry */ 30 + }, 31 + }; 32 + 33 + static int simatic_ipc_leds_gpio_elkhartlake_probe(struct platform_device *pdev) 34 + { 35 + return simatic_ipc_leds_gpio_probe(pdev, &simatic_ipc_led_gpio_table, 36 + NULL); 37 + } 38 + 39 + static int simatic_ipc_leds_gpio_elkhartlake_remove(struct platform_device *pdev) 40 + { 41 + return simatic_ipc_leds_gpio_remove(pdev, &simatic_ipc_led_gpio_table, 42 + NULL); 43 + } 44 + 45 + static struct platform_driver simatic_ipc_led_gpio_elkhartlake_driver = { 46 + .probe = simatic_ipc_leds_gpio_elkhartlake_probe, 47 + .remove = simatic_ipc_leds_gpio_elkhartlake_remove, 48 + .driver = { 49 + .name = KBUILD_MODNAME, 50 + }, 51 + }; 52 + module_platform_driver(simatic_ipc_led_gpio_elkhartlake_driver); 53 + 54 + MODULE_LICENSE("GPL v2"); 55 + MODULE_ALIAS("platform:" KBUILD_MODNAME); 56 + MODULE_SOFTDEP("pre: simatic-ipc-leds-gpio-core platform:elkhartlake-pinctrl"); 57 + MODULE_AUTHOR("Henning Schild <henning.schild@siemens.com>");
+1 -1
drivers/leds/simple/simatic-ipc-leds-gpio.h
··· 1 - // SPDX-License-Identifier: GPL-2.0 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 2 /* 3 3 * Siemens SIMATIC IPC driver for GPIO based LEDs 4 4 *
+1 -12
drivers/leds/trigger/ledtrig-netdev.c
··· 609 609 .groups = netdev_trig_groups, 610 610 }; 611 611 612 - static int __init netdev_trig_init(void) 613 - { 614 - return led_trigger_register(&netdev_led_trigger); 615 - } 616 - 617 - static void __exit netdev_trig_exit(void) 618 - { 619 - led_trigger_unregister(&netdev_led_trigger); 620 - } 621 - 622 - module_init(netdev_trig_init); 623 - module_exit(netdev_trig_exit); 612 + module_led_trigger(netdev_led_trigger); 624 613 625 614 MODULE_AUTHOR("Ben Whitten <ben.whitten@gmail.com>"); 626 615 MODULE_AUTHOR("Oliver Jowett <oliver@opencloud.com>");
+8 -4
drivers/leds/trigger/ledtrig-tty.c
··· 7 7 #include <linux/tty.h> 8 8 #include <uapi/linux/serial.h> 9 9 10 + #define LEDTRIG_TTY_INTERVAL 50 11 + 10 12 struct ledtrig_tty_data { 11 13 struct led_classdev *led_cdev; 12 14 struct delayed_work dwork; ··· 124 122 125 123 if (icount.rx != trigger_data->rx || 126 124 icount.tx != trigger_data->tx) { 127 - led_set_brightness_sync(trigger_data->led_cdev, LED_ON); 125 + unsigned long interval = LEDTRIG_TTY_INTERVAL; 126 + 127 + led_blink_set_oneshot(trigger_data->led_cdev, &interval, 128 + &interval, 0); 128 129 129 130 trigger_data->rx = icount.rx; 130 131 trigger_data->tx = icount.tx; 131 - } else { 132 - led_set_brightness_sync(trigger_data->led_cdev, LED_OFF); 133 132 } 134 133 135 134 out: 136 135 mutex_unlock(&trigger_data->mutex); 137 - schedule_delayed_work(&trigger_data->dwork, msecs_to_jiffies(100)); 136 + schedule_delayed_work(&trigger_data->dwork, 137 + msecs_to_jiffies(LEDTRIG_TTY_INTERVAL * 2)); 138 138 } 139 139 140 140 static struct attribute *ledtrig_tty_attrs[] = {
+1 -11
drivers/leds/uleds.c
··· 209 209 .name = ULEDS_NAME, 210 210 }; 211 211 212 - static int __init uleds_init(void) 213 - { 214 - return misc_register(&uleds_misc); 215 - } 216 - module_init(uleds_init); 217 - 218 - static void __exit uleds_exit(void) 219 - { 220 - misc_deregister(&uleds_misc); 221 - } 222 - module_exit(uleds_exit); 212 + module_misc_device(uleds_misc); 223 213 224 214 MODULE_AUTHOR("David Lechner <david@lechnology.com>"); 225 215 MODULE_DESCRIPTION("Userspace driver for the LED subsystem");
+3
include/linux/leds.h
··· 100 100 const char *name; 101 101 unsigned int brightness; 102 102 unsigned int max_brightness; 103 + unsigned int color; 103 104 int flags; 104 105 105 106 /* Lower 16 bits reflect status */ ··· 313 312 extern struct led_classdev *of_led_get(struct device_node *np, int index); 314 313 extern void led_put(struct led_classdev *led_cdev); 315 314 struct led_classdev *__must_check devm_of_led_get(struct device *dev, 315 + int index); 316 + struct led_classdev *__must_check devm_of_led_get_optional(struct device *dev, 316 317 int index); 317 318 318 319 /**