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

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

Pull LED updates from Lee Jones:
"This submission is a mix of new features, a number of fixes, some
clean-up/refactoring and a few Device Tree binding updates. The most
significant changes include new device support for the IS31FL3236A and
QNAP's status LEDs, a number of fixes for the Qualcomm flash, LP55xx,
MAX77705 and QNAP MCU drivers, along with some generic LED consumer
binding documentation and unification.

New Support & Features:
- Add support for the IS31FL3236A LED driver, including an optional
22kHz PWM frequency setting.
- Add support for the red and green status LEDs on QNAP MCU devices.

Improvements & Fixes:
- Fix an issue in the MAX77705 driver where an error value was
assigned but not returned.
- Correctly update the torch current clamp setting in the Qualcomm
flash LED driver to prevent unexpected clamping.
- Add a separate register map for the PMI8998 to the Qualcomm flash
LED driver to handle its unique register layout.
- Fix the state numbering for the USB LED in the QNAP MCU driver to
avoid command conflicts.
- Correct the memory programming address calculation for non-paged
devices like the LP5562 in the LP55xx driver.
- Add Device Tree support to the generic led_get() function, allowing
LEDs to be looked up by name.

Cleanups & Refactoring:
- Fix a spelling mistake in the Kconfig help text for the BD2606MVV
driver.
- Use devm_mutex_init() in the IS31FL319x driver to simplify code.

Device Tree Bindings Updates:
- Drop the redundant '-db' suffix from the IS31FL319x binding.
- Introduce generic LED consumer bindings for referencing LEDs via
phandles.
- Unify the 'leds' property across several bindings to use the new
generic consumer binding.
- Convert the AMS AS3645A LED controller binding to the DT schema
format"

* tag 'leds-next-6.18' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/leds:
dt-bindings: leds: as3645: Convert to DT schema
leds: led-class: Add Device Tree support to led_get()
dt-bindings: leds: Unify 'leds' property
dt-bindings: leds: Add generic LED consumer documentation
leds: is31fl319x: Use devm_mutex_init()
leds: leds-lp55xx: Use correct address for memory programming
dt-bindings: leds: issi,is31fl319x: Drop 'db' suffix duplicating dtschema
leds: qnap-mcu: Add support for the red and green status LEDs
leds: qnap-mcu: Fix state numbering for USB LED
leds: flash: leds-qcom-flash: Add a separate register map for PMI8998
leds: flash: leds-qcom-flash: Update torch current clamp setting
leds: max77705: Function return instead of variable assignment
leds: Kconfig: Fix spelling mistake "limitiation" -> "limitation"
leds: leds-is31fl32xx: Add support for is31fl3236a

