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

Pull LED updates from Lee Jones:
"Core Frameworks:
- Ensure seldom updated triggers have a brightness value before first
update

New Device Support:
- Add support for Simatic IPC Device BX_59A to IPC LEDs Core
- Add support for Qualcomm PMI8950 PWM to LPG Core

New Functionality:
- Add a bunch of new LED function identifiers
- Add support for High Resolution Timers in LED Trigger Patten

Fix-ups:
- Shift out Audio Trigger to the Sound subsystem
- Convert suitable calls to devm_* managed resources
- Device Tree binding adaptions/conversions/creation
- Remove superfluous code/variables/attributes and simplify overall
- Use/convert to new/better APIs/helpers/MACROs instead of
hand-rolling implementations

Bug Fixes:
- Repair enabling Torch Mode from V4L2 on the second LED
- Ensure PWM is disabled when suspending"

* tag 'leds-next-6.10' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/leds: (28 commits)
leds: mt6370: Remove unused field 'reg_cfgs' from 'struct mt6370_priv'
leds: lp50xx: Remove unused field 'num_of_banked_leds' from 'struct lp50xx'
leds: lp50xx: Remove unused field 'bank_modules' from 'struct lp50xx_led'
leds: aat1290: Remove unused field 'torch_brightness' from 'struct aat1290_led'
leds: sun50i-a100: Use match_string() helper to simplify the code
leds: pwm: Disable PWM when going to suspend
leds: trigger: pattern: Add support for hrtimer
leds: mt6360: Fix the second LED can not enable torch mode by V4L2
dt-bindings: leds: leds-qcom-lpg: Add support for PMI8950 PWM
leds: qcom-lpg: Add support for PMI8950 PWM
leds: apu: Remove duplicate DMI lookup data
leds: trigger: netdev: Remove not needed call to led_set_brightness in deactivate
dt-bindings: leds: Add LED_FUNCTION_SPEED_* for link speed on LAN/WAN
dt-bindings: leds: Add LED_FUNCTION_MOBILE for mobile network
leds: simatic-ipc-leds-gpio: Add support for module BX-59A
dt-bindings: leds: qcom-lpg: Document PM6150L compatible
dt-bindings: leds: pca963x: Convert text bindings to YAML
leds: an30259a: Use devm_mutex_init() for mutex initialization
leds: mlxreg: Use devm_mutex_init() for mutex initialization
leds: nic78bx: Use devm API to cleanup module's resources
...

