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

Pull LED updates from Lee Jones:
"New Drivers:
- Add support for Intel Cherry Trail Whiskey Cove PMIC LEDs
- Add support for Awinic AW20036/AW20054/AW20072 LEDs

New Device Support:
- Add support for PMI632 LPG to QCom LPG
- Add support for PMI8998 to QCom Flash
- Add support for MT6331, WLEDs and MT6332 to Mediatek MT6323 PMIC

New Functionality:
- Implement the LP55xx Charge Pump
- Add support for suspend / resume to Intel Cherry Trail Whiskey Cove PMIC
- Add support for breathing mode to Intel Cherry Trail Whiskey Cove PMIC
- Enable per-pin resolution Pinctrl in LEDs GPIO

Fix-ups:
- Allow thread to sleep by switching from spinlock to mutex
- Add lots of Device Tree bindings / support
- Adapt relationships / dependencies driven by Kconfig
- Switch I2C drivers from .probe_new() to .probe()
- Remove superfluous / duplicate code
- Replace strlcpy() with strscpy() for efficiency and overflow prevention
- Staticify various functions
- Trivial: Fixing coding style
- Simplify / reduce code

Bug Fixes:
- Prevent NETDEV_LED_MODE_LINKUP from being cleared on rename
- Repair race between led_set_brightness(LED_{OFF,FULL})
- Fix Oops relating to sleeping in critical sections
- Clear LED_INIT_DEFAULT_TRIGGER flag when clearing the current trigger
- Do not leak resources in error handling paths
- Fix unsigned comparison which can never be negative
- Provide missing NULL terminating entries in tables
- Fix misnaming issues"

* tag 'leds-next-6.5' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/leds: (53 commits)
leds: leds-mt6323: Adjust return/parameter types in wled get/set callbacks
leds: sgm3140: Add richtek,rt5033-led compatible
dt-bindings: leds: sgm3140: Document richtek,rt5033 compatible
dt-bindings: backlight: kinetic,ktz8866: Add missing type for "current-num-sinks"
dt-bindings: leds: Drop unneeded quotes
leds: Fix config reference for AW200xx driver
leds: leds-mt6323: Add support for WLEDs and MT6332
leds: leds-mt6323: Add support for MT6331 leds
leds: leds-mt6323: Open code and drop MT6323_CAL_HW_DUTY macro
leds: leds-mt6323: Drop MT6323_ prefix from macros and defines
leds: leds-mt6323: Specify registers and specs in platform data
dt-bindings: leds: leds-mt6323: Document mt6332 compatible
dt-bindings: leds: leds-mt6323: Document mt6331 compatible
leds: simatic-ipc-leds-gpio: Introduce more Kconfig switches
leds: simatic-ipc-leds-gpio: Split up into multiple drivers
leds: simatic-ipc-leds-gpio: Move two extra gpio pins into another table
leds: simatic-ipc-leds-gpio: Add terminating entries to gpio tables
leds: flash: leds-qcom-flash: Fix an unsigned comparison which can never be negative
leds: cht-wcove: Remove unneeded semicolon
leds: cht-wcove: Fix an unsigned comparison which can never be negative
...