+497 -145
-85
Documentation/devicetree/bindings/leds/ams,as3645a.txt
··· 1 - Analog devices AS3645A device tree bindings 2 - 3 - The AS3645A flash LED controller can drive two LEDs, one high current 4 - flash LED and one indicator LED. The high current flash LED can be 5 - used in torch mode as well. 6 - 7 - Ranges below noted as [a, b] are closed ranges between a and b, i.e. a 8 - and b are included in the range. 9 - 10 - Please also see common.txt in the same directory. 11 - 12 - 13 - Required properties 14 - =================== 15 - 16 - compatible : Must be "ams,as3645a". 17 - reg : The I2C address of the device. Typically 0x30. 18 - #address-cells : 1 19 - #size-cells : 0 20 - 21 - 22 - Required properties of the flash child node (0) 23 - =============================================== 24 - 25 - reg: 0 26 - flash-timeout-us: Flash timeout in microseconds. The value must be in 27 - the range [100000, 850000] and divisible by 50000. 28 - flash-max-microamp: Maximum flash current in microamperes. Has to be 29 - in the range between [200000, 500000] and 30 - divisible by 20000. 31 - led-max-microamp: Maximum torch (assist) current in microamperes. The 32 - value must be in the range between [20000, 160000] and 33 - divisible by 20000. 34 - ams,input-max-microamp: Maximum flash controller input current. The 35 - value must be in the range [1250000, 2000000] 36 - and divisible by 50000. 37 - 38 - 39 - Optional properties of the flash child node 40 - =========================================== 41 - 42 - function : See Documentation/devicetree/bindings/leds/common.txt. 43 - color : See Documentation/devicetree/bindings/leds/common.txt. 44 - label : See Documentation/devicetree/bindings/leds/common.txt (deprecated). 45 - 46 - 47 - Required properties of the indicator child node (1) 48 - =================================================== 49 - 50 - reg: 1 51 - led-max-microamp: Maximum indicator current. The allowed values are 52 - 2500, 5000, 7500 and 10000. 53 - 54 - Optional properties of the indicator child node 55 - =============================================== 56 - 57 - function : See Documentation/devicetree/bindings/leds/common.txt. 58 - color : See Documentation/devicetree/bindings/leds/common.txt. 59 - label : See Documentation/devicetree/bindings/leds/common.txt (deprecated). 60 - 61 - 62 - Example 63 - ======= 64 - 65 - #include <dt-bindings/leds/common.h> 66 - 67 - as3645a@30 { 68 - #address-cells = <1>; 69 - #size-cells = <0>; 70 - reg = <0x30>; 71 - compatible = "ams,as3645a"; 72 - led@0 { 73 - reg = <0x0>; 74 - flash-timeout-us = <150000>; 75 - flash-max-microamp = <320000>; 76 - led-max-microamp = <60000>; 77 - ams,input-max-microamp = <1750000>; 78 - function = LED_FUNCTION_FLASH; 79 - }; 80 - led@1 { 81 - reg = <0x1>; 82 - led-max-microamp = <10000>; 83 - function = LED_FUNCTION_INDICATOR; 84 - }; 85 - };
+130
Documentation/devicetree/bindings/leds/ams,as3645a.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/ams,as3645a.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Analog Devices AS3645A LED Controller 8 + 9 + maintainers: 10 + - Sakari Ailus <sakari.ailus@iki.fi> 11 + 12 + description: 13 + The AS3645A flash LED controller can drive two LEDs, one 14 + high current flash LED and one indicator LED. The high 15 + current flash LED can be used in torch mode as well. 16 + 17 + properties: 18 + compatible: 19 + const: ams,as3645a 20 + 21 + "#address-cells": 22 + const: 1 23 + 24 + "#size-cells": 25 + const: 0 26 + 27 + reg: 28 + maxItems: 1 29 + 30 + led@0: 31 + description: led0 describes the 'flash' feature 32 + type: object 33 + $ref: common.yaml# 34 + unevaluatedProperties: false 35 + 36 + properties: 37 + reg: 38 + const: 0 39 + 40 + flash-timeout-us: 41 + minimum: 100000 42 + maximum: 850000 43 + multipleOf: 50000 44 + 45 + flash-max-microamp: 46 + minimum: 200000 47 + maximum: 500000 48 + multipleOf: 20000 49 + 50 + led-max-microamp: 51 + minimum: 20000 52 + maximum: 160000 53 + multipleOf: 20000 54 + description: 55 + Maximum current when in torch (assist) mode. 56 + 57 + ams,input-max-microamp: 58 + minimum: 1250000 59 + maximum: 2000000 60 + multipleOf: 50000 61 + 62 + required: 63 + - reg 64 + - flash-timeout-us 65 + - flash-max-microamp 66 + - led-max-microamp 67 + - ams,input-max-microamp 68 + 69 + led@1: 70 + description: led1 describes the 'indicator' feature 71 + type: object 72 + $ref: common.yaml# 73 + unevaluatedProperties: false 74 + 75 + properties: 76 + reg: 77 + const: 1 78 + 79 + led-max-microamp: 80 + enum: 81 + - 2500 82 + - 5000 83 + - 7500 84 + - 10000 85 + description: 86 + Maximum indicator current. 87 + 88 + required: 89 + - reg 90 + - led-max-microamp 91 + 92 + required: 93 + - compatible 94 + - reg 95 + - "#size-cells" 96 + - "#address-cells" 97 + 98 + additionalProperties: false 99 + 100 + examples: 101 + - | 102 + #include <dt-bindings/leds/common.h> 103 + 104 + i2c{ 105 + #address-cells = <1>; 106 + #size-cells = <0>; 107 + 108 + led-controller@30 { 109 + compatible = "ams,as3645a"; 110 + #address-cells = <1>; 111 + #size-cells = <0>; 112 + reg = <0x30>; 113 + 114 + led@0 { 115 + reg = <0>; 116 + flash-timeout-us = <150000>; 117 + flash-max-microamp = <320000>; 118 + led-max-microamp = <60000>; 119 + ams,input-max-microamp = <1750000>; 120 + function = LED_FUNCTION_FLASH; 121 + }; 122 + 123 + led@1 { 124 + reg = <1>; 125 + led-max-microamp = <10000>; 126 + function = LED_FUNCTION_INDICATOR; 127 + }; 128 + }; 129 + }; 130 + ...
+1 -5
Documentation/devicetree/bindings/leds/backlight/led-backlight.yaml
··· 23 23 compatible: 24 24 const: led-backlight 25 25 26 - leds: 27 - description: A list of LED nodes 28 - $ref: /schemas/types.yaml#/definitions/phandle-array 29 - items: 30 - maxItems: 1 26 + leds: true 31 27 32 28 required: 33 29 - compatible
-1
Documentation/devicetree/bindings/leds/issi,is31fl319x.yaml
··· 42 42 description: GPIO attached to the SDB pin. 43 43 44 44 audio-gain-db: 45 - $ref: /schemas/types.yaml#/definitions/uint32 46 45 default: 0 47 46 description: Audio gain selection for external analog modulation input. 48 47 enum: [0, 3, 6, 9, 12, 15, 18, 21]
+67
Documentation/devicetree/bindings/leds/leds-consumer.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-consumer.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Common leds consumer 8 + 9 + maintainers: 10 + - Aleksandrs Vinarskis <alex@vinarskis.com> 11 + 12 + description: 13 + Some LED defined in DT are required by other DT consumers, for example 14 + v4l2 subnode may require privacy or flash LED. Unlike trigger-source 15 + approach which is typically used as 'soft' binding, referencing LED 16 + devices by phandle makes things simpler when 'hard' binding is desired. 17 + 18 + Document LED properties that its consumers may define. 19 + 20 + select: true 21 + 22 + properties: 23 + leds: 24 + oneOf: 25 + - type: object 26 + - $ref: /schemas/types.yaml#/definitions/phandle-array 27 + description: 28 + A list of LED device(s) required by a particular consumer. 29 + items: 30 + maxItems: 1 31 + 32 + led-names: 33 + description: 34 + A list of device name(s). Used to map LED devices to their respective 35 + functions, when consumer requires more than one LED. 36 + 37 + additionalProperties: true 38 + 39 + examples: 40 + - | 41 + #include <dt-bindings/gpio/gpio.h> 42 + #include <dt-bindings/leds/common.h> 43 + 44 + leds { 45 + compatible = "gpio-leds"; 46 + 47 + privacy_led: privacy-led { 48 + color = <LED_COLOR_ID_RED>; 49 + default-state = "off"; 50 + function = LED_FUNCTION_INDICATOR; 51 + gpios = <&tlmm 110 GPIO_ACTIVE_HIGH>; 52 + }; 53 + }; 54 + 55 + i2c { 56 + #address-cells = <1>; 57 + #size-cells = <0>; 58 + 59 + v4l2_node: camera@36 { 60 + reg = <0x36>; 61 + 62 + leds = <&privacy_led>; 63 + led-names = "privacy"; 64 + }; 65 + }; 66 + 67 + ...
+1 -4
Documentation/devicetree/bindings/leds/leds-group-multicolor.yaml
··· 17 17 compatible: 18 18 const: leds-group-multicolor 19 19 20 - leds: 21 - description: 22 - An aray of monochromatic leds 23 - $ref: /schemas/types.yaml#/definitions/phandle-array 20 + leds: true 24 21 25 22 required: 26 23 - leds
+8
Documentation/devicetree/bindings/media/video-interface-devices.yaml
··· 17 17 An array of phandles, each referring to a flash LED, a sub-node of the LED 18 18 driver device node. 19 19 20 + leds: 21 + minItems: 1 22 + maxItems: 1 23 + 24 + led-names: 25 + enum: 26 + - privacy 27 + 20 28 lens-focus: 21 29 $ref: /schemas/types.yaml#/definitions/phandle 22 30 description:
+1 -1
drivers/leds/Kconfig
··· 674 674 help 675 675 This option enables support for BD2606MVV LED driver chips 676 676 accessed via the I2C bus. It supports setting brightness, with 677 - the limitiation that there are groups of two channels sharing 677 + the limitation that there are groups of two channels sharing 678 678 a brightness setting, but not the on/off setting. 679 679 680 680 To compile this driver as a module, choose M here: the module will
+60 -27
drivers/leds/flash/leds-qcom-flash.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0-only 2 2 /* 3 - * Copyright (c) 2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved. 3 + * Copyright (c) 2022, 2024-2025 Qualcomm Innovation Center, Inc. All rights reserved. 4 4 */ 5 5 6 6 #include <linux/bitfield.h> ··· 114 114 REG_THERM_THRSH1, 115 115 REG_THERM_THRSH2, 116 116 REG_THERM_THRSH3, 117 + REG_TORCH_CLAMP, 117 118 REG_MAX_COUNT, 118 119 }; 119 120 121 + static const struct reg_field mvflash_3ch_pmi8998_regs[REG_MAX_COUNT] = { 122 + [REG_STATUS1] = REG_FIELD(0x08, 0, 5), 123 + [REG_STATUS2] = REG_FIELD(0x09, 0, 7), 124 + [REG_STATUS3] = REG_FIELD(0x0a, 0, 7), 125 + [REG_CHAN_TIMER] = REG_FIELD_ID(0x40, 0, 7, 3, 1), 126 + [REG_ITARGET] = REG_FIELD_ID(0x43, 0, 6, 3, 1), 127 + [REG_MODULE_EN] = REG_FIELD(0x46, 7, 7), 128 + [REG_IRESOLUTION] = REG_FIELD(0x47, 0, 5), 129 + [REG_CHAN_STROBE] = REG_FIELD_ID(0x49, 0, 2, 3, 1), 130 + [REG_CHAN_EN] = REG_FIELD(0x4c, 0, 2), 131 + [REG_THERM_THRSH1] = REG_FIELD(0x56, 0, 2), 132 + [REG_THERM_THRSH2] = REG_FIELD(0x57, 0, 2), 133 + [REG_THERM_THRSH3] = REG_FIELD(0x58, 0, 2), 134 + [REG_TORCH_CLAMP] = REG_FIELD(0xea, 0, 6), 135 + }; 136 + 120 137 static const struct reg_field mvflash_3ch_regs[REG_MAX_COUNT] = { 121 - REG_FIELD(0x08, 0, 7), /* status1 */ 122 - REG_FIELD(0x09, 0, 7), /* status2 */ 123 - REG_FIELD(0x0a, 0, 7), /* status3 */ 124 - REG_FIELD_ID(0x40, 0, 7, 3, 1), /* chan_timer */ 125 - REG_FIELD_ID(0x43, 0, 6, 3, 1), /* itarget */ 126 - REG_FIELD(0x46, 7, 7), /* module_en */ 127 - REG_FIELD(0x47, 0, 5), /* iresolution */ 128 - REG_FIELD_ID(0x49, 0, 2, 3, 1), /* chan_strobe */ 129 - REG_FIELD(0x4c, 0, 2), /* chan_en */ 130 - REG_FIELD(0x56, 0, 2), /* therm_thrsh1 */ 131 - REG_FIELD(0x57, 0, 2), /* therm_thrsh2 */ 132 - REG_FIELD(0x58, 0, 2), /* therm_thrsh3 */ 138 + [REG_STATUS1] = REG_FIELD(0x08, 0, 7), 139 + [REG_STATUS2] = REG_FIELD(0x09, 0, 7), 140 + [REG_STATUS3] = REG_FIELD(0x0a, 0, 7), 141 + [REG_CHAN_TIMER] = REG_FIELD_ID(0x40, 0, 7, 3, 1), 142 + [REG_ITARGET] = REG_FIELD_ID(0x43, 0, 6, 3, 1), 143 + [REG_MODULE_EN] = REG_FIELD(0x46, 7, 7), 144 + [REG_IRESOLUTION] = REG_FIELD(0x47, 0, 5), 145 + [REG_CHAN_STROBE] = REG_FIELD_ID(0x49, 0, 2, 3, 1), 146 + [REG_CHAN_EN] = REG_FIELD(0x4c, 0, 2), 147 + [REG_THERM_THRSH1] = REG_FIELD(0x56, 0, 2), 148 + [REG_THERM_THRSH2] = REG_FIELD(0x57, 0, 2), 149 + [REG_THERM_THRSH3] = REG_FIELD(0x58, 0, 2), 150 + [REG_TORCH_CLAMP] = REG_FIELD(0xec, 0, 6), 133 151 }; 134 152 135 153 static const struct reg_field mvflash_4ch_regs[REG_MAX_COUNT] = { 136 - REG_FIELD(0x06, 0, 7), /* status1 */ 137 - REG_FIELD(0x07, 0, 6), /* status2 */ 138 - REG_FIELD(0x09, 0, 7), /* status3 */ 139 - REG_FIELD_ID(0x3e, 0, 7, 4, 1), /* chan_timer */ 140 - REG_FIELD_ID(0x42, 0, 6, 4, 1), /* itarget */ 141 - REG_FIELD(0x46, 7, 7), /* module_en */ 142 - REG_FIELD(0x49, 0, 3), /* iresolution */ 143 - REG_FIELD_ID(0x4a, 0, 6, 4, 1), /* chan_strobe */ 144 - REG_FIELD(0x4e, 0, 3), /* chan_en */ 145 - REG_FIELD(0x7a, 0, 2), /* therm_thrsh1 */ 146 - REG_FIELD(0x78, 0, 2), /* therm_thrsh2 */ 154 + [REG_STATUS1] = REG_FIELD(0x06, 0, 7), 155 + [REG_STATUS2] = REG_FIELD(0x07, 0, 6), 156 + [REG_STATUS3] = REG_FIELD(0x09, 0, 7), 157 + [REG_CHAN_TIMER] = REG_FIELD_ID(0x3e, 0, 7, 4, 1), 158 + [REG_ITARGET] = REG_FIELD_ID(0x42, 0, 6, 4, 1), 159 + [REG_MODULE_EN] = REG_FIELD(0x46, 7, 7), 160 + [REG_IRESOLUTION] = REG_FIELD(0x49, 0, 3), 161 + [REG_CHAN_STROBE] = REG_FIELD_ID(0x4a, 0, 6, 4, 1), 162 + [REG_CHAN_EN] = REG_FIELD(0x4e, 0, 3), 163 + [REG_THERM_THRSH1] = REG_FIELD(0x7a, 0, 2), 164 + [REG_THERM_THRSH2] = REG_FIELD(0x78, 0, 2), 165 + [REG_TORCH_CLAMP] = REG_FIELD(0xed, 0, 6), 147 166 }; 148 167 149 168 struct qcom_flash_data { ··· 175 156 u8 max_channels; 176 157 u8 chan_en_bits; 177 158 u8 revision; 159 + u8 torch_clamp; 178 160 }; 179 161 180 162 struct qcom_flash_led { ··· 722 702 u32 current_ua, timeout_us; 723 703 u32 channels[4]; 724 704 int i, rc, count; 705 + u8 torch_clamp; 725 706 726 707 count = fwnode_property_count_u32(node, "led-sources"); 727 708 if (count <= 0) { ··· 771 750 772 751 current_ua = min_t(u32, current_ua, TORCH_CURRENT_MAX_UA * led->chan_count); 773 752 led->max_torch_current_ma = current_ua / UA_PER_MA; 753 + 754 + torch_clamp = (current_ua / led->chan_count) / TORCH_IRES_UA; 755 + if (torch_clamp != 0) 756 + torch_clamp--; 757 + 758 + flash_data->torch_clamp = max_t(u8, flash_data->torch_clamp, torch_clamp); 774 759 775 760 if (fwnode_property_present(node, "flash-max-microamp")) { 776 761 flash->led_cdev.flags |= LED_DEV_CAP_FLASH; ··· 878 851 return rc; 879 852 } 880 853 881 - if (val == FLASH_SUBTYPE_3CH_PM8150_VAL || val == FLASH_SUBTYPE_3CH_PMI8998_VAL) { 854 + if (val == FLASH_SUBTYPE_3CH_PM8150_VAL) { 882 855 flash_data->hw_type = QCOM_MVFLASH_3CH; 883 856 flash_data->max_channels = 3; 884 857 regs = devm_kmemdup(dev, mvflash_3ch_regs, sizeof(mvflash_3ch_regs), 885 858 GFP_KERNEL); 859 + if (!regs) 860 + return -ENOMEM; 861 + } else if (val == FLASH_SUBTYPE_3CH_PMI8998_VAL) { 862 + flash_data->hw_type = QCOM_MVFLASH_3CH; 863 + flash_data->max_channels = 3; 864 + regs = devm_kmemdup(dev, mvflash_3ch_pmi8998_regs, 865 + sizeof(mvflash_3ch_pmi8998_regs), GFP_KERNEL); 886 866 if (!regs) 887 867 return -ENOMEM; 888 868 } else if (val == FLASH_SUBTYPE_4CH_VAL) { ··· 951 917 flash_data->leds_count++; 952 918 } 953 919 954 - return 0; 955 - 920 + return regmap_field_write(flash_data->r_fields[REG_TORCH_CLAMP], flash_data->torch_clamp); 956 921 release: 957 922 while (flash_data->v4l2_flash[flash_data->leds_count] && flash_data->leds_count) 958 923 v4l2_flash_release(flash_data->v4l2_flash[flash_data->leds_count--]);
+15 -2
drivers/leds/led-class.c
··· 252 252 * of_led_get() - request a LED device via the LED framework 253 253 * @np: device node to get the LED device from 254 254 * @index: the index of the LED 255 + * @name: the name of the LED used to map it to its function, if present 255 256 * 256 257 * Returns the LED device parsed from the phandle specified in the "leds" 257 258 * property of a device tree node or a negative error-code on failure. 258 259 */ 259 - static struct led_classdev *of_led_get(struct device_node *np, int index) 260 + static struct led_classdev *of_led_get(struct device_node *np, int index, 261 + const char *name) 260 262 { 261 263 struct device *led_dev; 262 264 struct device_node *led_node; 263 265 266 + /* 267 + * For named LEDs, first look up the name in the "led-names" property. 268 + * If it cannot be found, then of_parse_phandle() will propagate the error. 269 + */ 270 + if (name) 271 + index = of_property_match_string(np, "led-names", name); 264 272 led_node = of_parse_phandle(np, "leds", index); 265 273 if (!led_node) 266 274 return ERR_PTR(-ENOENT); ··· 332 324 if (!dev) 333 325 return ERR_PTR(-EINVAL); 334 326 335 - led = of_led_get(dev->of_node, index); 327 + led = of_led_get(dev->of_node, index, NULL); 336 328 if (IS_ERR(led)) 337 329 return led; 338 330 ··· 350 342 struct led_classdev *led_get(struct device *dev, char *con_id) 351 343 { 352 344 struct led_lookup_data *lookup; 345 + struct led_classdev *led_cdev; 353 346 const char *provider = NULL; 354 347 struct device *led_dev; 348 + 349 + led_cdev = of_led_get(dev->of_node, -1, con_id); 350 + if (!IS_ERR(led_cdev) || PTR_ERR(led_cdev) != -ENOENT) 351 + return led_cdev; 355 352 356 353 mutex_lock(&leds_lookup_lock); 357 354 list_for_each_entry(lookup, &leds_lookup_list, list) {
+1 -7
drivers/leds/leds-is31fl319x.c
··· 483 483 return dezibel / IS31FL3196_AUDIO_GAIN_DB_STEP; 484 484 } 485 485 486 - static void is31f1319x_mutex_destroy(void *lock) 487 - { 488 - mutex_destroy(lock); 489 - } 490 - 491 486 static int is31fl319x_probe(struct i2c_client *client) 492 487 { 493 488 struct is31fl319x_chip *is31; ··· 498 503 if (!is31) 499 504 return -ENOMEM; 500 505 501 - mutex_init(&is31->lock); 502 - err = devm_add_action_or_reset(dev, is31f1319x_mutex_destroy, &is31->lock); 506 + err = devm_mutex_init(dev, &is31->lock); 503 507 if (err) 504 508 return err; 505 509
+41 -6
drivers/leds/leds-is31fl32xx.c
··· 32 32 #define IS31FL3216_CONFIG_SSD_ENABLE BIT(7) 33 33 #define IS31FL3216_CONFIG_SSD_DISABLE 0 34 34 35 + #define IS31FL32XX_PWM_FREQUENCY_22KHZ 0x01 36 + 35 37 struct is31fl32xx_priv; 36 38 struct is31fl32xx_led_data { 37 39 struct led_classdev cdev; ··· 55 53 * @pwm_update_reg : address of PWM Update register 56 54 * @global_control_reg : address of Global Control register (optional) 57 55 * @reset_reg : address of Reset register (optional) 56 + * @output_frequency_setting_reg: address of output frequency register (optional) 58 57 * @pwm_register_base : address of first PWM register 59 58 * @pwm_registers_reversed: : true if PWM registers count down instead of up 60 59 * @led_control_register_base : address of first LED control register (optional) ··· 79 76 u8 pwm_update_reg; 80 77 u8 global_control_reg; 81 78 u8 reset_reg; 79 + u8 output_frequency_setting_reg; 82 80 u8 pwm_register_base; 83 81 bool pwm_registers_reversed; 84 82 u8 led_control_register_base; ··· 94 90 .pwm_update_reg = 0x25, 95 91 .global_control_reg = 0x4a, 96 92 .reset_reg = 0x4f, 93 + .output_frequency_setting_reg = IS31FL32XX_REG_NONE, 94 + .pwm_register_base = 0x01, 95 + .led_control_register_base = 0x26, 96 + .enable_bits_per_led_control_register = 1, 97 + }; 98 + 99 + static const struct is31fl32xx_chipdef is31fl3236a_cdef = { 100 + .channels = 36, 101 + .shutdown_reg = 0x00, 102 + .pwm_update_reg = 0x25, 103 + .global_control_reg = 0x4a, 104 + .reset_reg = 0x4f, 105 + .output_frequency_setting_reg = 0x4b, 97 106 .pwm_register_base = 0x01, 98 107 .led_control_register_base = 0x26, 99 108 .enable_bits_per_led_control_register = 1, ··· 118 101 .pwm_update_reg = 0x25, 119 102 .global_control_reg = 0x4a, 120 103 .reset_reg = 0x4f, 104 + .output_frequency_setting_reg = IS31FL32XX_REG_NONE, 121 105 .pwm_register_base = 0x05, 122 106 .led_control_register_base = 0x2a, 123 107 .enable_bits_per_led_control_register = 1, ··· 130 112 .pwm_update_reg = 0x16, 131 113 .global_control_reg = IS31FL32XX_REG_NONE, 132 114 .reset_reg = 0x17, 115 + .output_frequency_setting_reg = IS31FL32XX_REG_NONE, 133 116 .pwm_register_base = 0x01, 134 117 .led_control_register_base = 0x13, 135 118 .enable_bits_per_led_control_register = 6, ··· 145 126 .pwm_update_reg = 0xB0, 146 127 .global_control_reg = IS31FL32XX_REG_NONE, 147 128 .reset_reg = IS31FL32XX_REG_NONE, 129 + .output_frequency_setting_reg = IS31FL32XX_REG_NONE, 148 130 .pwm_register_base = 0x10, 149 131 .pwm_registers_reversed = true, 150 132 .led_control_register_base = 0x01, ··· 383 363 static int is31fl32xx_parse_dt(struct device *dev, 384 364 struct is31fl32xx_priv *priv) 385 365 { 366 + const struct is31fl32xx_chipdef *cdef = priv->cdef; 386 367 int ret = 0; 368 + 369 + if ((cdef->output_frequency_setting_reg != IS31FL32XX_REG_NONE) && 370 + of_property_read_bool(dev_of_node(dev), "issi,22khz-pwm")) { 371 + 372 + ret = is31fl32xx_write(priv, cdef->output_frequency_setting_reg, 373 + IS31FL32XX_PWM_FREQUENCY_22KHZ); 374 + 375 + if (ret) { 376 + dev_err(dev, "Failed to write output PWM frequency register\n"); 377 + return ret; 378 + } 379 + } 387 380 388 381 for_each_available_child_of_node_scoped(dev_of_node(dev), child) { 389 382 struct led_init_data init_data = {}; ··· 437 404 } 438 405 439 406 static const struct of_device_id of_is31fl32xx_match[] = { 440 - { .compatible = "issi,is31fl3236", .data = &is31fl3236_cdef, }, 441 - { .compatible = "issi,is31fl3235", .data = &is31fl3235_cdef, }, 442 - { .compatible = "issi,is31fl3218", .data = &is31fl3218_cdef, }, 443 - { .compatible = "si-en,sn3218", .data = &is31fl3218_cdef, }, 444 - { .compatible = "issi,is31fl3216", .data = &is31fl3216_cdef, }, 445 - { .compatible = "si-en,sn3216", .data = &is31fl3216_cdef, }, 407 + { .compatible = "issi,is31fl3236", .data = &is31fl3236_cdef, }, 408 + { .compatible = "issi,is31fl3236a", .data = &is31fl3236a_cdef, }, 409 + { .compatible = "issi,is31fl3235", .data = &is31fl3235_cdef, }, 410 + { .compatible = "issi,is31fl3218", .data = &is31fl3218_cdef, }, 411 + { .compatible = "si-en,sn3218", .data = &is31fl3218_cdef, }, 412 + { .compatible = "issi,is31fl3216", .data = &is31fl3216_cdef, }, 413 + { .compatible = "si-en,sn3216", .data = &is31fl3216_cdef, }, 446 414 {}, 447 415 }; 448 416 ··· 500 466 */ 501 467 static const struct i2c_device_id is31fl32xx_id[] = { 502 468 { "is31fl3236" }, 469 + { "is31fl3236a" }, 503 470 { "is31fl3235" }, 504 471 { "is31fl3218" }, 505 472 { "sn3218" },
+1 -1
drivers/leds/leds-lp55xx-common.c
··· 212 212 * For LED chip that support page, PAGE is already set in load_engine. 213 213 */ 214 214 if (!cfg->pages_per_engine) 215 - start_addr += LP55xx_BYTES_PER_PAGE * idx; 215 + start_addr += LP55xx_BYTES_PER_PAGE * (idx - 1); 216 216 217 217 for (page = 0; page < program_length / LP55xx_BYTES_PER_PAGE; page++) { 218 218 /* Write to the next page each 32 bytes (if supported) */
+1 -1
drivers/leds/leds-max77705.c
··· 180 180 181 181 ret = fwnode_property_read_u32(np, "reg", &reg); 182 182 if (ret || reg >= MAX77705_LED_NUM_LEDS) 183 - ret = -EINVAL; 183 + return -EINVAL; 184 184 185 185 info = devm_kcalloc(dev, num_channels, sizeof(*info), GFP_KERNEL); 186 186 if (!info)
+170 -5
drivers/leds/leds-qnap-mcu.c
··· 104 104 } 105 105 106 106 enum qnap_mcu_usb_led_mode { 107 - QNAP_MCU_USB_LED_ON = 1, 108 - QNAP_MCU_USB_LED_OFF = 3, 109 - QNAP_MCU_USB_LED_BLINK = 2, 107 + QNAP_MCU_USB_LED_ON = 0, 108 + QNAP_MCU_USB_LED_OFF = 2, 109 + QNAP_MCU_USB_LED_BLINK = 1, 110 110 }; 111 111 112 112 struct qnap_mcu_usb_led { ··· 137 137 * Byte 3 is shared between the usb led target on/off/blink 138 138 * and also the buzzer control (in the input driver) 139 139 */ 140 - cmd[2] = 'D' + usb_led->mode; 140 + cmd[2] = 'E' + usb_led->mode; 141 141 142 142 return qnap_mcu_exec_with_ack(usb_led->mcu, cmd, sizeof(cmd)); 143 143 } ··· 161 161 * Byte 3 is shared between the USB LED target on/off/blink 162 162 * and also the buzzer control (in the input driver) 163 163 */ 164 - cmd[2] = 'D' + usb_led->mode; 164 + cmd[2] = 'E' + usb_led->mode; 165 165 166 166 return qnap_mcu_exec_with_ack(usb_led->mcu, cmd, sizeof(cmd)); 167 167 } ··· 190 190 return qnap_mcu_usb_led_set(&usb_led->cdev, 0); 191 191 } 192 192 193 + enum qnap_mcu_status_led_mode { 194 + QNAP_MCU_STATUS_LED_OFF = 0, 195 + QNAP_MCU_STATUS_LED_ON = 1, 196 + QNAP_MCU_STATUS_LED_BLINK_FAST = 2, /* 500ms / 500ms */ 197 + QNAP_MCU_STATUS_LED_BLINK_SLOW = 3, /* 1s / 1s */ 198 + }; 199 + 200 + struct qnap_mcu_status_led { 201 + struct led_classdev cdev; 202 + struct qnap_mcu_status_led *red; 203 + u8 mode; 204 + }; 205 + 206 + struct qnap_mcu_status { 207 + struct qnap_mcu *mcu; 208 + struct qnap_mcu_status_led red; 209 + struct qnap_mcu_status_led green; 210 + }; 211 + 212 + static inline struct qnap_mcu_status_led *cdev_to_qnap_mcu_status_led(struct led_classdev *led_cdev) 213 + { 214 + return container_of(led_cdev, struct qnap_mcu_status_led, cdev); 215 + } 216 + 217 + static inline struct qnap_mcu_status *statusled_to_qnap_mcu_status(struct qnap_mcu_status_led *led) 218 + { 219 + return container_of(led->red, struct qnap_mcu_status, red); 220 + } 221 + 222 + static u8 qnap_mcu_status_led_encode(struct qnap_mcu_status *status) 223 + { 224 + if (status->red.mode == QNAP_MCU_STATUS_LED_OFF) { 225 + switch (status->green.mode) { 226 + case QNAP_MCU_STATUS_LED_OFF: 227 + return '9'; 228 + case QNAP_MCU_STATUS_LED_ON: 229 + return '6'; 230 + case QNAP_MCU_STATUS_LED_BLINK_FAST: 231 + return '5'; 232 + case QNAP_MCU_STATUS_LED_BLINK_SLOW: 233 + return 'A'; 234 + } 235 + } else if (status->green.mode == QNAP_MCU_STATUS_LED_OFF) { 236 + switch (status->red.mode) { 237 + case QNAP_MCU_STATUS_LED_OFF: 238 + return '9'; 239 + case QNAP_MCU_STATUS_LED_ON: 240 + return '7'; 241 + case QNAP_MCU_STATUS_LED_BLINK_FAST: 242 + return '4'; 243 + case QNAP_MCU_STATUS_LED_BLINK_SLOW: 244 + return 'B'; 245 + } 246 + } else if (status->green.mode == QNAP_MCU_STATUS_LED_ON && 247 + status->red.mode == QNAP_MCU_STATUS_LED_ON) { 248 + return 'D'; 249 + } else if (status->green.mode == QNAP_MCU_STATUS_LED_BLINK_SLOW && 250 + status->red.mode == QNAP_MCU_STATUS_LED_BLINK_SLOW) { 251 + return 'C'; 252 + } 253 + 254 + /* 255 + * Here both LEDs are on in some fashion, either both blinking fast, 256 + * or in different speeds, so default to fast blinking for both. 257 + */ 258 + return '8'; 259 + } 260 + 261 + static int qnap_mcu_status_led_update(struct qnap_mcu *mcu, 262 + struct qnap_mcu_status *status) 263 + { 264 + u8 cmd[] = { '@', 'C', 0 }; 265 + 266 + cmd[2] = qnap_mcu_status_led_encode(status); 267 + 268 + return qnap_mcu_exec_with_ack(mcu, cmd, sizeof(cmd)); 269 + } 270 + 271 + static int qnap_mcu_status_led_set(struct led_classdev *led_cdev, 272 + enum led_brightness brightness) 273 + { 274 + struct qnap_mcu_status_led *status_led = cdev_to_qnap_mcu_status_led(led_cdev); 275 + struct qnap_mcu_status *base = statusled_to_qnap_mcu_status(status_led); 276 + 277 + /* Don't disturb a possible set blink-mode if LED stays on */ 278 + if (brightness != 0 && status_led->mode >= QNAP_MCU_STATUS_LED_BLINK_FAST) 279 + return 0; 280 + 281 + status_led->mode = brightness ? QNAP_MCU_STATUS_LED_ON : 282 + QNAP_MCU_STATUS_LED_OFF; 283 + 284 + return qnap_mcu_status_led_update(base->mcu, base); 285 + } 286 + 287 + static int qnap_mcu_status_led_blink_set(struct led_classdev *led_cdev, 288 + unsigned long *delay_on, 289 + unsigned long *delay_off) 290 + { 291 + struct qnap_mcu_status_led *status_led = cdev_to_qnap_mcu_status_led(led_cdev); 292 + struct qnap_mcu_status *base = statusled_to_qnap_mcu_status(status_led); 293 + 294 + if (status_led->mode == QNAP_MCU_STATUS_LED_OFF) 295 + return 0; 296 + 297 + if (*delay_on <= 500) { 298 + *delay_on = 500; 299 + *delay_off = 500; 300 + status_led->mode = QNAP_MCU_STATUS_LED_BLINK_FAST; 301 + } else { 302 + *delay_on = 1000; 303 + *delay_off = 1000; 304 + status_led->mode = QNAP_MCU_STATUS_LED_BLINK_SLOW; 305 + } 306 + 307 + return qnap_mcu_status_led_update(base->mcu, base); 308 + } 309 + 310 + static int qnap_mcu_register_status_leds(struct device *dev, struct qnap_mcu *mcu) 311 + { 312 + struct qnap_mcu_status *status; 313 + int ret; 314 + 315 + status = devm_kzalloc(dev, sizeof(*status), GFP_KERNEL); 316 + if (!status) 317 + return -ENOMEM; 318 + 319 + status->mcu = mcu; 320 + 321 + /* 322 + * point to the red led, so that statusled_to_qnap_mcu_status 323 + * can resolve the main status struct containing both leds 324 + */ 325 + status->red.red = &status->red; 326 + status->green.red = &status->red; 327 + 328 + status->red.mode = QNAP_MCU_STATUS_LED_OFF; 329 + status->red.cdev.name = "red:status"; 330 + status->red.cdev.brightness_set_blocking = qnap_mcu_status_led_set; 331 + status->red.cdev.blink_set = qnap_mcu_status_led_blink_set; 332 + status->red.cdev.brightness = 0; 333 + status->red.cdev.max_brightness = 1; 334 + 335 + status->green.mode = QNAP_MCU_STATUS_LED_OFF; 336 + status->green.cdev.name = "green:status"; 337 + status->green.cdev.brightness_set_blocking = qnap_mcu_status_led_set; 338 + status->green.cdev.blink_set = qnap_mcu_status_led_blink_set; 339 + status->green.cdev.brightness = 0; 340 + status->green.cdev.max_brightness = 1; 341 + 342 + ret = devm_led_classdev_register(dev, &status->red.cdev); 343 + if (ret) 344 + return ret; 345 + 346 + ret = devm_led_classdev_register(dev, &status->green.cdev); 347 + if (ret) 348 + return ret; 349 + 350 + return qnap_mcu_status_led_update(status->mcu, status); 351 + } 352 + 193 353 static int qnap_mcu_leds_probe(struct platform_device *pdev) 194 354 { 195 355 struct qnap_mcu *mcu = dev_get_drvdata(pdev->dev.parent); ··· 369 209 return dev_err_probe(&pdev->dev, ret, 370 210 "failed to register USB LED\n"); 371 211 } 212 + 213 + ret = qnap_mcu_register_status_leds(&pdev->dev, mcu); 214 + if (ret) 215 + return dev_err_probe(&pdev->dev, ret, 216 + "failed to register status LEDs\n"); 372 217 373 218 return 0; 374 219 }