+501 -275
+10
Documentation/ABI/testing/sysfs-class-led-trigger-pattern
··· 12 The exact format is described in: 13 Documentation/devicetree/bindings/leds/leds-trigger-pattern.txt 14 15 What: /sys/class/leds/<led>/hw_pattern 16 Date: September 2018 17 KernelVersion: 4.20
··· 12 The exact format is described in: 13 Documentation/devicetree/bindings/leds/leds-trigger-pattern.txt 14 15 + What: /sys/class/leds/<led>/hr_pattern 16 + Date: April 2024 17 + Description: 18 + Specify a software pattern for the LED, that supports altering 19 + the brightness for the specified duration with one software 20 + timer. It can do gradual dimming and step change of brightness. 21 + 22 + Unlike the /sys/class/leds/<led>/pattern, this attribute runs 23 + a pattern on high-resolution timer (hrtimer). 24 + 25 What: /sys/class/leds/<led>/hw_pattern 26 Date: September 2018 27 KernelVersion: 4.20
+6 -2
Documentation/devicetree/bindings/leds/leds-qcom-lpg.yaml
··· 27 - qcom,pm8994-lpg 28 - qcom,pmc8180c-lpg 29 - qcom,pmi632-lpg 30 - qcom,pmi8994-lpg 31 - qcom,pmi8998-lpg 32 - qcom,pmk8550-pwm 33 - items: 34 - enum: 35 - qcom,pm8550-pwm ··· 147 - qcom,pm8941-lpg 148 - qcom,pm8994-lpg 149 - qcom,pmc8180c-lpg 150 - qcom,pmi8994-lpg 151 - qcom,pmi8998-lpg 152 - qcom,pmk8550-pwm ··· 296 label = "blue"; 297 }; 298 }; 299 - 300 - ...
··· 27 - qcom,pm8994-lpg 28 - qcom,pmc8180c-lpg 29 - qcom,pmi632-lpg 30 + - qcom,pmi8950-pwm 31 - qcom,pmi8994-lpg 32 - qcom,pmi8998-lpg 33 - qcom,pmk8550-pwm 34 + - items: 35 + - enum: 36 + - qcom,pm6150l-lpg 37 + - const: qcom,pm8150l-lpg 38 - items: 39 - enum: 40 - qcom,pm8550-pwm ··· 142 - qcom,pm8941-lpg 143 - qcom,pm8994-lpg 144 - qcom,pmc8180c-lpg 145 + - qcom,pmi8950-pwm 146 - qcom,pmi8994-lpg 147 - qcom,pmi8998-lpg 148 - qcom,pmk8550-pwm ··· 290 label = "blue"; 291 }; 292 };
+140
Documentation/devicetree/bindings/leds/nxp,pca963x.yaml
···
··· 1 + # SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/leds/nxp,pca963x.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: NXP PCA963x LED controllers 8 + 9 + maintainers: 10 + - Laurent Pinchart <laurent.pinchart@ideasonboard.com> 11 + 12 + description: | 13 + The NXP PCA963x are I2C-controlled LED drivers optimized for 14 + Red/Green/Blue/Amber (RGBA) color mixing applications. Each LED is 15 + individually controllable and has its own PWM controller. 16 + 17 + Datasheets are available at 18 + 19 + - https://www.nxp.com/docs/en/data-sheet/PCA9632.pdf 20 + - https://www.nxp.com/docs/en/data-sheet/PCA9633.pdf 21 + - https://www.nxp.com/docs/en/data-sheet/PCA9634.pdf 22 + - https://www.nxp.com/docs/en/data-sheet/PCA9635.pdf 23 + 24 + properties: 25 + compatible: 26 + enum: 27 + - nxp,pca9632 28 + - nxp,pca9633 29 + - nxp,pca9634 30 + - nxp,pca9635 31 + 32 + reg: 33 + maxItems: 1 34 + 35 + "#address-cells": 36 + const: 1 37 + 38 + "#size-cells": 39 + const: 0 40 + 41 + nxp,hw-blink: 42 + type: boolean 43 + description: 44 + Use hardware blinking instead of software blinking 45 + 46 + nxp,inverted-out: 47 + type: boolean 48 + description: 49 + Invert the polarity of the generated PWM. 50 + 51 + nxp,period-scale: 52 + $ref: /schemas/types.yaml#/definitions/uint32 53 + description: 54 + In some configurations, the chip blinks faster than expected. This 55 + parameter provides a scaling ratio (fixed point, decimal divided by 1000) 56 + to compensate, e.g. 1300=1.3x and 750=0.75x. 57 + 58 + nxp,totem-pole: 59 + type: boolean 60 + description: 61 + Use totem pole (push-pull) instead of open-drain (pca9632 defaults to 62 + open-drain, newer chips to totem pole). 63 + 64 + patternProperties: 65 + "^led@[0-9a-f]+$": 66 + type: object 67 + $ref: common.yaml# 68 + unevaluatedProperties: false 69 + 70 + properties: 71 + reg: 72 + minimum: 0 73 + 74 + required: 75 + - reg 76 + 77 + allOf: 78 + - if: 79 + properties: 80 + compatible: 81 + contains: 82 + enum: 83 + - nxp,pca9632 84 + - nxp,pca9633 85 + then: 86 + patternProperties: 87 + "^led@[0-9a-f]+$": 88 + properties: 89 + reg: 90 + maximum: 3 91 + else: 92 + patternProperties: 93 + "^led@[0-9a-f]+$": 94 + properties: 95 + reg: 96 + maximum: 7 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@62 { 109 + compatible = "nxp,pca9632"; 110 + reg = <0x62>; 111 + #address-cells = <1>; 112 + #size-cells = <0>; 113 + 114 + led@0 { 115 + reg = <0>; 116 + color = <LED_COLOR_ID_RED>; 117 + function = LED_FUNCTION_STATUS; 118 + }; 119 + 120 + led@1 { 121 + reg = <1>; 122 + color = <LED_COLOR_ID_GREEN>; 123 + function = LED_FUNCTION_STATUS; 124 + }; 125 + 126 + led@2 { 127 + reg = <2>; 128 + color = <LED_COLOR_ID_BLUE>; 129 + function = LED_FUNCTION_STATUS; 130 + }; 131 + 132 + led@3 { 133 + reg = <3>; 134 + color = <LED_COLOR_ID_WHITE>; 135 + function = LED_FUNCTION_STATUS; 136 + }; 137 + }; 138 + }; 139 + 140 + ...
-52
Documentation/devicetree/bindings/leds/pca963x.txt
··· 1 - LEDs connected to pca9632, pca9633 or pca9634 2 - 3 - Required properties: 4 - - compatible : should be : "nxp,pca9632", "nxp,pca9633", "nxp,pca9634" or "nxp,pca9635" 5 - 6 - Optional properties: 7 - - nxp,totem-pole : use totem pole (push-pull) instead of open-drain (pca9632 defaults 8 - to open-drain, newer chips to totem pole) 9 - - nxp,hw-blink : use hardware blinking instead of software blinking 10 - - nxp,period-scale : In some configurations, the chip blinks faster than expected. 11 - This parameter provides a scaling ratio (fixed point, decimal divided 12 - by 1000) to compensate, e.g. 1300=1.3x and 750=0.75x. 13 - - nxp,inverted-out: invert the polarity of the generated PWM 14 - 15 - Each led is represented as a sub-node of the nxp,pca963x device. 16 - 17 - LED sub-node properties: 18 - - label : (optional) see Documentation/devicetree/bindings/leds/common.txt 19 - - reg : number of LED line (could be from 0 to 3 in pca9632 or pca9633, 20 - 0 to 7 in pca9634, or 0 to 15 in pca9635) 21 - - linux,default-trigger : (optional) 22 - see Documentation/devicetree/bindings/leds/common.txt 23 - 24 - Examples: 25 - 26 - pca9632: pca9632 { 27 - compatible = "nxp,pca9632"; 28 - #address-cells = <1>; 29 - #size-cells = <0>; 30 - reg = <0x62>; 31 - 32 - red@0 { 33 - label = "red"; 34 - reg = <0>; 35 - linux,default-trigger = "none"; 36 - }; 37 - green@1 { 38 - label = "green"; 39 - reg = <1>; 40 - linux,default-trigger = "none"; 41 - }; 42 - blue@2 { 43 - label = "blue"; 44 - reg = <2>; 45 - linux,default-trigger = "none"; 46 - }; 47 - unused@3 { 48 - label = "unused"; 49 - reg = <3>; 50 - linux,default-trigger = "none"; 51 - }; 52 - };
···
-1
arch/mips/configs/ci20_defconfig
··· 152 CONFIG_LEDS_TRIGGER_PANIC=y 153 CONFIG_LEDS_TRIGGER_NETDEV=y 154 CONFIG_LEDS_TRIGGER_PATTERN=y 155 - CONFIG_LEDS_TRIGGER_AUDIO=y 156 CONFIG_RTC_CLASS=y 157 CONFIG_RTC_DRV_JZ4740=y 158 CONFIG_DMADEVICES=y
··· 152 CONFIG_LEDS_TRIGGER_PANIC=y 153 CONFIG_LEDS_TRIGGER_NETDEV=y 154 CONFIG_LEDS_TRIGGER_PATTERN=y 155 CONFIG_RTC_CLASS=y 156 CONFIG_RTC_DRV_JZ4740=y 157 CONFIG_DMADEVICES=y
-2
drivers/leds/flash/leds-aat1290.c
··· 77 int *mm_current_scale; 78 /* device mode */ 79 bool movie_mode; 80 - /* brightness cache */ 81 - unsigned int torch_brightness; 82 }; 83 84 static struct aat1290_led *fled_cdev_to_led(
··· 77 int *mm_current_scale; 78 /* device mode */ 79 bool movie_mode; 80 }; 81 82 static struct aat1290_led *fled_cdev_to_led(
+11 -1
drivers/leds/flash/leds-mt6360.c
··· 241 u32 enable_mask = MT6360_STROBEN_MASK | MT6360_FLCSEN_MASK(led->led_no); 242 u32 val = state ? MT6360_FLCSEN_MASK(led->led_no) : 0; 243 u32 prev = priv->fled_strobe_used, curr; 244 - int ret; 245 246 mutex_lock(&priv->lock); 247 248 /* 249 * Only one set of flash control logic, use the flag to avoid torch is
··· 241 u32 enable_mask = MT6360_STROBEN_MASK | MT6360_FLCSEN_MASK(led->led_no); 242 u32 val = state ? MT6360_FLCSEN_MASK(led->led_no) : 0; 243 u32 prev = priv->fled_strobe_used, curr; 244 + int ret = 0; 245 246 mutex_lock(&priv->lock); 247 + 248 + /* 249 + * If the state of the upcoming change is the same as the current LED 250 + * device state, then skip the subsequent code to avoid conflict 251 + * with the flow of turning on LED torch mode in V4L2. 252 + */ 253 + if (state == !!(BIT(led->led_no) & prev)) { 254 + dev_info(lcdev->dev, "No change in strobe state [0x%x]\n", prev); 255 + goto unlock; 256 + } 257 258 /* 259 * Only one set of flash control logic, use the flag to avoid torch is
+4 -2
drivers/leds/led-triggers.c
··· 194 spin_unlock(&trig->leddev_list_lock); 195 led_cdev->trigger = trig; 196 197 if (trig->activate) 198 ret = trig->activate(led_cdev); 199 else 200 - ret = 0; 201 - 202 if (ret) 203 goto err_activate; 204 ··· 386 387 if (!trig) 388 return; 389 390 rcu_read_lock(); 391 list_for_each_entry_rcu(led_cdev, &trig->led_cdevs, trig_list)
··· 194 spin_unlock(&trig->leddev_list_lock); 195 led_cdev->trigger = trig; 196 197 + ret = 0; 198 if (trig->activate) 199 ret = trig->activate(led_cdev); 200 else 201 + led_set_brightness(led_cdev, trig->brightness); 202 if (ret) 203 goto err_activate; 204 ··· 386 387 if (!trig) 388 return; 389 + 390 + trig->brightness = brightness; 391 392 rcu_read_lock(); 393 list_for_each_entry_rcu(led_cdev, &trig->led_cdevs, trig_list)
+4 -10
drivers/leds/leds-an30259a.c
··· 283 if (err < 0) 284 return err; 285 286 - mutex_init(&chip->mutex); 287 chip->client = client; 288 i2c_set_clientdata(client, chip); 289 ··· 320 return 0; 321 322 exit: 323 - mutex_destroy(&chip->mutex); 324 return err; 325 - } 326 - 327 - static void an30259a_remove(struct i2c_client *client) 328 - { 329 - struct an30259a *chip = i2c_get_clientdata(client); 330 - 331 - mutex_destroy(&chip->mutex); 332 } 333 334 static const struct of_device_id an30259a_match_table[] = { ··· 342 .of_match_table = an30259a_match_table, 343 }, 344 .probe = an30259a_probe, 345 - .remove = an30259a_remove, 346 .id_table = an30259a_id, 347 }; 348
··· 283 if (err < 0) 284 return err; 285 286 + err = devm_mutex_init(&client->dev, &chip->mutex); 287 + if (err) 288 + return err; 289 + 290 chip->client = client; 291 i2c_set_clientdata(client, chip); 292 ··· 317 return 0; 318 319 exit: 320 return err; 321 } 322 323 static const struct of_device_id an30259a_match_table[] = { ··· 347 .of_match_table = an30259a_match_table, 348 }, 349 .probe = an30259a_probe, 350 .id_table = an30259a_id, 351 }; 352
+1 -2
drivers/leds/leds-apu.c
··· 181 struct platform_device *pdev; 182 int err; 183 184 - if (!(dmi_match(DMI_SYS_VENDOR, "PC Engines") && 185 - (dmi_match(DMI_PRODUCT_NAME, "APU") || dmi_match(DMI_PRODUCT_NAME, "apu1")))) { 186 pr_err("No PC Engines APUv1 board detected. For APUv2,3 support, enable CONFIG_PCENGINES_APU2\n"); 187 return -ENODEV; 188 }
··· 181 struct platform_device *pdev; 182 int err; 183 184 + if (!dmi_check_system(apu_led_dmi_table)) { 185 pr_err("No PC Engines APUv1 board detected. For APUv2,3 support, enable CONFIG_PCENGINES_APU2\n"); 186 return -ENODEV; 187 }
+21 -11
drivers/leds/leds-aw200xx.c
··· 530 .disable_locking = true, 531 }; 532 533 static int aw200xx_probe(struct i2c_client *client) 534 { 535 const struct aw200xx_chipdef *cdef; ··· 578 579 aw200xx_enable(chip); 580 581 ret = aw200xx_chip_check(chip); 582 if (ret) 583 return ret; 584 585 - mutex_init(&chip->mutex); 586 587 /* Need a lock now since after call aw200xx_probe_fw, sysfs nodes created */ 588 mutex_lock(&chip->mutex); 589 590 ret = aw200xx_chip_reset(chip); 591 if (ret) 592 goto out_unlock; 593 ··· 613 614 mutex_unlock(&chip->mutex); 615 return ret; 616 - } 617 - 618 - static void aw200xx_remove(struct i2c_client *client) 619 - { 620 - struct aw200xx *chip = i2c_get_clientdata(client); 621 - 622 - aw200xx_chip_reset(chip); 623 - aw200xx_disable(chip); 624 - mutex_destroy(&chip->mutex); 625 } 626 627 static const struct aw200xx_chipdef aw20036_cdef = { ··· 663 .of_match_table = aw200xx_match_table, 664 }, 665 .probe = aw200xx_probe, 666 - .remove = aw200xx_remove, 667 .id_table = aw200xx_id, 668 }; 669 module_i2c_driver(aw200xx_driver);
··· 530 .disable_locking = true, 531 }; 532 533 + static void aw200xx_chip_reset_action(void *data) 534 + { 535 + aw200xx_chip_reset(data); 536 + } 537 + 538 + static void aw200xx_disable_action(void *data) 539 + { 540 + aw200xx_disable(data); 541 + } 542 + 543 static int aw200xx_probe(struct i2c_client *client) 544 { 545 const struct aw200xx_chipdef *cdef; ··· 568 569 aw200xx_enable(chip); 570 571 + ret = devm_add_action(&client->dev, aw200xx_disable_action, chip); 572 + if (ret) 573 + return ret; 574 + 575 ret = aw200xx_chip_check(chip); 576 if (ret) 577 return ret; 578 579 + ret = devm_mutex_init(&client->dev, &chip->mutex); 580 + if (ret) 581 + return ret; 582 583 /* Need a lock now since after call aw200xx_probe_fw, sysfs nodes created */ 584 mutex_lock(&chip->mutex); 585 586 ret = aw200xx_chip_reset(chip); 587 + if (ret) 588 + goto out_unlock; 589 + 590 + ret = devm_add_action(&client->dev, aw200xx_chip_reset_action, chip); 591 if (ret) 592 goto out_unlock; 593 ··· 593 594 mutex_unlock(&chip->mutex); 595 return ret; 596 } 597 598 static const struct aw200xx_chipdef aw20036_cdef = { ··· 652 .of_match_table = aw200xx_match_table, 653 }, 654 .probe = aw200xx_probe, 655 .id_table = aw200xx_id, 656 }; 657 module_i2c_driver(aw200xx_driver);
+13 -12
drivers/leds/leds-aw2013.c
··· 320 return 0; 321 } 322 323 static const struct regmap_config aw2013_regmap_config = { 324 .reg_bits = 8, 325 .val_bits = 8, ··· 341 if (!chip) 342 return -ENOMEM; 343 344 - mutex_init(&chip->mutex); 345 mutex_lock(&chip->mutex); 346 347 chip->client = client; ··· 392 goto error_reg; 393 } 394 395 ret = aw2013_probe_dt(chip); 396 if (ret < 0) 397 goto error_reg; ··· 418 419 error: 420 mutex_unlock(&chip->mutex); 421 - mutex_destroy(&chip->mutex); 422 return ret; 423 - } 424 - 425 - static void aw2013_remove(struct i2c_client *client) 426 - { 427 - struct aw2013 *chip = i2c_get_clientdata(client); 428 - 429 - aw2013_chip_disable(chip); 430 - 431 - mutex_destroy(&chip->mutex); 432 } 433 434 static const struct of_device_id aw2013_match_table[] = { ··· 434 .of_match_table = aw2013_match_table, 435 }, 436 .probe = aw2013_probe, 437 - .remove = aw2013_remove, 438 }; 439 440 module_i2c_driver(aw2013_driver);
··· 320 return 0; 321 } 322 323 + static void aw2013_chip_disable_action(void *data) 324 + { 325 + aw2013_chip_disable(data); 326 + } 327 + 328 static const struct regmap_config aw2013_regmap_config = { 329 .reg_bits = 8, 330 .val_bits = 8, ··· 336 if (!chip) 337 return -ENOMEM; 338 339 + ret = devm_mutex_init(&client->dev, &chip->mutex); 340 + if (ret) 341 + return ret; 342 + 343 mutex_lock(&chip->mutex); 344 345 chip->client = client; ··· 384 goto error_reg; 385 } 386 387 + ret = devm_add_action(&client->dev, aw2013_chip_disable_action, chip); 388 + if (ret) 389 + goto error_reg; 390 + 391 ret = aw2013_probe_dt(chip); 392 if (ret < 0) 393 goto error_reg; ··· 406 407 error: 408 mutex_unlock(&chip->mutex); 409 return ret; 410 } 411 412 static const struct of_device_id aw2013_match_table[] = { ··· 432 .of_match_table = aw2013_match_table, 433 }, 434 .probe = aw2013_probe, 435 }; 436 437 module_i2c_driver(aw2013_driver);
+17 -12
drivers/leds/leds-lm3532.c
··· 542 return ret; 543 } 544 545 static int lm3532_parse_node(struct lm3532_data *priv) 546 { 547 struct fwnode_handle *child = NULL; ··· 562 "enable", GPIOD_OUT_LOW); 563 if (IS_ERR(priv->enable_gpio)) 564 priv->enable_gpio = NULL; 565 566 priv->regulator = devm_regulator_get(&priv->client->dev, "vin"); 567 if (IS_ERR(priv->regulator)) ··· 704 return ret; 705 } 706 707 - mutex_init(&drvdata->lock); 708 i2c_set_clientdata(client, drvdata); 709 710 ret = lm3532_parse_node(drvdata); ··· 717 } 718 719 return ret; 720 - } 721 - 722 - static void lm3532_remove(struct i2c_client *client) 723 - { 724 - struct lm3532_data *drvdata = i2c_get_clientdata(client); 725 - 726 - mutex_destroy(&drvdata->lock); 727 - 728 - if (drvdata->enable_gpio) 729 - gpiod_direction_output(drvdata->enable_gpio, 0); 730 } 731 732 static const struct of_device_id of_lm3532_leds_match[] = { ··· 733 734 static struct i2c_driver lm3532_i2c_driver = { 735 .probe = lm3532_probe, 736 - .remove = lm3532_remove, 737 .id_table = lm3532_id, 738 .driver = { 739 .name = LM3532_NAME,
··· 542 return ret; 543 } 544 545 + static void gpio_set_low_action(void *data) 546 + { 547 + struct lm3532_data *priv = data; 548 + 549 + gpiod_direction_output(priv->enable_gpio, 0); 550 + } 551 + 552 static int lm3532_parse_node(struct lm3532_data *priv) 553 { 554 struct fwnode_handle *child = NULL; ··· 555 "enable", GPIOD_OUT_LOW); 556 if (IS_ERR(priv->enable_gpio)) 557 priv->enable_gpio = NULL; 558 + 559 + if (priv->enable_gpio) { 560 + ret = devm_add_action(&priv->client->dev, gpio_set_low_action, priv); 561 + if (ret) 562 + return ret; 563 + } 564 565 priv->regulator = devm_regulator_get(&priv->client->dev, "vin"); 566 if (IS_ERR(priv->regulator)) ··· 691 return ret; 692 } 693 694 + ret = devm_mutex_init(&client->dev, &drvdata->lock); 695 + if (ret) 696 + return ret; 697 + 698 i2c_set_clientdata(client, drvdata); 699 700 ret = lm3532_parse_node(drvdata); ··· 701 } 702 703 return ret; 704 } 705 706 static const struct of_device_id of_lm3532_leds_match[] = { ··· 727 728 static struct i2c_driver lm3532_i2c_driver = { 729 .probe = lm3532_probe, 730 .id_table = lm3532_id, 731 .driver = { 732 .name = LM3532_NAME,
+11 -10
drivers/leds/leds-lp3952.c
··· 207 .cache_type = REGCACHE_MAPLE, 208 }; 209 210 static int lp3952_probe(struct i2c_client *client) 211 { 212 int status; ··· 232 dev_err(&client->dev, "Failed to enable gpio: %d\n", status); 233 return status; 234 } 235 236 priv->regmap = devm_regmap_init_i2c(client, &lp3952_regmap); 237 if (IS_ERR(priv->regmap)) { ··· 265 return 0; 266 } 267 268 - static void lp3952_remove(struct i2c_client *client) 269 - { 270 - struct lp3952_led_array *priv; 271 - 272 - priv = i2c_get_clientdata(client); 273 - lp3952_on_off(priv, LP3952_LED_ALL, false); 274 - gpiod_set_value(priv->enable_gpio, 0); 275 - } 276 - 277 static const struct i2c_device_id lp3952_id[] = { 278 {LP3952_NAME, 0}, 279 {} ··· 276 .name = LP3952_NAME, 277 }, 278 .probe = lp3952_probe, 279 - .remove = lp3952_remove, 280 .id_table = lp3952_id, 281 }; 282
··· 207 .cache_type = REGCACHE_MAPLE, 208 }; 209 210 + static void gpio_set_low_action(void *data) 211 + { 212 + struct lp3952_led_array *priv = data; 213 + 214 + gpiod_set_value(priv->enable_gpio, 0); 215 + } 216 + 217 static int lp3952_probe(struct i2c_client *client) 218 { 219 int status; ··· 225 dev_err(&client->dev, "Failed to enable gpio: %d\n", status); 226 return status; 227 } 228 + 229 + status = devm_add_action(&client->dev, gpio_set_low_action, priv); 230 + if (status) 231 + return status; 232 233 priv->regmap = devm_regmap_init_i2c(client, &lp3952_regmap); 234 if (IS_ERR(priv->regmap)) { ··· 254 return 0; 255 } 256 257 static const struct i2c_device_id lp3952_id[] = { 258 {LP3952_NAME, 0}, 259 {} ··· 274 .name = LP3952_NAME, 275 }, 276 .probe = lp3952_probe, 277 .id_table = lp3952_id, 278 }; 279
-5
drivers/leds/leds-lp50xx.c
··· 265 struct lp50xx_led { 266 struct led_classdev_mc mc_cdev; 267 struct lp50xx *priv; 268 - unsigned long bank_modules; 269 u8 ctrl_bank_enabled; 270 int led_number; 271 }; ··· 278 * @dev: pointer to the devices device struct 279 * @lock: lock for reading/writing the device 280 * @chip_info: chip specific information (ie num_leds) 281 - * @num_of_banked_leds: holds the number of banked LEDs 282 * @leds: array of LED strings 283 */ 284 struct lp50xx { ··· 288 struct device *dev; 289 struct mutex lock; 290 const struct lp50xx_chip_info *chip_info; 291 - int num_of_banked_leds; 292 293 /* This needs to be at the end of the struct */ 294 struct lp50xx_led leds[]; ··· 400 dev_err(priv->dev, "reg property is invalid\n"); 401 return -EINVAL; 402 } 403 - 404 - priv->num_of_banked_leds = num_leds; 405 406 ret = fwnode_property_read_u32_array(child, "reg", led_banks, num_leds); 407 if (ret) {
··· 265 struct lp50xx_led { 266 struct led_classdev_mc mc_cdev; 267 struct lp50xx *priv; 268 u8 ctrl_bank_enabled; 269 int led_number; 270 }; ··· 279 * @dev: pointer to the devices device struct 280 * @lock: lock for reading/writing the device 281 * @chip_info: chip specific information (ie num_leds) 282 * @leds: array of LED strings 283 */ 284 struct lp50xx { ··· 290 struct device *dev; 291 struct mutex lock; 292 const struct lp50xx_chip_info *chip_info; 293 294 /* This needs to be at the end of the struct */ 295 struct lp50xx_led leds[]; ··· 403 dev_err(priv->dev, "reg property is invalid\n"); 404 return -EINVAL; 405 } 406 407 ret = fwnode_property_read_u32_array(child, "reg", led_banks, num_leds); 408 if (ret) {
+5 -9
drivers/leds/leds-mlxreg.c
··· 256 { 257 struct mlxreg_core_platform_data *led_pdata; 258 struct mlxreg_led_priv_data *priv; 259 260 led_pdata = dev_get_platdata(&pdev->dev); 261 if (!led_pdata) { ··· 268 if (!priv) 269 return -ENOMEM; 270 271 - mutex_init(&priv->access_lock); 272 priv->pdev = pdev; 273 priv->pdata = led_pdata; 274 275 return mlxreg_led_config(priv); 276 - } 277 - 278 - static void mlxreg_led_remove(struct platform_device *pdev) 279 - { 280 - struct mlxreg_led_priv_data *priv = dev_get_drvdata(&pdev->dev); 281 - 282 - mutex_destroy(&priv->access_lock); 283 } 284 285 static struct platform_driver mlxreg_led_driver = { ··· 283 .name = "leds-mlxreg", 284 }, 285 .probe = mlxreg_led_probe, 286 - .remove_new = mlxreg_led_remove, 287 }; 288 289 module_platform_driver(mlxreg_led_driver);
··· 256 { 257 struct mlxreg_core_platform_data *led_pdata; 258 struct mlxreg_led_priv_data *priv; 259 + int err; 260 261 led_pdata = dev_get_platdata(&pdev->dev); 262 if (!led_pdata) { ··· 267 if (!priv) 268 return -ENOMEM; 269 270 + err = devm_mutex_init(&pdev->dev, &priv->access_lock); 271 + if (err) 272 + return err; 273 + 274 priv->pdev = pdev; 275 priv->pdata = led_pdata; 276 277 return mlxreg_led_config(priv); 278 } 279 280 static struct platform_driver mlxreg_led_driver = { ··· 286 .name = "leds-mlxreg", 287 }, 288 .probe = mlxreg_led_probe, 289 }; 290 291 module_platform_driver(mlxreg_led_driver);
+13 -10
drivers/leds/leds-nic78bx.c
··· 118 } 119 }; 120 121 static int nic78bx_probe(struct platform_device *pdev) 122 { 123 struct device *dev = &pdev->dev; ··· 161 led_data->io_base = io_rc->start; 162 spin_lock_init(&led_data->lock); 163 164 for (i = 0; i < ARRAY_SIZE(nic78bx_leds); i++) { 165 nic78bx_leds[i].data = led_data; 166 ··· 180 return ret; 181 } 182 183 - static void nic78bx_remove(struct platform_device *pdev) 184 - { 185 - struct nic78bx_led_data *led_data = platform_get_drvdata(pdev); 186 - 187 - /* Lock LED register */ 188 - outb(NIC78BX_LOCK_VALUE, 189 - led_data->io_base + NIC78BX_LOCK_REG_OFFSET); 190 - } 191 - 192 static const struct acpi_device_id led_device_ids[] = { 193 {"NIC78B3", 0}, 194 {"", 0}, ··· 188 189 static struct platform_driver led_driver = { 190 .probe = nic78bx_probe, 191 - .remove_new = nic78bx_remove, 192 .driver = { 193 .name = KBUILD_MODNAME, 194 .acpi_match_table = ACPI_PTR(led_device_ids),
··· 118 } 119 }; 120 121 + static void lock_led_reg_action(void *data) 122 + { 123 + struct nic78bx_led_data *led_data = data; 124 + 125 + /* Lock LED register */ 126 + outb(NIC78BX_LOCK_VALUE, 127 + led_data->io_base + NIC78BX_LOCK_REG_OFFSET); 128 + } 129 + 130 static int nic78bx_probe(struct platform_device *pdev) 131 { 132 struct device *dev = &pdev->dev; ··· 152 led_data->io_base = io_rc->start; 153 spin_lock_init(&led_data->lock); 154 155 + ret = devm_add_action(dev, lock_led_reg_action, led_data); 156 + if (ret) 157 + return ret; 158 + 159 for (i = 0; i < ARRAY_SIZE(nic78bx_leds); i++) { 160 nic78bx_leds[i].data = led_data; 161 ··· 167 return ret; 168 } 169 170 static const struct acpi_device_id led_device_ids[] = { 171 {"NIC78B3", 0}, 172 {"", 0}, ··· 184 185 static struct platform_driver led_driver = { 186 .probe = nic78bx_probe, 187 .driver = { 188 .name = KBUILD_MODNAME, 189 .acpi_match_table = ACPI_PTR(led_device_ids),
+7 -1
drivers/leds/leds-pwm.c
··· 53 duty = led_dat->pwmstate.period - duty; 54 55 led_dat->pwmstate.duty_cycle = duty; 56 - led_dat->pwmstate.enabled = true; 57 return pwm_apply_might_sleep(led_dat->pwm, &led_dat->pwmstate); 58 } 59
··· 53 duty = led_dat->pwmstate.period - duty; 54 55 led_dat->pwmstate.duty_cycle = duty; 56 + /* 57 + * Disabling a PWM doesn't guarantee that it emits the inactive level. 58 + * So keep it on. Only for suspending the PWM should be disabled because 59 + * otherwise it refuses to suspend. The possible downside is that the 60 + * LED might stay (or even go) on. 61 + */ 62 + led_dat->pwmstate.enabled = !(led_cdev->flags & LED_SUSPENDED); 63 return pwm_apply_might_sleep(led_dat->pwm, &led_dat->pwmstate); 64 } 65
+6 -8
drivers/leds/leds-sun50i-a100.c
··· 252 struct sun50i_a100_ledc *priv) 253 { 254 const char *format = "grb"; 255 - u32 i; 256 257 device_property_read_string(dev, "allwinner,pixel-format", &format); 258 259 - for (i = 0; i < ARRAY_SIZE(sun50i_a100_ledc_formats); i++) { 260 - if (!strcmp(format, sun50i_a100_ledc_formats[i])) { 261 - priv->format = i; 262 - return 0; 263 - } 264 - } 265 266 - return dev_err_probe(dev, -EINVAL, "Bad pixel format '%s'\n", format); 267 } 268 269 static void sun50i_a100_ledc_set_format(struct sun50i_a100_ledc *priv)
··· 252 struct sun50i_a100_ledc *priv) 253 { 254 const char *format = "grb"; 255 + int i; 256 257 device_property_read_string(dev, "allwinner,pixel-format", &format); 258 259 + i = match_string(sun50i_a100_ledc_formats, ARRAY_SIZE(sun50i_a100_ledc_formats), format); 260 + if (i < 0) 261 + return dev_err_probe(dev, i, "Bad pixel format '%s'\n", format); 262 263 + priv->format = i; 264 + return 0; 265 } 266 267 static void sun50i_a100_ledc_set_format(struct sun50i_a100_ledc *priv)
-1
drivers/leds/rgb/leds-mt6370-rgb.c
··· 149 struct regmap_field *fields[F_MAX_FIELDS]; 150 const struct reg_field *reg_fields; 151 const struct linear_range *ranges; 152 - struct reg_cfg *reg_cfgs; 153 const struct mt6370_pdata *pdata; 154 unsigned int leds_count; 155 unsigned int leds_active;
··· 149 struct regmap_field *fields[F_MAX_FIELDS]; 150 const struct reg_field *reg_fields; 151 const struct linear_range *ranges; 152 const struct mt6370_pdata *pdata; 153 unsigned int leds_count; 154 unsigned int leds_active;
+8
drivers/leds/rgb/leds-qcom-lpg.c
··· 1693 }, 1694 }; 1695 1696 static const struct lpg_data pm8994_lpg_data = { 1697 .lut_base = 0xb000, 1698 .lut_size = 64, ··· 1826 { .compatible = "qcom,pm8941-lpg", .data = &pm8941_lpg_data }, 1827 { .compatible = "qcom,pm8994-lpg", .data = &pm8994_lpg_data }, 1828 { .compatible = "qcom,pmi632-lpg", .data = &pmi632_lpg_data }, 1829 { .compatible = "qcom,pmi8994-lpg", .data = &pmi8994_lpg_data }, 1830 { .compatible = "qcom,pmi8998-lpg", .data = &pmi8998_lpg_data }, 1831 { .compatible = "qcom,pmc8180c-lpg", .data = &pm8150l_lpg_data },
··· 1693 }, 1694 }; 1695 1696 + static const struct lpg_data pmi8950_pwm_data = { 1697 + .num_channels = 1, 1698 + .channels = (const struct lpg_channel_data[]) { 1699 + { .base = 0xb000 }, 1700 + }, 1701 + }; 1702 + 1703 static const struct lpg_data pm8994_lpg_data = { 1704 .lut_base = 0xb000, 1705 .lut_size = 64, ··· 1819 { .compatible = "qcom,pm8941-lpg", .data = &pm8941_lpg_data }, 1820 { .compatible = "qcom,pm8994-lpg", .data = &pm8994_lpg_data }, 1821 { .compatible = "qcom,pmi632-lpg", .data = &pmi632_lpg_data }, 1822 + { .compatible = "qcom,pmi8950-pwm", .data = &pmi8950_pwm_data }, 1823 { .compatible = "qcom,pmi8994-lpg", .data = &pmi8994_lpg_data }, 1824 { .compatible = "qcom,pmi8998-lpg", .data = &pmi8998_lpg_data }, 1825 { .compatible = "qcom,pmc8180c-lpg", .data = &pm8150l_lpg_data },
+1
drivers/leds/simple/simatic-ipc-leds-gpio-core.c
··· 56 case SIMATIC_IPC_DEVICE_127E: 57 case SIMATIC_IPC_DEVICE_227G: 58 case SIMATIC_IPC_DEVICE_BX_21A: 59 break; 60 default: 61 return -ENODEV;
··· 56 case SIMATIC_IPC_DEVICE_127E: 57 case SIMATIC_IPC_DEVICE_227G: 58 case SIMATIC_IPC_DEVICE_BX_21A: 59 + case SIMATIC_IPC_DEVICE_BX_59A: 60 break; 61 default: 62 return -ENODEV;
+46 -6
drivers/leds/simple/simatic-ipc-leds-gpio-f7188x.c
··· 17 18 #include "simatic-ipc-leds-gpio.h" 19 20 - static struct gpiod_lookup_table simatic_ipc_led_gpio_table = { 21 .dev_id = "leds-gpio", 22 .table = { 23 GPIO_LOOKUP_IDX("gpio-f7188x-2", 0, NULL, 0, GPIO_ACTIVE_LOW), ··· 35 }, 36 }; 37 38 - static struct gpiod_lookup_table simatic_ipc_led_gpio_table_extra = { 39 .dev_id = NULL, /* Filled during initialization */ 40 .table = { 41 GPIO_LOOKUP_IDX("gpio-f7188x-3", 6, NULL, 6, GPIO_ACTIVE_HIGH), ··· 44 }, 45 }; 46 47 static int simatic_ipc_leds_gpio_f7188x_probe(struct platform_device *pdev) 48 { 49 - return simatic_ipc_leds_gpio_probe(pdev, &simatic_ipc_led_gpio_table, 50 - &simatic_ipc_led_gpio_table_extra); 51 } 52 53 static void simatic_ipc_leds_gpio_f7188x_remove(struct platform_device *pdev) 54 { 55 - simatic_ipc_leds_gpio_remove(pdev, &simatic_ipc_led_gpio_table, 56 - &simatic_ipc_led_gpio_table_extra); 57 } 58 59 static struct platform_driver simatic_ipc_led_gpio_driver = {
··· 17 18 #include "simatic-ipc-leds-gpio.h" 19 20 + struct simatic_ipc_led_tables { 21 + struct gpiod_lookup_table *led_lookup_table; 22 + struct gpiod_lookup_table *led_lookup_table_extra; 23 + }; 24 + 25 + static struct gpiod_lookup_table simatic_ipc_led_gpio_table_227g = { 26 .dev_id = "leds-gpio", 27 .table = { 28 GPIO_LOOKUP_IDX("gpio-f7188x-2", 0, NULL, 0, GPIO_ACTIVE_LOW), ··· 30 }, 31 }; 32 33 + static struct gpiod_lookup_table simatic_ipc_led_gpio_table_extra_227g = { 34 .dev_id = NULL, /* Filled during initialization */ 35 .table = { 36 GPIO_LOOKUP_IDX("gpio-f7188x-3", 6, NULL, 6, GPIO_ACTIVE_HIGH), ··· 39 }, 40 }; 41 42 + static struct gpiod_lookup_table simatic_ipc_led_gpio_table_bx_59a = { 43 + .dev_id = "leds-gpio", 44 + .table = { 45 + GPIO_LOOKUP_IDX("gpio-f7188x-2", 0, NULL, 0, GPIO_ACTIVE_LOW), 46 + GPIO_LOOKUP_IDX("gpio-f7188x-2", 3, NULL, 1, GPIO_ACTIVE_LOW), 47 + GPIO_LOOKUP_IDX("gpio-f7188x-5", 3, NULL, 2, GPIO_ACTIVE_LOW), 48 + GPIO_LOOKUP_IDX("gpio-f7188x-5", 2, NULL, 3, GPIO_ACTIVE_LOW), 49 + GPIO_LOOKUP_IDX("gpio-f7188x-7", 7, NULL, 4, GPIO_ACTIVE_LOW), 50 + GPIO_LOOKUP_IDX("gpio-f7188x-7", 4, NULL, 5, GPIO_ACTIVE_LOW), 51 + {} /* Terminating entry */ 52 + } 53 + }; 54 + 55 static int simatic_ipc_leds_gpio_f7188x_probe(struct platform_device *pdev) 56 { 57 + const struct simatic_ipc_platform *plat = dev_get_platdata(&pdev->dev); 58 + struct simatic_ipc_led_tables *led_tables; 59 + 60 + led_tables = devm_kzalloc(&pdev->dev, sizeof(*led_tables), GFP_KERNEL); 61 + if (!led_tables) 62 + return -ENOMEM; 63 + 64 + switch (plat->devmode) { 65 + case SIMATIC_IPC_DEVICE_227G: 66 + led_tables->led_lookup_table = &simatic_ipc_led_gpio_table_227g; 67 + led_tables->led_lookup_table_extra = &simatic_ipc_led_gpio_table_extra_227g; 68 + break; 69 + case SIMATIC_IPC_DEVICE_BX_59A: 70 + led_tables->led_lookup_table = &simatic_ipc_led_gpio_table_bx_59a; 71 + break; 72 + default: 73 + return -ENODEV; 74 + } 75 + 76 + platform_set_drvdata(pdev, led_tables); 77 + return simatic_ipc_leds_gpio_probe(pdev, led_tables->led_lookup_table, 78 + led_tables->led_lookup_table_extra); 79 } 80 81 static void simatic_ipc_leds_gpio_f7188x_remove(struct platform_device *pdev) 82 { 83 + struct simatic_ipc_led_tables *led_tables = platform_get_drvdata(pdev); 84 + 85 + simatic_ipc_leds_gpio_remove(pdev, led_tables->led_lookup_table, 86 + led_tables->led_lookup_table_extra); 87 } 88 89 static struct platform_driver simatic_ipc_led_gpio_driver = {
-7
drivers/leds/trigger/Kconfig
··· 136 which is a series of tuples, of brightness and duration (ms). 137 If unsure, say N 138 139 - config LEDS_TRIGGER_AUDIO 140 - tristate "Audio Mute LED Trigger" 141 - help 142 - This allows LEDs to be controlled by audio drivers for following 143 - the audio mute and mic-mute changes. 144 - If unsure, say N 145 - 146 config LEDS_TRIGGER_TTY 147 tristate "LED Trigger for TTY devices" 148 depends on TTY
··· 136 which is a series of tuples, of brightness and duration (ms). 137 If unsure, say N 138 139 config LEDS_TRIGGER_TTY 140 tristate "LED Trigger for TTY devices" 141 depends on TTY
-1
drivers/leds/trigger/Makefile
··· 14 obj-$(CONFIG_LEDS_TRIGGER_PANIC) += ledtrig-panic.o 15 obj-$(CONFIG_LEDS_TRIGGER_NETDEV) += ledtrig-netdev.o 16 obj-$(CONFIG_LEDS_TRIGGER_PATTERN) += ledtrig-pattern.o 17 - obj-$(CONFIG_LEDS_TRIGGER_AUDIO) += ledtrig-audio.o 18 obj-$(CONFIG_LEDS_TRIGGER_TTY) += ledtrig-tty.o
··· 14 obj-$(CONFIG_LEDS_TRIGGER_PANIC) += ledtrig-panic.o 15 obj-$(CONFIG_LEDS_TRIGGER_NETDEV) += ledtrig-netdev.o 16 obj-$(CONFIG_LEDS_TRIGGER_PATTERN) += ledtrig-pattern.o 17 obj-$(CONFIG_LEDS_TRIGGER_TTY) += ledtrig-tty.o
-67
drivers/leds/trigger/ledtrig-audio.c
··· 1 - // SPDX-License-Identifier: GPL-2.0 2 - // 3 - // Audio Mute LED trigger 4 - // 5 - 6 - #include <linux/kernel.h> 7 - #include <linux/leds.h> 8 - #include <linux/module.h> 9 - #include "../leds.h" 10 - 11 - static enum led_brightness audio_state[NUM_AUDIO_LEDS]; 12 - 13 - static int ledtrig_audio_mute_activate(struct led_classdev *led_cdev) 14 - { 15 - led_set_brightness_nosleep(led_cdev, audio_state[LED_AUDIO_MUTE]); 16 - return 0; 17 - } 18 - 19 - static int ledtrig_audio_micmute_activate(struct led_classdev *led_cdev) 20 - { 21 - led_set_brightness_nosleep(led_cdev, audio_state[LED_AUDIO_MICMUTE]); 22 - return 0; 23 - } 24 - 25 - static struct led_trigger ledtrig_audio[NUM_AUDIO_LEDS] = { 26 - [LED_AUDIO_MUTE] = { 27 - .name = "audio-mute", 28 - .activate = ledtrig_audio_mute_activate, 29 - }, 30 - [LED_AUDIO_MICMUTE] = { 31 - .name = "audio-micmute", 32 - .activate = ledtrig_audio_micmute_activate, 33 - }, 34 - }; 35 - 36 - enum led_brightness ledtrig_audio_get(enum led_audio type) 37 - { 38 - return audio_state[type]; 39 - } 40 - EXPORT_SYMBOL_GPL(ledtrig_audio_get); 41 - 42 - void ledtrig_audio_set(enum led_audio type, enum led_brightness state) 43 - { 44 - audio_state[type] = state; 45 - led_trigger_event(&ledtrig_audio[type], state); 46 - } 47 - EXPORT_SYMBOL_GPL(ledtrig_audio_set); 48 - 49 - static int __init ledtrig_audio_init(void) 50 - { 51 - led_trigger_register(&ledtrig_audio[LED_AUDIO_MUTE]); 52 - led_trigger_register(&ledtrig_audio[LED_AUDIO_MICMUTE]); 53 - return 0; 54 - } 55 - module_init(ledtrig_audio_init); 56 - 57 - static void __exit ledtrig_audio_exit(void) 58 - { 59 - led_trigger_unregister(&ledtrig_audio[LED_AUDIO_MUTE]); 60 - led_trigger_unregister(&ledtrig_audio[LED_AUDIO_MICMUTE]); 61 - } 62 - module_exit(ledtrig_audio_exit); 63 - 64 - MODULE_DESCRIPTION("LED trigger for audio mute control"); 65 - MODULE_LICENSE("GPL v2"); 66 - MODULE_ALIAS("ledtrig:audio-mute"); 67 - MODULE_ALIAS("ledtrig:audio-micmute");
···
-2
drivers/leds/trigger/ledtrig-netdev.c
··· 724 725 cancel_delayed_work_sync(&trigger_data->work); 726 727 - led_set_brightness(led_cdev, LED_OFF); 728 - 729 dev_put(trigger_data->net_dev); 730 731 kfree(trigger_data);
··· 724 725 cancel_delayed_work_sync(&trigger_data->work); 726 727 dev_put(trigger_data->net_dev); 728 729 kfree(trigger_data);
+103 -23
drivers/leds/trigger/ledtrig-pattern.c
··· 13 #include <linux/mutex.h> 14 #include <linux/slab.h> 15 #include <linux/timer.h> 16 17 #define MAX_PATTERNS 1024 18 /* ··· 21 * every 50 milliseconds. 22 */ 23 #define UPDATE_INTERVAL 50 24 25 struct pattern_trig_data { 26 struct led_classdev *led_cdev; ··· 39 int last_repeat; 40 int delta_t; 41 bool is_indefinite; 42 - bool is_hw_pattern; 43 struct timer_list timer; 44 }; 45 46 static void pattern_trig_update_patterns(struct pattern_trig_data *data) ··· 79 return data->curr->brightness - step_brightness; 80 } 81 82 - static void pattern_trig_timer_function(struct timer_list *t) 83 { 84 - struct pattern_trig_data *data = from_timer(data, t, timer); 85 86 for (;;) { 87 if (!data->is_indefinite && !data->repeat) 88 break; ··· 116 /* Step change of brightness */ 117 led_set_brightness(data->led_cdev, 118 data->curr->brightness); 119 - mod_timer(&data->timer, 120 - jiffies + msecs_to_jiffies(data->curr->delta_t)); 121 if (!data->next->delta_t) { 122 /* Skip the tuple with zero duration */ 123 pattern_trig_update_patterns(data); ··· 138 139 led_set_brightness(data->led_cdev, 140 pattern_trig_compute_brightness(data)); 141 - mod_timer(&data->timer, 142 - jiffies + msecs_to_jiffies(UPDATE_INTERVAL)); 143 144 /* Accumulate the gradual dimming time */ 145 data->delta_t += UPDATE_INTERVAL; ··· 148 } 149 } 150 151 static int pattern_trig_start_pattern(struct led_classdev *led_cdev) 152 { 153 struct pattern_trig_data *data = led_cdev->trigger_data; ··· 174 if (!data->npatterns) 175 return 0; 176 177 - if (data->is_hw_pattern) { 178 return led_cdev->pattern_set(led_cdev, data->patterns, 179 data->npatterns, data->repeat); 180 } ··· 186 data->delta_t = 0; 187 data->curr = data->patterns; 188 data->next = data->patterns + 1; 189 - data->timer.expires = jiffies; 190 - add_timer(&data->timer); 191 192 return 0; 193 } ··· 224 225 mutex_lock(&data->lock); 226 227 - del_timer_sync(&data->timer); 228 229 - if (data->is_hw_pattern) 230 led_cdev->pattern_clear(led_cdev); 231 232 data->last_repeat = data->repeat = res; ··· 245 static DEVICE_ATTR_RW(repeat); 246 247 static ssize_t pattern_trig_show_patterns(struct pattern_trig_data *data, 248 - char *buf, bool hw_pattern) 249 { 250 ssize_t count = 0; 251 int i; 252 253 mutex_lock(&data->lock); 254 255 - if (!data->npatterns || (data->is_hw_pattern ^ hw_pattern)) 256 goto out; 257 258 for (i = 0; i < data->npatterns; i++) { ··· 309 310 static ssize_t pattern_trig_store_patterns(struct led_classdev *led_cdev, 311 const char *buf, const u32 *buf_int, 312 - size_t count, bool hw_pattern) 313 { 314 struct pattern_trig_data *data = led_cdev->trigger_data; 315 int err = 0; 316 317 mutex_lock(&data->lock); 318 319 - del_timer_sync(&data->timer); 320 321 - if (data->is_hw_pattern) 322 led_cdev->pattern_clear(led_cdev); 323 324 - data->is_hw_pattern = hw_pattern; 325 data->npatterns = 0; 326 327 if (buf) ··· 346 struct led_classdev *led_cdev = dev_get_drvdata(dev); 347 struct pattern_trig_data *data = led_cdev->trigger_data; 348 349 - return pattern_trig_show_patterns(data, buf, false); 350 } 351 352 static ssize_t pattern_store(struct device *dev, struct device_attribute *attr, ··· 354 { 355 struct led_classdev *led_cdev = dev_get_drvdata(dev); 356 357 - return pattern_trig_store_patterns(led_cdev, buf, NULL, count, false); 358 } 359 360 static DEVICE_ATTR_RW(pattern); ··· 366 struct led_classdev *led_cdev = dev_get_drvdata(dev); 367 struct pattern_trig_data *data = led_cdev->trigger_data; 368 369 - return pattern_trig_show_patterns(data, buf, true); 370 } 371 372 static ssize_t hw_pattern_store(struct device *dev, ··· 375 { 376 struct led_classdev *led_cdev = dev_get_drvdata(dev); 377 378 - return pattern_trig_store_patterns(led_cdev, buf, NULL, count, true); 379 } 380 381 static DEVICE_ATTR_RW(hw_pattern); 382 383 static umode_t pattern_trig_attrs_mode(struct kobject *kobj, 384 struct attribute *attr, int index) ··· 409 struct led_classdev *led_cdev = dev_get_drvdata(dev); 410 411 if (attr == &dev_attr_repeat.attr || attr == &dev_attr_pattern.attr) 412 return attr->mode; 413 else if (attr == &dev_attr_hw_pattern.attr && led_cdev->pattern_set) 414 return attr->mode; ··· 421 static struct attribute *pattern_trig_attrs[] = { 422 &dev_attr_pattern.attr, 423 &dev_attr_hw_pattern.attr, 424 &dev_attr_repeat.attr, 425 NULL 426 }; ··· 451 goto out; 452 } 453 454 - err = pattern_trig_store_patterns(led_cdev, NULL, pattern, size, false); 455 if (err < 0) 456 dev_warn(led_cdev->dev, 457 "Pattern initialization failed with error %d\n", err); ··· 476 led_cdev->pattern_clear = NULL; 477 } 478 479 data->is_indefinite = true; 480 data->last_repeat = -1; 481 mutex_init(&data->lock); 482 data->led_cdev = led_cdev; 483 led_set_trigger_data(led_cdev, data); 484 timer_setup(&data->timer, pattern_trig_timer_function, 0); 485 led_cdev->activated = true; 486 487 if (led_cdev->flags & LED_INIT_DEFAULT_TRIGGER) { ··· 510 led_cdev->pattern_clear(led_cdev); 511 512 timer_shutdown_sync(&data->timer); 513 514 led_set_brightness(led_cdev, LED_OFF); 515 kfree(data);
··· 13 #include <linux/mutex.h> 14 #include <linux/slab.h> 15 #include <linux/timer.h> 16 + #include <linux/hrtimer.h> 17 18 #define MAX_PATTERNS 1024 19 /* ··· 20 * every 50 milliseconds. 21 */ 22 #define UPDATE_INTERVAL 50 23 + 24 + enum pattern_type { 25 + PATTERN_TYPE_SW, /* Use standard timer for software pattern */ 26 + PATTERN_TYPE_HR, /* Use hrtimer for software pattern */ 27 + PATTERN_TYPE_HW, /* Hardware pattern */ 28 + }; 29 30 struct pattern_trig_data { 31 struct led_classdev *led_cdev; ··· 32 int last_repeat; 33 int delta_t; 34 bool is_indefinite; 35 + enum pattern_type type; 36 struct timer_list timer; 37 + struct hrtimer hrtimer; 38 }; 39 40 static void pattern_trig_update_patterns(struct pattern_trig_data *data) ··· 71 return data->curr->brightness - step_brightness; 72 } 73 74 + static void pattern_trig_timer_start(struct pattern_trig_data *data) 75 { 76 + if (data->type == PATTERN_TYPE_HR) { 77 + hrtimer_start(&data->hrtimer, ns_to_ktime(0), HRTIMER_MODE_REL); 78 + } else { 79 + data->timer.expires = jiffies; 80 + add_timer(&data->timer); 81 + } 82 + } 83 84 + static void pattern_trig_timer_cancel(struct pattern_trig_data *data) 85 + { 86 + if (data->type == PATTERN_TYPE_HR) 87 + hrtimer_cancel(&data->hrtimer); 88 + else 89 + del_timer_sync(&data->timer); 90 + } 91 + 92 + static void pattern_trig_timer_restart(struct pattern_trig_data *data, 93 + unsigned long interval) 94 + { 95 + if (data->type == PATTERN_TYPE_HR) 96 + hrtimer_forward_now(&data->hrtimer, ms_to_ktime(interval)); 97 + else 98 + mod_timer(&data->timer, jiffies + msecs_to_jiffies(interval)); 99 + } 100 + 101 + static void pattern_trig_timer_common_function(struct pattern_trig_data *data) 102 + { 103 for (;;) { 104 if (!data->is_indefinite && !data->repeat) 105 break; ··· 83 /* Step change of brightness */ 84 led_set_brightness(data->led_cdev, 85 data->curr->brightness); 86 + pattern_trig_timer_restart(data, data->curr->delta_t); 87 if (!data->next->delta_t) { 88 /* Skip the tuple with zero duration */ 89 pattern_trig_update_patterns(data); ··· 106 107 led_set_brightness(data->led_cdev, 108 pattern_trig_compute_brightness(data)); 109 + pattern_trig_timer_restart(data, UPDATE_INTERVAL); 110 111 /* Accumulate the gradual dimming time */ 112 data->delta_t += UPDATE_INTERVAL; ··· 117 } 118 } 119 120 + static void pattern_trig_timer_function(struct timer_list *t) 121 + { 122 + struct pattern_trig_data *data = from_timer(data, t, timer); 123 + 124 + return pattern_trig_timer_common_function(data); 125 + } 126 + 127 + static enum hrtimer_restart pattern_trig_hrtimer_function(struct hrtimer *t) 128 + { 129 + struct pattern_trig_data *data = 130 + container_of(t, struct pattern_trig_data, hrtimer); 131 + 132 + pattern_trig_timer_common_function(data); 133 + if (!data->is_indefinite && !data->repeat) 134 + return HRTIMER_NORESTART; 135 + 136 + return HRTIMER_RESTART; 137 + } 138 + 139 static int pattern_trig_start_pattern(struct led_classdev *led_cdev) 140 { 141 struct pattern_trig_data *data = led_cdev->trigger_data; ··· 124 if (!data->npatterns) 125 return 0; 126 127 + if (data->type == PATTERN_TYPE_HW) { 128 return led_cdev->pattern_set(led_cdev, data->patterns, 129 data->npatterns, data->repeat); 130 } ··· 136 data->delta_t = 0; 137 data->curr = data->patterns; 138 data->next = data->patterns + 1; 139 + pattern_trig_timer_start(data); 140 141 return 0; 142 } ··· 175 176 mutex_lock(&data->lock); 177 178 + pattern_trig_timer_cancel(data); 179 180 + if (data->type == PATTERN_TYPE_HW) 181 led_cdev->pattern_clear(led_cdev); 182 183 data->last_repeat = data->repeat = res; ··· 196 static DEVICE_ATTR_RW(repeat); 197 198 static ssize_t pattern_trig_show_patterns(struct pattern_trig_data *data, 199 + char *buf, enum pattern_type type) 200 { 201 ssize_t count = 0; 202 int i; 203 204 mutex_lock(&data->lock); 205 206 + if (!data->npatterns || data->type != type) 207 goto out; 208 209 for (i = 0; i < data->npatterns; i++) { ··· 260 261 static ssize_t pattern_trig_store_patterns(struct led_classdev *led_cdev, 262 const char *buf, const u32 *buf_int, 263 + size_t count, enum pattern_type type) 264 { 265 struct pattern_trig_data *data = led_cdev->trigger_data; 266 int err = 0; 267 268 mutex_lock(&data->lock); 269 270 + pattern_trig_timer_cancel(data); 271 272 + if (data->type == PATTERN_TYPE_HW) 273 led_cdev->pattern_clear(led_cdev); 274 275 + data->type = type; 276 data->npatterns = 0; 277 278 if (buf) ··· 297 struct led_classdev *led_cdev = dev_get_drvdata(dev); 298 struct pattern_trig_data *data = led_cdev->trigger_data; 299 300 + return pattern_trig_show_patterns(data, buf, PATTERN_TYPE_SW); 301 } 302 303 static ssize_t pattern_store(struct device *dev, struct device_attribute *attr, ··· 305 { 306 struct led_classdev *led_cdev = dev_get_drvdata(dev); 307 308 + return pattern_trig_store_patterns(led_cdev, buf, NULL, count, 309 + PATTERN_TYPE_SW); 310 } 311 312 static DEVICE_ATTR_RW(pattern); ··· 316 struct led_classdev *led_cdev = dev_get_drvdata(dev); 317 struct pattern_trig_data *data = led_cdev->trigger_data; 318 319 + return pattern_trig_show_patterns(data, buf, PATTERN_TYPE_HW); 320 } 321 322 static ssize_t hw_pattern_store(struct device *dev, ··· 325 { 326 struct led_classdev *led_cdev = dev_get_drvdata(dev); 327 328 + return pattern_trig_store_patterns(led_cdev, buf, NULL, count, 329 + PATTERN_TYPE_HW); 330 } 331 332 static DEVICE_ATTR_RW(hw_pattern); 333 + 334 + static ssize_t hr_pattern_show(struct device *dev, 335 + struct device_attribute *attr, char *buf) 336 + { 337 + struct led_classdev *led_cdev = dev_get_drvdata(dev); 338 + struct pattern_trig_data *data = led_cdev->trigger_data; 339 + 340 + return pattern_trig_show_patterns(data, buf, PATTERN_TYPE_HR); 341 + } 342 + 343 + static ssize_t hr_pattern_store(struct device *dev, 344 + struct device_attribute *attr, 345 + const char *buf, size_t count) 346 + { 347 + struct led_classdev *led_cdev = dev_get_drvdata(dev); 348 + 349 + return pattern_trig_store_patterns(led_cdev, buf, NULL, count, 350 + PATTERN_TYPE_HR); 351 + } 352 + 353 + static DEVICE_ATTR_RW(hr_pattern); 354 355 static umode_t pattern_trig_attrs_mode(struct kobject *kobj, 356 struct attribute *attr, int index) ··· 337 struct led_classdev *led_cdev = dev_get_drvdata(dev); 338 339 if (attr == &dev_attr_repeat.attr || attr == &dev_attr_pattern.attr) 340 + return attr->mode; 341 + else if (attr == &dev_attr_hr_pattern.attr) 342 return attr->mode; 343 else if (attr == &dev_attr_hw_pattern.attr && led_cdev->pattern_set) 344 return attr->mode; ··· 347 static struct attribute *pattern_trig_attrs[] = { 348 &dev_attr_pattern.attr, 349 &dev_attr_hw_pattern.attr, 350 + &dev_attr_hr_pattern.attr, 351 &dev_attr_repeat.attr, 352 NULL 353 }; ··· 376 goto out; 377 } 378 379 + err = pattern_trig_store_patterns(led_cdev, NULL, pattern, size, 380 + PATTERN_TYPE_SW); 381 if (err < 0) 382 dev_warn(led_cdev->dev, 383 "Pattern initialization failed with error %d\n", err); ··· 400 led_cdev->pattern_clear = NULL; 401 } 402 403 + data->type = PATTERN_TYPE_SW; 404 data->is_indefinite = true; 405 data->last_repeat = -1; 406 mutex_init(&data->lock); 407 data->led_cdev = led_cdev; 408 led_set_trigger_data(led_cdev, data); 409 timer_setup(&data->timer, pattern_trig_timer_function, 0); 410 + hrtimer_init(&data->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); 411 + data->hrtimer.function = pattern_trig_hrtimer_function; 412 led_cdev->activated = true; 413 414 if (led_cdev->flags & LED_INIT_DEFAULT_TRIGGER) { ··· 431 led_cdev->pattern_clear(led_cdev); 432 433 timer_shutdown_sync(&data->timer); 434 + hrtimer_cancel(&data->hrtimer); 435 436 led_set_brightness(led_cdev, LED_OFF); 437 kfree(data);
+3
include/dt-bindings/leds/common.h
··· 91 #define LED_FUNCTION_INDICATOR "indicator" 92 #define LED_FUNCTION_LAN "lan" 93 #define LED_FUNCTION_MAIL "mail" 94 #define LED_FUNCTION_MTD "mtd" 95 #define LED_FUNCTION_PANIC "panic" 96 #define LED_FUNCTION_PROGRAMMING "programming" 97 #define LED_FUNCTION_RX "rx" 98 #define LED_FUNCTION_SD "sd" 99 #define LED_FUNCTION_STANDBY "standby" 100 #define LED_FUNCTION_TORCH "torch" 101 #define LED_FUNCTION_TX "tx"
··· 91 #define LED_FUNCTION_INDICATOR "indicator" 92 #define LED_FUNCTION_LAN "lan" 93 #define LED_FUNCTION_MAIL "mail" 94 + #define LED_FUNCTION_MOBILE "mobile" 95 #define LED_FUNCTION_MTD "mtd" 96 #define LED_FUNCTION_PANIC "panic" 97 #define LED_FUNCTION_PROGRAMMING "programming" 98 #define LED_FUNCTION_RX "rx" 99 #define LED_FUNCTION_SD "sd" 100 + #define LED_FUNCTION_SPEED_LAN "speed-lan" 101 + #define LED_FUNCTION_SPEED_WAN "speed-wan" 102 #define LED_FUNCTION_STANDBY "standby" 103 #define LED_FUNCTION_TORCH "torch" 104 #define LED_FUNCTION_TX "tx"
+15 -14
include/linux/leds.h
··· 455 int (*activate)(struct led_classdev *led_cdev); 456 void (*deactivate)(struct led_classdev *led_cdev); 457 458 /* LED-private triggers have this set */ 459 struct led_hw_trigger_type *trigger_type; 460 ··· 511 return led_cdev->trigger_data; 512 } 513 514 #define module_led_trigger(__led_trigger) \ 515 module_driver(__led_trigger, led_trigger_register, \ 516 led_trigger_unregister) ··· 551 static inline void *led_get_trigger_data(struct led_classdev *led_cdev) 552 { 553 return NULL; 554 } 555 556 #endif /* CONFIG_LEDS_TRIGGERS */ ··· 704 LED_AUDIO_MICMUTE, /* mic mute LED */ 705 NUM_AUDIO_LEDS 706 }; 707 - 708 - #if IS_ENABLED(CONFIG_LEDS_TRIGGER_AUDIO) 709 - enum led_brightness ledtrig_audio_get(enum led_audio type); 710 - void ledtrig_audio_set(enum led_audio type, enum led_brightness state); 711 - #else 712 - static inline enum led_brightness ledtrig_audio_get(enum led_audio type) 713 - { 714 - return LED_OFF; 715 - } 716 - static inline void ledtrig_audio_set(enum led_audio type, 717 - enum led_brightness state) 718 - { 719 - } 720 - #endif 721 722 #endif /* __LINUX_LEDS_H_INCLUDED */
··· 455 int (*activate)(struct led_classdev *led_cdev); 456 void (*deactivate)(struct led_classdev *led_cdev); 457 458 + /* Brightness set by led_trigger_event */ 459 + enum led_brightness brightness; 460 + 461 /* LED-private triggers have this set */ 462 struct led_hw_trigger_type *trigger_type; 463 ··· 508 return led_cdev->trigger_data; 509 } 510 511 + static inline enum led_brightness 512 + led_trigger_get_brightness(const struct led_trigger *trigger) 513 + { 514 + return trigger ? trigger->brightness : LED_OFF; 515 + } 516 + 517 #define module_led_trigger(__led_trigger) \ 518 module_driver(__led_trigger, led_trigger_register, \ 519 led_trigger_unregister) ··· 542 static inline void *led_get_trigger_data(struct led_classdev *led_cdev) 543 { 544 return NULL; 545 + } 546 + 547 + static inline enum led_brightness 548 + led_trigger_get_brightness(const struct led_trigger *trigger) 549 + { 550 + return LED_OFF; 551 } 552 553 #endif /* CONFIG_LEDS_TRIGGERS */ ··· 689 LED_AUDIO_MICMUTE, /* mic mute LED */ 690 NUM_AUDIO_LEDS 691 }; 692 693 #endif /* __LINUX_LEDS_H_INCLUDED */
+27
include/linux/mutex.h
··· 22 #include <linux/cleanup.h> 23 #include <linux/mutex_types.h> 24 25 #ifdef CONFIG_DEBUG_LOCK_ALLOC 26 # define __DEP_MAP_MUTEX_INITIALIZER(lockname) \ 27 , .dep_map = { \ ··· 118 __mutex_init((mutex), #mutex, &__key); \ 119 } while (0) 120 #endif /* CONFIG_PREEMPT_RT */ 121 122 /* 123 * See kernel/locking/mutex.c for detailed documentation of these APIs.
··· 22 #include <linux/cleanup.h> 23 #include <linux/mutex_types.h> 24 25 + struct device; 26 + 27 #ifdef CONFIG_DEBUG_LOCK_ALLOC 28 # define __DEP_MAP_MUTEX_INITIALIZER(lockname) \ 29 , .dep_map = { \ ··· 116 __mutex_init((mutex), #mutex, &__key); \ 117 } while (0) 118 #endif /* CONFIG_PREEMPT_RT */ 119 + 120 + #ifdef CONFIG_DEBUG_MUTEXES 121 + 122 + int __devm_mutex_init(struct device *dev, struct mutex *lock); 123 + 124 + #else 125 + 126 + static inline int __devm_mutex_init(struct device *dev, struct mutex *lock) 127 + { 128 + /* 129 + * When CONFIG_DEBUG_MUTEXES is off mutex_destroy() is just a nop so 130 + * no really need to register it in the devm subsystem. 131 + */ 132 + return 0; 133 + } 134 + 135 + #endif 136 + 137 + #define devm_mutex_init(dev, mutex) \ 138 + ({ \ 139 + typeof(mutex) mutex_ = (mutex); \ 140 + \ 141 + mutex_init(mutex_); \ 142 + __devm_mutex_init(dev, mutex_); \ 143 + }) 144 145 /* 146 * See kernel/locking/mutex.c for detailed documentation of these APIs.
+12
kernel/locking/mutex-debug.c
··· 12 */ 13 #include <linux/mutex.h> 14 #include <linux/delay.h> 15 #include <linux/export.h> 16 #include <linux/poison.h> 17 #include <linux/sched.h> ··· 89 #endif 90 lock->magic = lock; 91 } 92 93 /*** 94 * mutex_destroy - mark a mutex unusable
··· 12 */ 13 #include <linux/mutex.h> 14 #include <linux/delay.h> 15 + #include <linux/device.h> 16 #include <linux/export.h> 17 #include <linux/poison.h> 18 #include <linux/sched.h> ··· 88 #endif 89 lock->magic = lock; 90 } 91 + 92 + static void devm_mutex_release(void *res) 93 + { 94 + mutex_destroy(res); 95 + } 96 + 97 + int __devm_mutex_init(struct device *dev, struct mutex *lock) 98 + { 99 + return devm_add_action_or_reset(dev, devm_mutex_release, lock); 100 + } 101 + EXPORT_SYMBOL_GPL(__devm_mutex_init); 102 103 /*** 104 * mutex_destroy - mark a mutex unusable
-1
sound/core/Kconfig
··· 262 tristate 263 select NEW_LEDS if SND_CTL_LED 264 select LEDS_TRIGGERS if SND_CTL_LED 265 - select LEDS_TRIGGER_AUDIO if SND_CTL_LED 266 267 source "sound/core/seq/Kconfig"
··· 262 tristate 263 select NEW_LEDS if SND_CTL_LED 264 select LEDS_TRIGGERS if SND_CTL_LED 265 266 source "sound/core/seq/Kconfig"
+17 -3
sound/core/control_led.c
··· 53 54 static DEFINE_MUTEX(snd_ctl_led_mutex); 55 static bool snd_ctl_led_card_valid[SNDRV_CARDS]; 56 static struct snd_ctl_led snd_ctl_leds[MAX_LED] = { 57 { 58 .name = "speaker", ··· 175 case MODE_FOLLOW_ROUTE: if (route >= 0) route ^= 1; break; 176 case MODE_FOLLOW_MUTE: /* noop */ break; 177 } 178 - if (route >= 0) 179 - ledtrig_audio_set(led->trigger_type, route ? LED_OFF : LED_ON); 180 } 181 182 static struct snd_ctl_led_ctl *snd_ctl_led_find(struct snd_kcontrol *kctl, unsigned int ioff) ··· 424 struct device_attribute *attr, char *buf) 425 { 426 struct snd_ctl_led *led = container_of(dev, struct snd_ctl_led, dev); 427 428 - return sysfs_emit(buf, "%u\n", ledtrig_audio_get(led->trigger_type)); 429 } 430 431 static DEVICE_ATTR_RW(mode); ··· 716 struct snd_ctl_led *led; 717 unsigned int group; 718 719 device_initialize(&snd_ctl_led_dev); 720 snd_ctl_led_dev.class = &sound_class; 721 snd_ctl_led_dev.release = snd_ctl_led_dev_release; ··· 771 } 772 device_unregister(&snd_ctl_led_dev); 773 snd_ctl_led_clean(NULL); 774 } 775 776 module_init(snd_ctl_led_init) 777 module_exit(snd_ctl_led_exit)
··· 53 54 static DEFINE_MUTEX(snd_ctl_led_mutex); 55 static bool snd_ctl_led_card_valid[SNDRV_CARDS]; 56 + static struct led_trigger *snd_ctl_ledtrig_audio[NUM_AUDIO_LEDS]; 57 static struct snd_ctl_led snd_ctl_leds[MAX_LED] = { 58 { 59 .name = "speaker", ··· 174 case MODE_FOLLOW_ROUTE: if (route >= 0) route ^= 1; break; 175 case MODE_FOLLOW_MUTE: /* noop */ break; 176 } 177 + if (route >= 0) { 178 + struct led_trigger *trig = snd_ctl_ledtrig_audio[led->trigger_type]; 179 + 180 + led_trigger_event(trig, route ? LED_OFF : LED_ON); 181 + } 182 } 183 184 static struct snd_ctl_led_ctl *snd_ctl_led_find(struct snd_kcontrol *kctl, unsigned int ioff) ··· 420 struct device_attribute *attr, char *buf) 421 { 422 struct snd_ctl_led *led = container_of(dev, struct snd_ctl_led, dev); 423 + struct led_trigger *trig = snd_ctl_ledtrig_audio[led->trigger_type]; 424 425 + return sysfs_emit(buf, "%u\n", led_trigger_get_brightness(trig)); 426 } 427 428 static DEVICE_ATTR_RW(mode); ··· 711 struct snd_ctl_led *led; 712 unsigned int group; 713 714 + led_trigger_register_simple("audio-mute", &snd_ctl_ledtrig_audio[LED_AUDIO_MUTE]); 715 + led_trigger_register_simple("audio-micmute", &snd_ctl_ledtrig_audio[LED_AUDIO_MICMUTE]); 716 + 717 device_initialize(&snd_ctl_led_dev); 718 snd_ctl_led_dev.class = &sound_class; 719 snd_ctl_led_dev.release = snd_ctl_led_dev_release; ··· 763 } 764 device_unregister(&snd_ctl_led_dev); 765 snd_ctl_led_clean(NULL); 766 + 767 + led_trigger_unregister_simple(snd_ctl_ledtrig_audio[LED_AUDIO_MUTE]); 768 + led_trigger_unregister_simple(snd_ctl_ledtrig_audio[LED_AUDIO_MICMUTE]); 769 } 770 771 module_init(snd_ctl_led_init) 772 module_exit(snd_ctl_led_exit) 773 + 774 + MODULE_ALIAS("ledtrig:audio-mute"); 775 + MODULE_ALIAS("ledtrig:audio-micmute");