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.9' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/leds

Pull LED updates from Lee Jones:
"Core Framework:
- Introduce ExpressWire library

New Drivers:
- Add support for ON Semiconductor NCP5623 RGB LED Driver

New Device Support:
- Add support for PM660L to Qualcomm's LPG driver

New Functionality:
- Dynamically load modules required for the default-trigger
- Add some support for suspend and resume
- Allow LEDs to remain lit during suspend

Fix-ups:
- Device Tree binding adaptions/conversions/creation
- Fix include lists; alphabetise, remove unused, explicitly add used
- Add new led_match_default_trigger to avoid duplication
- Add module alias' to aid auto-loading
- Default to hw_control if no others are specified
- De-bloat the supported link speed attribute lists
- Remove superfluous code and simplify overall
- Constify some variables

Bug Fixes:
- Prevent kernel panic when renaming the net interface
- Fix Kconfig related build errors
- Ensure mutexes are unlocked prior to destroying them
- Provide clean-up between state changes to avoid invalid state
- Fix some broken kernel-doc headers"

* tag 'leds-next-6.9' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/leds: (41 commits)
leds: ncp5623: Add MS suffix to time defines
leds: Add NCP5623 multi-led driver
dt-bindings: leds: Add NCP5623 multi-LED Controller
leds: mlxreg: Drop an excess struct mlxreg_led_data member
leds: leds-mlxcpld: Fix struct mlxcpld_led_priv member name
leds: lm3601x: Fix struct lm3601_led kernel-doc warnings
leds: Fix ifdef check for gpio_led_register_device()
dt-bindings: leds: qcom-lpg: Narrow nvmem for other variants
dt-bindings: leds: qcom-lpg: Drop redundant qcom,pm8550-pwm in if:then:
dt-bindings: leds: Add LED_FUNCTION_WAN_ONLINE for Internet access
leds: sgm3140: Add missing timer cleanup and flash gpio control
leds: expresswire: Don't depend on NEW_LEDS
Revert "leds: Only descend into leds directory when CONFIG_NEW_LEDS is set"
leds: aw2013: Unlock mutex before destroying it
leds: qcom-lpg: Add QCOM_PBS dependency
leds: rgb: leds-group-multicolor: Allow LEDs to stay on in suspend
leds: trigger: netdev: Fix kernel panic on interface rename trig notify
leds: qcom-lpg: Add PM660L configuration and compatible
leds: spi-byte: Use devm_led_classdev_register_ext()
leds: pca963x: Add support for suspend and resume
...