+2206 -393
+5
Documentation/ABI/testing/sysfs-class-led-driver-aw200xx
··· 1 + What: /sys/class/leds/<led>/dim 2 + Date: May 2023 3 + Description: 64-level DIM current. If you write a negative value or 4 + "auto", the dim will be calculated according to the 5 + brightness.
+126
Documentation/devicetree/bindings/leds/awinic,aw200xx.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/awinic,aw200xx.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: AWINIC AW200XX LED 8 + 9 + maintainers: 10 + - Martin Kurbanov <mmkurbanov@sberdevices.ru> 11 + 12 + description: | 13 + This controller is present on AW20036/AW20054/AW20072. 14 + It is a 3x12/6x9/6x12 matrix LED programmed via 15 + an I2C interface, up to 36/54/72 LEDs or 12/18/24 RGBs, 16 + 3 pattern controllers for auto breathing or group dimming control. 17 + 18 + For more product information please see the link below: 19 + aw20036 - https://www.awinic.com/en/productDetail/AW20036QNR#tech-docs 20 + aw20054 - https://www.awinic.com/en/productDetail/AW20054QNR#tech-docs 21 + aw20072 - https://www.awinic.com/en/productDetail/AW20072QNR#tech-docs 22 + 23 + properties: 24 + compatible: 25 + enum: 26 + - awinic,aw20036 27 + - awinic,aw20054 28 + - awinic,aw20072 29 + 30 + reg: 31 + maxItems: 1 32 + 33 + "#address-cells": 34 + const: 1 35 + 36 + "#size-cells": 37 + const: 0 38 + 39 + awinic,display-rows: 40 + $ref: /schemas/types.yaml#/definitions/uint32 41 + description: 42 + Leds matrix size 43 + 44 + patternProperties: 45 + "^led@[0-9a-f]$": 46 + type: object 47 + $ref: common.yaml# 48 + unevaluatedProperties: false 49 + 50 + properties: 51 + reg: 52 + description: 53 + LED number 54 + maxItems: 1 55 + 56 + led-max-microamp: 57 + default: 9780 58 + description: | 59 + Note that a driver will take the minimum of all LED limits 60 + since the chip has a single global setting. 61 + The maximum output current of each LED is calculated by the 62 + following formula: 63 + IMAXled = 160000 * (592 / 600.5) * (1 / display-rows) 64 + And the minimum output current formula: 65 + IMINled = 3300 * (592 / 600.5) * (1 / display-rows) 66 + 67 + required: 68 + - compatible 69 + - reg 70 + - "#address-cells" 71 + - "#size-cells" 72 + - awinic,display-rows 73 + 74 + allOf: 75 + - if: 76 + properties: 77 + compatible: 78 + contains: 79 + const: awinic,aw20036 80 + then: 81 + properties: 82 + awinic,display-rows: 83 + enum: [1, 2, 3] 84 + else: 85 + properties: 86 + awinic,display-rows: 87 + enum: [1, 2, 3, 4, 5, 6, 7] 88 + 89 + additionalProperties: false 90 + 91 + examples: 92 + - | 93 + #include <dt-bindings/leds/common.h> 94 + 95 + i2c { 96 + #address-cells = <1>; 97 + #size-cells = <0>; 98 + 99 + led-controller@3a { 100 + compatible = "awinic,aw20036"; 101 + reg = <0x3a>; 102 + #address-cells = <1>; 103 + #size-cells = <0>; 104 + awinic,display-rows = <3>; 105 + 106 + led@0 { 107 + reg = <0x0>; 108 + color = <LED_COLOR_ID_RED>; 109 + led-max-microamp = <9780>; 110 + }; 111 + 112 + led@1 { 113 + reg = <0x1>; 114 + color = <LED_COLOR_ID_GREEN>; 115 + led-max-microamp = <9780>; 116 + }; 117 + 118 + led@2 { 119 + reg = <0x2>; 120 + color = <LED_COLOR_ID_BLUE>; 121 + led-max-microamp = <9780>; 122 + }; 123 + }; 124 + }; 125 + 126 + ...
+1
Documentation/devicetree/bindings/leds/backlight/kinetic,ktz8866.yaml
··· 33 33 34 34 current-num-sinks: 35 35 description: number of the LED current sinks' channels. 36 + $ref: /schemas/types.yaml#/definitions/uint32 36 37 enum: [1, 2, 3, 4, 5, 6] 37 38 38 39 kinetic,current-ramp-delay-ms:
-2
Documentation/devicetree/bindings/leds/common.yaml
··· 105 105 - audio-mute 106 106 # LED indicates bluetooth power state 107 107 - bluetooth-power 108 - # LED indicates activity of all CPUs 109 - - cpu 110 108 # LED indicates camera flash state 111 109 - flash 112 110 # LED indicated keyboard capslock
+1 -1
Documentation/devicetree/bindings/leds/leds-class-multicolor.yaml
··· 34 34 - color 35 35 36 36 allOf: 37 - - $ref: "common.yaml#" 37 + - $ref: common.yaml# 38 38 39 39 additionalProperties: true 40 40
+10
Documentation/devicetree/bindings/leds/leds-lp55xx.yaml
··· 66 66 '#size-cells': 67 67 const: 0 68 68 69 + ti,charge-pump-mode: 70 + description: 71 + Set the operating mode of the internal charge pump as defined in 72 + <dt-bindings/leds/leds-lp55xx.h>. 73 + $ref: /schemas/types.yaml#/definitions/uint32 74 + default: 3 # auto 75 + maximum: 3 76 + 69 77 patternProperties: 70 78 '^multi-led@[0-8]$': 71 79 type: object ··· 160 152 examples: 161 153 - | 162 154 #include <dt-bindings/leds/common.h> 155 + #include <dt-bindings/leds/leds-lp55xx.h> 163 156 164 157 i2c { 165 158 #address-cells = <1>; ··· 173 164 reg = <0x32>; 174 165 clock-mode = /bits/ 8 <2>; 175 166 pwr-sel = /bits/ 8 <3>; /* D1~9 connected to VOUT */ 167 + ti,charge-pump-mode = <LP55XX_CP_BYPASS>; 176 168 177 169 led@0 { 178 170 reg = <0>;
+4 -1
Documentation/devicetree/bindings/leds/leds-mt6323.txt
··· 12 12 Documentation/devicetree/bindings/soc/mediatek/mediatek,pwrap.yaml 13 13 14 14 Required properties: 15 - - compatible : Must be "mediatek,mt6323-led" 15 + - compatible : Must be one of 16 + - "mediatek,mt6323-led" 17 + - "mediatek,mt6331-led" 18 + - "mediatek,mt6332-led" 16 19 - address-cells : Must be 1 17 20 - size-cells : Must be 0 18 21
+18 -12
Documentation/devicetree/bindings/leds/leds-qcom-lpg.yaml
··· 16 16 17 17 properties: 18 18 compatible: 19 - enum: 20 - - qcom,pm660l-lpg 21 - - qcom,pm8150b-lpg 22 - - qcom,pm8150l-lpg 23 - - qcom,pm8350c-pwm 24 - - qcom,pm8916-pwm 25 - - qcom,pm8941-lpg 26 - - qcom,pm8994-lpg 27 - - qcom,pmc8180c-lpg 28 - - qcom,pmi8994-lpg 29 - - qcom,pmi8998-lpg 30 - - qcom,pmk8550-pwm 19 + oneOf: 20 + - enum: 21 + - qcom,pm660l-lpg 22 + - qcom,pm8150b-lpg 23 + - qcom,pm8150l-lpg 24 + - qcom,pm8350c-pwm 25 + - qcom,pm8916-pwm 26 + - qcom,pm8941-lpg 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 36 + - const: qcom,pm8350c-pwm 31 37 32 38 "#pwm-cells": 33 39 const: 2
+1
Documentation/devicetree/bindings/leds/leds-sgm3140.yaml
··· 20 20 compatible: 21 21 enum: 22 22 - ocs,ocp8110 23 + - richtek,rt5033-led 23 24 - sgmicro,sgm3140 24 25 25 26 enable-gpios:
+2
Documentation/devicetree/bindings/leds/qcom,spmi-flash-led.yaml
··· 26 26 - qcom,pm8150c-flash-led 27 27 - qcom,pm8150l-flash-led 28 28 - qcom,pm8350c-flash-led 29 + - qcom,pm8550-flash-led 30 + - qcom,pmi8998-flash-led 29 31 - const: qcom,spmi-flash-led 30 32 31 33 reg:
+1 -1
Documentation/devicetree/bindings/leds/rohm,bd71828-leds.yaml
··· 32 32 properties: 33 33 rohm,led-compatible: 34 34 description: LED identification string 35 - $ref: "/schemas/types.yaml#/definitions/string" 35 + $ref: /schemas/types.yaml#/definitions/string 36 36 enum: 37 37 - bd71828-ambled 38 38 - bd71828-grnled
+1
Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml
··· 71 71 - qcom,pm8998 72 72 - qcom,pma8084 73 73 - qcom,pmd9635 74 + - qcom,pmi632 74 75 - qcom,pmi8950 75 76 - qcom,pmi8962 76 77 - qcom,pmi8994
+1
Documentation/leds/index.rst
··· 17 17 uleds 18 18 19 19 leds-blinkm 20 + leds-cht-wcove 20 21 leds-el15203000 21 22 leds-lm3556 22 23 leds-lp3944
+38
Documentation/leds/leds-cht-wcove.rst
··· 1 + .. SPDX-License-Identifier: GPL-2.0 2 + 3 + =========================================================== 4 + Kernel driver for Intel Cherry Trail Whiskey Cove PMIC LEDs 5 + =========================================================== 6 + 7 + /sys/class/leds/<led>/hw_pattern 8 + -------------------------------- 9 + 10 + Specify a hardware pattern for the Whiskey Cove PMIC LEDs. 11 + 12 + The only supported pattern is hardware breathing mode:: 13 + 14 + "0 2000 1 2000" 15 + 16 + ^ 17 + | 18 + Max-| --- 19 + | / \ 20 + | / \ 21 + | / \ / 22 + | / \ / 23 + Min-|- --- 24 + | 25 + 0------2------4--> time (sec) 26 + 27 + The rise and fall times must be the same value. 28 + Supported values are 2000, 1000, 500 and 250 for 29 + breathing frequencies of 1/4, 1/2, 1 and 2 Hz. 30 + 31 + The set pattern only controls the timing. For max brightness the last 32 + set brightness is used and the max brightness can be changed 33 + while breathing by writing the brightness attribute. 34 + 35 + This is just like how blinking works in the LED subsystem, 36 + for both sw and hw blinking the brightness can also be changed 37 + while blinking. Breathing on this hw really is just a variant 38 + mode of blinking.
+2 -1
Documentation/leds/well-known-leds.txt
··· 58 58 59 59 * System notification 60 60 61 + Good: "rgb:status" 61 62 Legacy: "status-led:{red,green,blue}" (Motorola Droid 4) 62 63 Legacy: "lp5523:{r,g,b}" (Nokia N900) 63 64 ··· 66 65 67 66 * Power management 68 67 69 - Good: "platform:*:charging" (allwinner sun50i) 68 + Good: "platform:*:charging" (allwinner sun50i, leds-cht-wcove) 70 69 71 70 * Screen 72 71
+30 -7
drivers/leds/Kconfig
··· 94 94 95 95 Say Y to if your machine is a Dell Wyse 3020 thin client. 96 96 97 + config LEDS_AW200XX 98 + tristate "LED support for Awinic AW20036/AW20054/AW20072" 99 + depends on LEDS_CLASS 100 + depends on I2C 101 + help 102 + This option enables support for the AW20036/AW20054/AW20072 LED driver. 103 + It is a 3x12/6x9/6x12 matrix LED driver programmed via 104 + an I2C interface, up to 36/54/72 LEDs or 12/18/24 RGBs, 105 + 3 pattern controllers for auto breathing or group dimming control. 106 + 107 + To compile this driver as a module, choose M here: the module 108 + will be called leds-aw200xx. 109 + 97 110 config LEDS_AW2013 98 111 tristate "LED support for Awinic AW2013" 99 112 depends on LEDS_CLASS && I2C && OF ··· 134 121 help 135 122 This option enables support for LEDs connected to the BCM6358 136 123 LED HW controller accessed via MMIO registers. 124 + 125 + config LEDS_CHT_WCOVE 126 + tristate "LED support for Intel Cherry Trail Whiskey Cove PMIC" 127 + depends on LEDS_CLASS 128 + depends on INTEL_SOC_PMIC_CHTWC 129 + help 130 + This option enables support for charger and general purpose LEDs 131 + connected to the Intel Cherrytrail Whiskey Cove PMIC. 132 + 133 + To compile this driver as a module, choose M here: the module 134 + will be called leds-cht-wcove. 137 135 138 136 config LEDS_CPCAP 139 137 tristate "LED Support for Motorola CPCAP" ··· 700 676 701 677 config LEDS_OT200 702 678 tristate "LED support for the Bachmann OT200" 703 - depends on LEDS_CLASS && HAS_IOMEM && (X86_32 || COMPILE_TEST) 679 + depends on LEDS_CLASS && HAS_IOPORT && (X86_32 || COMPILE_TEST) 704 680 help 705 681 This option enables support for the LEDs on the Bachmann OT200. 706 682 Say Y to enable LEDs on the Bachmann OT200. ··· 831 807 supported: Ubiquiti airCube ISP microcontroller based LED controller. 832 808 833 809 config LEDS_TI_LMU_COMMON 834 - tristate "LED driver for TI LMU" 835 - depends on LEDS_CLASS 810 + tristate "LED driver for TI LMU" if COMPILE_TEST 836 811 select REGMAP 837 812 help 838 813 Say Y to enable the LED driver for TI LMU devices. ··· 840 817 841 818 config LEDS_LM3697 842 819 tristate "LED driver for LM3697" 843 - depends on LEDS_TI_LMU_COMMON 844 - depends on I2C && OF 820 + depends on LEDS_CLASS && I2C && OF 821 + select LEDS_TI_LMU_COMMON 845 822 help 846 823 Say Y to enable the LM3697 LED driver for TI LMU devices. 847 824 This supports the LED device LM3697. 848 825 849 826 config LEDS_LM36274 850 827 tristate "LED driver for LM36274" 851 - depends on LEDS_TI_LMU_COMMON 852 - depends on MFD_TI_LMU 828 + depends on LEDS_CLASS && MFD_TI_LMU 829 + select LEDS_TI_LMU_COMMON 853 830 help 854 831 Say Y to enable the LM36274 LED driver for TI LMU devices. 855 832 This supports the LED device LM36274.
+2
drivers/leds/Makefile
··· 14 14 obj-$(CONFIG_LEDS_AN30259A) += leds-an30259a.o 15 15 obj-$(CONFIG_LEDS_APU) += leds-apu.o 16 16 obj-$(CONFIG_LEDS_ARIEL) += leds-ariel.o 17 + obj-$(CONFIG_LEDS_AW200XX) += leds-aw200xx.o 17 18 obj-$(CONFIG_LEDS_AW2013) += leds-aw2013.o 18 19 obj-$(CONFIG_LEDS_BCM6328) += leds-bcm6328.o 19 20 obj-$(CONFIG_LEDS_BCM6358) += leds-bcm6358.o 20 21 obj-$(CONFIG_LEDS_BD2606MVV) += leds-bd2606mvv.o 21 22 obj-$(CONFIG_LEDS_BD2802) += leds-bd2802.o 22 23 obj-$(CONFIG_LEDS_BLINKM) += leds-blinkm.o 24 + obj-$(CONFIG_LEDS_CHT_WCOVE) += leds-cht-wcove.o 23 25 obj-$(CONFIG_LEDS_CLEVO_MAIL) += leds-clevo-mail.o 24 26 obj-$(CONFIG_LEDS_COBALT_QUBE) += leds-cobalt-qube.o 25 27 obj-$(CONFIG_LEDS_COBALT_RAQ) += leds-cobalt-raq.o
+1 -1
drivers/leds/flash/leds-aat1290.c
··· 425 425 struct led_classdev *led_cdev = &led->fled_cdev.led_cdev; 426 426 struct led_flash_setting *s; 427 427 428 - strlcpy(v4l2_sd_cfg->dev_name, led_cdev->dev->kobj.name, 428 + strscpy(v4l2_sd_cfg->dev_name, led_cdev->dev->kobj.name, 429 429 sizeof(v4l2_sd_cfg->dev_name)); 430 430 431 431 s = &v4l2_sd_cfg->intensity;
+3 -3
drivers/leds/flash/leds-as3645a.c
··· 651 651 }, 652 652 }; 653 653 654 - strlcpy(cfg.dev_name, led->dev->kobj.name, sizeof(cfg.dev_name)); 655 - strlcpy(cfgind.dev_name, flash->iled_cdev.dev->kobj.name, 654 + strscpy(cfg.dev_name, led->dev->kobj.name, sizeof(cfg.dev_name)); 655 + strscpy(cfgind.dev_name, flash->iled_cdev.dev->kobj.name, 656 656 sizeof(cfgind.dev_name)); 657 657 658 658 flash->vf = v4l2_flash_init( ··· 759 759 .of_match_table = as3645a_of_table, 760 760 .name = AS_NAME, 761 761 }, 762 - .probe_new = as3645a_probe, 762 + .probe = as3645a_probe, 763 763 .remove = as3645a_remove, 764 764 .id_table = as3645a_id_table, 765 765 };
+1 -1
drivers/leds/flash/leds-lm3601x.c
··· 471 471 .name = "lm3601x", 472 472 .of_match_table = of_lm3601x_leds_match, 473 473 }, 474 - .probe_new = lm3601x_probe, 474 + .probe = lm3601x_probe, 475 475 .remove = lm3601x_remove, 476 476 .id_table = lm3601x_id, 477 477 };
+13 -4
drivers/leds/flash/leds-qcom-flash.c
··· 18 18 #define FLASH_TYPE_VAL 0x18 19 19 20 20 #define FLASH_SUBTYPE_REG 0x05 21 - #define FLASH_SUBTYPE_3CH_VAL 0x04 21 + #define FLASH_SUBTYPE_3CH_PM8150_VAL 0x04 22 + #define FLASH_SUBTYPE_3CH_PMI8998_VAL 0x03 22 23 #define FLASH_SUBTYPE_4CH_VAL 0x07 23 24 24 25 #define FLASH_STS_3CH_OTST1 BIT(0) ··· 417 416 bool enable = !!brightness; 418 417 int rc; 419 418 419 + rc = set_flash_strobe(led, SW_STROBE, false); 420 + if (rc) 421 + return rc; 422 + 423 + rc = set_flash_module_en(led, false); 424 + if (rc) 425 + return rc; 426 + 420 427 rc = set_flash_current(led, current_ma, TORCH_MODE); 421 428 if (rc) 422 429 return rc; ··· 538 529 struct led_init_data init_data; 539 530 struct led_classdev_flash *flash = &led->flash; 540 531 struct led_flash_setting *brightness, *timeout; 541 - u32 count, current_ua, timeout_us; 532 + u32 current_ua, timeout_us; 542 533 u32 channels[4]; 543 - int i, rc; 534 + int i, rc, count; 544 535 545 536 count = fwnode_property_count_u32(node, "led-sources"); 546 537 if (count <= 0) { ··· 691 682 return rc; 692 683 } 693 684 694 - if (val == FLASH_SUBTYPE_3CH_VAL) { 685 + if (val == FLASH_SUBTYPE_3CH_PM8150_VAL || val == FLASH_SUBTYPE_3CH_PMI8998_VAL) { 695 686 flash_data->hw_type = QCOM_MVFLASH_3CH; 696 687 flash_data->max_channels = 3; 697 688 regs = mvflash_3ch_regs;
+1 -1
drivers/leds/flash/leds-rt4505.c
··· 419 419 .name = "rt4505", 420 420 .of_match_table = of_match_ptr(rt4505_leds_match), 421 421 }, 422 - .probe_new = rt4505_probe, 422 + .probe = rt4505_probe, 423 423 .remove = rt4505_remove, 424 424 .shutdown = rt4505_shutdown, 425 425 };
+1
drivers/leds/flash/leds-sgm3140.c
··· 291 291 292 292 static const struct of_device_id sgm3140_dt_match[] = { 293 293 { .compatible = "ocs,ocp8110" }, 294 + { .compatible = "richtek,rt5033-led" }, 294 295 { .compatible = "sgmicro,sgm3140" }, 295 296 { /* sentinel */ } 296 297 };
+1 -1
drivers/leds/led-class.c
··· 409 409 int ret = 0; 410 410 struct device *dev; 411 411 412 - strlcpy(name, init_name, len); 412 + strscpy(name, init_name, len); 413 413 414 414 while ((ret < len) && 415 415 (dev = class_find_device_by_name(leds_class, name))) {
+68 -13
drivers/leds/led-core.c
··· 114 114 mod_timer(&led_cdev->blink_timer, jiffies + msecs_to_jiffies(delay)); 115 115 } 116 116 117 - static void set_brightness_delayed(struct work_struct *ws) 117 + static void set_brightness_delayed_set_brightness(struct led_classdev *led_cdev, 118 + unsigned int value) 118 119 { 119 - struct led_classdev *led_cdev = 120 - container_of(ws, struct led_classdev, set_brightness_work); 121 120 int ret = 0; 122 121 123 - if (test_and_clear_bit(LED_BLINK_DISABLE, &led_cdev->work_flags)) { 124 - led_cdev->delayed_set_value = LED_OFF; 125 - led_stop_software_blink(led_cdev); 126 - } 127 - 128 - ret = __led_set_brightness(led_cdev, led_cdev->delayed_set_value); 122 + ret = __led_set_brightness(led_cdev, value); 129 123 if (ret == -ENOTSUPP) 130 - ret = __led_set_brightness_blocking(led_cdev, 131 - led_cdev->delayed_set_value); 124 + ret = __led_set_brightness_blocking(led_cdev, value); 132 125 if (ret < 0 && 133 126 /* LED HW might have been unplugged, therefore don't warn */ 134 127 !(ret == -ENODEV && (led_cdev->flags & LED_UNREGISTERING) && 135 128 (led_cdev->flags & LED_HW_PLUGGABLE))) 136 129 dev_err(led_cdev->dev, 137 130 "Setting an LED's brightness failed (%d)\n", ret); 131 + } 132 + 133 + static void set_brightness_delayed(struct work_struct *ws) 134 + { 135 + struct led_classdev *led_cdev = 136 + container_of(ws, struct led_classdev, set_brightness_work); 137 + 138 + if (test_and_clear_bit(LED_BLINK_DISABLE, &led_cdev->work_flags)) { 139 + led_stop_software_blink(led_cdev); 140 + set_bit(LED_SET_BRIGHTNESS_OFF, &led_cdev->work_flags); 141 + } 142 + 143 + /* 144 + * Triggers may call led_set_brightness(LED_OFF), 145 + * led_set_brightness(LED_FULL) in quick succession to disable blinking 146 + * and turn the LED on. Both actions may have been scheduled to run 147 + * before this work item runs once. To make sure this works properly 148 + * handle LED_SET_BRIGHTNESS_OFF first. 149 + */ 150 + if (test_and_clear_bit(LED_SET_BRIGHTNESS_OFF, &led_cdev->work_flags)) 151 + set_brightness_delayed_set_brightness(led_cdev, LED_OFF); 152 + 153 + if (test_and_clear_bit(LED_SET_BRIGHTNESS, &led_cdev->work_flags)) 154 + set_brightness_delayed_set_brightness(led_cdev, led_cdev->delayed_set_value); 155 + 156 + if (test_and_clear_bit(LED_SET_BLINK, &led_cdev->work_flags)) { 157 + unsigned long delay_on = led_cdev->delayed_delay_on; 158 + unsigned long delay_off = led_cdev->delayed_delay_off; 159 + 160 + led_blink_set(led_cdev, &delay_on, &delay_off); 161 + } 138 162 } 139 163 140 164 static void led_set_software_blink(struct led_classdev *led_cdev, ··· 253 229 } 254 230 EXPORT_SYMBOL_GPL(led_blink_set_oneshot); 255 231 232 + void led_blink_set_nosleep(struct led_classdev *led_cdev, unsigned long delay_on, 233 + unsigned long delay_off) 234 + { 235 + /* If necessary delegate to a work queue task. */ 236 + if (led_cdev->blink_set && led_cdev->brightness_set_blocking) { 237 + led_cdev->delayed_delay_on = delay_on; 238 + led_cdev->delayed_delay_off = delay_off; 239 + set_bit(LED_SET_BLINK, &led_cdev->work_flags); 240 + schedule_work(&led_cdev->set_brightness_work); 241 + return; 242 + } 243 + 244 + led_blink_set(led_cdev, &delay_on, &delay_off); 245 + } 246 + EXPORT_SYMBOL_GPL(led_blink_set_nosleep); 247 + 256 248 void led_stop_software_blink(struct led_classdev *led_cdev) 257 249 { 258 250 del_timer_sync(&led_cdev->blink_timer); ··· 311 271 if (!__led_set_brightness(led_cdev, value)) 312 272 return; 313 273 314 - /* If brightness setting can sleep, delegate it to a work queue task */ 315 - led_cdev->delayed_set_value = value; 274 + /* 275 + * Brightness setting can sleep, delegate it to a work queue task. 276 + * value 0 / LED_OFF is special, since it also disables hw-blinking 277 + * (sw-blink disable is handled in led_set_brightness()). 278 + * To avoid a hw-blink-disable getting lost when a second brightness 279 + * change is done immediately afterwards (before the work runs), 280 + * it uses a separate work_flag. 281 + */ 282 + if (value) { 283 + led_cdev->delayed_set_value = value; 284 + set_bit(LED_SET_BRIGHTNESS, &led_cdev->work_flags); 285 + } else { 286 + clear_bit(LED_SET_BRIGHTNESS, &led_cdev->work_flags); 287 + clear_bit(LED_SET_BLINK, &led_cdev->work_flags); 288 + set_bit(LED_SET_BRIGHTNESS_OFF, &led_cdev->work_flags); 289 + } 290 + 316 291 schedule_work(&led_cdev->set_brightness_work); 317 292 } 318 293 EXPORT_SYMBOL_GPL(led_set_brightness_nopm);
+9 -8
drivers/leds/led-triggers.c
··· 185 185 led_cdev->trigger = NULL; 186 186 led_cdev->trigger_data = NULL; 187 187 led_cdev->activated = false; 188 + led_cdev->flags &= ~LED_INIT_DEFAULT_TRIGGER; 188 189 led_set_brightness(led_cdev, LED_OFF); 189 190 } 190 191 if (trig) { ··· 394 393 EXPORT_SYMBOL_GPL(led_trigger_event); 395 394 396 395 static void led_trigger_blink_setup(struct led_trigger *trig, 397 - unsigned long *delay_on, 398 - unsigned long *delay_off, 396 + unsigned long delay_on, 397 + unsigned long delay_off, 399 398 int oneshot, 400 399 int invert) 401 400 { ··· 407 406 rcu_read_lock(); 408 407 list_for_each_entry_rcu(led_cdev, &trig->led_cdevs, trig_list) { 409 408 if (oneshot) 410 - led_blink_set_oneshot(led_cdev, delay_on, delay_off, 409 + led_blink_set_oneshot(led_cdev, &delay_on, &delay_off, 411 410 invert); 412 411 else 413 - led_blink_set(led_cdev, delay_on, delay_off); 412 + led_blink_set_nosleep(led_cdev, delay_on, delay_off); 414 413 } 415 414 rcu_read_unlock(); 416 415 } 417 416 418 417 void led_trigger_blink(struct led_trigger *trig, 419 - unsigned long *delay_on, 420 - unsigned long *delay_off) 418 + unsigned long delay_on, 419 + unsigned long delay_off) 421 420 { 422 421 led_trigger_blink_setup(trig, delay_on, delay_off, 0, 0); 423 422 } 424 423 EXPORT_SYMBOL_GPL(led_trigger_blink); 425 424 426 425 void led_trigger_blink_oneshot(struct led_trigger *trig, 427 - unsigned long *delay_on, 428 - unsigned long *delay_off, 426 + unsigned long delay_on, 427 + unsigned long delay_off, 429 428 int invert) 430 429 { 431 430 led_trigger_blink_setup(trig, delay_on, delay_off, 1, invert);
+1 -1
drivers/leds/leds-an30259a.c
··· 346 346 .name = "leds-an30259a", 347 347 .of_match_table = of_match_ptr(an30259a_match_table), 348 348 }, 349 - .probe_new = an30259a_probe, 349 + .probe = an30259a_probe, 350 350 .remove = an30259a_remove, 351 351 .id_table = an30259a_id, 352 352 };
+594
drivers/leds/leds-aw200xx.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Awinic AW20036/AW20054/AW20072 LED driver 4 + * 5 + * Copyright (c) 2023, SberDevices. All Rights Reserved. 6 + * 7 + * Author: Martin Kurbanov <mmkurbanov@sberdevices.ru> 8 + */ 9 + 10 + #include <linux/bitfield.h> 11 + #include <linux/bits.h> 12 + #include <linux/container_of.h> 13 + #include <linux/i2c.h> 14 + #include <linux/leds.h> 15 + #include <linux/mod_devicetable.h> 16 + #include <linux/module.h> 17 + #include <linux/mutex.h> 18 + #include <linux/regmap.h> 19 + #include <linux/time.h> 20 + #include <linux/units.h> 21 + 22 + #define AW200XX_DIM_MAX (BIT(6) - 1) 23 + #define AW200XX_FADE_MAX (BIT(8) - 1) 24 + #define AW200XX_IMAX_DEFAULT_uA 60000 25 + #define AW200XX_IMAX_MAX_uA 160000 26 + #define AW200XX_IMAX_MIN_uA 3300 27 + 28 + /* Page 0 */ 29 + #define AW200XX_REG_PAGE0_BASE 0xc000 30 + 31 + /* Select page register */ 32 + #define AW200XX_REG_PAGE 0xF0 33 + #define AW200XX_PAGE_MASK (GENMASK(7, 6) | GENMASK(2, 0)) 34 + #define AW200XX_PAGE_SHIFT 0 35 + #define AW200XX_NUM_PAGES 6 36 + #define AW200XX_PAGE_SIZE 256 37 + #define AW200XX_REG(page, reg) \ 38 + (AW200XX_REG_PAGE0_BASE + (page) * AW200XX_PAGE_SIZE + (reg)) 39 + #define AW200XX_REG_MAX \ 40 + AW200XX_REG(AW200XX_NUM_PAGES - 1, AW200XX_PAGE_SIZE - 1) 41 + #define AW200XX_PAGE0 0 42 + #define AW200XX_PAGE1 1 43 + #define AW200XX_PAGE2 2 44 + #define AW200XX_PAGE3 3 45 + #define AW200XX_PAGE4 4 46 + #define AW200XX_PAGE5 5 47 + 48 + /* Chip ID register */ 49 + #define AW200XX_REG_IDR AW200XX_REG(AW200XX_PAGE0, 0x00) 50 + #define AW200XX_IDR_CHIPID 0x18 51 + 52 + /* Sleep mode register */ 53 + #define AW200XX_REG_SLPCR AW200XX_REG(AW200XX_PAGE0, 0x01) 54 + #define AW200XX_SLPCR_ACTIVE 0x00 55 + 56 + /* Reset register */ 57 + #define AW200XX_REG_RSTR AW200XX_REG(AW200XX_PAGE0, 0x02) 58 + #define AW200XX_RSTR_RESET 0x01 59 + 60 + /* Global current configuration register */ 61 + #define AW200XX_REG_GCCR AW200XX_REG(AW200XX_PAGE0, 0x03) 62 + #define AW200XX_GCCR_IMAX_MASK GENMASK(7, 4) 63 + #define AW200XX_GCCR_IMAX(x) ((x) << 4) 64 + #define AW200XX_GCCR_ALLON BIT(3) 65 + 66 + /* Fast clear display control register */ 67 + #define AW200XX_REG_FCD AW200XX_REG(AW200XX_PAGE0, 0x04) 68 + #define AW200XX_FCD_CLEAR 0x01 69 + 70 + /* Display size configuration */ 71 + #define AW200XX_REG_DSIZE AW200XX_REG(AW200XX_PAGE0, 0x80) 72 + #define AW200XX_DSIZE_COLUMNS_MAX 12 73 + 74 + #define AW200XX_LED2REG(x, columns) \ 75 + ((x) + (((x) / (columns)) * (AW200XX_DSIZE_COLUMNS_MAX - (columns)))) 76 + 77 + /* 78 + * DIM current configuration register (page 4). 79 + * The even address for current DIM configuration. 80 + * The odd address for current FADE configuration 81 + */ 82 + #define AW200XX_REG_DIM(x, columns) \ 83 + AW200XX_REG(AW200XX_PAGE4, AW200XX_LED2REG(x, columns) * 2) 84 + #define AW200XX_REG_DIM2FADE(x) ((x) + 1) 85 + 86 + /* 87 + * Duty ratio of display scan (see p.15 of datasheet for formula): 88 + * duty = (592us / 600.5us) * (1 / (display_rows + 1)) 89 + * 90 + * Multiply to 1000 (MILLI) to improve the accuracy of calculations. 91 + */ 92 + #define AW200XX_DUTY_RATIO(rows) \ 93 + (((592UL * USEC_PER_SEC) / 600500UL) * (MILLI / (rows)) / MILLI) 94 + 95 + struct aw200xx_chipdef { 96 + u32 channels; 97 + u32 display_size_rows_max; 98 + u32 display_size_columns; 99 + }; 100 + 101 + struct aw200xx_led { 102 + struct led_classdev cdev; 103 + struct aw200xx *chip; 104 + int dim; 105 + u32 num; 106 + }; 107 + 108 + struct aw200xx { 109 + const struct aw200xx_chipdef *cdef; 110 + struct i2c_client *client; 111 + struct regmap *regmap; 112 + struct mutex mutex; 113 + u32 num_leds; 114 + u32 display_rows; 115 + struct aw200xx_led leds[]; 116 + }; 117 + 118 + static ssize_t dim_show(struct device *dev, struct device_attribute *devattr, 119 + char *buf) 120 + { 121 + struct led_classdev *cdev = dev_get_drvdata(dev); 122 + struct aw200xx_led *led = container_of(cdev, struct aw200xx_led, cdev); 123 + int dim = led->dim; 124 + 125 + if (dim < 0) 126 + return sysfs_emit(buf, "auto\n"); 127 + 128 + return sysfs_emit(buf, "%d\n", dim); 129 + } 130 + 131 + static ssize_t dim_store(struct device *dev, struct device_attribute *devattr, 132 + const char *buf, size_t count) 133 + { 134 + struct led_classdev *cdev = dev_get_drvdata(dev); 135 + struct aw200xx_led *led = container_of(cdev, struct aw200xx_led, cdev); 136 + struct aw200xx *chip = led->chip; 137 + u32 columns = chip->cdef->display_size_columns; 138 + int dim; 139 + ssize_t ret; 140 + 141 + if (sysfs_streq(buf, "auto")) { 142 + dim = -1; 143 + } else { 144 + ret = kstrtoint(buf, 0, &dim); 145 + if (ret) 146 + return ret; 147 + 148 + if (dim > AW200XX_DIM_MAX) 149 + return -EINVAL; 150 + } 151 + 152 + mutex_lock(&chip->mutex); 153 + 154 + if (dim >= 0) { 155 + ret = regmap_write(chip->regmap, 156 + AW200XX_REG_DIM(led->num, columns), dim); 157 + if (ret) 158 + goto out_unlock; 159 + } 160 + 161 + led->dim = dim; 162 + ret = count; 163 + 164 + out_unlock: 165 + mutex_unlock(&chip->mutex); 166 + return ret; 167 + } 168 + static DEVICE_ATTR_RW(dim); 169 + 170 + static struct attribute *dim_attrs[] = { 171 + &dev_attr_dim.attr, 172 + NULL 173 + }; 174 + ATTRIBUTE_GROUPS(dim); 175 + 176 + static int aw200xx_brightness_set(struct led_classdev *cdev, 177 + enum led_brightness brightness) 178 + { 179 + struct aw200xx_led *led = container_of(cdev, struct aw200xx_led, cdev); 180 + struct aw200xx *chip = led->chip; 181 + int dim; 182 + u32 reg; 183 + int ret; 184 + 185 + mutex_lock(&chip->mutex); 186 + 187 + reg = AW200XX_REG_DIM(led->num, chip->cdef->display_size_columns); 188 + 189 + dim = led->dim; 190 + if (dim < 0) 191 + dim = max_t(int, 192 + brightness / (AW200XX_FADE_MAX / AW200XX_DIM_MAX), 193 + 1); 194 + 195 + ret = regmap_write(chip->regmap, reg, dim); 196 + if (ret) 197 + goto out_unlock; 198 + 199 + ret = regmap_write(chip->regmap, 200 + AW200XX_REG_DIM2FADE(reg), brightness); 201 + 202 + out_unlock: 203 + mutex_unlock(&chip->mutex); 204 + 205 + return ret; 206 + } 207 + 208 + static u32 aw200xx_imax_from_global(const struct aw200xx *const chip, 209 + u32 global_imax_uA) 210 + { 211 + u64 led_imax_uA; 212 + 213 + /* 214 + * The output current of each LED (see p.14 of datasheet for formula): 215 + * Iled = Imax * (dim / 63) * ((fade + 1) / 256) * duty 216 + * 217 + * The value of duty is determined by the following formula: 218 + * duty = (592us / 600.5us) * (1 / (display_rows + 1)) 219 + * 220 + * Calculated for the maximum values of fade and dim. 221 + * We divide by 1000 because we earlier multiplied by 1000 to improve 222 + * accuracy when calculating the duty. 223 + */ 224 + led_imax_uA = global_imax_uA * AW200XX_DUTY_RATIO(chip->display_rows); 225 + do_div(led_imax_uA, MILLI); 226 + 227 + return led_imax_uA; 228 + } 229 + 230 + static u32 aw200xx_imax_to_global(const struct aw200xx *const chip, 231 + u32 led_imax_uA) 232 + { 233 + u32 duty = AW200XX_DUTY_RATIO(chip->display_rows); 234 + 235 + /* The output current of each LED (see p.14 of datasheet for formula) */ 236 + return (led_imax_uA * 1000U) / duty; 237 + } 238 + 239 + #define AW200XX_IMAX_MULTIPLIER1 10000 240 + #define AW200XX_IMAX_MULTIPLIER2 3333 241 + #define AW200XX_IMAX_BASE_VAL1 0 242 + #define AW200XX_IMAX_BASE_VAL2 8 243 + 244 + /* 245 + * The AW200XX has a 4-bit register (GCCR) to configure the global current, 246 + * which ranges from 3.3mA to 160mA. The following table indicates the values 247 + * of the global current, divided into two parts: 248 + * 249 + * +-----------+-----------------+-----------+-----------------+ 250 + * | reg value | global max (mA) | reg value | global max (mA) | 251 + * +-----------+-----------------+-----------+-----------------+ 252 + * | 0 | 10 | 8 | 3.3 | 253 + * | 1 | 20 | 9 | 6.7 | 254 + * | 2 | 30 | 10 | 10 | 255 + * | 3 | 40 | 11 | 13.3 | 256 + * | 4 | 60 | 12 | 20 | 257 + * | 5 | 80 | 13 | 26.7 | 258 + * | 6 | 120 | 14 | 40 | 259 + * | 7 | 160 | 15 | 53.3 | 260 + * +-----------+-----------------+-----------+-----------------+ 261 + * 262 + * The left part with a multiplier of 10, and the right part with a multiplier 263 + * of 3.3. 264 + * So we have two formulas to calculate the global current: 265 + * for the left part of the table: 266 + * imax = coefficient * 10 267 + * 268 + * for the right part of the table: 269 + * imax = coefficient * 3.3 270 + * 271 + * The coefficient table consists of the following values: 272 + * 1, 2, 3, 4, 6, 8, 12, 16. 273 + */ 274 + static int aw200xx_set_imax(const struct aw200xx *const chip, 275 + u32 led_imax_uA) 276 + { 277 + u32 g_imax_uA = aw200xx_imax_to_global(chip, led_imax_uA); 278 + u32 coeff_table[] = {1, 2, 3, 4, 6, 8, 12, 16}; 279 + u32 gccr_imax = UINT_MAX; 280 + u32 cur_imax = 0; 281 + int i; 282 + 283 + for (i = 0; i < ARRAY_SIZE(coeff_table); i++) { 284 + u32 imax; 285 + 286 + /* select closest ones */ 287 + imax = coeff_table[i] * AW200XX_IMAX_MULTIPLIER1; 288 + if (g_imax_uA >= imax && imax > cur_imax) { 289 + cur_imax = imax; 290 + gccr_imax = i + AW200XX_IMAX_BASE_VAL1; 291 + } 292 + 293 + imax = coeff_table[i] * AW200XX_IMAX_MULTIPLIER2; 294 + imax = DIV_ROUND_CLOSEST(imax, 100) * 100; 295 + if (g_imax_uA >= imax && imax > cur_imax) { 296 + cur_imax = imax; 297 + gccr_imax = i + AW200XX_IMAX_BASE_VAL2; 298 + } 299 + } 300 + 301 + if (gccr_imax == UINT_MAX) 302 + return -EINVAL; 303 + 304 + return regmap_update_bits(chip->regmap, AW200XX_REG_GCCR, 305 + AW200XX_GCCR_IMAX_MASK, 306 + AW200XX_GCCR_IMAX(gccr_imax)); 307 + } 308 + 309 + static int aw200xx_chip_reset(const struct aw200xx *const chip) 310 + { 311 + int ret; 312 + 313 + ret = regmap_write(chip->regmap, AW200XX_REG_RSTR, AW200XX_RSTR_RESET); 314 + if (ret) 315 + return ret; 316 + 317 + regcache_mark_dirty(chip->regmap); 318 + return regmap_write(chip->regmap, AW200XX_REG_FCD, AW200XX_FCD_CLEAR); 319 + } 320 + 321 + static int aw200xx_chip_init(const struct aw200xx *const chip) 322 + { 323 + int ret; 324 + 325 + ret = regmap_write(chip->regmap, AW200XX_REG_DSIZE, 326 + chip->display_rows - 1); 327 + if (ret) 328 + return ret; 329 + 330 + ret = regmap_write(chip->regmap, AW200XX_REG_SLPCR, 331 + AW200XX_SLPCR_ACTIVE); 332 + if (ret) 333 + return ret; 334 + 335 + return regmap_update_bits(chip->regmap, AW200XX_REG_GCCR, 336 + AW200XX_GCCR_ALLON, AW200XX_GCCR_ALLON); 337 + } 338 + 339 + static int aw200xx_chip_check(const struct aw200xx *const chip) 340 + { 341 + struct device *dev = &chip->client->dev; 342 + u32 chipid; 343 + int ret; 344 + 345 + ret = regmap_read(chip->regmap, AW200XX_REG_IDR, &chipid); 346 + if (ret) 347 + return dev_err_probe(dev, ret, "Failed to read chip ID\n"); 348 + 349 + if (chipid != AW200XX_IDR_CHIPID) 350 + return dev_err_probe(dev, -ENODEV, 351 + "Chip reported wrong ID: %x\n", chipid); 352 + 353 + return 0; 354 + } 355 + 356 + static int aw200xx_probe_fw(struct device *dev, struct aw200xx *chip) 357 + { 358 + struct fwnode_handle *child; 359 + u32 current_min, current_max, min_uA; 360 + int ret; 361 + int i; 362 + 363 + ret = device_property_read_u32(dev, "awinic,display-rows", 364 + &chip->display_rows); 365 + if (ret) 366 + return dev_err_probe(dev, ret, 367 + "Failed to read 'display-rows' property\n"); 368 + 369 + if (!chip->display_rows || 370 + chip->display_rows > chip->cdef->display_size_rows_max) { 371 + return dev_err_probe(dev, ret, 372 + "Invalid leds display size %u\n", 373 + chip->display_rows); 374 + } 375 + 376 + current_max = aw200xx_imax_from_global(chip, AW200XX_IMAX_MAX_uA); 377 + current_min = aw200xx_imax_from_global(chip, AW200XX_IMAX_MIN_uA); 378 + min_uA = UINT_MAX; 379 + i = 0; 380 + 381 + device_for_each_child_node(dev, child) { 382 + struct led_init_data init_data = {}; 383 + struct aw200xx_led *led; 384 + u32 source, imax; 385 + 386 + ret = fwnode_property_read_u32(child, "reg", &source); 387 + if (ret) { 388 + dev_err(dev, "Missing reg property\n"); 389 + chip->num_leds--; 390 + continue; 391 + } 392 + 393 + if (source >= chip->cdef->channels) { 394 + dev_err(dev, "LED reg %u out of range (max %u)\n", 395 + source, chip->cdef->channels); 396 + chip->num_leds--; 397 + continue; 398 + } 399 + 400 + ret = fwnode_property_read_u32(child, "led-max-microamp", 401 + &imax); 402 + if (ret) { 403 + dev_info(&chip->client->dev, 404 + "DT property led-max-microamp is missing\n"); 405 + } else if (imax < current_min || imax > current_max) { 406 + dev_err(dev, "Invalid value %u for led-max-microamp\n", 407 + imax); 408 + chip->num_leds--; 409 + continue; 410 + } else { 411 + min_uA = min(min_uA, imax); 412 + } 413 + 414 + led = &chip->leds[i]; 415 + led->dim = -1; 416 + led->num = source; 417 + led->chip = chip; 418 + led->cdev.brightness_set_blocking = aw200xx_brightness_set; 419 + led->cdev.groups = dim_groups; 420 + init_data.fwnode = child; 421 + 422 + ret = devm_led_classdev_register_ext(dev, &led->cdev, 423 + &init_data); 424 + if (ret) { 425 + fwnode_handle_put(child); 426 + break; 427 + } 428 + 429 + i++; 430 + } 431 + 432 + if (!chip->num_leds) 433 + return -EINVAL; 434 + 435 + if (min_uA == UINT_MAX) { 436 + min_uA = aw200xx_imax_from_global(chip, 437 + AW200XX_IMAX_DEFAULT_uA); 438 + } 439 + 440 + return aw200xx_set_imax(chip, min_uA); 441 + } 442 + 443 + static const struct regmap_range_cfg aw200xx_ranges[] = { 444 + { 445 + .name = "aw200xx", 446 + .range_min = 0, 447 + .range_max = AW200XX_REG_MAX, 448 + .selector_reg = AW200XX_REG_PAGE, 449 + .selector_mask = AW200XX_PAGE_MASK, 450 + .selector_shift = AW200XX_PAGE_SHIFT, 451 + .window_start = 0, 452 + .window_len = AW200XX_PAGE_SIZE, 453 + }, 454 + }; 455 + 456 + static const struct regmap_range aw200xx_writeonly_ranges[] = { 457 + regmap_reg_range(AW200XX_REG(AW200XX_PAGE1, 0x00), AW200XX_REG_MAX), 458 + }; 459 + 460 + static const struct regmap_access_table aw200xx_readable_table = { 461 + .no_ranges = aw200xx_writeonly_ranges, 462 + .n_no_ranges = ARRAY_SIZE(aw200xx_writeonly_ranges), 463 + }; 464 + 465 + static const struct regmap_range aw200xx_readonly_ranges[] = { 466 + regmap_reg_range(AW200XX_REG_IDR, AW200XX_REG_IDR), 467 + }; 468 + 469 + static const struct regmap_access_table aw200xx_writeable_table = { 470 + .no_ranges = aw200xx_readonly_ranges, 471 + .n_no_ranges = ARRAY_SIZE(aw200xx_readonly_ranges), 472 + }; 473 + 474 + static const struct regmap_config aw200xx_regmap_config = { 475 + .reg_bits = 8, 476 + .val_bits = 8, 477 + .max_register = AW200XX_REG_MAX, 478 + .ranges = aw200xx_ranges, 479 + .num_ranges = ARRAY_SIZE(aw200xx_ranges), 480 + .rd_table = &aw200xx_readable_table, 481 + .wr_table = &aw200xx_writeable_table, 482 + .cache_type = REGCACHE_RBTREE, 483 + }; 484 + 485 + static int aw200xx_probe(struct i2c_client *client) 486 + { 487 + const struct aw200xx_chipdef *cdef; 488 + struct aw200xx *chip; 489 + int count; 490 + int ret; 491 + 492 + cdef = device_get_match_data(&client->dev); 493 + if (!cdef) 494 + return -ENODEV; 495 + 496 + count = device_get_child_node_count(&client->dev); 497 + if (!count || count > cdef->channels) 498 + return dev_err_probe(&client->dev, -EINVAL, 499 + "Incorrect number of leds (%d)", count); 500 + 501 + chip = devm_kzalloc(&client->dev, struct_size(chip, leds, count), 502 + GFP_KERNEL); 503 + if (!chip) 504 + return -ENOMEM; 505 + 506 + chip->cdef = cdef; 507 + chip->num_leds = count; 508 + chip->client = client; 509 + i2c_set_clientdata(client, chip); 510 + 511 + chip->regmap = devm_regmap_init_i2c(client, &aw200xx_regmap_config); 512 + if (IS_ERR(chip->regmap)) 513 + return PTR_ERR(chip->regmap); 514 + 515 + ret = aw200xx_chip_check(chip); 516 + if (ret) 517 + return ret; 518 + 519 + mutex_init(&chip->mutex); 520 + 521 + /* Need a lock now since after call aw200xx_probe_fw, sysfs nodes created */ 522 + mutex_lock(&chip->mutex); 523 + 524 + ret = aw200xx_chip_reset(chip); 525 + if (ret) 526 + goto out_unlock; 527 + 528 + ret = aw200xx_probe_fw(&client->dev, chip); 529 + if (ret) 530 + goto out_unlock; 531 + 532 + ret = aw200xx_chip_init(chip); 533 + 534 + out_unlock: 535 + mutex_unlock(&chip->mutex); 536 + return ret; 537 + } 538 + 539 + static void aw200xx_remove(struct i2c_client *client) 540 + { 541 + struct aw200xx *chip = i2c_get_clientdata(client); 542 + 543 + aw200xx_chip_reset(chip); 544 + mutex_destroy(&chip->mutex); 545 + } 546 + 547 + static const struct aw200xx_chipdef aw20036_cdef = { 548 + .channels = 36, 549 + .display_size_rows_max = 3, 550 + .display_size_columns = 12, 551 + }; 552 + 553 + static const struct aw200xx_chipdef aw20054_cdef = { 554 + .channels = 54, 555 + .display_size_rows_max = 6, 556 + .display_size_columns = 9, 557 + }; 558 + 559 + static const struct aw200xx_chipdef aw20072_cdef = { 560 + .channels = 72, 561 + .display_size_rows_max = 6, 562 + .display_size_columns = 12, 563 + }; 564 + 565 + static const struct i2c_device_id aw200xx_id[] = { 566 + { "aw20036" }, 567 + { "aw20054" }, 568 + { "aw20072" }, 569 + {} 570 + }; 571 + MODULE_DEVICE_TABLE(i2c, aw200xx_id); 572 + 573 + static const struct of_device_id aw200xx_match_table[] = { 574 + { .compatible = "awinic,aw20036", .data = &aw20036_cdef, }, 575 + { .compatible = "awinic,aw20054", .data = &aw20054_cdef, }, 576 + { .compatible = "awinic,aw20072", .data = &aw20072_cdef, }, 577 + {} 578 + }; 579 + MODULE_DEVICE_TABLE(of, aw200xx_match_table); 580 + 581 + static struct i2c_driver aw200xx_driver = { 582 + .driver = { 583 + .name = "aw200xx", 584 + .of_match_table = aw200xx_match_table, 585 + }, 586 + .probe_new = aw200xx_probe, 587 + .remove = aw200xx_remove, 588 + .id_table = aw200xx_id, 589 + }; 590 + module_i2c_driver(aw200xx_driver); 591 + 592 + MODULE_AUTHOR("Martin Kurbanov <mmkurbanov@sberdevices.ru>"); 593 + MODULE_DESCRIPTION("AW200XX LED driver"); 594 + MODULE_LICENSE("GPL");
+1 -1
drivers/leds/leds-aw2013.c
··· 422 422 .name = "leds-aw2013", 423 423 .of_match_table = of_match_ptr(aw2013_match_table), 424 424 }, 425 - .probe_new = aw2013_probe, 425 + .probe = aw2013_probe, 426 426 .remove = aw2013_remove, 427 427 }; 428 428
+1 -1
drivers/leds/leds-bd2606mvv.c
··· 150 150 .name = "leds-bd2606mvv", 151 151 .of_match_table = of_match_ptr(of_bd2606mvv_leds_match), 152 152 }, 153 - .probe_new = bd2606mvv_probe, 153 + .probe = bd2606mvv_probe, 154 154 }; 155 155 156 156 module_i2c_driver(bd2606mvv_driver);
+1 -1
drivers/leds/leds-bd2802.c
··· 786 786 .name = "BD2802", 787 787 .pm = &bd2802_pm, 788 788 }, 789 - .probe_new = bd2802_probe, 789 + .probe = bd2802_probe, 790 790 .remove = bd2802_remove, 791 791 .id_table = bd2802_id, 792 792 };
+2 -2
drivers/leds/leds-blinkm.c
··· 561 561 return -ENODEV; 562 562 } 563 563 564 - strlcpy(info->type, "blinkm", I2C_NAME_SIZE); 564 + strscpy(info->type, "blinkm", I2C_NAME_SIZE); 565 565 return 0; 566 566 } 567 567 ··· 730 730 .driver = { 731 731 .name = "blinkm", 732 732 }, 733 - .probe_new = blinkm_probe, 733 + .probe = blinkm_probe, 734 734 .remove = blinkm_remove, 735 735 .id_table = blinkm_id, 736 736 .detect = blinkm_detect,
+476
drivers/leds/leds-cht-wcove.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Driver for LEDs connected to the Intel Cherry Trail Whiskey Cove PMIC 4 + * 5 + * Copyright 2019 Yauhen Kharuzhy <jekhor@gmail.com> 6 + * Copyright 2023 Hans de Goede <hansg@kernel.org> 7 + * 8 + * Register info comes from the Lenovo Yoga Book Android opensource code 9 + * available from Lenovo. File lenovo_yb1_x90f_l_osc_201803.7z path in the 7z: 10 + * YB1_source_code/kernel/cht/drivers/misc/charger_gp_led.c 11 + */ 12 + 13 + #include <linux/kernel.h> 14 + #include <linux/leds.h> 15 + #include <linux/mfd/intel_soc_pmic.h> 16 + #include <linux/module.h> 17 + #include <linux/mod_devicetable.h> 18 + #include <linux/platform_device.h> 19 + #include <linux/regmap.h> 20 + #include <linux/suspend.h> 21 + 22 + #define CHT_WC_LED1_CTRL 0x5e1f 23 + #define CHT_WC_LED1_FSM 0x5e20 24 + #define CHT_WC_LED1_PWM 0x5e21 25 + 26 + #define CHT_WC_LED2_CTRL 0x4fdf 27 + #define CHT_WC_LED2_FSM 0x4fe0 28 + #define CHT_WC_LED2_PWM 0x4fe1 29 + 30 + #define CHT_WC_LED1_SWCTL BIT(0) /* HW or SW control of charging led */ 31 + #define CHT_WC_LED1_ON BIT(1) 32 + 33 + #define CHT_WC_LED2_ON BIT(0) 34 + #define CHT_WC_LED_I_MA2_5 (2 << 2) /* LED current limit */ 35 + #define CHT_WC_LED_I_MASK GENMASK(3, 2) /* LED current limit mask */ 36 + 37 + #define CHT_WC_LED_F_1_4_HZ (0 << 4) 38 + #define CHT_WC_LED_F_1_2_HZ (1 << 4) 39 + #define CHT_WC_LED_F_1_HZ (2 << 4) 40 + #define CHT_WC_LED_F_2_HZ (3 << 4) 41 + #define CHT_WC_LED_F_MASK GENMASK(5, 4) 42 + 43 + #define CHT_WC_LED_EFF_OFF (0 << 1) 44 + #define CHT_WC_LED_EFF_ON (1 << 1) 45 + #define CHT_WC_LED_EFF_BLINKING (2 << 1) 46 + #define CHT_WC_LED_EFF_BREATHING (3 << 1) 47 + #define CHT_WC_LED_EFF_MASK GENMASK(2, 1) 48 + 49 + #define CHT_WC_LED_COUNT 2 50 + 51 + struct cht_wc_led_regs { 52 + /* Register addresses */ 53 + u16 ctrl; 54 + u16 fsm; 55 + u16 pwm; 56 + /* Mask + values for turning the LED on/off */ 57 + u8 on_off_mask; 58 + u8 on_val; 59 + u8 off_val; 60 + }; 61 + 62 + struct cht_wc_led_saved_regs { 63 + unsigned int ctrl; 64 + unsigned int fsm; 65 + unsigned int pwm; 66 + }; 67 + 68 + struct cht_wc_led { 69 + struct led_classdev cdev; 70 + const struct cht_wc_led_regs *regs; 71 + struct regmap *regmap; 72 + struct mutex mutex; 73 + struct cht_wc_led_saved_regs saved_regs; 74 + }; 75 + 76 + struct cht_wc_leds { 77 + struct cht_wc_led leds[CHT_WC_LED_COUNT]; 78 + /* Saved LED1 initial register values */ 79 + struct cht_wc_led_saved_regs led1_initial_regs; 80 + }; 81 + 82 + static const struct cht_wc_led_regs cht_wc_led_regs[CHT_WC_LED_COUNT] = { 83 + { 84 + .ctrl = CHT_WC_LED1_CTRL, 85 + .fsm = CHT_WC_LED1_FSM, 86 + .pwm = CHT_WC_LED1_PWM, 87 + .on_off_mask = CHT_WC_LED1_SWCTL | CHT_WC_LED1_ON, 88 + .on_val = CHT_WC_LED1_SWCTL | CHT_WC_LED1_ON, 89 + .off_val = CHT_WC_LED1_SWCTL, 90 + }, 91 + { 92 + .ctrl = CHT_WC_LED2_CTRL, 93 + .fsm = CHT_WC_LED2_FSM, 94 + .pwm = CHT_WC_LED2_PWM, 95 + .on_off_mask = CHT_WC_LED2_ON, 96 + .on_val = CHT_WC_LED2_ON, 97 + .off_val = 0, 98 + }, 99 + }; 100 + 101 + static const char * const cht_wc_leds_names[CHT_WC_LED_COUNT] = { 102 + "platform::" LED_FUNCTION_CHARGING, 103 + "platform::" LED_FUNCTION_INDICATOR, 104 + }; 105 + 106 + static int cht_wc_leds_brightness_set(struct led_classdev *cdev, 107 + enum led_brightness value) 108 + { 109 + struct cht_wc_led *led = container_of(cdev, struct cht_wc_led, cdev); 110 + int ret; 111 + 112 + mutex_lock(&led->mutex); 113 + 114 + if (!value) { 115 + ret = regmap_update_bits(led->regmap, led->regs->ctrl, 116 + led->regs->on_off_mask, led->regs->off_val); 117 + if (ret < 0) { 118 + dev_err(cdev->dev, "Failed to turn off: %d\n", ret); 119 + goto out; 120 + } 121 + 122 + /* Disable HW blinking */ 123 + ret = regmap_update_bits(led->regmap, led->regs->fsm, 124 + CHT_WC_LED_EFF_MASK, CHT_WC_LED_EFF_ON); 125 + if (ret < 0) 126 + dev_err(cdev->dev, "Failed to update LED FSM reg: %d\n", ret); 127 + } else { 128 + ret = regmap_write(led->regmap, led->regs->pwm, value); 129 + if (ret < 0) { 130 + dev_err(cdev->dev, "Failed to set brightness: %d\n", ret); 131 + goto out; 132 + } 133 + 134 + ret = regmap_update_bits(led->regmap, led->regs->ctrl, 135 + led->regs->on_off_mask, led->regs->on_val); 136 + if (ret < 0) 137 + dev_err(cdev->dev, "Failed to turn on: %d\n", ret); 138 + } 139 + out: 140 + mutex_unlock(&led->mutex); 141 + return ret; 142 + } 143 + 144 + static enum led_brightness cht_wc_leds_brightness_get(struct led_classdev *cdev) 145 + { 146 + struct cht_wc_led *led = container_of(cdev, struct cht_wc_led, cdev); 147 + unsigned int val; 148 + int ret; 149 + 150 + mutex_lock(&led->mutex); 151 + 152 + ret = regmap_read(led->regmap, led->regs->ctrl, &val); 153 + if (ret < 0) { 154 + dev_err(cdev->dev, "Failed to read LED CTRL reg: %d\n", ret); 155 + ret = 0; 156 + goto done; 157 + } 158 + 159 + val &= led->regs->on_off_mask; 160 + if (val != led->regs->on_val) { 161 + ret = 0; 162 + goto done; 163 + } 164 + 165 + ret = regmap_read(led->regmap, led->regs->pwm, &val); 166 + if (ret < 0) { 167 + dev_err(cdev->dev, "Failed to read LED PWM reg: %d\n", ret); 168 + ret = 0; 169 + goto done; 170 + } 171 + 172 + ret = val; 173 + done: 174 + mutex_unlock(&led->mutex); 175 + 176 + return ret; 177 + } 178 + 179 + /* Return blinking period for given CTRL reg value */ 180 + static unsigned long cht_wc_leds_get_period(int ctrl) 181 + { 182 + ctrl &= CHT_WC_LED_F_MASK; 183 + 184 + switch (ctrl) { 185 + case CHT_WC_LED_F_1_4_HZ: 186 + return 1000 * 4; 187 + case CHT_WC_LED_F_1_2_HZ: 188 + return 1000 * 2; 189 + case CHT_WC_LED_F_1_HZ: 190 + return 1000; 191 + case CHT_WC_LED_F_2_HZ: 192 + return 1000 / 2; 193 + } 194 + 195 + return 0; 196 + } 197 + 198 + /* 199 + * Find suitable hardware blink mode for given period. 200 + * period < 750 ms - select 2 HZ 201 + * 750 ms <= period < 1500 ms - select 1 HZ 202 + * 1500 ms <= period < 3000 ms - select 1/2 HZ 203 + * 3000 ms <= period < 5000 ms - select 1/4 HZ 204 + * 5000 ms <= period - return -1 205 + */ 206 + static int cht_wc_leds_find_freq(unsigned long period) 207 + { 208 + if (period < 750) 209 + return CHT_WC_LED_F_2_HZ; 210 + else if (period < 1500) 211 + return CHT_WC_LED_F_1_HZ; 212 + else if (period < 3000) 213 + return CHT_WC_LED_F_1_2_HZ; 214 + else if (period < 5000) 215 + return CHT_WC_LED_F_1_4_HZ; 216 + else 217 + return -1; 218 + } 219 + 220 + static int cht_wc_leds_set_effect(struct led_classdev *cdev, 221 + unsigned long *delay_on, 222 + unsigned long *delay_off, 223 + u8 effect) 224 + { 225 + struct cht_wc_led *led = container_of(cdev, struct cht_wc_led, cdev); 226 + int ctrl, ret; 227 + 228 + mutex_lock(&led->mutex); 229 + 230 + /* Blink with 1 Hz as default if nothing specified */ 231 + if (!*delay_on && !*delay_off) 232 + *delay_on = *delay_off = 500; 233 + 234 + ctrl = cht_wc_leds_find_freq(*delay_on + *delay_off); 235 + if (ctrl < 0) { 236 + /* Disable HW blinking */ 237 + ret = regmap_update_bits(led->regmap, led->regs->fsm, 238 + CHT_WC_LED_EFF_MASK, CHT_WC_LED_EFF_ON); 239 + if (ret < 0) 240 + dev_err(cdev->dev, "Failed to update LED FSM reg: %d\n", ret); 241 + 242 + /* Fallback to software timer */ 243 + *delay_on = *delay_off = 0; 244 + ret = -EINVAL; 245 + goto done; 246 + } 247 + 248 + ret = regmap_update_bits(led->regmap, led->regs->fsm, 249 + CHT_WC_LED_EFF_MASK, effect); 250 + if (ret < 0) 251 + dev_err(cdev->dev, "Failed to update LED FSM reg: %d\n", ret); 252 + 253 + /* Set the frequency and make sure the LED is on */ 254 + ret = regmap_update_bits(led->regmap, led->regs->ctrl, 255 + CHT_WC_LED_F_MASK | led->regs->on_off_mask, 256 + ctrl | led->regs->on_val); 257 + if (ret < 0) 258 + dev_err(cdev->dev, "Failed to update LED CTRL reg: %d\n", ret); 259 + 260 + *delay_off = *delay_on = cht_wc_leds_get_period(ctrl) / 2; 261 + 262 + done: 263 + mutex_unlock(&led->mutex); 264 + 265 + return ret; 266 + } 267 + 268 + static int cht_wc_leds_blink_set(struct led_classdev *cdev, 269 + unsigned long *delay_on, 270 + unsigned long *delay_off) 271 + { 272 + u8 effect = CHT_WC_LED_EFF_BLINKING; 273 + 274 + /* 275 + * The desired default behavior of LED1 / the charge LED is breathing 276 + * while charging and on/solid when full. Since triggers cannot select 277 + * breathing, blink_set() gets called when charging. Use slow breathing 278 + * when the default "charging-blink-full-solid" trigger is used to 279 + * achieve the desired default behavior. 280 + */ 281 + if (cdev->flags & LED_INIT_DEFAULT_TRIGGER) { 282 + *delay_on = *delay_off = 1000; 283 + effect = CHT_WC_LED_EFF_BREATHING; 284 + } 285 + 286 + return cht_wc_leds_set_effect(cdev, delay_on, delay_off, effect); 287 + } 288 + 289 + static int cht_wc_leds_pattern_set(struct led_classdev *cdev, 290 + struct led_pattern *pattern, 291 + u32 len, int repeat) 292 + { 293 + unsigned long delay_off, delay_on; 294 + 295 + if (repeat > 0 || len != 2 || 296 + pattern[0].brightness != 0 || pattern[1].brightness != 1 || 297 + pattern[0].delta_t != pattern[1].delta_t || 298 + (pattern[0].delta_t != 250 && pattern[0].delta_t != 500 && 299 + pattern[0].delta_t != 1000 && pattern[0].delta_t != 2000)) 300 + return -EINVAL; 301 + 302 + delay_off = pattern[0].delta_t; 303 + delay_on = pattern[1].delta_t; 304 + 305 + return cht_wc_leds_set_effect(cdev, &delay_on, &delay_off, CHT_WC_LED_EFF_BREATHING); 306 + } 307 + 308 + static int cht_wc_leds_pattern_clear(struct led_classdev *cdev) 309 + { 310 + return cht_wc_leds_brightness_set(cdev, 0); 311 + } 312 + 313 + static int cht_wc_led_save_regs(struct cht_wc_led *led, 314 + struct cht_wc_led_saved_regs *saved_regs) 315 + { 316 + int ret; 317 + 318 + ret = regmap_read(led->regmap, led->regs->ctrl, &saved_regs->ctrl); 319 + if (ret < 0) 320 + return ret; 321 + 322 + ret = regmap_read(led->regmap, led->regs->fsm, &saved_regs->fsm); 323 + if (ret < 0) 324 + return ret; 325 + 326 + return regmap_read(led->regmap, led->regs->pwm, &saved_regs->pwm); 327 + } 328 + 329 + static void cht_wc_led_restore_regs(struct cht_wc_led *led, 330 + const struct cht_wc_led_saved_regs *saved_regs) 331 + { 332 + regmap_write(led->regmap, led->regs->ctrl, saved_regs->ctrl); 333 + regmap_write(led->regmap, led->regs->fsm, saved_regs->fsm); 334 + regmap_write(led->regmap, led->regs->pwm, saved_regs->pwm); 335 + } 336 + 337 + static int cht_wc_leds_probe(struct platform_device *pdev) 338 + { 339 + struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent); 340 + struct cht_wc_leds *leds; 341 + int ret; 342 + int i; 343 + 344 + /* 345 + * On the Lenovo Yoga Tab 3 the LED1 driver output is actually 346 + * connected to a haptic feedback motor rather then a LED. 347 + * So do not register a LED classdev there (LED2 is unused). 348 + */ 349 + if (pmic->cht_wc_model == INTEL_CHT_WC_LENOVO_YT3_X90) 350 + return -ENODEV; 351 + 352 + leds = devm_kzalloc(&pdev->dev, sizeof(*leds), GFP_KERNEL); 353 + if (!leds) 354 + return -ENOMEM; 355 + 356 + /* 357 + * LED1 might be in hw-controlled mode when this driver gets loaded; and 358 + * since the PMIC is always powered by the battery any changes made are 359 + * permanent. Save LED1 regs to restore them on remove() or shutdown(). 360 + */ 361 + leds->leds[0].regs = &cht_wc_led_regs[0]; 362 + leds->leds[0].regmap = pmic->regmap; 363 + ret = cht_wc_led_save_regs(&leds->leds[0], &leds->led1_initial_regs); 364 + if (ret < 0) 365 + return ret; 366 + 367 + /* Set LED1 default trigger based on machine model */ 368 + switch (pmic->cht_wc_model) { 369 + case INTEL_CHT_WC_GPD_WIN_POCKET: 370 + leds->leds[0].cdev.default_trigger = "max170xx_battery-charging-blink-full-solid"; 371 + break; 372 + case INTEL_CHT_WC_XIAOMI_MIPAD2: 373 + leds->leds[0].cdev.default_trigger = "bq27520-0-charging-blink-full-solid"; 374 + break; 375 + case INTEL_CHT_WC_LENOVO_YOGABOOK1: 376 + leds->leds[0].cdev.default_trigger = "bq27542-0-charging-blink-full-solid"; 377 + break; 378 + default: 379 + dev_warn(&pdev->dev, "Unknown model, no default charging trigger\n"); 380 + break; 381 + } 382 + 383 + for (i = 0; i < CHT_WC_LED_COUNT; i++) { 384 + struct cht_wc_led *led = &leds->leds[i]; 385 + 386 + led->regs = &cht_wc_led_regs[i]; 387 + led->regmap = pmic->regmap; 388 + mutex_init(&led->mutex); 389 + led->cdev.name = cht_wc_leds_names[i]; 390 + led->cdev.brightness_set_blocking = cht_wc_leds_brightness_set; 391 + led->cdev.brightness_get = cht_wc_leds_brightness_get; 392 + led->cdev.blink_set = cht_wc_leds_blink_set; 393 + led->cdev.pattern_set = cht_wc_leds_pattern_set; 394 + led->cdev.pattern_clear = cht_wc_leds_pattern_clear; 395 + led->cdev.max_brightness = 255; 396 + 397 + ret = led_classdev_register(&pdev->dev, &led->cdev); 398 + if (ret < 0) 399 + return ret; 400 + } 401 + 402 + platform_set_drvdata(pdev, leds); 403 + return 0; 404 + } 405 + 406 + static void cht_wc_leds_remove(struct platform_device *pdev) 407 + { 408 + struct cht_wc_leds *leds = platform_get_drvdata(pdev); 409 + int i; 410 + 411 + for (i = 0; i < CHT_WC_LED_COUNT; i++) 412 + led_classdev_unregister(&leds->leds[i].cdev); 413 + 414 + /* Restore LED1 regs if hw-control was active else leave LED1 off */ 415 + if (!(leds->led1_initial_regs.ctrl & CHT_WC_LED1_SWCTL)) 416 + cht_wc_led_restore_regs(&leds->leds[0], &leds->led1_initial_regs); 417 + } 418 + 419 + static void cht_wc_leds_disable(struct platform_device *pdev) 420 + { 421 + struct cht_wc_leds *leds = platform_get_drvdata(pdev); 422 + int i; 423 + 424 + for (i = 0; i < CHT_WC_LED_COUNT; i++) 425 + cht_wc_leds_brightness_set(&leds->leds[i].cdev, 0); 426 + 427 + /* Restore LED1 regs if hw-control was active else leave LED1 off */ 428 + if (!(leds->led1_initial_regs.ctrl & CHT_WC_LED1_SWCTL)) 429 + cht_wc_led_restore_regs(&leds->leds[0], &leds->led1_initial_regs); 430 + } 431 + 432 + /* On suspend save current settings and turn LEDs off */ 433 + static int cht_wc_leds_suspend(struct device *dev) 434 + { 435 + struct cht_wc_leds *leds = dev_get_drvdata(dev); 436 + int i, ret; 437 + 438 + for (i = 0; i < CHT_WC_LED_COUNT; i++) { 439 + ret = cht_wc_led_save_regs(&leds->leds[i], &leds->leds[i].saved_regs); 440 + if (ret < 0) 441 + return ret; 442 + } 443 + 444 + cht_wc_leds_disable(to_platform_device(dev)); 445 + return 0; 446 + } 447 + 448 + /* On resume restore the saved settings */ 449 + static int cht_wc_leds_resume(struct device *dev) 450 + { 451 + struct cht_wc_leds *leds = dev_get_drvdata(dev); 452 + int i; 453 + 454 + for (i = 0; i < CHT_WC_LED_COUNT; i++) 455 + cht_wc_led_restore_regs(&leds->leds[i], &leds->leds[i].saved_regs); 456 + 457 + return 0; 458 + } 459 + 460 + static DEFINE_SIMPLE_DEV_PM_OPS(cht_wc_leds_pm, cht_wc_leds_suspend, cht_wc_leds_resume); 461 + 462 + static struct platform_driver cht_wc_leds_driver = { 463 + .probe = cht_wc_leds_probe, 464 + .remove_new = cht_wc_leds_remove, 465 + .shutdown = cht_wc_leds_disable, 466 + .driver = { 467 + .name = "cht_wcove_leds", 468 + .pm = pm_sleep_ptr(&cht_wc_leds_pm), 469 + }, 470 + }; 471 + module_platform_driver(cht_wc_leds_driver); 472 + 473 + MODULE_ALIAS("platform:cht_wcove_leds"); 474 + MODULE_DESCRIPTION("Intel Cherry Trail Whiskey Cove PMIC LEDs driver"); 475 + MODULE_AUTHOR("Yauhen Kharuzhy <jekhor@gmail.com>"); 476 + MODULE_LICENSE("GPL");
+18
drivers/leds/leds-gpio.c
··· 13 13 #include <linux/leds.h> 14 14 #include <linux/module.h> 15 15 #include <linux/of.h> 16 + #include <linux/pinctrl/consumer.h> 16 17 #include <linux/platform_device.h> 17 18 #include <linux/property.h> 18 19 #include <linux/slab.h> ··· 78 77 struct fwnode_handle *fwnode, gpio_blink_set_t blink_set) 79 78 { 80 79 struct led_init_data init_data = {}; 80 + struct pinctrl *pinctrl; 81 81 int ret, state; 82 82 83 83 led_dat->cdev.default_trigger = template->default_trigger; ··· 119 117 init_data.fwnode = fwnode; 120 118 ret = devm_led_classdev_register_ext(parent, &led_dat->cdev, 121 119 &init_data); 120 + } 121 + 122 + if (ret) 123 + return ret; 124 + 125 + pinctrl = devm_pinctrl_get_select_default(led_dat->cdev.dev); 126 + if (IS_ERR(pinctrl)) { 127 + ret = PTR_ERR(pinctrl); 128 + if (ret != -ENODEV) { 129 + dev_warn(led_dat->cdev.dev, 130 + "Failed to select %pOF pinctrl: %d\n", 131 + to_of_node(fwnode), ret); 132 + } else { 133 + /* pinctrl-%d not present, not an error */ 134 + ret = 0; 135 + } 122 136 } 123 137 124 138 return ret;
+1 -1
drivers/leds/leds-is31fl319x.c
··· 602 602 .name = "leds-is31fl319x", 603 603 .of_match_table = of_is31fl319x_match, 604 604 }, 605 - .probe_new = is31fl319x_probe, 605 + .probe = is31fl319x_probe, 606 606 .id_table = is31fl319x_id, 607 607 }; 608 608
+1 -1
drivers/leds/leds-is31fl32xx.c
··· 488 488 .name = "is31fl32xx", 489 489 .of_match_table = of_is31fl32xx_match, 490 490 }, 491 - .probe_new = is31fl32xx_probe, 491 + .probe = is31fl32xx_probe, 492 492 .remove = is31fl32xx_remove, 493 493 .id_table = is31fl32xx_id, 494 494 };
+1 -1
drivers/leds/leds-lm3530.c
··· 484 484 MODULE_DEVICE_TABLE(i2c, lm3530_id); 485 485 486 486 static struct i2c_driver lm3530_i2c_driver = { 487 - .probe_new = lm3530_probe, 487 + .probe = lm3530_probe, 488 488 .remove = lm3530_remove, 489 489 .id_table = lm3530_id, 490 490 .driver = {
+1 -1
drivers/leds/leds-lm3532.c
··· 726 726 MODULE_DEVICE_TABLE(i2c, lm3532_id); 727 727 728 728 static struct i2c_driver lm3532_i2c_driver = { 729 - .probe_new = lm3532_probe, 729 + .probe = lm3532_probe, 730 730 .remove = lm3532_remove, 731 731 .id_table = lm3532_id, 732 732 .driver = {
+1 -1
drivers/leds/leds-lm355x.c
··· 516 516 .name = LM355x_NAME, 517 517 .pm = NULL, 518 518 }, 519 - .probe_new = lm355x_probe, 519 + .probe = lm355x_probe, 520 520 .remove = lm355x_remove, 521 521 .id_table = lm355x_id, 522 522 };
+1 -1
drivers/leds/leds-lm3642.c
··· 401 401 .name = LM3642_NAME, 402 402 .pm = NULL, 403 403 }, 404 - .probe_new = lm3642_probe, 404 + .probe = lm3642_probe, 405 405 .remove = lm3642_remove, 406 406 .id_table = lm3642_id, 407 407 };
+1 -1
drivers/leds/leds-lm3692x.c
··· 518 518 .name = "lm3692x", 519 519 .of_match_table = of_lm3692x_leds_match, 520 520 }, 521 - .probe_new = lm3692x_probe, 521 + .probe = lm3692x_probe, 522 522 .remove = lm3692x_remove, 523 523 .id_table = lm3692x_id, 524 524 };
+1 -1
drivers/leds/leds-lm3697.c
··· 376 376 .name = "lm3697", 377 377 .of_match_table = of_lm3697_leds_match, 378 378 }, 379 - .probe_new = lm3697_probe, 379 + .probe = lm3697_probe, 380 380 .remove = lm3697_remove, 381 381 .id_table = lm3697_id, 382 382 };
+1 -1
drivers/leds/leds-lp3944.c
··· 427 427 .driver = { 428 428 .name = "lp3944", 429 429 }, 430 - .probe_new = lp3944_probe, 430 + .probe = lp3944_probe, 431 431 .remove = lp3944_remove, 432 432 .id_table = lp3944_id, 433 433 };
+1 -1
drivers/leds/leds-lp3952.c
··· 273 273 .driver = { 274 274 .name = LP3952_NAME, 275 275 }, 276 - .probe_new = lp3952_probe, 276 + .probe = lp3952_probe, 277 277 .remove = lp3952_remove, 278 278 .id_table = lp3952_id, 279 279 };
+1 -1
drivers/leds/leds-lp50xx.c
··· 608 608 .name = "lp50xx", 609 609 .of_match_table = of_lp50xx_leds_match, 610 610 }, 611 - .probe_new = lp50xx_probe, 611 + .probe = lp50xx_probe, 612 612 .remove = lp50xx_remove, 613 613 .id_table = lp50xx_id, 614 614 };
+6 -7
drivers/leds/leds-lp5521.c
··· 58 58 /* CONFIG register */ 59 59 #define LP5521_PWM_HF 0x40 /* PWM: 0 = 256Hz, 1 = 558Hz */ 60 60 #define LP5521_PWRSAVE_EN 0x20 /* 1 = Power save mode */ 61 - #define LP5521_CP_MODE_OFF 0 /* Charge pump (CP) off */ 62 - #define LP5521_CP_MODE_BYPASS 8 /* CP forced to bypass mode */ 63 - #define LP5521_CP_MODE_1X5 0x10 /* CP forced to 1.5x mode */ 64 - #define LP5521_CP_MODE_AUTO 0x18 /* Automatic mode selection */ 61 + #define LP5521_CP_MODE_MASK 0x18 /* Charge pump mode */ 62 + #define LP5521_CP_MODE_SHIFT 3 65 63 #define LP5521_R_TO_BATT 0x04 /* R out: 0 = CP, 1 = Vbat */ 66 64 #define LP5521_CLK_INT 0x01 /* Internal clock */ 67 - #define LP5521_DEFAULT_CFG \ 68 - (LP5521_PWM_HF | LP5521_PWRSAVE_EN | LP5521_CP_MODE_AUTO) 65 + #define LP5521_DEFAULT_CFG (LP5521_PWM_HF | LP5521_PWRSAVE_EN) 69 66 70 67 /* Status */ 71 68 #define LP5521_EXT_CLK_USED 0x08 ··· 306 309 val = LP5521_DEFAULT_CFG; 307 310 if (!lp55xx_is_extclk_used(chip)) 308 311 val |= LP5521_CLK_INT; 312 + 313 + val |= (chip->pdata->charge_pump_mode << LP5521_CP_MODE_SHIFT) & LP5521_CP_MODE_MASK; 309 314 310 315 ret = lp55xx_write(chip, LP5521_REG_CONFIG, val); 311 316 if (ret) ··· 607 608 .name = "lp5521", 608 609 .of_match_table = of_match_ptr(of_lp5521_leds_match), 609 610 }, 610 - .probe_new = lp5521_probe, 611 + .probe = lp5521_probe, 611 612 .remove = lp5521_remove, 612 613 .id_table = lp5521_id, 613 614 };
+10 -6
drivers/leds/leds-lp5523.c
··· 57 57 #define LP5523_AUTO_INC 0x40 58 58 #define LP5523_PWR_SAVE 0x20 59 59 #define LP5523_PWM_PWR_SAVE 0x04 60 - #define LP5523_CP_AUTO 0x18 60 + #define LP5523_CP_MODE_MASK 0x18 61 + #define LP5523_CP_MODE_SHIFT 3 61 62 #define LP5523_AUTO_CLK 0x02 63 + #define LP5523_DEFAULT_CONFIG \ 64 + (LP5523_AUTO_INC | LP5523_PWR_SAVE | LP5523_AUTO_CLK | LP5523_PWM_PWR_SAVE) 62 65 63 66 #define LP5523_EN_LEDTEST 0x80 64 67 #define LP5523_LEDTEST_DONE 0x80 ··· 128 125 static int lp5523_post_init_device(struct lp55xx_chip *chip) 129 126 { 130 127 int ret; 128 + int val; 131 129 132 130 ret = lp55xx_write(chip, LP5523_REG_ENABLE, LP5523_ENABLE); 133 131 if (ret) ··· 137 133 /* Chip startup time is 500 us, 1 - 2 ms gives some margin */ 138 134 usleep_range(1000, 2000); 139 135 140 - ret = lp55xx_write(chip, LP5523_REG_CONFIG, 141 - LP5523_AUTO_INC | LP5523_PWR_SAVE | 142 - LP5523_CP_AUTO | LP5523_AUTO_CLK | 143 - LP5523_PWM_PWR_SAVE); 136 + val = LP5523_DEFAULT_CONFIG; 137 + val |= (chip->pdata->charge_pump_mode << LP5523_CP_MODE_SHIFT) & LP5523_CP_MODE_MASK; 138 + 139 + ret = lp55xx_write(chip, LP5523_REG_CONFIG, val); 144 140 if (ret) 145 141 return ret; 146 142 ··· 987 983 .name = "lp5523x", 988 984 .of_match_table = of_match_ptr(of_lp5523_leds_match), 989 985 }, 990 - .probe_new = lp5523_probe, 986 + .probe = lp5523_probe, 991 987 .remove = lp5523_remove, 992 988 .id_table = lp5523_id, 993 989 };
+1 -1
drivers/leds/leds-lp5562.c
··· 603 603 .name = "lp5562", 604 604 .of_match_table = of_match_ptr(of_lp5562_leds_match), 605 605 }, 606 - .probe_new = lp5562_probe, 606 + .probe = lp5562_probe, 607 607 .remove = lp5562_remove, 608 608 .id_table = lp5562_id, 609 609 };
+9
drivers/leds/leds-lp55xx-common.c
··· 18 18 #include <linux/platform_data/leds-lp55xx.h> 19 19 #include <linux/slab.h> 20 20 #include <linux/gpio/consumer.h> 21 + #include <dt-bindings/leds/leds-lp55xx.h> 21 22 22 23 #include "leds-lp55xx-common.h" 23 24 ··· 690 689 return ERR_PTR(-EINVAL); 691 690 } 692 691 i++; 692 + } 693 + 694 + if (of_property_read_u32(np, "ti,charge-pump-mode", &pdata->charge_pump_mode)) 695 + pdata->charge_pump_mode = LP55XX_CP_AUTO; 696 + 697 + if (pdata->charge_pump_mode > LP55XX_CP_AUTO) { 698 + dev_err(dev, "invalid charge pump mode %d\n", pdata->charge_pump_mode); 699 + return ERR_PTR(-EINVAL); 693 700 } 694 701 695 702 of_property_read_string(np, "label", &pdata->label);
+6 -4
drivers/leds/leds-lp8501.c
··· 53 53 #define LP8501_PWM_PSAVE BIT(7) 54 54 #define LP8501_AUTO_INC BIT(6) 55 55 #define LP8501_PWR_SAVE BIT(5) 56 - #define LP8501_CP_AUTO 0x18 56 + #define LP8501_CP_MODE_MASK 0x18 57 + #define LP8501_CP_MODE_SHIFT 3 57 58 #define LP8501_INT_CLK BIT(0) 58 - #define LP8501_DEFAULT_CFG \ 59 - (LP8501_PWM_PSAVE | LP8501_AUTO_INC | LP8501_PWR_SAVE | LP8501_CP_AUTO) 59 + #define LP8501_DEFAULT_CFG (LP8501_PWM_PSAVE | LP8501_AUTO_INC | LP8501_PWR_SAVE) 60 60 61 61 #define LP8501_REG_RESET 0x3D 62 62 #define LP8501_RESET 0xFF ··· 101 101 102 102 if (chip->pdata->clock_mode != LP55XX_CLOCK_EXT) 103 103 val |= LP8501_INT_CLK; 104 + 105 + val |= (chip->pdata->charge_pump_mode << LP8501_CP_MODE_SHIFT) & LP8501_CP_MODE_MASK; 104 106 105 107 ret = lp55xx_write(chip, LP8501_REG_CONFIG, val); 106 108 if (ret) ··· 394 392 .name = "lp8501", 395 393 .of_match_table = of_match_ptr(of_lp8501_leds_match), 396 394 }, 397 - .probe_new = lp8501_probe, 395 + .probe = lp8501_probe, 398 396 .remove = lp8501_remove, 399 397 .id_table = lp8501_id, 400 398 };
+1 -1
drivers/leds/leds-lp8860.c
··· 475 475 .name = "lp8860", 476 476 .of_match_table = of_lp8860_leds_match, 477 477 }, 478 - .probe_new = lp8860_probe, 478 + .probe = lp8860_probe, 479 479 .remove = lp8860_remove, 480 480 .id_table = lp8860_id, 481 481 };
+343 -97
drivers/leds/leds-mt6323.c
··· 14 14 #include <linux/regmap.h> 15 15 16 16 /* 17 - * Register field for MT6323_TOP_CKPDN0 to enable 17 + * Register field for TOP_CKPDN0 to enable 18 18 * 32K clock common for LED device. 19 19 */ 20 - #define MT6323_RG_DRV_32K_CK_PDN BIT(11) 21 - #define MT6323_RG_DRV_32K_CK_PDN_MASK BIT(11) 20 + #define RG_DRV_32K_CK_PDN BIT(11) 21 + #define RG_DRV_32K_CK_PDN_MASK BIT(11) 22 + 23 + /* 32K/1M/6M clock common for WLED device */ 24 + #define RG_VWLED_1M_CK_PDN BIT(0) 25 + #define RG_VWLED_32K_CK_PDN BIT(12) 26 + #define RG_VWLED_6M_CK_PDN BIT(13) 22 27 23 28 /* 24 - * Register field for MT6323_TOP_CKPDN2 to enable 29 + * Register field for TOP_CKPDN2 to enable 25 30 * individual clock for LED device. 26 31 */ 27 - #define MT6323_RG_ISINK_CK_PDN(i) BIT(i) 28 - #define MT6323_RG_ISINK_CK_PDN_MASK(i) BIT(i) 32 + #define RG_ISINK_CK_PDN(i) BIT(i) 33 + #define RG_ISINK_CK_PDN_MASK(i) BIT(i) 29 34 30 35 /* 31 - * Register field for MT6323_TOP_CKCON1 to select 36 + * Register field for TOP_CKCON1 to select 32 37 * clock source. 33 38 */ 34 - #define MT6323_RG_ISINK_CK_SEL_MASK(i) (BIT(10) << (i)) 39 + #define RG_ISINK_CK_SEL_MASK(i) (BIT(10) << (i)) 35 40 36 - /* 37 - * Register for MT6323_ISINK_CON0 to setup the 38 - * duty cycle of the blink. 39 - */ 40 - #define MT6323_ISINK_CON0(i) (MT6323_ISINK0_CON0 + 0x8 * (i)) 41 - #define MT6323_ISINK_DIM_DUTY_MASK (0x1f << 8) 42 - #define MT6323_ISINK_DIM_DUTY(i) (((i) << 8) & \ 43 - MT6323_ISINK_DIM_DUTY_MASK) 41 + #define ISINK_CON(r, i) (r + 0x8 * (i)) 44 42 45 - /* Register to setup the period of the blink. */ 46 - #define MT6323_ISINK_CON1(i) (MT6323_ISINK0_CON1 + 0x8 * (i)) 47 - #define MT6323_ISINK_DIM_FSEL_MASK (0xffff) 48 - #define MT6323_ISINK_DIM_FSEL(i) ((i) & MT6323_ISINK_DIM_FSEL_MASK) 43 + /* ISINK_CON0: Register to setup the duty cycle of the blink. */ 44 + #define ISINK_DIM_DUTY_MASK (0x1f << 8) 45 + #define ISINK_DIM_DUTY(i) (((i) << 8) & ISINK_DIM_DUTY_MASK) 49 46 50 - /* Register to control the brightness. */ 51 - #define MT6323_ISINK_CON2(i) (MT6323_ISINK0_CON2 + 0x8 * (i)) 52 - #define MT6323_ISINK_CH_STEP_SHIFT 12 53 - #define MT6323_ISINK_CH_STEP_MASK (0x7 << 12) 54 - #define MT6323_ISINK_CH_STEP(i) (((i) << 12) & \ 55 - MT6323_ISINK_CH_STEP_MASK) 56 - #define MT6323_ISINK_SFSTR0_TC_MASK (0x3 << 1) 57 - #define MT6323_ISINK_SFSTR0_TC(i) (((i) << 1) & \ 58 - MT6323_ISINK_SFSTR0_TC_MASK) 59 - #define MT6323_ISINK_SFSTR0_EN_MASK BIT(0) 60 - #define MT6323_ISINK_SFSTR0_EN BIT(0) 47 + /* ISINK_CON1: Register to setup the period of the blink. */ 48 + #define ISINK_DIM_FSEL_MASK (0xffff) 49 + #define ISINK_DIM_FSEL(i) ((i) & ISINK_DIM_FSEL_MASK) 50 + 51 + /* ISINK_CON2: Register to control the brightness. */ 52 + #define ISINK_CH_STEP_SHIFT 12 53 + #define ISINK_CH_STEP_MASK (0x7 << 12) 54 + #define ISINK_CH_STEP(i) (((i) << 12) & ISINK_CH_STEP_MASK) 55 + #define ISINK_SFSTR0_TC_MASK (0x3 << 1) 56 + #define ISINK_SFSTR0_TC(i) (((i) << 1) & ISINK_SFSTR0_TC_MASK) 57 + #define ISINK_SFSTR0_EN_MASK BIT(0) 58 + #define ISINK_SFSTR0_EN BIT(0) 61 59 62 60 /* Register to LED channel enablement. */ 63 - #define MT6323_ISINK_CH_EN_MASK(i) BIT(i) 64 - #define MT6323_ISINK_CH_EN(i) BIT(i) 61 + #define ISINK_CH_EN_MASK(i) BIT(i) 62 + #define ISINK_CH_EN(i) BIT(i) 65 63 66 - #define MT6323_MAX_PERIOD 10000 67 - #define MT6323_MAX_LEDS 4 68 - #define MT6323_MAX_BRIGHTNESS 6 69 - #define MT6323_UNIT_DUTY 3125 70 - #define MT6323_CAL_HW_DUTY(o, p) DIV_ROUND_CLOSEST((o) * 100000ul,\ 71 - (p) * MT6323_UNIT_DUTY) 64 + #define MAX_SUPPORTED_LEDS 8 72 65 73 66 struct mt6323_leds; 74 67 ··· 80 87 }; 81 88 82 89 /** 90 + * struct mt6323_regs - register spec for the LED device 91 + * @top_ckpdn: Offset to ISINK_CKPDN[0..x] registers 92 + * @num_top_ckpdn: Number of ISINK_CKPDN registers 93 + * @top_ckcon: Offset to ISINK_CKCON[0..x] registers 94 + * @num_top_ckcon: Number of ISINK_CKCON registers 95 + * @isink_con: Offset to ISINKx_CON[0..x] registers 96 + * @num_isink_con: Number of ISINKx_CON registers 97 + * @isink_max_regs: Number of ISINK[0..x] registers 98 + * @isink_en_ctrl: Offset to ISINK_EN_CTRL register 99 + * @iwled_en_ctrl: Offset to IWLED_EN_CTRL register 100 + */ 101 + struct mt6323_regs { 102 + const u16 *top_ckpdn; 103 + u8 num_top_ckpdn; 104 + const u16 *top_ckcon; 105 + u8 num_top_ckcon; 106 + const u16 *isink_con; 107 + u8 num_isink_con; 108 + u8 isink_max_regs; 109 + u16 isink_en_ctrl; 110 + u16 iwled_en_ctrl; 111 + }; 112 + 113 + /** 114 + * struct mt6323_hwspec - hardware specific parameters 115 + * @max_period: Maximum period for all LEDs 116 + * @max_leds: Maximum number of supported LEDs 117 + * @max_wleds: Maximum number of WLEDs 118 + * @max_brightness: Maximum brightness for all LEDs 119 + * @unit_duty: Steps of duty per period 120 + */ 121 + struct mt6323_hwspec { 122 + u16 max_period; 123 + u8 max_leds; 124 + u8 max_wleds; 125 + u16 max_brightness; 126 + u16 unit_duty; 127 + }; 128 + 129 + /** 130 + * struct mt6323_data - device specific data 131 + * @regs: Register spec for this device 132 + * @spec: Hardware specific parameters 133 + */ 134 + struct mt6323_data { 135 + const struct mt6323_regs *regs; 136 + const struct mt6323_hwspec *spec; 137 + }; 138 + 139 + /** 83 140 * struct mt6323_leds - state container for holding LED controller 84 141 * of the driver 85 142 * @dev: the device pointer 86 143 * @hw: the underlying hardware providing shared 87 144 * bus for the register operations 145 + * @pdata: device specific data 88 146 * @lock: the lock among process context 89 147 * @led: the array that contains the state of individual 90 148 * LED device ··· 143 99 struct mt6323_leds { 144 100 struct device *dev; 145 101 struct mt6397_chip *hw; 102 + const struct mt6323_data *pdata; 146 103 /* protect among process context */ 147 104 struct mutex lock; 148 - struct mt6323_led *led[MT6323_MAX_LEDS]; 105 + struct mt6323_led *led[MAX_SUPPORTED_LEDS]; 149 106 }; 150 107 151 108 static int mt6323_led_hw_brightness(struct led_classdev *cdev, ··· 154 109 { 155 110 struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev); 156 111 struct mt6323_leds *leds = led->parent; 112 + const struct mt6323_regs *regs = leds->pdata->regs; 157 113 struct regmap *regmap = leds->hw->regmap; 158 114 u32 con2_mask = 0, con2_val = 0; 159 115 int ret; ··· 163 117 * Setup current output for the corresponding 164 118 * brightness level. 165 119 */ 166 - con2_mask |= MT6323_ISINK_CH_STEP_MASK | 167 - MT6323_ISINK_SFSTR0_TC_MASK | 168 - MT6323_ISINK_SFSTR0_EN_MASK; 169 - con2_val |= MT6323_ISINK_CH_STEP(brightness - 1) | 170 - MT6323_ISINK_SFSTR0_TC(2) | 171 - MT6323_ISINK_SFSTR0_EN; 120 + con2_mask |= ISINK_CH_STEP_MASK | 121 + ISINK_SFSTR0_TC_MASK | 122 + ISINK_SFSTR0_EN_MASK; 123 + con2_val |= ISINK_CH_STEP(brightness - 1) | 124 + ISINK_SFSTR0_TC(2) | 125 + ISINK_SFSTR0_EN; 172 126 173 - ret = regmap_update_bits(regmap, MT6323_ISINK_CON2(led->id), 127 + ret = regmap_update_bits(regmap, ISINK_CON(regs->isink_con[2], led->id), 174 128 con2_mask, con2_val); 175 129 return ret; 176 130 } ··· 179 133 { 180 134 struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev); 181 135 struct mt6323_leds *leds = led->parent; 136 + const struct mt6323_regs *regs = leds->pdata->regs; 182 137 struct regmap *regmap = leds->hw->regmap; 183 138 unsigned int status; 184 139 int ret; 185 140 186 - status = MT6323_ISINK_CH_EN(led->id); 187 - ret = regmap_update_bits(regmap, MT6323_ISINK_EN_CTRL, 188 - MT6323_ISINK_CH_EN_MASK(led->id), ~status); 141 + status = ISINK_CH_EN(led->id); 142 + ret = regmap_update_bits(regmap, regs->isink_en_ctrl, 143 + ISINK_CH_EN_MASK(led->id), ~status); 189 144 if (ret < 0) 190 145 return ret; 191 146 192 147 usleep_range(100, 300); 193 - ret = regmap_update_bits(regmap, MT6323_TOP_CKPDN2, 194 - MT6323_RG_ISINK_CK_PDN_MASK(led->id), 195 - MT6323_RG_ISINK_CK_PDN(led->id)); 148 + ret = regmap_update_bits(regmap, regs->top_ckpdn[2], 149 + RG_ISINK_CK_PDN_MASK(led->id), 150 + RG_ISINK_CK_PDN(led->id)); 196 151 if (ret < 0) 197 152 return ret; 198 153 ··· 205 158 { 206 159 struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev); 207 160 struct mt6323_leds *leds = led->parent; 161 + const struct mt6323_regs *regs = leds->pdata->regs; 208 162 struct regmap *regmap = leds->hw->regmap; 209 163 unsigned int status; 210 164 int ret; 211 165 212 - ret = regmap_read(regmap, MT6323_TOP_CKPDN2, &status); 166 + ret = regmap_read(regmap, regs->top_ckpdn[2], &status); 213 167 if (ret < 0) 214 168 return ret; 215 169 216 - if (status & MT6323_RG_ISINK_CK_PDN_MASK(led->id)) 170 + if (status & RG_ISINK_CK_PDN_MASK(led->id)) 217 171 return 0; 218 172 219 - ret = regmap_read(regmap, MT6323_ISINK_EN_CTRL, &status); 173 + ret = regmap_read(regmap, regs->isink_en_ctrl, &status); 220 174 if (ret < 0) 221 175 return ret; 222 176 223 - if (!(status & MT6323_ISINK_CH_EN(led->id))) 177 + if (!(status & ISINK_CH_EN(led->id))) 224 178 return 0; 225 179 226 - ret = regmap_read(regmap, MT6323_ISINK_CON2(led->id), &status); 180 + ret = regmap_read(regmap, ISINK_CON(regs->isink_con[2], led->id), &status); 227 181 if (ret < 0) 228 182 return ret; 229 183 230 - return ((status & MT6323_ISINK_CH_STEP_MASK) 231 - >> MT6323_ISINK_CH_STEP_SHIFT) + 1; 184 + return ((status & ISINK_CH_STEP_MASK) 185 + >> ISINK_CH_STEP_SHIFT) + 1; 232 186 } 233 187 234 188 static int mt6323_led_hw_on(struct led_classdev *cdev, ··· 237 189 { 238 190 struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev); 239 191 struct mt6323_leds *leds = led->parent; 192 + const struct mt6323_regs *regs = leds->pdata->regs; 240 193 struct regmap *regmap = leds->hw->regmap; 241 194 unsigned int status; 242 195 int ret; ··· 247 198 * clock and channel and let work with continuous blink as 248 199 * the default. 249 200 */ 250 - ret = regmap_update_bits(regmap, MT6323_TOP_CKCON1, 251 - MT6323_RG_ISINK_CK_SEL_MASK(led->id), 0); 201 + ret = regmap_update_bits(regmap, regs->top_ckcon[1], 202 + RG_ISINK_CK_SEL_MASK(led->id), 0); 252 203 if (ret < 0) 253 204 return ret; 254 205 255 - status = MT6323_RG_ISINK_CK_PDN(led->id); 256 - ret = regmap_update_bits(regmap, MT6323_TOP_CKPDN2, 257 - MT6323_RG_ISINK_CK_PDN_MASK(led->id), 206 + status = RG_ISINK_CK_PDN(led->id); 207 + ret = regmap_update_bits(regmap, regs->top_ckpdn[2], 208 + RG_ISINK_CK_PDN_MASK(led->id), 258 209 ~status); 259 210 if (ret < 0) 260 211 return ret; 261 212 262 213 usleep_range(100, 300); 263 214 264 - ret = regmap_update_bits(regmap, MT6323_ISINK_EN_CTRL, 265 - MT6323_ISINK_CH_EN_MASK(led->id), 266 - MT6323_ISINK_CH_EN(led->id)); 215 + ret = regmap_update_bits(regmap, regs->isink_en_ctrl, 216 + ISINK_CH_EN_MASK(led->id), 217 + ISINK_CH_EN(led->id)); 267 218 if (ret < 0) 268 219 return ret; 269 220 ··· 271 222 if (ret < 0) 272 223 return ret; 273 224 274 - ret = regmap_update_bits(regmap, MT6323_ISINK_CON0(led->id), 275 - MT6323_ISINK_DIM_DUTY_MASK, 276 - MT6323_ISINK_DIM_DUTY(31)); 225 + ret = regmap_update_bits(regmap, ISINK_CON(regs->isink_con[0], led->id), 226 + ISINK_DIM_DUTY_MASK, 227 + ISINK_DIM_DUTY(31)); 277 228 if (ret < 0) 278 229 return ret; 279 230 280 - ret = regmap_update_bits(regmap, MT6323_ISINK_CON1(led->id), 281 - MT6323_ISINK_DIM_FSEL_MASK, 282 - MT6323_ISINK_DIM_FSEL(1000)); 231 + ret = regmap_update_bits(regmap, ISINK_CON(regs->isink_con[1], led->id), 232 + ISINK_DIM_FSEL_MASK, 233 + ISINK_DIM_FSEL(1000)); 283 234 if (ret < 0) 284 235 return ret; 285 236 ··· 292 243 { 293 244 struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev); 294 245 struct mt6323_leds *leds = led->parent; 246 + const struct mt6323_regs *regs = leds->pdata->regs; 247 + const struct mt6323_hwspec *spec = leds->pdata->spec; 295 248 struct regmap *regmap = leds->hw->regmap; 296 249 unsigned long period; 297 250 u8 duty_hw; ··· 316 265 */ 317 266 period = *delay_on + *delay_off; 318 267 319 - if (period > MT6323_MAX_PERIOD) 268 + if (period > spec->max_period) 320 269 return -EINVAL; 321 270 322 271 /* 323 272 * Calculate duty_hw based on the percentage of period during 324 273 * which the led is ON. 325 274 */ 326 - duty_hw = MT6323_CAL_HW_DUTY(*delay_on, period); 275 + duty_hw = DIV_ROUND_CLOSEST(*delay_on * 100000ul, period * spec->unit_duty); 327 276 328 277 /* hardware doesn't support zero duty cycle. */ 329 278 if (!duty_hw) ··· 341 290 led->current_brightness = cdev->max_brightness; 342 291 } 343 292 344 - ret = regmap_update_bits(regmap, MT6323_ISINK_CON0(led->id), 345 - MT6323_ISINK_DIM_DUTY_MASK, 346 - MT6323_ISINK_DIM_DUTY(duty_hw - 1)); 293 + ret = regmap_update_bits(regmap, ISINK_CON(regs->isink_con[0], led->id), 294 + ISINK_DIM_DUTY_MASK, 295 + ISINK_DIM_DUTY(duty_hw - 1)); 347 296 if (ret < 0) 348 297 goto out; 349 298 350 - ret = regmap_update_bits(regmap, MT6323_ISINK_CON1(led->id), 351 - MT6323_ISINK_DIM_FSEL_MASK, 352 - MT6323_ISINK_DIM_FSEL(period - 1)); 299 + ret = regmap_update_bits(regmap, ISINK_CON(regs->isink_con[1], led->id), 300 + ISINK_DIM_FSEL_MASK, 301 + ISINK_DIM_FSEL(period - 1)); 353 302 out: 354 303 mutex_unlock(&leds->lock); 355 304 ··· 376 325 } else { 377 326 ret = mt6323_led_hw_off(cdev); 378 327 if (ret < 0) 328 + goto out; 329 + } 330 + 331 + led->current_brightness = brightness; 332 + out: 333 + mutex_unlock(&leds->lock); 334 + 335 + return ret; 336 + } 337 + 338 + static int mtk_wled_hw_on(struct led_classdev *cdev) 339 + { 340 + struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev); 341 + struct mt6323_leds *leds = led->parent; 342 + const struct mt6323_regs *regs = leds->pdata->regs; 343 + struct regmap *regmap = leds->hw->regmap; 344 + int ret; 345 + 346 + ret = regmap_clear_bits(regmap, regs->top_ckpdn[0], RG_VWLED_32K_CK_PDN); 347 + if (ret) 348 + return ret; 349 + 350 + ret = regmap_clear_bits(regmap, regs->top_ckpdn[0], RG_VWLED_6M_CK_PDN); 351 + if (ret) 352 + return ret; 353 + 354 + ret = regmap_clear_bits(regmap, regs->top_ckpdn[0], RG_VWLED_1M_CK_PDN); 355 + if (ret) 356 + return ret; 357 + 358 + usleep_range(5000, 6000); 359 + 360 + /* Enable WLED channel pair */ 361 + ret = regmap_set_bits(regmap, regs->iwled_en_ctrl, BIT(led->id)); 362 + if (ret) 363 + return ret; 364 + 365 + ret = regmap_set_bits(regmap, regs->iwled_en_ctrl, BIT(led->id + 1)); 366 + if (ret) 367 + return ret; 368 + 369 + return 0; 370 + } 371 + 372 + static int mtk_wled_hw_off(struct led_classdev *cdev) 373 + { 374 + struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev); 375 + struct mt6323_leds *leds = led->parent; 376 + const struct mt6323_regs *regs = leds->pdata->regs; 377 + struct regmap *regmap = leds->hw->regmap; 378 + int ret; 379 + 380 + ret = regmap_clear_bits(regmap, regs->iwled_en_ctrl, BIT(led->id + 1)); 381 + if (ret) 382 + return ret; 383 + 384 + ret = regmap_clear_bits(regmap, regs->iwled_en_ctrl, BIT(led->id)); 385 + if (ret) 386 + return ret; 387 + 388 + ret = regmap_set_bits(regmap, regs->top_ckpdn[0], RG_VWLED_32K_CK_PDN); 389 + if (ret) 390 + return ret; 391 + 392 + ret = regmap_set_bits(regmap, regs->top_ckpdn[0], RG_VWLED_6M_CK_PDN); 393 + if (ret) 394 + return ret; 395 + 396 + ret = regmap_set_bits(regmap, regs->top_ckpdn[0], RG_VWLED_1M_CK_PDN); 397 + if (ret) 398 + return ret; 399 + 400 + return 0; 401 + } 402 + 403 + static enum led_brightness mt6323_get_wled_brightness(struct led_classdev *cdev) 404 + { 405 + struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev); 406 + struct mt6323_leds *leds = led->parent; 407 + const struct mt6323_regs *regs = leds->pdata->regs; 408 + struct regmap *regmap = leds->hw->regmap; 409 + unsigned int status; 410 + int ret; 411 + 412 + ret = regmap_read(regmap, regs->iwled_en_ctrl, &status); 413 + if (ret) 414 + return 0; 415 + 416 + /* Always two channels per WLED */ 417 + status &= BIT(led->id) | BIT(led->id + 1); 418 + 419 + return status ? led->current_brightness : 0; 420 + } 421 + 422 + static int mt6323_wled_set_brightness(struct led_classdev *cdev, 423 + enum led_brightness brightness) 424 + { 425 + struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev); 426 + struct mt6323_leds *leds = led->parent; 427 + int ret = 0; 428 + 429 + mutex_lock(&leds->lock); 430 + 431 + if (brightness) { 432 + if (!led->current_brightness) 433 + ret = mtk_wled_hw_on(cdev); 434 + if (ret) 435 + goto out; 436 + } else { 437 + ret = mtk_wled_hw_off(cdev); 438 + if (ret) 379 439 goto out; 380 440 } 381 441 ··· 531 369 struct mt6397_chip *hw = dev_get_drvdata(dev->parent); 532 370 struct mt6323_leds *leds; 533 371 struct mt6323_led *led; 372 + const struct mt6323_regs *regs; 373 + const struct mt6323_hwspec *spec; 534 374 int ret; 535 375 unsigned int status; 536 376 u32 reg; 377 + u8 max_leds; 537 378 538 379 leds = devm_kzalloc(dev, sizeof(*leds), GFP_KERNEL); 539 380 if (!leds) ··· 544 379 545 380 platform_set_drvdata(pdev, leds); 546 381 leds->dev = dev; 382 + leds->pdata = device_get_match_data(dev); 383 + regs = leds->pdata->regs; 384 + spec = leds->pdata->spec; 385 + max_leds = spec->max_leds + spec->max_wleds; 547 386 548 387 /* 549 388 * leds->hw points to the underlying bus for the register ··· 556 387 leds->hw = hw; 557 388 mutex_init(&leds->lock); 558 389 559 - status = MT6323_RG_DRV_32K_CK_PDN; 560 - ret = regmap_update_bits(leds->hw->regmap, MT6323_TOP_CKPDN0, 561 - MT6323_RG_DRV_32K_CK_PDN_MASK, ~status); 390 + status = RG_DRV_32K_CK_PDN; 391 + ret = regmap_update_bits(leds->hw->regmap, regs->top_ckpdn[0], 392 + RG_DRV_32K_CK_PDN_MASK, ~status); 562 393 if (ret < 0) { 563 394 dev_err(leds->dev, 564 - "Failed to update MT6323_TOP_CKPDN0 Register\n"); 395 + "Failed to update TOP_CKPDN0 Register\n"); 565 396 return ret; 566 397 } 567 398 568 399 for_each_available_child_of_node(np, child) { 569 400 struct led_init_data init_data = {}; 401 + bool is_wled; 570 402 571 403 ret = of_property_read_u32(child, "reg", &reg); 572 404 if (ret) { ··· 575 405 goto put_child_node; 576 406 } 577 407 578 - if (reg >= MT6323_MAX_LEDS || leds->led[reg]) { 408 + if (reg >= max_leds || reg >= MAX_SUPPORTED_LEDS || 409 + leds->led[reg]) { 579 410 dev_err(dev, "Invalid led reg %u\n", reg); 580 411 ret = -EINVAL; 581 412 goto put_child_node; ··· 588 417 goto put_child_node; 589 418 } 590 419 420 + is_wled = of_property_read_bool(child, "mediatek,is-wled"); 421 + 591 422 leds->led[reg] = led; 592 423 leds->led[reg]->id = reg; 593 - leds->led[reg]->cdev.max_brightness = MT6323_MAX_BRIGHTNESS; 594 - leds->led[reg]->cdev.brightness_set_blocking = 595 - mt6323_led_set_brightness; 596 - leds->led[reg]->cdev.blink_set = mt6323_led_set_blink; 597 - leds->led[reg]->cdev.brightness_get = 598 - mt6323_get_led_hw_brightness; 424 + leds->led[reg]->cdev.max_brightness = spec->max_brightness; 425 + 426 + if (is_wled) { 427 + leds->led[reg]->cdev.brightness_set_blocking = 428 + mt6323_wled_set_brightness; 429 + leds->led[reg]->cdev.brightness_get = 430 + mt6323_get_wled_brightness; 431 + } else { 432 + leds->led[reg]->cdev.brightness_set_blocking = 433 + mt6323_led_set_brightness; 434 + leds->led[reg]->cdev.blink_set = mt6323_led_set_blink; 435 + leds->led[reg]->cdev.brightness_get = 436 + mt6323_get_led_hw_brightness; 437 + } 599 438 leds->led[reg]->parent = leds; 600 439 601 440 ret = mt6323_led_set_dt_default(&leds->led[reg]->cdev, child); ··· 635 454 static int mt6323_led_remove(struct platform_device *pdev) 636 455 { 637 456 struct mt6323_leds *leds = platform_get_drvdata(pdev); 457 + const struct mt6323_regs *regs = leds->pdata->regs; 638 458 int i; 639 459 640 460 /* Turn the LEDs off on driver removal. */ 641 461 for (i = 0 ; leds->led[i] ; i++) 642 462 mt6323_led_hw_off(&leds->led[i]->cdev); 643 463 644 - regmap_update_bits(leds->hw->regmap, MT6323_TOP_CKPDN0, 645 - MT6323_RG_DRV_32K_CK_PDN_MASK, 646 - MT6323_RG_DRV_32K_CK_PDN); 464 + regmap_update_bits(leds->hw->regmap, regs->top_ckpdn[0], 465 + RG_DRV_32K_CK_PDN_MASK, 466 + RG_DRV_32K_CK_PDN); 647 467 648 468 mutex_destroy(&leds->lock); 649 469 650 470 return 0; 651 471 } 652 472 473 + static const struct mt6323_regs mt6323_registers = { 474 + .top_ckpdn = (const u16[]){ 0x102, 0x106, 0x10e }, 475 + .num_top_ckpdn = 3, 476 + .top_ckcon = (const u16[]){ 0x120, 0x126 }, 477 + .num_top_ckcon = 2, 478 + .isink_con = (const u16[]){ 0x330, 0x332, 0x334 }, 479 + .num_isink_con = 3, 480 + .isink_max_regs = 4, /* ISINK[0..3] */ 481 + .isink_en_ctrl = 0x356, 482 + }; 483 + 484 + static const struct mt6323_regs mt6331_registers = { 485 + .top_ckpdn = (const u16[]){ 0x138, 0x13e, 0x144 }, 486 + .num_top_ckpdn = 3, 487 + .top_ckcon = (const u16[]){ 0x14c, 0x14a }, 488 + .num_top_ckcon = 2, 489 + .isink_con = (const u16[]){ 0x40c, 0x40e, 0x410, 0x412, 0x414 }, 490 + .num_isink_con = 5, 491 + .isink_max_regs = 4, /* ISINK[0..3] */ 492 + .isink_en_ctrl = 0x43a, 493 + }; 494 + 495 + static const struct mt6323_regs mt6332_registers = { 496 + .top_ckpdn = (const u16[]){ 0x8094, 0x809a, 0x80a0 }, 497 + .num_top_ckpdn = 3, 498 + .top_ckcon = (const u16[]){ 0x80a6, 0x80ac }, 499 + .num_top_ckcon = 2, 500 + .isink_con = (const u16[]){ 0x8cd4 }, 501 + .num_isink_con = 1, 502 + .isink_max_regs = 12, /* IWLED[0..2, 3..9] */ 503 + .iwled_en_ctrl = 0x8cda, 504 + }; 505 + 506 + static const struct mt6323_hwspec mt6323_spec = { 507 + .max_period = 10000, 508 + .max_leds = 4, 509 + .max_brightness = 6, 510 + .unit_duty = 3125, 511 + }; 512 + 513 + static const struct mt6323_hwspec mt6332_spec = { 514 + /* There are no LEDs in MT6332. Only WLEDs are present. */ 515 + .max_leds = 0, 516 + .max_wleds = 1, 517 + .max_brightness = 1024, 518 + }; 519 + 520 + static const struct mt6323_data mt6323_pdata = { 521 + .regs = &mt6323_registers, 522 + .spec = &mt6323_spec, 523 + }; 524 + 525 + static const struct mt6323_data mt6331_pdata = { 526 + .regs = &mt6331_registers, 527 + .spec = &mt6323_spec, 528 + }; 529 + 530 + static const struct mt6323_data mt6332_pdata = { 531 + .regs = &mt6332_registers, 532 + .spec = &mt6332_spec, 533 + }; 534 + 653 535 static const struct of_device_id mt6323_led_dt_match[] = { 654 - { .compatible = "mediatek,mt6323-led" }, 536 + { .compatible = "mediatek,mt6323-led", .data = &mt6323_pdata}, 537 + { .compatible = "mediatek,mt6331-led", .data = &mt6331_pdata }, 538 + { .compatible = "mediatek,mt6332-led", .data = &mt6332_pdata }, 655 539 {}, 656 540 }; 657 541 MODULE_DEVICE_TABLE(of, mt6323_led_dt_match);
+1 -1
drivers/leds/leds-pca9532.c
··· 102 102 .name = "leds-pca953x", 103 103 .of_match_table = of_match_ptr(of_pca9532_leds_match), 104 104 }, 105 - .probe_new = pca9532_probe, 105 + .probe = pca9532_probe, 106 106 .remove = pca9532_remove, 107 107 .id_table = pca9532_id, 108 108 };
+1 -1
drivers/leds/leds-pca955x.c
··· 668 668 .name = "leds-pca955x", 669 669 .of_match_table = of_pca955x_match, 670 670 }, 671 - .probe_new = pca955x_probe, 671 + .probe = pca955x_probe, 672 672 .id_table = pca955x_id, 673 673 }; 674 674
+1 -1
drivers/leds/leds-pca963x.c
··· 431 431 .name = "leds-pca963x", 432 432 .of_match_table = of_pca963x_match, 433 433 }, 434 - .probe_new = pca963x_probe, 434 + .probe = pca963x_probe, 435 435 .id_table = pca963x_id, 436 436 }; 437 437
+1 -1
drivers/leds/leds-spi-byte.c
··· 98 98 return -ENOMEM; 99 99 100 100 of_property_read_string(child, "label", &name); 101 - strlcpy(led->name, name, sizeof(led->name)); 101 + strscpy(led->name, name, sizeof(led->name)); 102 102 led->spi = spi; 103 103 mutex_init(&led->mutex); 104 104 led->cdef = device_get_match_data(dev);
+1 -1
drivers/leds/leds-tca6507.c
··· 808 808 .name = "leds-tca6507", 809 809 .of_match_table = of_match_ptr(of_tca6507_leds_match), 810 810 }, 811 - .probe_new = tca6507_probe, 811 + .probe = tca6507_probe, 812 812 .remove = tca6507_remove, 813 813 .id_table = tca6507_id, 814 814 };
+1 -1
drivers/leds/leds-tlc591xx.c
··· 230 230 .name = "tlc591xx", 231 231 .of_match_table = of_match_ptr(of_tlc591xx_leds_match), 232 232 }, 233 - .probe_new = tlc591xx_probe, 233 + .probe = tlc591xx_probe, 234 234 .id_table = tlc591xx_id, 235 235 }; 236 236
+1 -1
drivers/leds/leds-turris-omnia.c
··· 271 271 MODULE_DEVICE_TABLE(i2c, omnia_id); 272 272 273 273 static struct i2c_driver omnia_leds_driver = { 274 - .probe_new = omnia_leds_probe, 274 + .probe = omnia_leds_probe, 275 275 .remove = omnia_leds_remove, 276 276 .id_table = omnia_id, 277 277 .driver = {
+21 -2
drivers/leds/rgb/leds-qcom-lpg.c
··· 1173 1173 i = 0; 1174 1174 for_each_available_child_of_node(np, child) { 1175 1175 ret = lpg_parse_channel(lpg, child, &led->channels[i]); 1176 - if (ret < 0) 1176 + if (ret < 0) { 1177 + of_node_put(child); 1177 1178 return ret; 1179 + } 1178 1180 1179 1181 info[i].color_index = led->channels[i]->color; 1180 1182 info[i].intensity = 0; ··· 1354 1352 1355 1353 for_each_available_child_of_node(pdev->dev.of_node, np) { 1356 1354 ret = lpg_add_led(lpg, np); 1357 - if (ret) 1355 + if (ret) { 1356 + of_node_put(np); 1358 1357 return ret; 1358 + } 1359 1359 } 1360 1360 1361 1361 for (i = 0; i < lpg->num_channels; i++) ··· 1415 1411 { .base = 0xb400 }, 1416 1412 { .base = 0xb500 }, 1417 1413 { .base = 0xb600 }, 1414 + }, 1415 + }; 1416 + 1417 + /* PMI632 uses SDAM instead of LUT for pattern */ 1418 + static const struct lpg_data pmi632_lpg_data = { 1419 + .triled_base = 0xd000, 1420 + 1421 + .num_channels = 5, 1422 + .channels = (const struct lpg_channel_data[]) { 1423 + { .base = 0xb300, .triled_mask = BIT(7) }, 1424 + { .base = 0xb400, .triled_mask = BIT(6) }, 1425 + { .base = 0xb500, .triled_mask = BIT(5) }, 1426 + { .base = 0xb600 }, 1427 + { .base = 0xb700 }, 1418 1428 }, 1419 1429 }; 1420 1430 ··· 1523 1505 { .compatible = "qcom,pm8916-pwm", .data = &pm8916_pwm_data }, 1524 1506 { .compatible = "qcom,pm8941-lpg", .data = &pm8941_lpg_data }, 1525 1507 { .compatible = "qcom,pm8994-lpg", .data = &pm8994_lpg_data }, 1508 + { .compatible = "qcom,pmi632-lpg", .data = &pmi632_lpg_data }, 1526 1509 { .compatible = "qcom,pmi8994-lpg", .data = &pmi8994_lpg_data }, 1527 1510 { .compatible = "qcom,pmi8998-lpg", .data = &pmi8998_lpg_data }, 1528 1511 { .compatible = "qcom,pmc8180c-lpg", .data = &pm8150l_lpg_data },
+28 -3
drivers/leds/simple/Kconfig
··· 1 1 # SPDX-License-Identifier: GPL-2.0-only 2 2 config LEDS_SIEMENS_SIMATIC_IPC 3 3 tristate "LED driver for Siemens Simatic IPCs" 4 - depends on LEDS_GPIO 5 4 depends on SIEMENS_SIMATIC_IPC 6 5 help 7 6 This option enables support for the LEDs of several Industrial PCs 8 7 from Siemens. 9 8 10 - To compile this driver as a module, choose M here: the modules 11 - will be called simatic-ipc-leds and simatic-ipc-leds-gpio. 9 + To compile this driver as a module, choose M here: the module 10 + will be called simatic-ipc-leds. 11 + 12 + config LEDS_SIEMENS_SIMATIC_IPC_APOLLOLAKE 13 + tristate "LED driver for Siemens Simatic IPCs based on Intel Apollo Lake GPIO" 14 + depends on LEDS_GPIO 15 + depends on PINCTRL_BROXTON 16 + depends on SIEMENS_SIMATIC_IPC 17 + default LEDS_SIEMENS_SIMATIC_IPC 18 + help 19 + This option enables support for the LEDs of several Industrial PCs 20 + from Siemens based on Apollo Lake GPIO i.e. IPC127E. 21 + 22 + To compile this driver as a module, choose M here: the module 23 + will be called simatic-ipc-leds-gpio-apollolake. 24 + 25 + config LEDS_SIEMENS_SIMATIC_IPC_F7188X 26 + tristate "LED driver for Siemens Simatic IPCs based on Nuvoton GPIO" 27 + depends on LEDS_GPIO 28 + depends on GPIO_F7188X 29 + depends on SIEMENS_SIMATIC_IPC 30 + default LEDS_SIEMENS_SIMATIC_IPC 31 + help 32 + This option enables support for the LEDs of several Industrial PCs 33 + from Siemens based on Nuvoton GPIO i.e. IPC227G. 34 + 35 + To compile this driver as a module, choose M here: the module 36 + will be called simatic-ipc-leds-gpio-f7188x.
+3 -2
drivers/leds/simple/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0 2 - obj-$(CONFIG_LEDS_SIEMENS_SIMATIC_IPC) += simatic-ipc-leds.o 3 - obj-$(CONFIG_LEDS_SIEMENS_SIMATIC_IPC) += simatic-ipc-leds-gpio.o 2 + obj-$(CONFIG_LEDS_SIEMENS_SIMATIC_IPC) += simatic-ipc-leds.o 3 + obj-$(CONFIG_LEDS_SIEMENS_SIMATIC_IPC_APOLLOLAKE) += simatic-ipc-leds-gpio-core.o simatic-ipc-leds-gpio-apollolake.o 4 + obj-$(CONFIG_LEDS_SIEMENS_SIMATIC_IPC_F7188X) += simatic-ipc-leds-gpio-core.o simatic-ipc-leds-gpio-f7188x.o
+66
drivers/leds/simple/simatic-ipc-leds-gpio-apollolake.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Siemens SIMATIC IPC driver for GPIO based LEDs 4 + * 5 + * Copyright (c) Siemens AG, 2023 6 + * 7 + * Author: 8 + * Henning Schild <henning.schild@siemens.com> 9 + */ 10 + 11 + #include <linux/gpio/machine.h> 12 + #include <linux/gpio/consumer.h> 13 + #include <linux/leds.h> 14 + #include <linux/module.h> 15 + #include <linux/platform_device.h> 16 + #include <linux/platform_data/x86/simatic-ipc-base.h> 17 + 18 + #include "simatic-ipc-leds-gpio.h" 19 + 20 + static struct gpiod_lookup_table simatic_ipc_led_gpio_table = { 21 + .dev_id = "leds-gpio", 22 + .table = { 23 + GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 52, NULL, 0, GPIO_ACTIVE_LOW), 24 + GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 53, NULL, 1, GPIO_ACTIVE_LOW), 25 + GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 57, NULL, 2, GPIO_ACTIVE_LOW), 26 + GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 58, NULL, 3, GPIO_ACTIVE_LOW), 27 + GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 60, NULL, 4, GPIO_ACTIVE_LOW), 28 + GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 51, NULL, 5, GPIO_ACTIVE_LOW), 29 + {} /* Terminating entry */ 30 + }, 31 + }; 32 + 33 + static struct gpiod_lookup_table simatic_ipc_led_gpio_table_extra = { 34 + .dev_id = NULL, /* Filled during initialization */ 35 + .table = { 36 + GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 56, NULL, 6, GPIO_ACTIVE_LOW), 37 + GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 59, NULL, 7, GPIO_ACTIVE_HIGH), 38 + {} /* Terminating entry */ 39 + }, 40 + }; 41 + 42 + static int simatic_ipc_leds_gpio_apollolake_probe(struct platform_device *pdev) 43 + { 44 + return simatic_ipc_leds_gpio_probe(pdev, &simatic_ipc_led_gpio_table, 45 + &simatic_ipc_led_gpio_table_extra); 46 + } 47 + 48 + static int simatic_ipc_leds_gpio_apollolake_remove(struct platform_device *pdev) 49 + { 50 + return simatic_ipc_leds_gpio_remove(pdev, &simatic_ipc_led_gpio_table, 51 + &simatic_ipc_led_gpio_table_extra); 52 + } 53 + 54 + static struct platform_driver simatic_ipc_led_gpio_apollolake_driver = { 55 + .probe = simatic_ipc_leds_gpio_apollolake_probe, 56 + .remove = simatic_ipc_leds_gpio_apollolake_remove, 57 + .driver = { 58 + .name = KBUILD_MODNAME, 59 + }, 60 + }; 61 + module_platform_driver(simatic_ipc_led_gpio_apollolake_driver); 62 + 63 + MODULE_LICENSE("GPL v2"); 64 + MODULE_ALIAS("platform:" KBUILD_MODNAME); 65 + MODULE_SOFTDEP("pre: simatic-ipc-leds-gpio-core platform:apollolake-pinctrl"); 66 + MODULE_AUTHOR("Henning Schild <henning.schild@siemens.com>");
+104
drivers/leds/simple/simatic-ipc-leds-gpio-core.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Siemens SIMATIC IPC driver for GPIO based LEDs 4 + * 5 + * Copyright (c) Siemens AG, 2023 6 + * 7 + * Author: 8 + * Henning Schild <henning.schild@siemens.com> 9 + */ 10 + 11 + #include <linux/gpio/machine.h> 12 + #include <linux/gpio/consumer.h> 13 + #include <linux/leds.h> 14 + #include <linux/module.h> 15 + #include <linux/platform_device.h> 16 + #include <linux/platform_data/x86/simatic-ipc-base.h> 17 + 18 + #include "simatic-ipc-leds-gpio.h" 19 + 20 + static struct platform_device *simatic_leds_pdev; 21 + 22 + static const struct gpio_led simatic_ipc_gpio_leds[] = { 23 + { .name = "red:" LED_FUNCTION_STATUS "-1" }, 24 + { .name = "green:" LED_FUNCTION_STATUS "-1" }, 25 + { .name = "red:" LED_FUNCTION_STATUS "-2" }, 26 + { .name = "green:" LED_FUNCTION_STATUS "-2" }, 27 + { .name = "red:" LED_FUNCTION_STATUS "-3" }, 28 + { .name = "green:" LED_FUNCTION_STATUS "-3" }, 29 + }; 30 + 31 + static const struct gpio_led_platform_data simatic_ipc_gpio_leds_pdata = { 32 + .num_leds = ARRAY_SIZE(simatic_ipc_gpio_leds), 33 + .leds = simatic_ipc_gpio_leds, 34 + }; 35 + 36 + int simatic_ipc_leds_gpio_remove(struct platform_device *pdev, 37 + struct gpiod_lookup_table *table, 38 + struct gpiod_lookup_table *table_extra) 39 + { 40 + gpiod_remove_lookup_table(table); 41 + gpiod_remove_lookup_table(table_extra); 42 + platform_device_unregister(simatic_leds_pdev); 43 + 44 + return 0; 45 + } 46 + EXPORT_SYMBOL_GPL(simatic_ipc_leds_gpio_remove); 47 + 48 + int simatic_ipc_leds_gpio_probe(struct platform_device *pdev, 49 + struct gpiod_lookup_table *table, 50 + struct gpiod_lookup_table *table_extra) 51 + { 52 + const struct simatic_ipc_platform *plat = pdev->dev.platform_data; 53 + struct device *dev = &pdev->dev; 54 + struct gpio_desc *gpiod; 55 + int err; 56 + 57 + switch (plat->devmode) { 58 + case SIMATIC_IPC_DEVICE_127E: 59 + case SIMATIC_IPC_DEVICE_227G: 60 + break; 61 + default: 62 + return -ENODEV; 63 + } 64 + 65 + gpiod_add_lookup_table(table); 66 + simatic_leds_pdev = platform_device_register_resndata(NULL, 67 + "leds-gpio", PLATFORM_DEVID_NONE, NULL, 0, 68 + &simatic_ipc_gpio_leds_pdata, 69 + sizeof(simatic_ipc_gpio_leds_pdata)); 70 + if (IS_ERR(simatic_leds_pdev)) { 71 + err = PTR_ERR(simatic_leds_pdev); 72 + goto out; 73 + } 74 + 75 + table_extra->dev_id = dev_name(dev); 76 + gpiod_add_lookup_table(table_extra); 77 + 78 + /* PM_BIOS_BOOT_N */ 79 + gpiod = gpiod_get_index(dev, NULL, 6, GPIOD_OUT_LOW); 80 + if (IS_ERR(gpiod)) { 81 + err = PTR_ERR(gpiod); 82 + goto out; 83 + } 84 + gpiod_put(gpiod); 85 + 86 + /* PM_WDT_OUT */ 87 + gpiod = gpiod_get_index(dev, NULL, 7, GPIOD_OUT_LOW); 88 + if (IS_ERR(gpiod)) { 89 + err = PTR_ERR(gpiod); 90 + goto out; 91 + } 92 + gpiod_put(gpiod); 93 + 94 + return 0; 95 + out: 96 + simatic_ipc_leds_gpio_remove(pdev, table, table_extra); 97 + 98 + return err; 99 + } 100 + EXPORT_SYMBOL_GPL(simatic_ipc_leds_gpio_probe); 101 + 102 + MODULE_LICENSE("GPL v2"); 103 + MODULE_SOFTDEP("pre: platform:leds-gpio"); 104 + MODULE_AUTHOR("Henning Schild <henning.schild@siemens.com>");
+66
drivers/leds/simple/simatic-ipc-leds-gpio-f7188x.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Siemens SIMATIC IPC driver for GPIO based LEDs 4 + * 5 + * Copyright (c) Siemens AG, 2023 6 + * 7 + * Author: 8 + * Henning Schild <henning.schild@siemens.com> 9 + */ 10 + 11 + #include <linux/gpio/machine.h> 12 + #include <linux/gpio/consumer.h> 13 + #include <linux/leds.h> 14 + #include <linux/module.h> 15 + #include <linux/platform_device.h> 16 + #include <linux/platform_data/x86/simatic-ipc-base.h> 17 + 18 + #include "simatic-ipc-leds-gpio.h" 19 + 20 + static struct gpiod_lookup_table simatic_ipc_led_gpio_table = { 21 + .dev_id = "leds-gpio", 22 + .table = { 23 + GPIO_LOOKUP_IDX("gpio-f7188x-2", 0, NULL, 0, GPIO_ACTIVE_LOW), 24 + GPIO_LOOKUP_IDX("gpio-f7188x-2", 1, NULL, 1, GPIO_ACTIVE_LOW), 25 + GPIO_LOOKUP_IDX("gpio-f7188x-2", 2, NULL, 2, GPIO_ACTIVE_LOW), 26 + GPIO_LOOKUP_IDX("gpio-f7188x-2", 3, NULL, 3, GPIO_ACTIVE_LOW), 27 + GPIO_LOOKUP_IDX("gpio-f7188x-2", 4, NULL, 4, GPIO_ACTIVE_LOW), 28 + GPIO_LOOKUP_IDX("gpio-f7188x-2", 5, NULL, 5, GPIO_ACTIVE_LOW), 29 + {} /* Terminating entry */ 30 + }, 31 + }; 32 + 33 + static struct gpiod_lookup_table simatic_ipc_led_gpio_table_extra = { 34 + .dev_id = NULL, /* Filled during initialization */ 35 + .table = { 36 + GPIO_LOOKUP_IDX("gpio-f7188x-3", 6, NULL, 6, GPIO_ACTIVE_HIGH), 37 + GPIO_LOOKUP_IDX("gpio-f7188x-3", 7, NULL, 7, GPIO_ACTIVE_HIGH), 38 + {} /* Terminating entry */ 39 + }, 40 + }; 41 + 42 + static int simatic_ipc_leds_gpio_f7188x_probe(struct platform_device *pdev) 43 + { 44 + return simatic_ipc_leds_gpio_probe(pdev, &simatic_ipc_led_gpio_table, 45 + &simatic_ipc_led_gpio_table_extra); 46 + } 47 + 48 + static int simatic_ipc_leds_gpio_f7188x_remove(struct platform_device *pdev) 49 + { 50 + return simatic_ipc_leds_gpio_remove(pdev, &simatic_ipc_led_gpio_table, 51 + &simatic_ipc_led_gpio_table_extra); 52 + } 53 + 54 + static struct platform_driver simatic_ipc_led_gpio_driver = { 55 + .probe = simatic_ipc_leds_gpio_f7188x_probe, 56 + .remove = simatic_ipc_leds_gpio_f7188x_remove, 57 + .driver = { 58 + .name = KBUILD_MODNAME, 59 + }, 60 + }; 61 + module_platform_driver(simatic_ipc_led_gpio_driver); 62 + 63 + MODULE_LICENSE("GPL v2"); 64 + MODULE_ALIAS("platform:" KBUILD_MODNAME); 65 + MODULE_SOFTDEP("pre: simatic-ipc-leds-gpio-core gpio_f7188x"); 66 + MODULE_AUTHOR("Henning Schild <henning.schild@siemens.com>");
-139
drivers/leds/simple/simatic-ipc-leds-gpio.c
··· 1 - // SPDX-License-Identifier: GPL-2.0 2 - /* 3 - * Siemens SIMATIC IPC driver for GPIO based LEDs 4 - * 5 - * Copyright (c) Siemens AG, 2022 6 - * 7 - * Authors: 8 - * Henning Schild <henning.schild@siemens.com> 9 - */ 10 - 11 - #include <linux/gpio/machine.h> 12 - #include <linux/gpio/consumer.h> 13 - #include <linux/leds.h> 14 - #include <linux/module.h> 15 - #include <linux/platform_device.h> 16 - #include <linux/platform_data/x86/simatic-ipc-base.h> 17 - 18 - static struct gpiod_lookup_table *simatic_ipc_led_gpio_table; 19 - 20 - static struct gpiod_lookup_table simatic_ipc_led_gpio_table_127e = { 21 - .dev_id = "leds-gpio", 22 - .table = { 23 - GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 52, NULL, 0, GPIO_ACTIVE_LOW), 24 - GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 53, NULL, 1, GPIO_ACTIVE_LOW), 25 - GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 57, NULL, 2, GPIO_ACTIVE_LOW), 26 - GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 58, NULL, 3, GPIO_ACTIVE_LOW), 27 - GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 60, NULL, 4, GPIO_ACTIVE_LOW), 28 - GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 51, NULL, 5, GPIO_ACTIVE_LOW), 29 - GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 56, NULL, 6, GPIO_ACTIVE_LOW), 30 - GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 59, NULL, 7, GPIO_ACTIVE_HIGH), 31 - }, 32 - }; 33 - 34 - static struct gpiod_lookup_table simatic_ipc_led_gpio_table_227g = { 35 - .dev_id = "leds-gpio", 36 - .table = { 37 - GPIO_LOOKUP_IDX("gpio-f7188x-2", 0, NULL, 0, GPIO_ACTIVE_LOW), 38 - GPIO_LOOKUP_IDX("gpio-f7188x-2", 1, NULL, 1, GPIO_ACTIVE_LOW), 39 - GPIO_LOOKUP_IDX("gpio-f7188x-2", 2, NULL, 2, GPIO_ACTIVE_LOW), 40 - GPIO_LOOKUP_IDX("gpio-f7188x-2", 3, NULL, 3, GPIO_ACTIVE_LOW), 41 - GPIO_LOOKUP_IDX("gpio-f7188x-2", 4, NULL, 4, GPIO_ACTIVE_LOW), 42 - GPIO_LOOKUP_IDX("gpio-f7188x-2", 5, NULL, 5, GPIO_ACTIVE_LOW), 43 - GPIO_LOOKUP_IDX("gpio-f7188x-3", 6, NULL, 6, GPIO_ACTIVE_HIGH), 44 - GPIO_LOOKUP_IDX("gpio-f7188x-3", 7, NULL, 7, GPIO_ACTIVE_HIGH), 45 - } 46 - }; 47 - 48 - static const struct gpio_led simatic_ipc_gpio_leds[] = { 49 - { .name = "red:" LED_FUNCTION_STATUS "-1" }, 50 - { .name = "green:" LED_FUNCTION_STATUS "-1" }, 51 - { .name = "red:" LED_FUNCTION_STATUS "-2" }, 52 - { .name = "green:" LED_FUNCTION_STATUS "-2" }, 53 - { .name = "red:" LED_FUNCTION_STATUS "-3" }, 54 - { .name = "green:" LED_FUNCTION_STATUS "-3" }, 55 - }; 56 - 57 - static const struct gpio_led_platform_data simatic_ipc_gpio_leds_pdata = { 58 - .num_leds = ARRAY_SIZE(simatic_ipc_gpio_leds), 59 - .leds = simatic_ipc_gpio_leds, 60 - }; 61 - 62 - static struct platform_device *simatic_leds_pdev; 63 - 64 - static int simatic_ipc_leds_gpio_remove(struct platform_device *pdev) 65 - { 66 - gpiod_remove_lookup_table(simatic_ipc_led_gpio_table); 67 - platform_device_unregister(simatic_leds_pdev); 68 - 69 - return 0; 70 - } 71 - 72 - static int simatic_ipc_leds_gpio_probe(struct platform_device *pdev) 73 - { 74 - const struct simatic_ipc_platform *plat = pdev->dev.platform_data; 75 - struct gpio_desc *gpiod; 76 - int err; 77 - 78 - switch (plat->devmode) { 79 - case SIMATIC_IPC_DEVICE_127E: 80 - if (!IS_ENABLED(CONFIG_PINCTRL_BROXTON)) 81 - return -ENODEV; 82 - simatic_ipc_led_gpio_table = &simatic_ipc_led_gpio_table_127e; 83 - break; 84 - case SIMATIC_IPC_DEVICE_227G: 85 - if (!IS_ENABLED(CONFIG_GPIO_F7188X)) 86 - return -ENODEV; 87 - request_module("gpio-f7188x"); 88 - simatic_ipc_led_gpio_table = &simatic_ipc_led_gpio_table_227g; 89 - break; 90 - default: 91 - return -ENODEV; 92 - } 93 - 94 - gpiod_add_lookup_table(simatic_ipc_led_gpio_table); 95 - simatic_leds_pdev = platform_device_register_resndata(NULL, 96 - "leds-gpio", PLATFORM_DEVID_NONE, NULL, 0, 97 - &simatic_ipc_gpio_leds_pdata, 98 - sizeof(simatic_ipc_gpio_leds_pdata)); 99 - if (IS_ERR(simatic_leds_pdev)) { 100 - err = PTR_ERR(simatic_leds_pdev); 101 - goto out; 102 - } 103 - 104 - /* PM_BIOS_BOOT_N */ 105 - gpiod = gpiod_get_index(&simatic_leds_pdev->dev, NULL, 6, GPIOD_OUT_LOW); 106 - if (IS_ERR(gpiod)) { 107 - err = PTR_ERR(gpiod); 108 - goto out; 109 - } 110 - gpiod_put(gpiod); 111 - 112 - /* PM_WDT_OUT */ 113 - gpiod = gpiod_get_index(&simatic_leds_pdev->dev, NULL, 7, GPIOD_OUT_LOW); 114 - if (IS_ERR(gpiod)) { 115 - err = PTR_ERR(gpiod); 116 - goto out; 117 - } 118 - gpiod_put(gpiod); 119 - 120 - return 0; 121 - out: 122 - simatic_ipc_leds_gpio_remove(pdev); 123 - 124 - return err; 125 - } 126 - 127 - static struct platform_driver simatic_ipc_led_gpio_driver = { 128 - .probe = simatic_ipc_leds_gpio_probe, 129 - .remove = simatic_ipc_leds_gpio_remove, 130 - .driver = { 131 - .name = KBUILD_MODNAME, 132 - } 133 - }; 134 - module_platform_driver(simatic_ipc_led_gpio_driver); 135 - 136 - MODULE_LICENSE("GPL v2"); 137 - MODULE_ALIAS("platform:" KBUILD_MODNAME); 138 - MODULE_SOFTDEP("pre: platform:leds-gpio"); 139 - MODULE_AUTHOR("Henning Schild <henning.schild@siemens.com>");
+22
drivers/leds/simple/simatic-ipc-leds-gpio.h
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Siemens SIMATIC IPC driver for GPIO based LEDs 4 + * 5 + * Copyright (c) Siemens AG, 2023 6 + * 7 + * Author: 8 + * Henning Schild <henning.schild@siemens.com> 9 + */ 10 + 11 + #ifndef _SIMATIC_IPC_LEDS_GPIO_H 12 + #define _SIMATIC_IPC_LEDS_GPIO_H 13 + 14 + int simatic_ipc_leds_gpio_probe(struct platform_device *pdev, 15 + struct gpiod_lookup_table *table, 16 + struct gpiod_lookup_table *table_extra); 17 + 18 + int simatic_ipc_leds_gpio_remove(struct platform_device *pdev, 19 + struct gpiod_lookup_table *table, 20 + struct gpiod_lookup_table *table_extra); 21 + 22 + #endif /* _SIMATIC_IPC_LEDS_GPIO_H */
-1
drivers/leds/simple/simatic-ipc-leds.c
··· 126 126 .name = KBUILD_MODNAME, 127 127 } 128 128 }; 129 - 130 129 module_platform_driver(simatic_ipc_led_driver); 131 130 132 131 MODULE_LICENSE("GPL v2");
+3 -6
drivers/leds/trigger/ledtrig-disk.c
··· 19 19 20 20 void ledtrig_disk_activity(bool write) 21 21 { 22 - unsigned long blink_delay = BLINK_DELAY; 23 - 24 - led_trigger_blink_oneshot(ledtrig_disk, 25 - &blink_delay, &blink_delay, 0); 22 + led_trigger_blink_oneshot(ledtrig_disk, BLINK_DELAY, BLINK_DELAY, 0); 26 23 if (write) 27 24 led_trigger_blink_oneshot(ledtrig_disk_write, 28 - &blink_delay, &blink_delay, 0); 25 + BLINK_DELAY, BLINK_DELAY, 0); 29 26 else 30 27 led_trigger_blink_oneshot(ledtrig_disk_read, 31 - &blink_delay, &blink_delay, 0); 28 + BLINK_DELAY, BLINK_DELAY, 0); 32 29 } 33 30 EXPORT_SYMBOL(ledtrig_disk_activity); 34 31
+2 -6
drivers/leds/trigger/ledtrig-mtd.c
··· 22 22 23 23 void ledtrig_mtd_activity(void) 24 24 { 25 - unsigned long blink_delay = BLINK_DELAY; 26 - 27 - led_trigger_blink_oneshot(ledtrig_mtd, 28 - &blink_delay, &blink_delay, 0); 29 - led_trigger_blink_oneshot(ledtrig_nand, 30 - &blink_delay, &blink_delay, 0); 25 + led_trigger_blink_oneshot(ledtrig_mtd, BLINK_DELAY, BLINK_DELAY, 0); 26 + led_trigger_blink_oneshot(ledtrig_nand, BLINK_DELAY, BLINK_DELAY, 0); 31 27 } 32 28 EXPORT_SYMBOL(ledtrig_mtd_activity); 33 29
+2 -4
drivers/leds/trigger/ledtrig-netdev.c
··· 462 462 get_device_state(trigger_data); 463 463 fallthrough; 464 464 case NETDEV_REGISTER: 465 - if (trigger_data->net_dev) 466 - dev_put(trigger_data->net_dev); 465 + dev_put(trigger_data->net_dev); 467 466 dev_hold(dev); 468 467 trigger_data->net_dev = dev; 469 468 break; ··· 593 594 594 595 cancel_delayed_work_sync(&trigger_data->work); 595 596 596 - if (trigger_data->net_dev) 597 - dev_put(trigger_data->net_dev); 597 + dev_put(trigger_data->net_dev); 598 598 599 599 kfree(trigger_data); 600 600 }
+2 -6
drivers/net/arcnet/arcnet.c
··· 196 196 void arcnet_led_event(struct net_device *dev, enum arcnet_led_event event) 197 197 { 198 198 struct arcnet_local *lp = netdev_priv(dev); 199 - unsigned long led_delay = 350; 200 - unsigned long tx_delay = 50; 201 199 202 200 switch (event) { 203 201 case ARCNET_LED_EVENT_RECON: 204 - led_trigger_blink_oneshot(lp->recon_led_trig, 205 - &led_delay, &led_delay, 0); 202 + led_trigger_blink_oneshot(lp->recon_led_trig, 350, 350, 0); 206 203 break; 207 204 case ARCNET_LED_EVENT_OPEN: 208 205 led_trigger_event(lp->tx_led_trig, LED_OFF); ··· 210 213 led_trigger_event(lp->recon_led_trig, LED_OFF); 211 214 break; 212 215 case ARCNET_LED_EVENT_TX: 213 - led_trigger_blink_oneshot(lp->tx_led_trig, 214 - &tx_delay, &tx_delay, 0); 216 + led_trigger_blink_oneshot(lp->tx_led_trig, 50, 50, 0); 215 217 break; 216 218 } 217 219 }
+4 -3
drivers/platform/x86/simatic-ipc.c
··· 68 68 } 69 69 70 70 if (ledmode != SIMATIC_IPC_DEVICE_NONE) { 71 - if (ledmode == SIMATIC_IPC_DEVICE_127E || 72 - ledmode == SIMATIC_IPC_DEVICE_227G) 73 - pdevname = KBUILD_MODNAME "_leds_gpio"; 71 + if (ledmode == SIMATIC_IPC_DEVICE_127E) 72 + pdevname = KBUILD_MODNAME "_leds_gpio_apollolake"; 73 + if (ledmode == SIMATIC_IPC_DEVICE_227G) 74 + pdevname = KBUILD_MODNAME "_leds_gpio_f7188x"; 74 75 platform_data.devmode = ledmode; 75 76 ipc_led_platform_device = 76 77 platform_device_register_data(NULL,
+1 -4
drivers/power/supply/power_supply_leds.c
··· 22 22 static void power_supply_update_bat_leds(struct power_supply *psy) 23 23 { 24 24 union power_supply_propval status; 25 - unsigned long delay_on = 0; 26 - unsigned long delay_off = 0; 27 25 28 26 if (power_supply_get_property(psy, POWER_SUPPLY_PROP_STATUS, &status)) 29 27 return; ··· 41 43 led_trigger_event(psy->charging_full_trig, LED_FULL); 42 44 led_trigger_event(psy->charging_trig, LED_FULL); 43 45 led_trigger_event(psy->full_trig, LED_OFF); 44 - led_trigger_blink(psy->charging_blink_full_solid_trig, 45 - &delay_on, &delay_off); 46 + led_trigger_blink(psy->charging_blink_full_solid_trig, 0, 0); 46 47 break; 47 48 default: 48 49 led_trigger_event(psy->charging_full_trig, LED_OFF);
+1 -3
drivers/usb/common/led.c
··· 14 14 15 15 #define BLINK_DELAY 30 16 16 17 - static unsigned long usb_blink_delay = BLINK_DELAY; 18 - 19 17 DEFINE_LED_TRIGGER(ledtrig_usb_gadget); 20 18 DEFINE_LED_TRIGGER(ledtrig_usb_host); 21 19 ··· 30 32 break; 31 33 } 32 34 /* led_trigger_blink_oneshot() handles trig == NULL gracefully */ 33 - led_trigger_blink_oneshot(trig, &usb_blink_delay, &usb_blink_delay, 0); 35 + led_trigger_blink_oneshot(trig, BLINK_DELAY, BLINK_DELAY, 0); 34 36 } 35 37 EXPORT_SYMBOL_GPL(usb_led_activity); 36 38
+10
include/dt-bindings/leds/leds-lp55xx.h
··· 1 + /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ 2 + #ifndef _DT_BINDINGS_LEDS_LP55XX_H 3 + #define _DT_BINDINGS_LEDS_LP55XX_H 4 + 5 + #define LP55XX_CP_OFF 0 6 + #define LP55XX_CP_BYPASS 1 7 + #define LP55XX_CP_BOOST 2 8 + #define LP55XX_CP_AUTO 3 9 + 10 + #endif /* _DT_BINDINGS_LEDS_LP55XX_H */
+35 -8
include/linux/leds.h
··· 124 124 #define LED_BLINK_INVERT 3 125 125 #define LED_BLINK_BRIGHTNESS_CHANGE 4 126 126 #define LED_BLINK_DISABLE 5 127 + /* Brightness off also disables hw-blinking so it is a separate action */ 128 + #define LED_SET_BRIGHTNESS_OFF 6 129 + #define LED_SET_BRIGHTNESS 7 130 + #define LED_SET_BLINK 8 127 131 128 132 /* Set LED brightness level 129 133 * Must not sleep. Use brightness_set_blocking for drivers ··· 151 147 * match the values specified exactly. 152 148 * Deactivate blinking again when the brightness is set to LED_OFF 153 149 * via the brightness_set() callback. 150 + * For led_blink_set_nosleep() the LED core assumes that blink_set 151 + * implementations, of drivers which do not use brightness_set_blocking, 152 + * will not sleep. Therefor if brightness_set_blocking is not set 153 + * this function must not sleep! 154 154 */ 155 155 int (*blink_set)(struct led_classdev *led_cdev, 156 156 unsigned long *delay_on, ··· 178 170 179 171 struct work_struct set_brightness_work; 180 172 int delayed_set_value; 173 + unsigned long delayed_delay_on; 174 + unsigned long delayed_delay_off; 181 175 182 176 #ifdef CONFIG_LEDS_TRIGGERS 183 177 /* Protects the trigger data below */ ··· 325 315 * software blinking if there is no hardware blinking or if 326 316 * the LED refuses the passed values. 327 317 * 318 + * This function may sleep! 319 + * 328 320 * Note that if software blinking is active, simply calling 329 321 * led_cdev->brightness_set() will not stop the blinking, 330 322 * use led_set_brightness() instead. 331 323 */ 332 324 void led_blink_set(struct led_classdev *led_cdev, unsigned long *delay_on, 333 325 unsigned long *delay_off); 326 + 327 + /** 328 + * led_blink_set_nosleep - set blinking, guaranteed to not sleep 329 + * @led_cdev: the LED to start blinking 330 + * @delay_on: the time it should be on (in ms) 331 + * @delay_off: the time it should ble off (in ms) 332 + * 333 + * This function makes the LED blink and is guaranteed to not sleep. Otherwise 334 + * this is the same as led_blink_set(), see led_blink_set() for details. 335 + */ 336 + void led_blink_set_nosleep(struct led_classdev *led_cdev, unsigned long delay_on, 337 + unsigned long delay_off); 338 + 334 339 /** 335 340 * led_blink_set_oneshot - do a oneshot software blink 336 341 * @led_cdev: the LED to start blinking ··· 359 334 * 360 335 * If invert is set, led blinks for delay_off first, then for 361 336 * delay_on and leave the led on after the on-off cycle. 337 + * 338 + * This function is guaranteed not to sleep. 362 339 */ 363 340 void led_blink_set_oneshot(struct led_classdev *led_cdev, 364 341 unsigned long *delay_on, unsigned long *delay_off, ··· 503 476 struct led_trigger **trigger); 504 477 void led_trigger_unregister_simple(struct led_trigger *trigger); 505 478 void led_trigger_event(struct led_trigger *trigger, enum led_brightness event); 506 - void led_trigger_blink(struct led_trigger *trigger, unsigned long *delay_on, 507 - unsigned long *delay_off); 479 + void led_trigger_blink(struct led_trigger *trigger, unsigned long delay_on, 480 + unsigned long delay_off); 508 481 void led_trigger_blink_oneshot(struct led_trigger *trigger, 509 - unsigned long *delay_on, 510 - unsigned long *delay_off, 482 + unsigned long delay_on, 483 + unsigned long delay_off, 511 484 int invert); 512 485 void led_trigger_set_default(struct led_classdev *led_cdev); 513 486 int led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trigger); ··· 557 530 static inline void led_trigger_event(struct led_trigger *trigger, 558 531 enum led_brightness event) {} 559 532 static inline void led_trigger_blink(struct led_trigger *trigger, 560 - unsigned long *delay_on, 561 - unsigned long *delay_off) {} 533 + unsigned long delay_on, 534 + unsigned long delay_off) {} 562 535 static inline void led_trigger_blink_oneshot(struct led_trigger *trigger, 563 - unsigned long *delay_on, 564 - unsigned long *delay_off, 536 + unsigned long delay_on, 537 + unsigned long delay_off, 565 538 int invert) {} 566 539 static inline void led_trigger_set_default(struct led_classdev *led_cdev) {} 567 540 static inline int led_trigger_set(struct led_classdev *led_cdev,
+3
include/linux/platform_data/leds-lp55xx.h
··· 73 73 /* Clock configuration */ 74 74 u8 clock_mode; 75 75 76 + /* Charge pump mode */ 77 + u32 charge_pump_mode; 78 + 76 79 /* optional enable GPIO */ 77 80 struct gpio_desc *enable_gpiod; 78 81
+1 -1
net/mac80211/led.c
··· 282 282 } 283 283 } 284 284 285 - led_trigger_blink(&local->tpt_led, &on, &off); 285 + led_trigger_blink(&local->tpt_led, on, off); 286 286 } 287 287 288 288 const char *
+2 -6
net/mac80211/led.h
··· 13 13 static inline void ieee80211_led_rx(struct ieee80211_local *local) 14 14 { 15 15 #ifdef CONFIG_MAC80211_LEDS 16 - unsigned long led_delay = MAC80211_BLINK_DELAY; 17 - 18 16 if (!atomic_read(&local->rx_led_active)) 19 17 return; 20 - led_trigger_blink_oneshot(&local->rx_led, &led_delay, &led_delay, 0); 18 + led_trigger_blink_oneshot(&local->rx_led, MAC80211_BLINK_DELAY, MAC80211_BLINK_DELAY, 0); 21 19 #endif 22 20 } 23 21 24 22 static inline void ieee80211_led_tx(struct ieee80211_local *local) 25 23 { 26 24 #ifdef CONFIG_MAC80211_LEDS 27 - unsigned long led_delay = MAC80211_BLINK_DELAY; 28 - 29 25 if (!atomic_read(&local->tx_led_active)) 30 26 return; 31 - led_trigger_blink_oneshot(&local->tx_led, &led_delay, &led_delay, 0); 27 + led_trigger_blink_oneshot(&local->tx_led, MAC80211_BLINK_DELAY, MAC80211_BLINK_DELAY, 0); 32 28 #endif 33 29 } 34 30
+1 -2
net/netfilter/xt_LED.c
··· 43 43 { 44 44 const struct xt_led_info *ledinfo = par->targinfo; 45 45 struct xt_led_info_internal *ledinternal = ledinfo->internal_data; 46 - unsigned long led_delay = XT_LED_BLINK_DELAY; 47 46 48 47 /* 49 48 * If "always blink" is enabled, and there's still some time until the ··· 51 52 if ((ledinfo->delay > 0) && ledinfo->always_blink && 52 53 timer_pending(&ledinternal->timer)) 53 54 led_trigger_blink_oneshot(&ledinternal->netfilter_led_trigger, 54 - &led_delay, &led_delay, 1); 55 + XT_LED_BLINK_DELAY, XT_LED_BLINK_DELAY, 1); 55 56 else 56 57 led_trigger_event(&ledinternal->netfilter_led_trigger, LED_FULL); 57 58