+1033 -188
+12
Documentation/ABI/testing/sysfs-class-led-trigger-netdev
··· 88 88 speed of 10MBps of the named network device. 89 89 Setting this value also immediately changes the LED state. 90 90 91 + Present only if the named network device supports 10Mbps link speed. 92 + 91 93 What: /sys/class/leds/<led>/link_100 92 94 Date: Jun 2023 93 95 KernelVersion: 6.5 ··· 102 100 If set to 1, the LED's normal state reflects the link state 103 101 speed of 100Mbps of the named network device. 104 102 Setting this value also immediately changes the LED state. 103 + 104 + Present only if the named network device supports 100Mbps link speed. 105 105 106 106 What: /sys/class/leds/<led>/link_1000 107 107 Date: Jun 2023 ··· 118 114 speed of 1000Mbps of the named network device. 119 115 Setting this value also immediately changes the LED state. 120 116 117 + Present only if the named network device supports 1000Mbps link speed. 118 + 121 119 What: /sys/class/leds/<led>/link_2500 122 120 Date: Nov 2023 123 121 KernelVersion: 6.8 ··· 132 126 If set to 1, the LED's normal state reflects the link state 133 127 speed of 2500Mbps of the named network device. 134 128 Setting this value also immediately changes the LED state. 129 + 130 + Present only if the named network device supports 2500Mbps link speed. 135 131 136 132 What: /sys/class/leds/<led>/link_5000 137 133 Date: Nov 2023 ··· 148 140 speed of 5000Mbps of the named network device. 149 141 Setting this value also immediately changes the LED state. 150 142 143 + Present only if the named network device supports 5000Mbps link speed. 144 + 151 145 What: /sys/class/leds/<led>/link_10000 152 146 Date: Nov 2023 153 147 KernelVersion: 6.8 ··· 162 152 If set to 1, the LED's normal state reflects the link state 163 153 speed of 10000Mbps of the named network device. 164 154 Setting this value also immediately changes the LED state. 155 + 156 + Present only if the named network device supports 10000Mbps link speed. 165 157 166 158 What: /sys/class/leds/<led>/half_duplex 167 159 Date: Jun 2023
+7 -7
Documentation/ABI/testing/sysfs-class-led-trigger-tty
··· 1 - What: /sys/class/leds/<led>/ttyname 1 + What: /sys/class/leds/<tty_led>/ttyname 2 2 Date: Dec 2020 3 3 KernelVersion: 5.10 4 4 Contact: linux-leds@vger.kernel.org 5 5 Description: 6 6 Specifies the tty device name of the triggering tty 7 7 8 - What: /sys/class/leds/<led>/rx 8 + What: /sys/class/leds/<tty_led>/rx 9 9 Date: February 2024 10 10 KernelVersion: 6.8 11 11 Description: ··· 13 13 If set to 0, the LED will not blink on reception. 14 14 If set to 1 (default), the LED will blink on reception. 15 15 16 - What: /sys/class/leds/<led>/tx 16 + What: /sys/class/leds/<tty_led>/tx 17 17 Date: February 2024 18 18 KernelVersion: 6.8 19 19 Description: ··· 21 21 If set to 0, the LED will not blink on transmission. 22 22 If set to 1 (default), the LED will blink on transmission. 23 23 24 - What: /sys/class/leds/<led>/cts 24 + What: /sys/class/leds/<tty_led>/cts 25 25 Date: February 2024 26 26 KernelVersion: 6.8 27 27 Description: ··· 31 31 If set to 0 (default), the LED will not evaluate CTS. 32 32 If set to 1, the LED will evaluate CTS. 33 33 34 - What: /sys/class/leds/<led>/dsr 34 + What: /sys/class/leds/<tty_led>/dsr 35 35 Date: February 2024 36 36 KernelVersion: 6.8 37 37 Description: ··· 41 41 If set to 0 (default), the LED will not evaluate DSR. 42 42 If set to 1, the LED will evaluate DSR. 43 43 44 - What: /sys/class/leds/<led>/dcd 44 + What: /sys/class/leds/<tty_led>/dcd 45 45 Date: February 2024 46 46 KernelVersion: 6.8 47 47 Description: ··· 51 51 If set to 0 (default), the LED will not evaluate CAR (DCD). 52 52 If set to 1, the LED will evaluate CAR (DCD). 53 53 54 - What: /sys/class/leds/<led>/rng 54 + What: /sys/class/leds/<tty_led>/rng 55 55 Date: February 2024 56 56 KernelVersion: 6.8 57 57 Description:
+101 -1
Documentation/devicetree/bindings/leds/leds-qcom-lpg.yaml
··· 11 11 12 12 description: > 13 13 The Qualcomm Light Pulse Generator consists of three different hardware blocks; 14 - a ramp generator with lookup table, the light pulse generator and a three 14 + a ramp generator with lookup table (LUT), the light pulse generator and a three 15 15 channel current sink. These blocks are found in a wide range of Qualcomm PMICs. 16 16 17 17 properties: ··· 63 63 - description: dtest line to attach 64 64 - description: flags for the attachment 65 65 66 + nvmem: 67 + description: > 68 + This property is required for PMICs that supports PPG, which is when a 69 + PMIC stores LPG per-channel data and pattern LUT in SDAM modules instead 70 + of in a LUT peripheral. For PMICs, such as PM8350C, per-channel data 71 + and pattern LUT is separated into 2 SDAM modules. In that case, phandles 72 + to both SDAM modules need to be specified. 73 + minItems: 1 74 + maxItems: 2 75 + 76 + nvmem-names: 77 + minItems: 1 78 + items: 79 + - const: lpg_chan_sdam 80 + - const: lut_sdam 81 + 82 + qcom,pbs: 83 + $ref: /schemas/types.yaml#/definitions/phandle 84 + description: > 85 + Phandle of the Qualcomm Programmable Boot Sequencer node (PBS). 86 + PBS node is used to trigger LPG pattern sequences for PMICs that support 87 + single SDAM PPG. 88 + 66 89 multi-led: 67 90 type: object 68 91 $ref: leds-class-multicolor.yaml# ··· 128 105 - compatible 129 106 130 107 additionalProperties: false 108 + 109 + allOf: 110 + - if: 111 + properties: 112 + compatible: 113 + contains: 114 + enum: 115 + - qcom,pm660l-lpg 116 + - qcom,pm8150b-lpg 117 + - qcom,pm8150l-lpg 118 + - qcom,pm8916-pwm 119 + - qcom,pm8941-lpg 120 + - qcom,pm8994-lpg 121 + - qcom,pmc8180c-lpg 122 + - qcom,pmi8994-lpg 123 + - qcom,pmi8998-lpg 124 + - qcom,pmk8550-pwm 125 + then: 126 + properties: 127 + nvmem: false 128 + nvmem-names: false 129 + 130 + - if: 131 + properties: 132 + compatible: 133 + contains: 134 + const: qcom,pmi632-lpg 135 + then: 136 + properties: 137 + nvmem: 138 + maxItems: 1 139 + nvmem-names: 140 + maxItems: 1 141 + 142 + - if: 143 + properties: 144 + compatible: 145 + contains: 146 + enum: 147 + - qcom,pm8350c-pwm 148 + then: 149 + properties: 150 + nvmem: 151 + minItems: 2 152 + nvmem-names: 153 + minItems: 2 131 154 132 155 examples: 133 156 - | ··· 260 191 compatible = "qcom,pm8916-pwm"; 261 192 #pwm-cells = <2>; 262 193 }; 194 + - | 195 + #include <dt-bindings/leds/common.h> 196 + 197 + led-controller { 198 + compatible = "qcom,pmi632-lpg"; 199 + #address-cells = <1>; 200 + #size-cells = <0>; 201 + #pwm-cells = <2>; 202 + nvmem-names = "lpg_chan_sdam"; 203 + nvmem = <&pmi632_sdam_7>; 204 + qcom,pbs = <&pmi632_pbs_client3>; 205 + 206 + led@1 { 207 + reg = <1>; 208 + color = <LED_COLOR_ID_RED>; 209 + label = "red"; 210 + }; 211 + 212 + led@2 { 213 + reg = <2>; 214 + color = <LED_COLOR_ID_GREEN>; 215 + label = "green"; 216 + }; 217 + 218 + led@3 { 219 + reg = <3>; 220 + color = <LED_COLOR_ID_BLUE>; 221 + label = "blue"; 222 + }; 223 + }; 224 + 263 225 ...
+96
Documentation/devicetree/bindings/leds/onnn,ncp5623.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/onnn,ncp5623.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: ON Semiconductor NCP5623 multi-LED Driver 8 + 9 + maintainers: 10 + - Abdel Alkuor <alkuor@gmail.com> 11 + 12 + description: 13 + NCP5623 Triple Output I2C Controlled LED Driver. 14 + https://www.onsemi.com/pdf/datasheet/ncp5623-d.pdf 15 + 16 + properties: 17 + compatible: 18 + enum: 19 + - onnn,ncp5623 20 + 21 + reg: 22 + const: 0x38 23 + 24 + multi-led: 25 + type: object 26 + $ref: leds-class-multicolor.yaml# 27 + unevaluatedProperties: false 28 + 29 + properties: 30 + "#address-cells": 31 + const: 1 32 + 33 + "#size-cells": 34 + const: 0 35 + 36 + patternProperties: 37 + "^led@[0-2]$": 38 + type: object 39 + $ref: common.yaml# 40 + unevaluatedProperties: false 41 + 42 + properties: 43 + reg: 44 + minimum: 0 45 + maximum: 2 46 + 47 + required: 48 + - reg 49 + - color 50 + 51 + required: 52 + - "#address-cells" 53 + - "#size-cells" 54 + 55 + required: 56 + - compatible 57 + - reg 58 + - multi-led 59 + 60 + additionalProperties: false 61 + 62 + examples: 63 + - | 64 + #include <dt-bindings/leds/common.h> 65 + 66 + i2c { 67 + #address-cells = <1>; 68 + #size-cells = <0>; 69 + 70 + led-controller@38 { 71 + compatible = "onnn,ncp5623"; 72 + reg = <0x38>; 73 + 74 + multi-led { 75 + color = <LED_COLOR_ID_RGB>; 76 + 77 + #address-cells = <1>; 78 + #size-cells = <0>; 79 + 80 + led@0 { 81 + reg = <0>; 82 + color = <LED_COLOR_ID_RED>; 83 + }; 84 + 85 + led@1 { 86 + reg = <1>; 87 + color = <LED_COLOR_ID_GREEN>; 88 + }; 89 + 90 + led@2 { 91 + reg = <2>; 92 + color = <LED_COLOR_ID_BLUE>; 93 + }; 94 + }; 95 + }; 96 + };
+1 -1
drivers/Makefile
··· 135 135 obj-y += mmc/ 136 136 obj-y += ufs/ 137 137 obj-$(CONFIG_MEMSTICK) += memstick/ 138 - obj-$(CONFIG_NEW_LEDS) += leds/ 138 + obj-y += leds/ 139 139 obj-$(CONFIG_INFINIBAND) += infiniband/ 140 140 obj-y += firmware/ 141 141 obj-$(CONFIG_CRYPTO) += crypto/
+8 -2
drivers/leds/Kconfig
··· 6 6 As this function is used by arch code it must not be compiled as a 7 7 module. 8 8 9 + # This library does not depend on NEW_LEDS and must be independent so it can be 10 + # selected from other subsystems (specifically backlight). 11 + config LEDS_EXPRESSWIRE 12 + bool 13 + depends on GPIOLIB 14 + 9 15 menuconfig NEW_LEDS 10 16 bool "LED Support" 11 17 help ··· 405 399 config LEDS_LP50XX 406 400 tristate "LED Support for TI LP5036/30/24/18/12/09 LED driver chip" 407 401 depends on LEDS_CLASS && REGMAP_I2C 408 - depends on LEDS_CLASS_MULTICOLOR || !LEDS_CLASS_MULTICOLOR 402 + depends on LEDS_CLASS_MULTICOLOR 409 403 help 410 404 If you say yes here you get support for the Texas Instruments 411 405 LP5036, LP5030, LP5024, LP5018, LP5012 and LP5009 LED driver. ··· 416 410 config LEDS_LP55XX_COMMON 417 411 tristate "Common Driver for TI/National LP5521/5523/55231/5562/8501" 418 412 depends on LEDS_CLASS 419 - depends on LEDS_CLASS_MULTICOLOR || !LEDS_CLASS_MULTICOLOR 413 + depends on LEDS_CLASS_MULTICOLOR 420 414 depends on OF 421 415 depends on I2C 422 416 select FW_LOADER
+2 -2
drivers/leds/flash/Kconfig
··· 52 52 config LEDS_MT6360 53 53 tristate "LED Support for Mediatek MT6360 PMIC" 54 54 depends on LEDS_CLASS && OF 55 - depends on LEDS_CLASS_FLASH || !LEDS_CLASS_FLASH 56 - depends on LEDS_CLASS_MULTICOLOR || !LEDS_CLASS_MULTICOLOR 55 + depends on LEDS_CLASS_FLASH 56 + depends on LEDS_CLASS_MULTICOLOR 57 57 depends on V4L2_FLASH_LED_CLASS || !V4L2_FLASH_LED_CLASS 58 58 depends on MFD_MT6360 59 59 help
+1 -2
drivers/leds/flash/leds-lm3601x.c
··· 70 70 }; 71 71 72 72 /** 73 - * struct lm3601x_led - 73 + * struct lm3601x_led - private lm3601x LED data 74 74 * @fled_cdev: flash LED class device pointer 75 75 * @client: Pointer to the I2C client 76 76 * @regmap: Devices register map 77 77 * @lock: Lock for reading/writing the device 78 - * @led_name: LED label for the Torch or IR LED 79 78 * @flash_timeout: the timeout for the flash 80 79 * @last_flag: last known flags register value 81 80 * @torch_current_max: maximum current for the torch
+3
drivers/leds/flash/leds-sgm3140.c
··· 114 114 "failed to enable regulator: %d\n", ret); 115 115 return ret; 116 116 } 117 + gpiod_set_value_cansleep(priv->flash_gpio, 0); 117 118 gpiod_set_value_cansleep(priv->enable_gpio, 1); 118 119 } else { 120 + del_timer_sync(&priv->powerdown_timer); 121 + gpiod_set_value_cansleep(priv->flash_gpio, 0); 119 122 gpiod_set_value_cansleep(priv->enable_gpio, 0); 120 123 ret = regulator_disable(priv->vin_regulator); 121 124 if (ret) {
+6
drivers/leds/led-class.c
··· 552 552 led_init_core(led_cdev); 553 553 554 554 #ifdef CONFIG_LEDS_TRIGGERS 555 + /* 556 + * If no default trigger was given and hw_control_trigger is set, 557 + * make it the default trigger. 558 + */ 559 + if (!led_cdev->default_trigger && led_cdev->hw_control_trigger) 560 + led_cdev->default_trigger = led_cdev->hw_control_trigger; 555 561 led_trigger_set_default(led_cdev); 556 562 #endif 557 563
+26 -12
drivers/leds/led-triggers.c
··· 23 23 * Nests outside led_cdev->trigger_lock 24 24 */ 25 25 static DECLARE_RWSEM(triggers_list_lock); 26 - LIST_HEAD(trigger_list); 26 + static LIST_HEAD(trigger_list); 27 27 28 28 /* Used by LED Class */ 29 29 ··· 247 247 } 248 248 EXPORT_SYMBOL_GPL(led_trigger_remove); 249 249 250 + static bool led_match_default_trigger(struct led_classdev *led_cdev, 251 + struct led_trigger *trig) 252 + { 253 + if (!strcmp(led_cdev->default_trigger, trig->name) && 254 + trigger_relevant(led_cdev, trig)) { 255 + led_cdev->flags |= LED_INIT_DEFAULT_TRIGGER; 256 + led_trigger_set(led_cdev, trig); 257 + return true; 258 + } 259 + 260 + return false; 261 + } 262 + 250 263 void led_trigger_set_default(struct led_classdev *led_cdev) 251 264 { 252 265 struct led_trigger *trig; 266 + bool found = false; 253 267 254 268 if (!led_cdev->default_trigger) 255 269 return; ··· 271 257 down_read(&triggers_list_lock); 272 258 down_write(&led_cdev->trigger_lock); 273 259 list_for_each_entry(trig, &trigger_list, next_trig) { 274 - if (!strcmp(led_cdev->default_trigger, trig->name) && 275 - trigger_relevant(led_cdev, trig)) { 276 - led_cdev->flags |= LED_INIT_DEFAULT_TRIGGER; 277 - led_trigger_set(led_cdev, trig); 260 + found = led_match_default_trigger(led_cdev, trig); 261 + if (found) 278 262 break; 279 - } 280 263 } 281 264 up_write(&led_cdev->trigger_lock); 282 265 up_read(&triggers_list_lock); 266 + 267 + /* 268 + * If default trigger wasn't found, maybe trigger module isn't loaded yet. 269 + * Once loaded it will re-probe with all led_cdev's. 270 + */ 271 + if (!found) 272 + request_module_nowait("ledtrig:%s", led_cdev->default_trigger); 283 273 } 284 274 EXPORT_SYMBOL_GPL(led_trigger_set_default); 285 275 ··· 315 297 down_read(&leds_list_lock); 316 298 list_for_each_entry(led_cdev, &leds_list, node) { 317 299 down_write(&led_cdev->trigger_lock); 318 - if (!led_cdev->trigger && led_cdev->default_trigger && 319 - !strcmp(led_cdev->default_trigger, trig->name) && 320 - trigger_relevant(led_cdev, trig)) { 321 - led_cdev->flags |= LED_INIT_DEFAULT_TRIGGER; 322 - led_trigger_set(led_cdev, trig); 323 - } 300 + if (!led_cdev->trigger && led_cdev->default_trigger) 301 + led_match_default_trigger(led_cdev, trig); 324 302 up_write(&led_cdev->trigger_lock); 325 303 } 326 304 up_read(&leds_list_lock);
+1 -1
drivers/leds/leds-aw200xx.c
··· 282 282 u32 led_imax_uA) 283 283 { 284 284 u32 g_imax_uA = aw200xx_imax_to_global(chip, led_imax_uA); 285 - u32 coeff_table[] = {1, 2, 3, 4, 6, 8, 12, 16}; 285 + static const u32 coeff_table[] = {1, 2, 3, 4, 6, 8, 12, 16}; 286 286 u32 gccr_imax = UINT_MAX; 287 287 u32 cur_imax = 0; 288 288 int i;
+1
drivers/leds/leds-aw2013.c
··· 405 405 chip->regulators); 406 406 407 407 error: 408 + mutex_unlock(&chip->mutex); 408 409 mutex_destroy(&chip->mutex); 409 410 return ret; 410 411 }
+1 -1
drivers/leds/leds-mlxcpld.c
··· 77 77 78 78 /** 79 79 * struct mlxcpld_led_priv - LED private data: 80 - * @cled: LED class device instance 80 + * @cdev: LED class device instance 81 81 * @param: LED CPLD access parameters 82 82 **/ 83 83 struct mlxcpld_led_priv {
-1
drivers/leds/leds-mlxreg.c
··· 29 29 * @data: led configuration data; 30 30 * @led_cdev: led class data; 31 31 * @base_color: base led color (other colors have constant offset from base); 32 - * @led_data: led data; 33 32 * @data_parent: pointer to private device control data of parent; 34 33 * @led_cdev_name: class device name 35 34 */
+28
drivers/leds/leds-pca963x.c
··· 39 39 #define PCA963X_LED_PWM 0x2 /* Controlled through PWM */ 40 40 #define PCA963X_LED_GRP_PWM 0x3 /* Controlled through PWM/GRPPWM */ 41 41 42 + #define PCA963X_MODE1_SLEEP 0x04 /* Normal mode or Low Power mode, oscillator off */ 42 43 #define PCA963X_MODE2_OUTDRV 0x04 /* Open-drain or totem pole */ 43 44 #define PCA963X_MODE2_INVRT 0x10 /* Normal or inverted direction */ 44 45 #define PCA963X_MODE2_DMBLNK 0x20 /* Enable blinking */ ··· 381 380 return ret; 382 381 } 383 382 383 + static int pca963x_suspend(struct device *dev) 384 + { 385 + struct pca963x *chip = dev_get_drvdata(dev); 386 + u8 reg; 387 + 388 + reg = i2c_smbus_read_byte_data(chip->client, PCA963X_MODE1); 389 + reg = reg | BIT(PCA963X_MODE1_SLEEP); 390 + i2c_smbus_write_byte_data(chip->client, PCA963X_MODE1, reg); 391 + 392 + return 0; 393 + } 394 + 395 + static int pca963x_resume(struct device *dev) 396 + { 397 + struct pca963x *chip = dev_get_drvdata(dev); 398 + u8 reg; 399 + 400 + reg = i2c_smbus_read_byte_data(chip->client, PCA963X_MODE1); 401 + reg = reg & ~BIT(PCA963X_MODE1_SLEEP); 402 + i2c_smbus_write_byte_data(chip->client, PCA963X_MODE1, reg); 403 + 404 + return 0; 405 + } 406 + 407 + static DEFINE_SIMPLE_DEV_PM_OPS(pca963x_pm, pca963x_suspend, pca963x_resume); 408 + 384 409 static const struct of_device_id of_pca963x_match[] = { 385 410 { .compatible = "nxp,pca9632", }, 386 411 { .compatible = "nxp,pca9633", }, ··· 457 430 .driver = { 458 431 .name = "leds-pca963x", 459 432 .of_match_table = of_pca963x_match, 433 + .pm = pm_sleep_ptr(&pca963x_pm) 460 434 }, 461 435 .probe = pca963x_probe, 462 436 .id_table = pca963x_id,
+6 -5
drivers/leds/leds-spi-byte.c
··· 83 83 struct device_node *child; 84 84 struct device *dev = &spi->dev; 85 85 struct spi_byte_led *led; 86 - const char *name = "leds-spi-byte::"; 86 + struct led_init_data init_data = {}; 87 87 const char *state; 88 88 int ret; 89 89 ··· 97 97 if (!led) 98 98 return -ENOMEM; 99 99 100 - of_property_read_string(child, "label", &name); 101 - strscpy(led->name, name, sizeof(led->name)); 102 100 led->spi = spi; 103 101 mutex_init(&led->mutex); 104 102 led->cdef = device_get_match_data(dev); 105 - led->ldev.name = led->name; 106 103 led->ldev.brightness = LED_OFF; 107 104 led->ldev.max_brightness = led->cdef->max_value - led->cdef->off_value; 108 105 led->ldev.brightness_set_blocking = spi_byte_brightness_set_blocking; ··· 117 120 spi_byte_brightness_set_blocking(&led->ldev, 118 121 led->ldev.brightness); 119 122 120 - ret = devm_led_classdev_register(&spi->dev, &led->ldev); 123 + init_data.fwnode = of_fwnode_handle(child); 124 + init_data.devicename = "leds-spi-byte"; 125 + init_data.default_label = ":"; 126 + 127 + ret = devm_led_classdev_register_ext(&spi->dev, &led->ldev, &init_data); 121 128 if (ret) { 122 129 mutex_destroy(&led->mutex); 123 130 return ret;
-1
drivers/leds/leds.h
··· 30 30 31 31 extern struct rw_semaphore leds_list_lock; 32 32 extern struct list_head leds_list; 33 - extern struct list_head trigger_list; 34 33 extern const char * const led_colors[LED_COLOR_ID_MAX]; 35 34 36 35 #endif /* __LEDS_H_INCLUDED */
+12
drivers/leds/rgb/Kconfig
··· 27 27 To compile this driver as a module, choose M here: the module 28 28 will be called leds-ktd202x. 29 29 30 + config LEDS_NCP5623 31 + tristate "LED support for NCP5623" 32 + depends on I2C 33 + depends on OF 34 + help 35 + This option enables support for ON semiconductor NCP5623 36 + Triple Output I2C Controlled RGB LED Driver. 37 + 38 + To compile this driver as a module, choose M here: the module 39 + will be called leds-ncp5623. 40 + 30 41 config LEDS_PWM_MULTICOLOR 31 42 tristate "PWM driven multi-color LED Support" 32 43 depends on PWM ··· 52 41 tristate "LED support for Qualcomm LPG" 53 42 depends on OF 54 43 depends on PWM 44 + depends on QCOM_PBS || !QCOM_PBS 55 45 depends on SPMI 56 46 help 57 47 This option enables support for the Light Pulse Generator found in a
+1
drivers/leds/rgb/Makefile
··· 2 2 3 3 obj-$(CONFIG_LEDS_GROUP_MULTICOLOR) += leds-group-multicolor.o 4 4 obj-$(CONFIG_LEDS_KTD202X) += leds-ktd202x.o 5 + obj-$(CONFIG_LEDS_NCP5623) += leds-ncp5623.o 5 6 obj-$(CONFIG_LEDS_PWM_MULTICOLOR) += leds-pwm-multicolor.o 6 7 obj-$(CONFIG_LEDS_QCOM_LPG) += leds-qcom-lpg.o 7 8 obj-$(CONFIG_LEDS_MT6370_RGB) += leds-mt6370-rgb.o
+6 -2
drivers/leds/rgb/leds-group-multicolor.c
··· 69 69 struct mc_subled *subled; 70 70 struct leds_multicolor *priv; 71 71 unsigned int max_brightness = 0; 72 - int i, ret, count = 0; 72 + int i, ret, count = 0, common_flags = 0; 73 73 74 74 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 75 75 if (!priv) ··· 91 91 if (!priv->monochromatics) 92 92 return -ENOMEM; 93 93 94 + common_flags |= led_cdev->flags; 94 95 priv->monochromatics[count] = led_cdev; 95 96 96 97 max_brightness = max(max_brightness, led_cdev->max_brightness); ··· 115 114 116 115 /* Initialise the multicolor's LED class device */ 117 116 cdev = &priv->mc_cdev.led_cdev; 118 - cdev->flags = LED_CORE_SUSPENDRESUME; 119 117 cdev->brightness_set_blocking = leds_gmc_set; 120 118 cdev->max_brightness = max_brightness; 121 119 cdev->color = LED_COLOR_ID_MULTI; 122 120 priv->mc_cdev.num_colors = count; 121 + 122 + /* we only need suspend/resume if a sub-led requests it */ 123 + if (common_flags & LED_CORE_SUSPENDRESUME) 124 + cdev->flags = LED_CORE_SUSPENDRESUME; 123 125 124 126 init_data.fwnode = dev_fwnode(dev); 125 127 ret = devm_led_classdev_multicolor_register_ext(dev, &priv->mc_cdev, &init_data);
+271
drivers/leds/rgb/leds-ncp5623.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * NCP5623 Multi-LED Driver 4 + * 5 + * Author: Abdel Alkuor <alkuor@gmail.com> 6 + * Datasheet: https://www.onsemi.com/pdf/datasheet/ncp5623-d.pdf 7 + */ 8 + 9 + #include <linux/i2c.h> 10 + #include <linux/module.h> 11 + 12 + #include <linux/led-class-multicolor.h> 13 + 14 + #define NCP5623_FUNCTION_OFFSET 0x5 15 + #define NCP5623_REG(x) ((x) << NCP5623_FUNCTION_OFFSET) 16 + 17 + #define NCP5623_SHUTDOWN_REG NCP5623_REG(0x0) 18 + #define NCP5623_ILED_REG NCP5623_REG(0x1) 19 + #define NCP5623_PWM_REG(index) NCP5623_REG(0x2 + (index)) 20 + #define NCP5623_UPWARD_STEP_REG NCP5623_REG(0x5) 21 + #define NCP5623_DOWNWARD_STEP_REG NCP5623_REG(0x6) 22 + #define NCP5623_DIMMING_TIME_REG NCP5623_REG(0x7) 23 + 24 + #define NCP5623_MAX_BRIGHTNESS 0x1f 25 + #define NCP5623_MAX_DIM_TIME_MS 240 26 + #define NCP5623_DIM_STEP_MS 8 27 + 28 + struct ncp5623 { 29 + struct i2c_client *client; 30 + struct led_classdev_mc mc_dev; 31 + struct mutex lock; 32 + 33 + int current_brightness; 34 + unsigned long delay; 35 + }; 36 + 37 + static int ncp5623_write(struct i2c_client *client, u8 reg, u8 data) 38 + { 39 + return i2c_smbus_write_byte_data(client, reg | data, 0); 40 + } 41 + 42 + static int ncp5623_brightness_set(struct led_classdev *cdev, 43 + enum led_brightness brightness) 44 + { 45 + struct led_classdev_mc *mc_cdev = lcdev_to_mccdev(cdev); 46 + struct ncp5623 *ncp = container_of(mc_cdev, struct ncp5623, mc_dev); 47 + int ret; 48 + 49 + guard(mutex)(&ncp->lock); 50 + 51 + if (ncp->delay && time_is_after_jiffies(ncp->delay)) 52 + return -EBUSY; 53 + 54 + ncp->delay = 0; 55 + 56 + for (int i = 0; i < mc_cdev->num_colors; i++) { 57 + ret = ncp5623_write(ncp->client, 58 + NCP5623_PWM_REG(mc_cdev->subled_info[i].channel), 59 + min(mc_cdev->subled_info[i].intensity, 60 + NCP5623_MAX_BRIGHTNESS)); 61 + if (ret) 62 + return ret; 63 + } 64 + 65 + ret = ncp5623_write(ncp->client, NCP5623_DIMMING_TIME_REG, 0); 66 + if (ret) 67 + return ret; 68 + 69 + ret = ncp5623_write(ncp->client, NCP5623_ILED_REG, brightness); 70 + if (ret) 71 + return ret; 72 + 73 + ncp->current_brightness = brightness; 74 + 75 + return 0; 76 + } 77 + 78 + static int ncp5623_pattern_set(struct led_classdev *cdev, 79 + struct led_pattern *pattern, 80 + u32 len, int repeat) 81 + { 82 + struct led_classdev_mc *mc_cdev = lcdev_to_mccdev(cdev); 83 + struct ncp5623 *ncp = container_of(mc_cdev, struct ncp5623, mc_dev); 84 + int brightness_diff; 85 + u8 reg; 86 + int ret; 87 + 88 + guard(mutex)(&ncp->lock); 89 + 90 + if (ncp->delay && time_is_after_jiffies(ncp->delay)) 91 + return -EBUSY; 92 + 93 + ncp->delay = 0; 94 + 95 + if (pattern[0].delta_t > NCP5623_MAX_DIM_TIME_MS || 96 + (pattern[0].delta_t % NCP5623_DIM_STEP_MS) != 0) 97 + return -EINVAL; 98 + 99 + brightness_diff = pattern[0].brightness - ncp->current_brightness; 100 + 101 + if (brightness_diff == 0) 102 + return 0; 103 + 104 + if (pattern[0].delta_t) { 105 + if (brightness_diff > 0) 106 + reg = NCP5623_UPWARD_STEP_REG; 107 + else 108 + reg = NCP5623_DOWNWARD_STEP_REG; 109 + } else { 110 + reg = NCP5623_ILED_REG; 111 + } 112 + 113 + ret = ncp5623_write(ncp->client, reg, 114 + min(pattern[0].brightness, NCP5623_MAX_BRIGHTNESS)); 115 + if (ret) 116 + return ret; 117 + 118 + ret = ncp5623_write(ncp->client, 119 + NCP5623_DIMMING_TIME_REG, 120 + pattern[0].delta_t / NCP5623_DIM_STEP_MS); 121 + if (ret) 122 + return ret; 123 + 124 + /* 125 + * During testing, when the brightness difference is 1, for some 126 + * unknown reason, the time factor it takes to change to the new 127 + * value is the longest time possible. Otherwise, the time factor 128 + * is simply the brightness difference. 129 + * 130 + * For example: 131 + * current_brightness = 20 and new_brightness = 21 then the time it 132 + * takes to set the new brightness increments to the maximum possible 133 + * brightness from 20 then from 0 to 21. 134 + * time_factor = max_brightness - 20 + 21 135 + */ 136 + if (abs(brightness_diff) == 1) 137 + ncp->delay = NCP5623_MAX_BRIGHTNESS + brightness_diff; 138 + else 139 + ncp->delay = abs(brightness_diff); 140 + 141 + ncp->delay = msecs_to_jiffies(ncp->delay * pattern[0].delta_t) + jiffies; 142 + 143 + ncp->current_brightness = pattern[0].brightness; 144 + 145 + return 0; 146 + } 147 + 148 + static int ncp5623_pattern_clear(struct led_classdev *led_cdev) 149 + { 150 + return 0; 151 + } 152 + 153 + static int ncp5623_probe(struct i2c_client *client) 154 + { 155 + struct device *dev = &client->dev; 156 + struct fwnode_handle *mc_node, *led_node; 157 + struct led_init_data init_data = { }; 158 + int num_subleds = 0; 159 + struct ncp5623 *ncp; 160 + struct mc_subled *subled_info; 161 + u32 color_index; 162 + u32 reg; 163 + int ret; 164 + 165 + ncp = devm_kzalloc(dev, sizeof(*ncp), GFP_KERNEL); 166 + if (!ncp) 167 + return -ENOMEM; 168 + 169 + ncp->client = client; 170 + 171 + mc_node = device_get_named_child_node(dev, "multi-led"); 172 + if (!mc_node) 173 + return -EINVAL; 174 + 175 + fwnode_for_each_child_node(mc_node, led_node) 176 + num_subleds++; 177 + 178 + subled_info = devm_kcalloc(dev, num_subleds, sizeof(*subled_info), GFP_KERNEL); 179 + if (!subled_info) { 180 + ret = -ENOMEM; 181 + goto release_mc_node; 182 + } 183 + 184 + fwnode_for_each_available_child_node(mc_node, led_node) { 185 + ret = fwnode_property_read_u32(led_node, "color", &color_index); 186 + if (ret) { 187 + fwnode_handle_put(led_node); 188 + goto release_mc_node; 189 + } 190 + 191 + ret = fwnode_property_read_u32(led_node, "reg", &reg); 192 + if (ret) { 193 + fwnode_handle_put(led_node); 194 + goto release_mc_node; 195 + } 196 + 197 + subled_info[ncp->mc_dev.num_colors].channel = reg; 198 + subled_info[ncp->mc_dev.num_colors++].color_index = color_index; 199 + } 200 + 201 + init_data.fwnode = mc_node; 202 + 203 + ncp->mc_dev.led_cdev.max_brightness = NCP5623_MAX_BRIGHTNESS; 204 + ncp->mc_dev.subled_info = subled_info; 205 + ncp->mc_dev.led_cdev.brightness_set_blocking = ncp5623_brightness_set; 206 + ncp->mc_dev.led_cdev.pattern_set = ncp5623_pattern_set; 207 + ncp->mc_dev.led_cdev.pattern_clear = ncp5623_pattern_clear; 208 + ncp->mc_dev.led_cdev.default_trigger = "pattern"; 209 + 210 + mutex_init(&ncp->lock); 211 + i2c_set_clientdata(client, ncp); 212 + 213 + ret = led_classdev_multicolor_register_ext(dev, &ncp->mc_dev, &init_data); 214 + if (ret) 215 + goto destroy_lock; 216 + 217 + return 0; 218 + 219 + destroy_lock: 220 + mutex_destroy(&ncp->lock); 221 + 222 + release_mc_node: 223 + fwnode_handle_put(mc_node); 224 + 225 + return ret; 226 + } 227 + 228 + static void ncp5623_remove(struct i2c_client *client) 229 + { 230 + struct ncp5623 *ncp = i2c_get_clientdata(client); 231 + 232 + mutex_lock(&ncp->lock); 233 + ncp->delay = 0; 234 + mutex_unlock(&ncp->lock); 235 + 236 + ncp5623_write(client, NCP5623_DIMMING_TIME_REG, 0); 237 + led_classdev_multicolor_unregister(&ncp->mc_dev); 238 + mutex_destroy(&ncp->lock); 239 + } 240 + 241 + static void ncp5623_shutdown(struct i2c_client *client) 242 + { 243 + struct ncp5623 *ncp = i2c_get_clientdata(client); 244 + 245 + if (!(ncp->mc_dev.led_cdev.flags & LED_RETAIN_AT_SHUTDOWN)) 246 + ncp5623_write(client, NCP5623_SHUTDOWN_REG, 0); 247 + 248 + mutex_destroy(&ncp->lock); 249 + } 250 + 251 + static const struct of_device_id ncp5623_id[] = { 252 + { .compatible = "onnn,ncp5623" }, 253 + { } 254 + }; 255 + MODULE_DEVICE_TABLE(of, ncp5623_id); 256 + 257 + static struct i2c_driver ncp5623_i2c_driver = { 258 + .driver = { 259 + .name = "ncp5623", 260 + .of_match_table = ncp5623_id, 261 + }, 262 + .probe = ncp5623_probe, 263 + .remove = ncp5623_remove, 264 + .shutdown = ncp5623_shutdown, 265 + }; 266 + 267 + module_i2c_driver(ncp5623_i2c_driver); 268 + 269 + MODULE_AUTHOR("Abdel Alkuor <alkuor@gmail.com>"); 270 + MODULE_DESCRIPTION("NCP5623 Multi-LED driver"); 271 + MODULE_LICENSE("GPL");
+335 -29
drivers/leds/rgb/leds-qcom-lpg.c
··· 8 8 #include <linux/bitfield.h> 9 9 #include <linux/led-class-multicolor.h> 10 10 #include <linux/module.h> 11 + #include <linux/nvmem-consumer.h> 11 12 #include <linux/of.h> 12 13 #include <linux/platform_device.h> 13 14 #include <linux/pwm.h> 14 15 #include <linux/regmap.h> 15 16 #include <linux/slab.h> 17 + #include <linux/soc/qcom/qcom-pbs.h> 16 18 17 19 #define LPG_SUBTYPE_REG 0x05 18 20 #define LPG_SUBTYPE_LPG 0x2 ··· 41 39 #define PWM_SEC_ACCESS_REG 0xd0 42 40 #define PWM_DTEST_REG(x) (0xe2 + (x) - 1) 43 41 42 + #define SDAM_REG_PBS_SEQ_EN 0x42 43 + #define SDAM_PBS_TRIG_SET 0xe5 44 + #define SDAM_PBS_TRIG_CLR 0xe6 45 + 44 46 #define TRI_LED_SRC_SEL 0x45 45 47 #define TRI_LED_EN_CTL 0x46 46 48 #define TRI_LED_ATC_CTL 0x47 ··· 54 48 55 49 #define LPG_RESOLUTION_9BIT BIT(9) 56 50 #define LPG_RESOLUTION_15BIT BIT(15) 51 + #define PPG_MAX_LED_BRIGHTNESS 255 52 + 57 53 #define LPG_MAX_M 7 58 54 #define LPG_MAX_PREDIV 6 55 + 56 + #define DEFAULT_TICK_DURATION_US 7800 57 + #define RAMP_STEP_DURATION(x) (((x) * 1000 / DEFAULT_TICK_DURATION_US) & 0xff) 58 + 59 + #define SDAM_MAX_DEVICES 2 60 + /* LPG common config settings for PPG */ 61 + #define SDAM_START_BASE 0x40 62 + #define SDAM_REG_RAMP_STEP_DURATION 0x47 63 + 64 + #define SDAM_LUT_SDAM_LUT_PATTERN_OFFSET 0x45 65 + #define SDAM_LPG_SDAM_LUT_PATTERN_OFFSET 0x80 66 + 67 + /* LPG per channel config settings for PPG */ 68 + #define SDAM_LUT_EN_OFFSET 0x0 69 + #define SDAM_PATTERN_CONFIG_OFFSET 0x1 70 + #define SDAM_END_INDEX_OFFSET 0x3 71 + #define SDAM_START_INDEX_OFFSET 0x4 72 + #define SDAM_PBS_SCRATCH_LUT_COUNTER_OFFSET 0x6 73 + #define SDAM_PAUSE_HI_MULTIPLIER_OFFSET 0x8 74 + #define SDAM_PAUSE_LO_MULTIPLIER_OFFSET 0x9 59 75 60 76 struct lpg_channel; 61 77 struct lpg_data; ··· 92 64 * @lut_base: base address of the LUT block (optional) 93 65 * @lut_size: number of entries in the LUT block 94 66 * @lut_bitmap: allocation bitmap for LUT entries 67 + * @pbs_dev: PBS device 68 + * @lpg_chan_sdam: LPG SDAM peripheral device 69 + * @lut_sdam: LUT SDAM peripheral device 70 + * @pbs_en_bitmap: bitmap for tracking PBS triggers 95 71 * @triled_base: base address of the TRILED block (optional) 96 72 * @triled_src: power-source for the TRILED 97 73 * @triled_has_atc_ctl: true if there is TRI_LED_ATC_CTL register ··· 117 85 u32 lut_size; 118 86 unsigned long *lut_bitmap; 119 87 88 + struct pbs_dev *pbs_dev; 89 + struct nvmem_device *lpg_chan_sdam; 90 + struct nvmem_device *lut_sdam; 91 + unsigned long pbs_en_bitmap; 92 + 120 93 u32 triled_base; 121 94 u32 triled_src; 122 95 bool triled_has_atc_ctl; ··· 138 101 * @triled_mask: mask in TRILED to enable this channel 139 102 * @lut_mask: mask in LUT to start pattern generator for this channel 140 103 * @subtype: PMIC hardware block subtype 104 + * @sdam_offset: channel offset in LPG SDAM 141 105 * @in_use: channel is exposed to LED framework 142 106 * @color: color of the LED attached to this channel 143 107 * @dtest_line: DTEST line for output, or 0 if disabled ··· 167 129 unsigned int triled_mask; 168 130 unsigned int lut_mask; 169 131 unsigned int subtype; 132 + u32 sdam_offset; 170 133 171 134 bool in_use; 172 135 ··· 217 178 218 179 /** 219 180 * struct lpg_channel_data - per channel initialization data 181 + * @sdam_offset: Channel offset in LPG SDAM 220 182 * @base: base address for PWM channel registers 221 183 * @triled_mask: bitmask for controlling this channel in TRILED 222 184 */ 223 185 struct lpg_channel_data { 186 + unsigned int sdam_offset; 224 187 unsigned int base; 225 188 u8 triled_mask; 226 189 }; ··· 247 206 const struct lpg_channel_data *channels; 248 207 }; 249 208 209 + #define PBS_SW_TRIG_BIT BIT(0) 210 + 211 + static int lpg_clear_pbs_trigger(struct lpg *lpg, unsigned int lut_mask) 212 + { 213 + u8 val = 0; 214 + int rc; 215 + 216 + lpg->pbs_en_bitmap &= (~lut_mask); 217 + if (!lpg->pbs_en_bitmap) { 218 + rc = nvmem_device_write(lpg->lpg_chan_sdam, SDAM_REG_PBS_SEQ_EN, 1, &val); 219 + if (rc < 0) 220 + return rc; 221 + 222 + if (lpg->lut_sdam) { 223 + val = PBS_SW_TRIG_BIT; 224 + rc = nvmem_device_write(lpg->lpg_chan_sdam, SDAM_PBS_TRIG_CLR, 1, &val); 225 + if (rc < 0) 226 + return rc; 227 + } 228 + } 229 + 230 + return 0; 231 + } 232 + 233 + static int lpg_set_pbs_trigger(struct lpg *lpg, unsigned int lut_mask) 234 + { 235 + u8 val = PBS_SW_TRIG_BIT; 236 + int rc; 237 + 238 + if (!lpg->pbs_en_bitmap) { 239 + rc = nvmem_device_write(lpg->lpg_chan_sdam, SDAM_REG_PBS_SEQ_EN, 1, &val); 240 + if (rc < 0) 241 + return rc; 242 + 243 + if (lpg->lut_sdam) { 244 + rc = nvmem_device_write(lpg->lpg_chan_sdam, SDAM_PBS_TRIG_SET, 1, &val); 245 + if (rc < 0) 246 + return rc; 247 + } else { 248 + rc = qcom_pbs_trigger_event(lpg->pbs_dev, val); 249 + if (rc < 0) 250 + return rc; 251 + } 252 + } 253 + lpg->pbs_en_bitmap |= lut_mask; 254 + 255 + return 0; 256 + } 257 + 258 + static int lpg_sdam_configure_triggers(struct lpg_channel *chan, u8 set_trig) 259 + { 260 + u32 addr = SDAM_LUT_EN_OFFSET + chan->sdam_offset; 261 + 262 + if (!chan->lpg->lpg_chan_sdam) 263 + return 0; 264 + 265 + return nvmem_device_write(chan->lpg->lpg_chan_sdam, addr, 1, &set_trig); 266 + } 267 + 250 268 static int triled_set(struct lpg *lpg, unsigned int mask, unsigned int enable) 251 269 { 252 270 /* Skip if we don't have a triled block */ ··· 314 214 315 215 return regmap_update_bits(lpg->map, lpg->triled_base + TRI_LED_EN_CTL, 316 216 mask, enable); 217 + } 218 + 219 + static int lpg_lut_store_sdam(struct lpg *lpg, struct led_pattern *pattern, 220 + size_t len, unsigned int *lo_idx, unsigned int *hi_idx) 221 + { 222 + unsigned int idx; 223 + u8 brightness; 224 + int i, rc; 225 + u16 addr; 226 + 227 + if (len > lpg->lut_size) { 228 + dev_err(lpg->dev, "Pattern length (%zu) exceeds maximum pattern length (%d)\n", 229 + len, lpg->lut_size); 230 + return -EINVAL; 231 + } 232 + 233 + idx = bitmap_find_next_zero_area(lpg->lut_bitmap, lpg->lut_size, 0, len, 0); 234 + if (idx >= lpg->lut_size) 235 + return -ENOSPC; 236 + 237 + for (i = 0; i < len; i++) { 238 + brightness = pattern[i].brightness; 239 + 240 + if (lpg->lut_sdam) { 241 + addr = SDAM_LUT_SDAM_LUT_PATTERN_OFFSET + i + idx; 242 + rc = nvmem_device_write(lpg->lut_sdam, addr, 1, &brightness); 243 + } else { 244 + addr = SDAM_LPG_SDAM_LUT_PATTERN_OFFSET + i + idx; 245 + rc = nvmem_device_write(lpg->lpg_chan_sdam, addr, 1, &brightness); 246 + } 247 + 248 + if (rc < 0) 249 + return rc; 250 + } 251 + 252 + bitmap_set(lpg->lut_bitmap, idx, len); 253 + 254 + *lo_idx = idx; 255 + *hi_idx = idx + len - 1; 256 + 257 + return 0; 317 258 } 318 259 319 260 static int lpg_lut_store(struct lpg *lpg, struct led_pattern *pattern, ··· 397 256 398 257 static int lpg_lut_sync(struct lpg *lpg, unsigned int mask) 399 258 { 259 + if (!lpg->lut_base) 260 + return 0; 261 + 400 262 return regmap_write(lpg->map, lpg->lut_base + RAMP_CONTROL_REG, mask); 401 263 } 402 264 ··· 606 462 #define LPG_PATTERN_CONFIG_PAUSE_HI BIT(1) 607 463 #define LPG_PATTERN_CONFIG_PAUSE_LO BIT(0) 608 464 465 + static void lpg_sdam_apply_lut_control(struct lpg_channel *chan) 466 + { 467 + struct nvmem_device *lpg_chan_sdam = chan->lpg->lpg_chan_sdam; 468 + unsigned int lo_idx = chan->pattern_lo_idx; 469 + unsigned int hi_idx = chan->pattern_hi_idx; 470 + u8 val = 0, conf = 0, lut_offset = 0; 471 + unsigned int hi_pause, lo_pause; 472 + struct lpg *lpg = chan->lpg; 473 + 474 + if (!chan->ramp_enabled || chan->pattern_lo_idx == chan->pattern_hi_idx) 475 + return; 476 + 477 + hi_pause = DIV_ROUND_UP(chan->ramp_hi_pause_ms, chan->ramp_tick_ms); 478 + lo_pause = DIV_ROUND_UP(chan->ramp_lo_pause_ms, chan->ramp_tick_ms); 479 + 480 + if (!chan->ramp_oneshot) 481 + conf |= LPG_PATTERN_CONFIG_REPEAT; 482 + if (chan->ramp_hi_pause_ms && lpg->lut_sdam) 483 + conf |= LPG_PATTERN_CONFIG_PAUSE_HI; 484 + if (chan->ramp_lo_pause_ms && lpg->lut_sdam) 485 + conf |= LPG_PATTERN_CONFIG_PAUSE_LO; 486 + 487 + if (lpg->lut_sdam) { 488 + lut_offset = SDAM_LUT_SDAM_LUT_PATTERN_OFFSET - SDAM_START_BASE; 489 + hi_idx += lut_offset; 490 + lo_idx += lut_offset; 491 + } 492 + 493 + nvmem_device_write(lpg_chan_sdam, SDAM_PBS_SCRATCH_LUT_COUNTER_OFFSET + chan->sdam_offset, 1, &val); 494 + nvmem_device_write(lpg_chan_sdam, SDAM_PATTERN_CONFIG_OFFSET + chan->sdam_offset, 1, &conf); 495 + nvmem_device_write(lpg_chan_sdam, SDAM_END_INDEX_OFFSET + chan->sdam_offset, 1, &hi_idx); 496 + nvmem_device_write(lpg_chan_sdam, SDAM_START_INDEX_OFFSET + chan->sdam_offset, 1, &lo_idx); 497 + 498 + val = RAMP_STEP_DURATION(chan->ramp_tick_ms); 499 + nvmem_device_write(lpg_chan_sdam, SDAM_REG_RAMP_STEP_DURATION, 1, &val); 500 + 501 + if (lpg->lut_sdam) { 502 + nvmem_device_write(lpg_chan_sdam, SDAM_PAUSE_HI_MULTIPLIER_OFFSET + chan->sdam_offset, 1, &hi_pause); 503 + nvmem_device_write(lpg_chan_sdam, SDAM_PAUSE_LO_MULTIPLIER_OFFSET + chan->sdam_offset, 1, &lo_pause); 504 + } 505 + 506 + } 507 + 609 508 static void lpg_apply_lut_control(struct lpg_channel *chan) 610 509 { 611 510 struct lpg *lpg = chan->lpg; ··· 783 596 lpg_apply_pwm_value(chan); 784 597 lpg_apply_control(chan); 785 598 lpg_apply_sync(chan); 786 - lpg_apply_lut_control(chan); 599 + if (chan->lpg->lpg_chan_sdam) 600 + lpg_sdam_apply_lut_control(chan); 601 + else 602 + lpg_apply_lut_control(chan); 787 603 lpg_enable_glitch(chan); 788 604 } 789 605 ··· 811 621 chan->ramp_enabled = false; 812 622 } else if (chan->pattern_lo_idx != chan->pattern_hi_idx) { 813 623 lpg_calc_freq(chan, NSEC_PER_MSEC); 624 + lpg_sdam_configure_triggers(chan, 1); 814 625 815 626 chan->enabled = true; 816 627 chan->ramp_enabled = true; ··· 839 648 triled_set(lpg, triled_mask, triled_enabled); 840 649 841 650 /* Trigger start of ramp generator(s) */ 842 - if (lut_mask) 651 + if (lut_mask) { 843 652 lpg_lut_sync(lpg, lut_mask); 653 + lpg_set_pbs_trigger(lpg, lut_mask); 654 + } 844 655 } 845 656 846 657 static int lpg_brightness_single_set(struct led_classdev *cdev, ··· 959 766 struct led_pattern *pattern; 960 767 unsigned int brightness_a; 961 768 unsigned int brightness_b; 769 + unsigned int hi_pause = 0; 770 + unsigned int lo_pause = 0; 962 771 unsigned int actual_len; 963 - unsigned int hi_pause; 964 - unsigned int lo_pause; 965 772 unsigned int delta_t; 966 773 unsigned int lo_idx; 967 774 unsigned int hi_idx; ··· 1028 835 * If the specified pattern is a palindrome the ping pong mode is 1029 836 * enabled. In this scenario the delta_t of the middle entry (i.e. the 1030 837 * last in the programmed pattern) determines the "high pause". 838 + * 839 + * SDAM-based devices do not support "ping pong", and only supports 840 + * "low pause" and "high pause" with a dedicated SDAM LUT. 1031 841 */ 1032 842 1033 843 /* Detect palindromes and use "ping pong" to reduce LUT usage */ 1034 - for (i = 0; i < len / 2; i++) { 1035 - brightness_a = pattern[i].brightness; 1036 - brightness_b = pattern[len - i - 1].brightness; 844 + if (lpg->lut_base) { 845 + for (i = 0; i < len / 2; i++) { 846 + brightness_a = pattern[i].brightness; 847 + brightness_b = pattern[len - i - 1].brightness; 1037 848 1038 - if (brightness_a != brightness_b) { 1039 - ping_pong = false; 1040 - break; 849 + if (brightness_a != brightness_b) { 850 + ping_pong = false; 851 + break; 852 + } 1041 853 } 1042 - } 854 + } else 855 + ping_pong = false; 1043 856 1044 857 /* The pattern length to be written to the LUT */ 1045 858 if (ping_pong) ··· 1073 874 if (delta_t >= BIT(9)) 1074 875 goto out_free_pattern; 1075 876 1076 - /* Find "low pause" and "high pause" in the pattern */ 1077 - lo_pause = pattern[0].delta_t; 1078 - hi_pause = pattern[actual_len - 1].delta_t; 877 + /* 878 + * Find "low pause" and "high pause" in the pattern in the LUT case. 879 + * SDAM-based devices without dedicated LUT SDAM require equal 880 + * duration of all steps. 881 + */ 882 + if (lpg->lut_base || lpg->lut_sdam) { 883 + lo_pause = pattern[0].delta_t; 884 + hi_pause = pattern[actual_len - 1].delta_t; 885 + } else { 886 + if (delta_t != pattern[0].delta_t || delta_t != pattern[actual_len - 1].delta_t) 887 + goto out_free_pattern; 888 + } 889 + 1079 890 1080 891 mutex_lock(&lpg->lock); 1081 - ret = lpg_lut_store(lpg, pattern, actual_len, &lo_idx, &hi_idx); 892 + 893 + if (lpg->lut_base) 894 + ret = lpg_lut_store(lpg, pattern, actual_len, &lo_idx, &hi_idx); 895 + else 896 + ret = lpg_lut_store_sdam(lpg, pattern, actual_len, &lo_idx, &hi_idx); 897 + 1082 898 if (ret < 0) 1083 899 goto out_unlock; 1084 900 ··· 1141 927 { 1142 928 struct led_classdev_mc *mc = lcdev_to_mccdev(cdev); 1143 929 struct lpg_led *led = container_of(mc, struct lpg_led, mcdev); 1144 - int ret; 930 + unsigned int triled_mask = 0; 931 + int ret, i; 932 + 933 + for (i = 0; i < led->num_channels; i++) 934 + triled_mask |= led->channels[i]->triled_mask; 935 + triled_set(led->lpg, triled_mask, 0); 1145 936 1146 937 ret = lpg_pattern_set(led, pattern, len, repeat); 1147 938 if (ret < 0) ··· 1171 952 1172 953 for (i = 0; i < led->num_channels; i++) { 1173 954 chan = led->channels[i]; 955 + lpg_sdam_configure_triggers(chan, 0); 956 + lpg_clear_pbs_trigger(chan->lpg, chan->lut_mask); 1174 957 chan->pattern_lo_idx = 0; 1175 958 chan->pattern_hi_idx = 0; 1176 959 } ··· 1412 1191 cdev->brightness_set_blocking = lpg_brightness_mc_set; 1413 1192 cdev->blink_set = lpg_blink_mc_set; 1414 1193 1415 - /* Register pattern accessors only if we have a LUT block */ 1416 - if (lpg->lut_base) { 1194 + /* Register pattern accessors if we have a LUT block or when using PPG */ 1195 + if (lpg->lut_base || lpg->lpg_chan_sdam) { 1417 1196 cdev->pattern_set = lpg_pattern_mc_set; 1418 1197 cdev->pattern_clear = lpg_pattern_mc_clear; 1419 1198 } ··· 1426 1205 cdev->brightness_set_blocking = lpg_brightness_single_set; 1427 1206 cdev->blink_set = lpg_blink_single_set; 1428 1207 1429 - /* Register pattern accessors only if we have a LUT block */ 1430 - if (lpg->lut_base) { 1208 + /* Register pattern accessors if we have a LUT block or when using PPG */ 1209 + if (lpg->lut_base || lpg->lpg_chan_sdam) { 1431 1210 cdev->pattern_set = lpg_pattern_single_set; 1432 1211 cdev->pattern_clear = lpg_pattern_single_clear; 1433 1212 } 1434 1213 } 1435 1214 1436 1215 cdev->default_trigger = of_get_property(np, "linux,default-trigger", NULL); 1437 - cdev->max_brightness = LPG_RESOLUTION_9BIT - 1; 1216 + 1217 + if (lpg->lpg_chan_sdam) 1218 + cdev->max_brightness = PPG_MAX_LED_BRIGHTNESS; 1219 + else 1220 + cdev->max_brightness = LPG_RESOLUTION_9BIT - 1; 1438 1221 1439 1222 if (!of_property_read_string(np, "default-state", &state) && 1440 1223 !strcmp(state, "on")) ··· 1479 1254 chan->base = data->channels[i].base; 1480 1255 chan->triled_mask = data->channels[i].triled_mask; 1481 1256 chan->lut_mask = BIT(i); 1257 + chan->sdam_offset = data->channels[i].sdam_offset; 1482 1258 1483 1259 regmap_read(lpg->map, chan->base + LPG_SUBTYPE_REG, &chan->subtype); 1484 1260 } ··· 1525 1299 { 1526 1300 const struct lpg_data *data = lpg->data; 1527 1301 1528 - if (!data->lut_base) 1302 + if (!data->lut_size) 1529 1303 return 0; 1530 1304 1531 - lpg->lut_base = data->lut_base; 1532 1305 lpg->lut_size = data->lut_size; 1306 + if (data->lut_base) 1307 + lpg->lut_base = data->lut_base; 1533 1308 1534 1309 lpg->lut_bitmap = devm_bitmap_zalloc(lpg->dev, lpg->lut_size, GFP_KERNEL); 1535 1310 if (!lpg->lut_bitmap) 1536 1311 return -ENOMEM; 1312 + 1313 + return 0; 1314 + } 1315 + 1316 + static int lpg_init_sdam(struct lpg *lpg) 1317 + { 1318 + int i, sdam_count, rc; 1319 + u8 val = 0; 1320 + 1321 + sdam_count = of_property_count_strings(lpg->dev->of_node, "nvmem-names"); 1322 + if (sdam_count <= 0) 1323 + return 0; 1324 + if (sdam_count > SDAM_MAX_DEVICES) 1325 + return -EINVAL; 1326 + 1327 + /* Get the 1st SDAM device for LPG/LUT config */ 1328 + lpg->lpg_chan_sdam = devm_nvmem_device_get(lpg->dev, "lpg_chan_sdam"); 1329 + if (IS_ERR(lpg->lpg_chan_sdam)) 1330 + return dev_err_probe(lpg->dev, PTR_ERR(lpg->lpg_chan_sdam), 1331 + "Failed to get LPG chan SDAM device\n"); 1332 + 1333 + if (sdam_count == 1) { 1334 + /* Get PBS device node if single SDAM device */ 1335 + lpg->pbs_dev = get_pbs_client_device(lpg->dev); 1336 + if (IS_ERR(lpg->pbs_dev)) 1337 + return dev_err_probe(lpg->dev, PTR_ERR(lpg->pbs_dev), 1338 + "Failed to get PBS client device\n"); 1339 + } else if (sdam_count == 2) { 1340 + /* Get the 2nd SDAM device for LUT pattern */ 1341 + lpg->lut_sdam = devm_nvmem_device_get(lpg->dev, "lut_sdam"); 1342 + if (IS_ERR(lpg->lut_sdam)) 1343 + return dev_err_probe(lpg->dev, PTR_ERR(lpg->lut_sdam), 1344 + "Failed to get LPG LUT SDAM device\n"); 1345 + } 1346 + 1347 + for (i = 0; i < lpg->num_channels; i++) { 1348 + struct lpg_channel *chan = &lpg->channels[i]; 1349 + 1350 + if (chan->sdam_offset) { 1351 + rc = nvmem_device_write(lpg->lpg_chan_sdam, 1352 + SDAM_PBS_SCRATCH_LUT_COUNTER_OFFSET + chan->sdam_offset, 1, &val); 1353 + if (rc < 0) 1354 + return rc; 1355 + 1356 + rc = lpg_sdam_configure_triggers(chan, 0); 1357 + if (rc < 0) 1358 + return rc; 1359 + 1360 + rc = lpg_clear_pbs_trigger(chan->lpg, chan->lut_mask); 1361 + if (rc < 0) 1362 + return rc; 1363 + } 1364 + } 1537 1365 1538 1366 return 0; 1539 1367 } ··· 1626 1346 if (ret < 0) 1627 1347 return ret; 1628 1348 1349 + ret = lpg_init_sdam(lpg); 1350 + if (ret < 0) 1351 + return ret; 1352 + 1629 1353 ret = lpg_init_lut(lpg); 1630 1354 if (ret < 0) 1631 1355 return ret; ··· 1647 1363 1648 1364 return lpg_add_pwm(lpg); 1649 1365 } 1366 + 1367 + static const struct lpg_data pm660l_lpg_data = { 1368 + .lut_base = 0xb000, 1369 + .lut_size = 49, 1370 + 1371 + .triled_base = 0xd000, 1372 + .triled_has_atc_ctl = true, 1373 + .triled_has_src_sel = true, 1374 + 1375 + .num_channels = 4, 1376 + .channels = (const struct lpg_channel_data[]) { 1377 + { .base = 0xb100, .triled_mask = BIT(5) }, 1378 + { .base = 0xb200, .triled_mask = BIT(6) }, 1379 + { .base = 0xb300, .triled_mask = BIT(7) }, 1380 + { .base = 0xb400 }, 1381 + }, 1382 + }; 1650 1383 1651 1384 static const struct lpg_data pm8916_pwm_data = { 1652 1385 .num_channels = 1, ··· 1712 1411 static const struct lpg_data pmi632_lpg_data = { 1713 1412 .triled_base = 0xd000, 1714 1413 1414 + .lut_size = 64, 1415 + 1715 1416 .num_channels = 5, 1716 1417 .channels = (const struct lpg_channel_data[]) { 1717 - { .base = 0xb300, .triled_mask = BIT(7) }, 1718 - { .base = 0xb400, .triled_mask = BIT(6) }, 1719 - { .base = 0xb500, .triled_mask = BIT(5) }, 1418 + { .base = 0xb300, .triled_mask = BIT(7), .sdam_offset = 0x48 }, 1419 + { .base = 0xb400, .triled_mask = BIT(6), .sdam_offset = 0x56 }, 1420 + { .base = 0xb500, .triled_mask = BIT(5), .sdam_offset = 0x64 }, 1720 1421 { .base = 0xb600 }, 1721 1422 { .base = 0xb700 }, 1722 1423 }, ··· 1791 1488 static const struct lpg_data pm8350c_pwm_data = { 1792 1489 .triled_base = 0xef00, 1793 1490 1491 + .lut_size = 122, 1492 + 1794 1493 .num_channels = 4, 1795 1494 .channels = (const struct lpg_channel_data[]) { 1796 - { .base = 0xe800, .triled_mask = BIT(7) }, 1797 - { .base = 0xe900, .triled_mask = BIT(6) }, 1798 - { .base = 0xea00, .triled_mask = BIT(5) }, 1495 + { .base = 0xe800, .triled_mask = BIT(7), .sdam_offset = 0x48 }, 1496 + { .base = 0xe900, .triled_mask = BIT(6), .sdam_offset = 0x56 }, 1497 + { .base = 0xea00, .triled_mask = BIT(5), .sdam_offset = 0x64 }, 1799 1498 { .base = 0xeb00 }, 1800 1499 }, 1801 1500 }; ··· 1811 1506 }; 1812 1507 1813 1508 static const struct of_device_id lpg_of_table[] = { 1509 + { .compatible = "qcom,pm660l-lpg", .data = &pm660l_lpg_data }, 1814 1510 { .compatible = "qcom,pm8150b-lpg", .data = &pm8150b_lpg_data }, 1815 1511 { .compatible = "qcom,pm8150l-lpg", .data = &pm8150l_lpg_data }, 1816 1512 { .compatible = "qcom,pm8350c-pwm", .data = &pm8350c_pwm_data },
+2
drivers/leds/trigger/ledtrig-audio.c
··· 63 63 64 64 MODULE_DESCRIPTION("LED trigger for audio mute control"); 65 65 MODULE_LICENSE("GPL v2"); 66 + MODULE_ALIAS("ledtrig:audio-mute"); 67 + MODULE_ALIAS("ledtrig:audio-micmute");
+1
drivers/leds/trigger/ledtrig-default-on.c
··· 28 28 MODULE_AUTHOR("Nick Forbes <nick.forbes@incepta.com>"); 29 29 MODULE_DESCRIPTION("Default-ON LED trigger"); 30 30 MODULE_LICENSE("GPL v2"); 31 + MODULE_ALIAS("ledtrig:default-on");
+92 -10
drivers/leds/trigger/ledtrig-netdev.c
··· 18 18 #include <linux/jiffies.h> 19 19 #include <linux/kernel.h> 20 20 #include <linux/leds.h> 21 + #include <linux/linkmode.h> 21 22 #include <linux/list.h> 22 23 #include <linux/module.h> 23 24 #include <linux/netdevice.h> 24 25 #include <linux/mutex.h> 26 + #include <linux/phy.h> 25 27 #include <linux/rtnetlink.h> 26 28 #include <linux/timer.h> 27 29 #include "../leds.h" ··· 67 65 68 66 unsigned long mode; 69 67 int link_speed; 68 + __ETHTOOL_DECLARE_LINK_MODE_MASK(supported_link_modes); 70 69 u8 duplex; 71 70 72 71 bool carrier_link_up; 73 72 bool hw_control; 74 73 }; 74 + 75 + static const struct attribute_group netdev_trig_link_speed_attrs_group; 75 76 76 77 static void set_baseline_state(struct led_netdev_data *trigger_data) 77 78 { ··· 223 218 struct ethtool_link_ksettings cmd; 224 219 225 220 trigger_data->carrier_link_up = netif_carrier_ok(trigger_data->net_dev); 226 - if (!trigger_data->carrier_link_up) 221 + 222 + if (__ethtool_get_link_ksettings(trigger_data->net_dev, &cmd)) 227 223 return; 228 224 229 - if (!__ethtool_get_link_ksettings(trigger_data->net_dev, &cmd)) { 225 + if (trigger_data->carrier_link_up) { 230 226 trigger_data->link_speed = cmd.base.speed; 231 227 trigger_data->duplex = cmd.base.duplex; 232 228 } 229 + 230 + /* 231 + * Have a local copy of the link speed supported to avoid rtnl lock every time 232 + * modes are refreshed on any change event 233 + */ 234 + linkmode_copy(trigger_data->supported_link_modes, cmd.link_modes.supported); 233 235 } 234 236 235 237 static ssize_t device_name_show(struct device *dev, ··· 289 277 290 278 trigger_data->last_activity = 0; 291 279 292 - set_baseline_state(trigger_data); 280 + /* Skip if we're called from netdev_trig_activate() and hw_control is true */ 281 + if (!trigger_data->hw_control || led_get_trigger_data(trigger_data->led_cdev)) 282 + set_baseline_state(trigger_data); 283 + 293 284 mutex_unlock(&trigger_data->lock); 294 285 rtnl_unlock(); 295 286 ··· 310 295 311 296 if (ret < 0) 312 297 return ret; 298 + 299 + /* Refresh link_speed visibility */ 300 + sysfs_update_group(&dev->kobj, &netdev_trig_link_speed_attrs_group); 301 + 313 302 return size; 314 303 } 315 304 ··· 477 458 478 459 static DEVICE_ATTR_RO(offloaded); 479 460 480 - static struct attribute *netdev_trig_attrs[] = { 481 - &dev_attr_device_name.attr, 482 - &dev_attr_link.attr, 461 + #define CHECK_LINK_MODE_ATTR(link_speed) \ 462 + do { \ 463 + if (attr == &dev_attr_link_##link_speed.attr && \ 464 + link_ksettings.base.speed == SPEED_##link_speed) \ 465 + return attr->mode; \ 466 + } while (0) 467 + 468 + static umode_t netdev_trig_link_speed_visible(struct kobject *kobj, 469 + struct attribute *attr, int n) 470 + { 471 + struct device *dev = kobj_to_dev(kobj); 472 + struct led_netdev_data *trigger_data; 473 + unsigned long *supported_link_modes; 474 + u32 mode; 475 + 476 + trigger_data = led_trigger_get_drvdata(dev); 477 + supported_link_modes = trigger_data->supported_link_modes; 478 + 479 + /* 480 + * Search in the supported link mode mask a matching supported mode. 481 + * Stop at the first matching entry as we care only to check if a particular 482 + * speed is supported and not the kind. 483 + */ 484 + for_each_set_bit(mode, supported_link_modes, __ETHTOOL_LINK_MODE_MASK_NBITS) { 485 + struct ethtool_link_ksettings link_ksettings; 486 + 487 + ethtool_params_from_link_mode(&link_ksettings, mode); 488 + 489 + CHECK_LINK_MODE_ATTR(10); 490 + CHECK_LINK_MODE_ATTR(100); 491 + CHECK_LINK_MODE_ATTR(1000); 492 + CHECK_LINK_MODE_ATTR(2500); 493 + CHECK_LINK_MODE_ATTR(5000); 494 + CHECK_LINK_MODE_ATTR(10000); 495 + } 496 + 497 + return 0; 498 + } 499 + 500 + static struct attribute *netdev_trig_link_speed_attrs[] = { 483 501 &dev_attr_link_10.attr, 484 502 &dev_attr_link_100.attr, 485 503 &dev_attr_link_1000.attr, 486 504 &dev_attr_link_2500.attr, 487 505 &dev_attr_link_5000.attr, 488 506 &dev_attr_link_10000.attr, 507 + NULL 508 + }; 509 + 510 + static const struct attribute_group netdev_trig_link_speed_attrs_group = { 511 + .attrs = netdev_trig_link_speed_attrs, 512 + .is_visible = netdev_trig_link_speed_visible, 513 + }; 514 + 515 + static struct attribute *netdev_trig_attrs[] = { 516 + &dev_attr_device_name.attr, 517 + &dev_attr_link.attr, 489 518 &dev_attr_full_duplex.attr, 490 519 &dev_attr_half_duplex.attr, 491 520 &dev_attr_rx.attr, ··· 542 475 &dev_attr_offloaded.attr, 543 476 NULL 544 477 }; 545 - ATTRIBUTE_GROUPS(netdev_trig); 478 + 479 + static const struct attribute_group netdev_trig_attrs_group = { 480 + .attrs = netdev_trig_attrs, 481 + }; 482 + 483 + static const struct attribute_group *netdev_trig_groups[] = { 484 + &netdev_trig_attrs_group, 485 + &netdev_trig_link_speed_attrs_group, 486 + NULL, 487 + }; 546 488 547 489 static int netdev_trig_notify(struct notifier_block *nb, 548 490 unsigned long evt, void *dv) ··· 560 484 netdev_notifier_info_to_dev((struct netdev_notifier_info *)dv); 561 485 struct led_netdev_data *trigger_data = 562 486 container_of(nb, struct led_netdev_data, notifier); 487 + struct led_classdev *led_cdev = trigger_data->led_cdev; 563 488 564 489 if (evt != NETDEV_UP && evt != NETDEV_DOWN && evt != NETDEV_CHANGE 565 490 && evt != NETDEV_REGISTER && evt != NETDEV_UNREGISTER ··· 581 504 trigger_data->duplex = DUPLEX_UNKNOWN; 582 505 switch (evt) { 583 506 case NETDEV_CHANGENAME: 584 - get_device_state(trigger_data); 585 - fallthrough; 586 507 case NETDEV_REGISTER: 587 508 dev_put(trigger_data->net_dev); 588 509 dev_hold(dev); 589 510 trigger_data->net_dev = dev; 511 + if (evt == NETDEV_CHANGENAME) 512 + get_device_state(trigger_data); 590 513 break; 591 514 case NETDEV_UNREGISTER: 592 515 dev_put(trigger_data->net_dev); ··· 595 518 case NETDEV_UP: 596 519 case NETDEV_CHANGE: 597 520 get_device_state(trigger_data); 521 + /* Refresh link_speed visibility */ 522 + if (evt == NETDEV_CHANGE) 523 + sysfs_update_group(&led_cdev->dev->kobj, 524 + &netdev_trig_link_speed_attrs_group); 598 525 break; 599 526 } 600 527 ··· 698 617 if (dev) { 699 618 const char *name = dev_name(dev); 700 619 701 - set_device_name(trigger_data, name, strlen(name)); 702 620 trigger_data->hw_control = true; 621 + set_device_name(trigger_data, name, strlen(name)); 703 622 704 623 rc = led_cdev->hw_control_get(led_cdev, &mode); 705 624 if (!rc) ··· 744 663 MODULE_AUTHOR("Oliver Jowett <oliver@opencloud.com>"); 745 664 MODULE_DESCRIPTION("Netdev LED trigger"); 746 665 MODULE_LICENSE("GPL v2"); 666 + MODULE_ALIAS("ledtrig:netdev");
+7 -16
drivers/leds/trigger/ledtrig-panic.c
··· 21 21 */ 22 22 static void led_trigger_set_panic(struct led_classdev *led_cdev) 23 23 { 24 - struct led_trigger *trig; 24 + if (led_cdev->trigger) 25 + list_del(&led_cdev->trig_list); 26 + list_add_tail(&led_cdev->trig_list, &trigger->led_cdevs); 25 27 26 - list_for_each_entry(trig, &trigger_list, next_trig) { 27 - if (strcmp("panic", trig->name)) 28 - continue; 29 - if (led_cdev->trigger) 30 - list_del(&led_cdev->trig_list); 31 - list_add_tail(&led_cdev->trig_list, &trig->led_cdevs); 28 + /* Avoid the delayed blink path */ 29 + led_cdev->blink_delay_on = 0; 30 + led_cdev->blink_delay_off = 0; 32 31 33 - /* Avoid the delayed blink path */ 34 - led_cdev->blink_delay_on = 0; 35 - led_cdev->blink_delay_off = 0; 36 - 37 - led_cdev->trigger = trig; 38 - if (trig->activate) 39 - trig->activate(led_cdev); 40 - break; 41 - } 32 + led_cdev->trigger = trigger; 42 33 } 43 34 44 35 static int led_trigger_panic_notifier(struct notifier_block *nb,
+1 -1
drivers/staging/greybus/Kconfig
··· 64 64 65 65 config GREYBUS_LIGHT 66 66 tristate "Greybus LED Class driver" 67 - depends on LEDS_CLASS 67 + depends on LEDS_CLASS_FLASH 68 68 help 69 69 Select this option if you have a device that follows the 70 70 Greybus LED Class specification.
-21
drivers/staging/greybus/light.c
··· 29 29 struct attribute_group *attr_group; 30 30 const struct attribute_group **attr_groups; 31 31 struct led_classdev *led; 32 - #if IS_REACHABLE(CONFIG_LEDS_CLASS_FLASH) 33 32 struct led_classdev_flash fled; 34 33 struct led_flash_setting intensity_uA; 35 34 struct led_flash_setting timeout_us; 36 - #else 37 - struct led_classdev cled; 38 - #endif 39 35 struct gb_light *light; 40 36 bool is_registered; 41 37 bool releasing; ··· 80 84 | GB_CHANNEL_MODE_INDICATOR)); 81 85 } 82 86 83 - #if IS_REACHABLE(CONFIG_LEDS_CLASS_FLASH) 84 87 static struct gb_channel *get_channel_from_cdev(struct led_classdev *cdev) 85 88 { 86 89 struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(cdev); ··· 148 153 149 154 return __gb_lights_flash_intensity_set(channel, intensity); 150 155 } 151 - #else 152 - static struct gb_channel *get_channel_from_cdev(struct led_classdev *cdev) 153 - { 154 - return container_of(cdev, struct gb_channel, cled); 155 - } 156 - 157 - static struct led_classdev *get_channel_cdev(struct gb_channel *channel) 158 - { 159 - return &channel->cled; 160 - } 161 - 162 - static int __gb_lights_flash_brightness_set(struct gb_channel *channel) 163 - { 164 - return 0; 165 - } 166 - #endif 167 156 168 157 static int gb_lights_color_set(struct gb_channel *channel, u32 color); 169 158 static int gb_lights_fade_set(struct gb_channel *channel);
+4
include/dt-bindings/leds/common.h
··· 100 100 #define LED_FUNCTION_TX "tx" 101 101 #define LED_FUNCTION_USB "usb" 102 102 #define LED_FUNCTION_WAN "wan" 103 + #define LED_FUNCTION_WAN_ONLINE "wan-online" 103 104 #define LED_FUNCTION_WLAN "wlan" 105 + #define LED_FUNCTION_WLAN_2GHZ "wlan-2ghz" 106 + #define LED_FUNCTION_WLAN_5GHZ "wlan-5ghz" 107 + #define LED_FUNCTION_WLAN_6GHZ "wlan-6ghz" 104 108 #define LED_FUNCTION_WPS "wps" 105 109 106 110 #endif /* __DT_BINDINGS_LEDS_H */
-24
include/linux/led-class-flash.h
··· 85 85 return container_of(lcdev, struct led_classdev_flash, led_cdev); 86 86 } 87 87 88 - #if IS_ENABLED(CONFIG_LEDS_CLASS_FLASH) 89 88 /** 90 89 * led_classdev_flash_register_ext - register a new object of LED class with 91 90 * init data and with support for flash LEDs ··· 114 115 115 116 void devm_led_classdev_flash_unregister(struct device *parent, 116 117 struct led_classdev_flash *fled_cdev); 117 - 118 - #else 119 - 120 - static inline int led_classdev_flash_register_ext(struct device *parent, 121 - struct led_classdev_flash *fled_cdev, 122 - struct led_init_data *init_data) 123 - { 124 - return 0; 125 - } 126 - 127 - static inline void led_classdev_flash_unregister(struct led_classdev_flash *fled_cdev) {}; 128 - static inline int devm_led_classdev_flash_register_ext(struct device *parent, 129 - struct led_classdev_flash *fled_cdev, 130 - struct led_init_data *init_data) 131 - { 132 - return 0; 133 - } 134 - 135 - static inline void devm_led_classdev_flash_unregister(struct device *parent, 136 - struct led_classdev_flash *fled_cdev) 137 - {}; 138 - 139 - #endif /* IS_ENABLED(CONFIG_LEDS_CLASS_FLASH) */ 140 118 141 119 static inline int led_classdev_flash_register(struct device *parent, 142 120 struct led_classdev_flash *fled_cdev)
-29
include/linux/led-class-multicolor.h
··· 30 30 return container_of(led_cdev, struct led_classdev_mc, led_cdev); 31 31 } 32 32 33 - #if IS_ENABLED(CONFIG_LEDS_CLASS_MULTICOLOR) 34 33 /** 35 34 * led_classdev_multicolor_register_ext - register a new object of led_classdev 36 35 * class with support for multicolor LEDs ··· 63 64 64 65 void devm_led_classdev_multicolor_unregister(struct device *parent, 65 66 struct led_classdev_mc *mcled_cdev); 66 - #else 67 - 68 - static inline int led_classdev_multicolor_register_ext(struct device *parent, 69 - struct led_classdev_mc *mcled_cdev, 70 - struct led_init_data *init_data) 71 - { 72 - return 0; 73 - } 74 - 75 - static inline void led_classdev_multicolor_unregister(struct led_classdev_mc *mcled_cdev) {}; 76 - static inline int led_mc_calc_color_components(struct led_classdev_mc *mcled_cdev, 77 - enum led_brightness brightness) 78 - { 79 - return 0; 80 - } 81 - 82 - static inline int devm_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 0; 87 - } 88 - 89 - static inline void devm_led_classdev_multicolor_unregister(struct device *parent, 90 - struct led_classdev_mc *mcled_cdev) 91 - {}; 92 - 93 - #endif /* IS_ENABLED(CONFIG_LEDS_CLASS_MULTICOLOR) */ 94 67 95 68 static inline int led_classdev_multicolor_register(struct device *parent, 96 69 struct led_classdev_mc *mcled_cdev)
+1 -20
include/linux/leds.h
··· 82 82 bool devname_mandatory; 83 83 }; 84 84 85 - #if IS_ENABLED(CONFIG_NEW_LEDS) 86 85 enum led_default_state led_init_default_state_get(struct fwnode_handle *fwnode); 87 - #else 88 - static inline enum led_default_state 89 - led_init_default_state_get(struct fwnode_handle *fwnode) 90 - { 91 - return LEDS_DEFSTATE_OFF; 92 - } 93 - #endif 94 86 95 87 struct led_hw_trigger_type { 96 88 int dummy; ··· 271 279 return led_classdev_register_ext(parent, led_cdev, NULL); 272 280 } 273 281 274 - #if IS_ENABLED(CONFIG_LEDS_CLASS) 275 282 int devm_led_classdev_register_ext(struct device *parent, 276 283 struct led_classdev *led_cdev, 277 284 struct led_init_data *init_data); 278 - #else 279 - static inline int 280 - devm_led_classdev_register_ext(struct device *parent, 281 - struct led_classdev *led_cdev, 282 - struct led_init_data *init_data) 283 - { 284 - return 0; 285 - } 286 - #endif 287 - 288 285 static inline int devm_led_classdev_register(struct device *parent, 289 286 struct led_classdev *led_cdev) 290 287 { ··· 639 658 gpio_blink_set_t gpio_blink_set; 640 659 }; 641 660 642 - #ifdef CONFIG_NEW_LEDS 661 + #ifdef CONFIG_LEDS_GPIO_REGISTER 643 662 struct platform_device *gpio_led_register_device( 644 663 int id, const struct gpio_led_platform_data *pdata); 645 664 #else