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

Pull LED updates from Lee Jones:
"Core Frameworks:
- Add support for a bunch more colours

New Drivers:
- Add support for Kinetic KTD2026/7 RGB/White LEDs

New Functionality:
- Add support for device to enter HW Controlled Mode to Turris Omnia
LEDs
- Add support for HW Gamma Correction to Turris Omnia LEDs

Fix-ups:
- Apply new __counted_by() annotation to several data structures
containing flexible arrays
- Rid the return value from Platform's .remove() operation
- Use *_cansleep() variants for instances were threads can sleep
- Improve the semantics when setting the brightness
- Generic clean-ups; code reduction, coding style, standard patterns
- Replace strncpy() with strscpy()
- Fix-up / add various documentation
- Re-author the GPIO associated Trigger to use trigger-sources
- Move to using standard APIs and helpers
- Improve error checking
- Stop using static GPIO bases

Bug Fixes:
- Fix Pointer to Enum casing warnings
- Do not pretend that I2C backed device supports SMBUS
- Ensure PWM LEDs are extinguished when disabled, rather than held in
a state
- Fix 'output may be truncated' warnings"

* tag 'leds-next-6.7' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/leds: (43 commits)
leds: lp5521: Add an error check in lp5521_post_init_device
leds: gpio: Update headers
leds: gpio: Remove unneeded assignment
leds: gpio: Move temporary variable for struct device to gpio_led_probe()
leds: gpio: Refactor code to use devm_gpiod_get_index_optional()
leds: gpio: Utilise PTR_ERR_OR_ZERO()
leds: gpio: Keep driver firmware interface agnostic
leds: core: Refactor led_update_brightness() to use standard pattern
leds: turris-omnia: Fix brightness setting and trigger activating
leds: sc27xx: Move mutex_init() down
leds: trigger: netdev: Move size check in set_device_name
leds: Add ktd202x driver
dt-bindings: leds: Add Kinetic KTD2026/2027 LED
leds: core: Add more colors from DT bindings to led_colors
dt-bindings: leds: Last color ID is now 14 (LED_COLOR_ID_LIME)
leds: tca6507: Don't use fixed GPIO base
leds: lp3952: Convert to use maple tree register cache
leds: lm392x: Convert to use maple tree register cache
leds: aw200xx: Convert to use maple tree register cache
leds: lm3601x: Convert to use maple tree register cache
...

+1348 -365
+14
Documentation/ABI/testing/sysfs-class-led-driver-turris-omnia
··· 12 12 able to change this setting from software. 13 13 14 14 Format: %i 15 + 16 + What: /sys/class/leds/<led>/device/gamma_correction 17 + Date: August 2023 18 + KernelVersion: 6.6 19 + Contact: Marek Behún <kabel@kernel.org> 20 + Description: (RW) Newer versions of the microcontroller firmware of the 21 + Turris Omnia router support gamma correction for the RGB LEDs. 22 + This feature can be enabled/disabled by writing to this file. 23 + 24 + If the feature is not supported because the MCU firmware is too 25 + old, the file always reads as 0, and writing to the file results 26 + in the EOPNOTSUPP error. 27 + 28 + Format: %i
+3 -1
Documentation/devicetree/bindings/leds/common.yaml
··· 43 43 LED_COLOR_ID available, add a new one. 44 44 $ref: /schemas/types.yaml#/definitions/uint32 45 45 minimum: 0 46 - maximum: 9 46 + maximum: 14 47 47 48 48 function-enumerator: 49 49 description: ··· 191 191 each of them having its own LED assigned (assuming they are not 192 192 hardwired). In such cases this property should contain phandle(s) of 193 193 related source device(s). 194 + Another example is a GPIO line that will be monitored and mirror the 195 + state of the line (with or without inversion flags) to the LED. 194 196 In many cases LED can be related to more than one device (e.g. one USB LED 195 197 vs. multiple USB ports). Each source should be represented by a node in 196 198 the device tree and be referenced by a phandle and a set of phandle
+171
Documentation/devicetree/bindings/leds/kinetic,ktd202x.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/kinetic,ktd202x.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Kinetic KTD2026/7 RGB/White LED Driver 8 + 9 + maintainers: 10 + - André Apitzsch <git@apitzsch.eu> 11 + 12 + description: | 13 + The KTD2026/7 is a RGB/White LED driver with I2C interface. 14 + 15 + The data sheet can be found at: 16 + https://www.kinet-ic.com/uploads/KTD2026-7-04h.pdf 17 + 18 + properties: 19 + compatible: 20 + enum: 21 + - kinetic,ktd2026 22 + - kinetic,ktd2027 23 + 24 + reg: 25 + maxItems: 1 26 + 27 + vin-supply: 28 + description: Regulator providing power to the "VIN" pin. 29 + 30 + vio-supply: 31 + description: Regulator providing power for pull-up of the I/O lines. 32 + Note that this regulator does not directly connect to KTD2026, but is 33 + needed for the correct operation of the status ("ST") and I2C lines. 34 + 35 + "#address-cells": 36 + const: 1 37 + 38 + "#size-cells": 39 + const: 0 40 + 41 + multi-led: 42 + type: object 43 + $ref: leds-class-multicolor.yaml# 44 + unevaluatedProperties: false 45 + 46 + properties: 47 + "#address-cells": 48 + const: 1 49 + 50 + "#size-cells": 51 + const: 0 52 + 53 + patternProperties: 54 + "^led@[0-3]$": 55 + type: object 56 + $ref: common.yaml# 57 + unevaluatedProperties: false 58 + 59 + properties: 60 + reg: 61 + description: Index of the LED. 62 + minimum: 0 63 + maximum: 3 64 + 65 + required: 66 + - reg 67 + - color 68 + 69 + required: 70 + - "#address-cells" 71 + - "#size-cells" 72 + 73 + patternProperties: 74 + "^led@[0-3]$": 75 + type: object 76 + $ref: common.yaml# 77 + unevaluatedProperties: false 78 + 79 + properties: 80 + reg: 81 + description: Index of the LED. 82 + minimum: 0 83 + maximum: 3 84 + 85 + required: 86 + - reg 87 + 88 + required: 89 + - compatible 90 + - reg 91 + - "#address-cells" 92 + - "#size-cells" 93 + 94 + additionalProperties: false 95 + 96 + examples: 97 + - | 98 + #include <dt-bindings/leds/common.h> 99 + 100 + i2c { 101 + #address-cells = <1>; 102 + #size-cells = <0>; 103 + 104 + led-controller@30 { 105 + compatible = "kinetic,ktd2026"; 106 + reg = <0x30>; 107 + #address-cells = <1>; 108 + #size-cells = <0>; 109 + 110 + vin-supply = <&pm8916_l17>; 111 + vio-supply = <&pm8916_l6>; 112 + 113 + led@0 { 114 + reg = <0>; 115 + function = LED_FUNCTION_STATUS; 116 + color = <LED_COLOR_ID_RED>; 117 + }; 118 + 119 + led@1 { 120 + reg = <1>; 121 + function = LED_FUNCTION_STATUS; 122 + color = <LED_COLOR_ID_GREEN>; 123 + }; 124 + 125 + led@2 { 126 + reg = <2>; 127 + function = LED_FUNCTION_STATUS; 128 + color = <LED_COLOR_ID_BLUE>; 129 + }; 130 + }; 131 + }; 132 + - | 133 + #include <dt-bindings/leds/common.h> 134 + 135 + i2c { 136 + #address-cells = <1>; 137 + #size-cells = <0>; 138 + 139 + led-controller@30 { 140 + compatible = "kinetic,ktd2026"; 141 + reg = <0x30>; 142 + #address-cells = <1>; 143 + #size-cells = <0>; 144 + 145 + vin-supply = <&pm8916_l17>; 146 + vio-supply = <&pm8916_l6>; 147 + 148 + multi-led { 149 + color = <LED_COLOR_ID_RGB>; 150 + function = LED_FUNCTION_STATUS; 151 + 152 + #address-cells = <1>; 153 + #size-cells = <0>; 154 + 155 + led@0 { 156 + reg = <0>; 157 + color = <LED_COLOR_ID_RED>; 158 + }; 159 + 160 + led@1 { 161 + reg = <1>; 162 + color = <LED_COLOR_ID_GREEN>; 163 + }; 164 + 165 + led@2 { 166 + reg = <2>; 167 + color = <LED_COLOR_ID_BLUE>; 168 + }; 169 + }; 170 + }; 171 + };
+1
drivers/leds/Kconfig
··· 187 187 depends on I2C 188 188 depends on MACH_ARMADA_38X || COMPILE_TEST 189 189 depends on OF 190 + select LEDS_TRIGGERS 190 191 help 191 192 This option enables basic support for the LEDs found on the front 192 193 side of CZ.NIC's Turris Omnia router. There are 12 RGB LEDs on the
+2 -4
drivers/leds/blink/leds-lgm-sso.c
··· 837 837 return 0; 838 838 } 839 839 840 - static int intel_sso_led_remove(struct platform_device *pdev) 840 + static void intel_sso_led_remove(struct platform_device *pdev) 841 841 { 842 842 struct sso_led_priv *priv; 843 843 struct sso_led *led, *n; ··· 850 850 } 851 851 852 852 regmap_exit(priv->mmap); 853 - 854 - return 0; 855 853 } 856 854 857 855 static const struct of_device_id of_sso_led_match[] = { ··· 861 863 862 864 static struct platform_driver intel_sso_led_driver = { 863 865 .probe = intel_sso_led_probe, 864 - .remove = intel_sso_led_remove, 866 + .remove_new = intel_sso_led_remove, 865 867 .driver = { 866 868 .name = "lgm-ssoled", 867 869 .of_match_table = of_sso_led_match,
+2 -4
drivers/leds/flash/leds-aat1290.c
··· 522 522 return ret; 523 523 } 524 524 525 - static int aat1290_led_remove(struct platform_device *pdev) 525 + static void aat1290_led_remove(struct platform_device *pdev) 526 526 { 527 527 struct aat1290_led *led = platform_get_drvdata(pdev); 528 528 ··· 530 530 led_classdev_flash_unregister(&led->fled_cdev); 531 531 532 532 mutex_destroy(&led->lock); 533 - 534 - return 0; 535 533 } 536 534 537 535 static const struct of_device_id aat1290_led_dt_match[] = { ··· 540 542 541 543 static struct platform_driver aat1290_led_driver = { 542 544 .probe = aat1290_led_probe, 543 - .remove = aat1290_led_remove, 545 + .remove_new = aat1290_led_remove, 544 546 .driver = { 545 547 .name = "aat1290", 546 548 .of_match_table = aat1290_led_dt_match,
+2 -4
drivers/leds/flash/leds-ktd2692.c
··· 386 386 return 0; 387 387 } 388 388 389 - static int ktd2692_remove(struct platform_device *pdev) 389 + static void ktd2692_remove(struct platform_device *pdev) 390 390 { 391 391 struct ktd2692_context *led = platform_get_drvdata(pdev); 392 392 393 393 led_classdev_flash_unregister(&led->fled_cdev); 394 394 395 395 mutex_destroy(&led->lock); 396 - 397 - return 0; 398 396 } 399 397 400 398 static const struct of_device_id ktd2692_match[] = { ··· 407 409 .of_match_table = ktd2692_match, 408 410 }, 409 411 .probe = ktd2692_probe, 410 - .remove = ktd2692_remove, 412 + .remove_new = ktd2692_remove, 411 413 }; 412 414 413 415 module_platform_driver(ktd2692_driver);
+1 -1
drivers/leds/flash/leds-lm3601x.c
··· 123 123 .max_register = LM3601X_DEV_ID_REG, 124 124 .reg_defaults = lm3601x_regmap_defs, 125 125 .num_reg_defaults = ARRAY_SIZE(lm3601x_regmap_defs), 126 - .cache_type = REGCACHE_RBTREE, 126 + .cache_type = REGCACHE_MAPLE, 127 127 .volatile_reg = lm3601x_volatile_reg, 128 128 }; 129 129
+2 -4
drivers/leds/flash/leds-max77693.c
··· 1016 1016 return ret; 1017 1017 } 1018 1018 1019 - static int max77693_led_remove(struct platform_device *pdev) 1019 + static void max77693_led_remove(struct platform_device *pdev) 1020 1020 { 1021 1021 struct max77693_led_device *led = platform_get_drvdata(pdev); 1022 1022 struct max77693_sub_led *sub_leds = led->sub_leds; ··· 1032 1032 } 1033 1033 1034 1034 mutex_destroy(&led->lock); 1035 - 1036 - return 0; 1037 1035 } 1038 1036 1039 1037 static const struct of_device_id max77693_led_dt_match[] = { ··· 1042 1044 1043 1045 static struct platform_driver max77693_led_driver = { 1044 1046 .probe = max77693_led_probe, 1045 - .remove = max77693_led_remove, 1047 + .remove_new = max77693_led_remove, 1046 1048 .driver = { 1047 1049 .name = "max77693-led", 1048 1050 .of_match_table = max77693_led_dt_match,
+3 -4
drivers/leds/flash/leds-mt6360.c
··· 91 91 unsigned int fled_torch_used; 92 92 unsigned int leds_active; 93 93 unsigned int leds_count; 94 - struct mt6360_led leds[]; 94 + struct mt6360_led leds[] __counted_by(leds_count); 95 95 }; 96 96 97 97 static int mt6360_mc_brightness_set(struct led_classdev *lcdev, ··· 855 855 return ret; 856 856 } 857 857 858 - static int mt6360_led_remove(struct platform_device *pdev) 858 + static void mt6360_led_remove(struct platform_device *pdev) 859 859 { 860 860 struct mt6360_priv *priv = platform_get_drvdata(pdev); 861 861 862 862 mt6360_v4l2_flash_release(priv); 863 - return 0; 864 863 } 865 864 866 865 static const struct of_device_id __maybe_unused mt6360_led_of_id[] = { ··· 874 875 .of_match_table = mt6360_led_of_id, 875 876 }, 876 877 .probe = mt6360_led_probe, 877 - .remove = mt6360_led_remove, 878 + .remove_new = mt6360_led_remove, 878 879 }; 879 880 module_platform_driver(mt6360_led_driver); 880 881
+1 -1
drivers/leds/flash/leds-mt6370-flash.c
··· 81 81 unsigned int fled_torch_used; 82 82 unsigned int leds_active; 83 83 unsigned int leds_count; 84 - struct mt6370_led leds[]; 84 + struct mt6370_led leds[] __counted_by(leds_count); 85 85 }; 86 86 87 87 static int mt6370_torch_brightness_set(struct led_classdev *lcdev, enum led_brightness level)
+2 -3
drivers/leds/flash/leds-qcom-flash.c
··· 755 755 return rc; 756 756 } 757 757 758 - static int qcom_flash_led_remove(struct platform_device *pdev) 758 + static void qcom_flash_led_remove(struct platform_device *pdev) 759 759 { 760 760 struct qcom_flash_data *flash_data = platform_get_drvdata(pdev); 761 761 ··· 763 763 v4l2_flash_release(flash_data->v4l2_flash[flash_data->leds_count--]); 764 764 765 765 mutex_destroy(&flash_data->lock); 766 - return 0; 767 766 } 768 767 769 768 static const struct of_device_id qcom_flash_led_match_table[] = { ··· 777 778 .of_match_table = qcom_flash_led_match_table, 778 779 }, 779 780 .probe = qcom_flash_led_probe, 780 - .remove = qcom_flash_led_remove, 781 + .remove_new = qcom_flash_led_remove, 781 782 }; 782 783 783 784 module_platform_driver(qcom_flash_led_driver);
+2 -4
drivers/leds/flash/leds-rt8515.c
··· 367 367 return 0; 368 368 } 369 369 370 - static int rt8515_remove(struct platform_device *pdev) 370 + static void rt8515_remove(struct platform_device *pdev) 371 371 { 372 372 struct rt8515 *rt = platform_get_drvdata(pdev); 373 373 374 374 rt8515_v4l2_flash_release(rt); 375 375 del_timer_sync(&rt->powerdown_timer); 376 376 mutex_destroy(&rt->lock); 377 - 378 - return 0; 379 377 } 380 378 381 379 static const struct of_device_id rt8515_match[] = { ··· 388 390 .of_match_table = rt8515_match, 389 391 }, 390 392 .probe = rt8515_probe, 391 - .remove = rt8515_remove, 393 + .remove_new = rt8515_remove, 392 394 }; 393 395 module_platform_driver(rt8515_driver); 394 396
+2 -4
drivers/leds/flash/leds-sgm3140.c
··· 278 278 return ret; 279 279 } 280 280 281 - static int sgm3140_remove(struct platform_device *pdev) 281 + static void sgm3140_remove(struct platform_device *pdev) 282 282 { 283 283 struct sgm3140 *priv = platform_get_drvdata(pdev); 284 284 285 285 del_timer_sync(&priv->powerdown_timer); 286 286 287 287 v4l2_flash_release(priv->v4l2_flash); 288 - 289 - return 0; 290 288 } 291 289 292 290 static const struct of_device_id sgm3140_dt_match[] = { ··· 297 299 298 300 static struct platform_driver sgm3140_driver = { 299 301 .probe = sgm3140_probe, 300 - .remove = sgm3140_remove, 302 + .remove_new = sgm3140_remove, 301 303 .driver = { 302 304 .name = "sgm3140", 303 305 .of_match_table = sgm3140_dt_match,
+11 -6
drivers/leds/led-core.c
··· 36 36 [LED_COLOR_ID_IR] = "ir", 37 37 [LED_COLOR_ID_MULTI] = "multicolor", 38 38 [LED_COLOR_ID_RGB] = "rgb", 39 + [LED_COLOR_ID_PURPLE] = "purple", 40 + [LED_COLOR_ID_ORANGE] = "orange", 41 + [LED_COLOR_ID_PINK] = "pink", 42 + [LED_COLOR_ID_CYAN] = "cyan", 43 + [LED_COLOR_ID_LIME] = "lime", 39 44 }; 40 45 EXPORT_SYMBOL_GPL(led_colors); 41 46 ··· 364 359 365 360 int led_update_brightness(struct led_classdev *led_cdev) 366 361 { 367 - int ret = 0; 362 + int ret; 368 363 369 364 if (led_cdev->brightness_get) { 370 365 ret = led_cdev->brightness_get(led_cdev); 371 - if (ret >= 0) { 372 - led_cdev->brightness = ret; 373 - return 0; 374 - } 366 + if (ret < 0) 367 + return ret; 368 + 369 + led_cdev->brightness = ret; 375 370 } 376 371 377 - return ret; 372 + return 0; 378 373 } 379 374 EXPORT_SYMBOL_GPL(led_update_brightness); 380 375
+2 -4
drivers/leds/leds-88pm860x.c
··· 215 215 return 0; 216 216 } 217 217 218 - static int pm860x_led_remove(struct platform_device *pdev) 218 + static void pm860x_led_remove(struct platform_device *pdev) 219 219 { 220 220 struct pm860x_led *data = platform_get_drvdata(pdev); 221 221 222 222 led_classdev_unregister(&data->cdev); 223 - 224 - return 0; 225 223 } 226 224 227 225 static struct platform_driver pm860x_led_driver = { ··· 227 229 .name = "88pm860x-led", 228 230 }, 229 231 .probe = pm860x_led_probe, 230 - .remove = pm860x_led_remove, 232 + .remove_new = pm860x_led_remove, 231 233 }; 232 234 233 235 module_platform_driver(pm860x_led_driver);
+2 -4
drivers/leds/leds-adp5520.c
··· 163 163 return ret; 164 164 } 165 165 166 - static int adp5520_led_remove(struct platform_device *pdev) 166 + static void adp5520_led_remove(struct platform_device *pdev) 167 167 { 168 168 struct adp5520_leds_platform_data *pdata = dev_get_platdata(&pdev->dev); 169 169 struct adp5520_led *led; ··· 177 177 for (i = 0; i < pdata->num_leds; i++) { 178 178 led_classdev_unregister(&led[i].cdev); 179 179 } 180 - 181 - return 0; 182 180 } 183 181 184 182 static struct platform_driver adp5520_led_driver = { ··· 184 186 .name = "adp5520-led", 185 187 }, 186 188 .probe = adp5520_led_probe, 187 - .remove = adp5520_led_remove, 189 + .remove_new = adp5520_led_remove, 188 190 }; 189 191 190 192 module_platform_driver(adp5520_led_driver);
+2 -2
drivers/leds/leds-aw200xx.c
··· 112 112 struct mutex mutex; 113 113 u32 num_leds; 114 114 u32 display_rows; 115 - struct aw200xx_led leds[]; 115 + struct aw200xx_led leds[] __counted_by(num_leds); 116 116 }; 117 117 118 118 static ssize_t dim_show(struct device *dev, struct device_attribute *devattr, ··· 479 479 .num_ranges = ARRAY_SIZE(aw200xx_ranges), 480 480 .rd_table = &aw200xx_readable_table, 481 481 .wr_table = &aw200xx_writeable_table, 482 - .cache_type = REGCACHE_RBTREE, 482 + .cache_type = REGCACHE_MAPLE, 483 483 }; 484 484 485 485 static int aw200xx_probe(struct i2c_client *client)
+2 -3
drivers/leds/leds-clevo-mail.c
··· 159 159 return led_classdev_register(&pdev->dev, &clevo_mail_led); 160 160 } 161 161 162 - static int clevo_mail_led_remove(struct platform_device *pdev) 162 + static void clevo_mail_led_remove(struct platform_device *pdev) 163 163 { 164 164 led_classdev_unregister(&clevo_mail_led); 165 - return 0; 166 165 } 167 166 168 167 static struct platform_driver clevo_mail_led_driver = { 169 - .remove = clevo_mail_led_remove, 168 + .remove_new = clevo_mail_led_remove, 170 169 .driver = { 171 170 .name = KBUILD_MODNAME, 172 171 },
+1 -1
drivers/leds/leds-cr0014114.c
··· 56 56 struct spi_device *spi; 57 57 u8 *buf; 58 58 unsigned long delay; 59 - struct cr0014114_led leds[]; 59 + struct cr0014114_led leds[] __counted_by(count); 60 60 }; 61 61 62 62 static void cr0014114_calc_crc(u8 *buf, const size_t len)
+2 -4
drivers/leds/leds-da903x.c
··· 121 121 return 0; 122 122 } 123 123 124 - static int da903x_led_remove(struct platform_device *pdev) 124 + static void da903x_led_remove(struct platform_device *pdev) 125 125 { 126 126 struct da903x_led *led = platform_get_drvdata(pdev); 127 127 128 128 led_classdev_unregister(&led->cdev); 129 - 130 - return 0; 131 129 } 132 130 133 131 static struct platform_driver da903x_led_driver = { ··· 133 135 .name = "da903x-led", 134 136 }, 135 137 .probe = da903x_led_probe, 136 - .remove = da903x_led_remove, 138 + .remove_new = da903x_led_remove, 137 139 }; 138 140 139 141 module_platform_driver(da903x_led_driver);
+2 -4
drivers/leds/leds-da9052.c
··· 156 156 return error; 157 157 } 158 158 159 - static int da9052_led_remove(struct platform_device *pdev) 159 + static void da9052_led_remove(struct platform_device *pdev) 160 160 { 161 161 struct da9052_led *led = platform_get_drvdata(pdev); 162 162 struct da9052_pdata *pdata; ··· 172 172 da9052_set_led_brightness(&led[i], LED_OFF); 173 173 led_classdev_unregister(&led[i].cdev); 174 174 } 175 - 176 - return 0; 177 175 } 178 176 179 177 static struct platform_driver da9052_led_driver = { ··· 179 181 .name = "da9052-leds", 180 182 }, 181 183 .probe = da9052_led_probe, 182 - .remove = da9052_led_remove, 184 + .remove_new = da9052_led_remove, 183 185 }; 184 186 185 187 module_platform_driver(da9052_led_driver);
+1 -1
drivers/leds/leds-el15203000.c
··· 80 80 struct spi_device *spi; 81 81 unsigned long delay; 82 82 size_t count; 83 - struct el15203000_led leds[]; 83 + struct el15203000_led leds[] __counted_by(count); 84 84 }; 85 85 86 86 #define to_el15203000_led(d) container_of(d, struct el15203000_led, ldev)
+27 -29
drivers/leds/leds-gpio.c
··· 6 6 * Raphael Assenat <raph@8d.com> 7 7 * Copyright (C) 2008 Freescale Semiconductor, Inc. 8 8 */ 9 + #include <linux/container_of.h> 10 + #include <linux/device.h> 9 11 #include <linux/err.h> 10 12 #include <linux/gpio.h> 11 13 #include <linux/gpio/consumer.h> 12 - #include <linux/kernel.h> 13 14 #include <linux/leds.h> 15 + #include <linux/mod_devicetable.h> 14 16 #include <linux/module.h> 15 - #include <linux/of.h> 17 + #include <linux/overflow.h> 16 18 #include <linux/pinctrl/consumer.h> 17 19 #include <linux/platform_device.h> 18 20 #include <linux/property.h> 19 21 #include <linux/slab.h> 22 + #include <linux/types.h> 23 + 20 24 #include "leds.h" 21 25 22 26 struct gpio_led_data { ··· 129 125 return ret; 130 126 131 127 pinctrl = devm_pinctrl_get_select_default(led_dat->cdev.dev); 132 - if (IS_ERR(pinctrl)) { 133 - ret = PTR_ERR(pinctrl); 134 - if (ret != -ENODEV) { 135 - dev_warn(led_dat->cdev.dev, 136 - "Failed to select %pOF pinctrl: %d\n", 137 - to_of_node(fwnode), ret); 138 - } else { 139 - /* pinctrl-%d not present, not an error */ 140 - ret = 0; 141 - } 128 + ret = PTR_ERR_OR_ZERO(pinctrl); 129 + /* pinctrl-%d not present, not an error */ 130 + if (ret == -ENODEV) 131 + ret = 0; 132 + if (ret) { 133 + dev_warn(led_dat->cdev.dev, "Failed to select %pfw pinctrl: %d\n", 134 + fwnode, ret); 142 135 } 143 136 144 137 return ret; ··· 143 142 144 143 struct gpio_leds_priv { 145 144 int num_leds; 146 - struct gpio_led_data leds[]; 145 + struct gpio_led_data leds[] __counted_by(num_leds); 147 146 }; 148 147 149 - static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev) 148 + static struct gpio_leds_priv *gpio_leds_create(struct device *dev) 150 149 { 151 - struct device *dev = &pdev->dev; 152 150 struct fwnode_handle *child; 153 151 struct gpio_leds_priv *priv; 154 152 int count, ret; ··· 221 221 * device, this will hit the board file, if any and get 222 222 * the GPIO from there. 223 223 */ 224 - gpiod = devm_gpiod_get_index(dev, NULL, idx, GPIOD_OUT_LOW); 225 - if (!IS_ERR(gpiod)) { 224 + gpiod = devm_gpiod_get_index_optional(dev, NULL, idx, GPIOD_OUT_LOW); 225 + if (IS_ERR(gpiod)) 226 + return gpiod; 227 + if (gpiod) { 226 228 gpiod_set_consumer_name(gpiod, template->name); 227 229 return gpiod; 228 230 } 229 - if (PTR_ERR(gpiod) != -ENOENT) 230 - return gpiod; 231 231 232 232 /* 233 233 * This is the legacy code path for platform code that ··· 256 256 257 257 static int gpio_led_probe(struct platform_device *pdev) 258 258 { 259 - struct gpio_led_platform_data *pdata = dev_get_platdata(&pdev->dev); 259 + struct device *dev = &pdev->dev; 260 + struct gpio_led_platform_data *pdata = dev_get_platdata(dev); 260 261 struct gpio_leds_priv *priv; 261 - int i, ret = 0; 262 + int i, ret; 262 263 263 264 if (pdata && pdata->num_leds) { 264 - priv = devm_kzalloc(&pdev->dev, struct_size(priv, leds, pdata->num_leds), 265 - GFP_KERNEL); 265 + priv = devm_kzalloc(dev, struct_size(priv, leds, pdata->num_leds), GFP_KERNEL); 266 266 if (!priv) 267 267 return -ENOMEM; 268 268 ··· 275 275 led_dat->gpiod = template->gpiod; 276 276 else 277 277 led_dat->gpiod = 278 - gpio_led_get_gpiod(&pdev->dev, 279 - i, template); 278 + gpio_led_get_gpiod(dev, i, template); 280 279 if (IS_ERR(led_dat->gpiod)) { 281 - dev_info(&pdev->dev, "Skipping unavailable LED gpio %d (%s)\n", 280 + dev_info(dev, "Skipping unavailable LED gpio %d (%s)\n", 282 281 template->gpio, template->name); 283 282 continue; 284 283 } 285 284 286 - ret = create_gpio_led(template, led_dat, 287 - &pdev->dev, NULL, 285 + ret = create_gpio_led(template, led_dat, dev, NULL, 288 286 pdata->gpio_blink_set); 289 287 if (ret < 0) 290 288 return ret; 291 289 } 292 290 } else { 293 - priv = gpio_leds_create(pdev); 291 + priv = gpio_leds_create(dev); 294 292 if (IS_ERR(priv)) 295 293 return PTR_ERR(priv); 296 294 }
+2 -4
drivers/leds/leds-lm3533.c
··· 718 718 return ret; 719 719 } 720 720 721 - static int lm3533_led_remove(struct platform_device *pdev) 721 + static void lm3533_led_remove(struct platform_device *pdev) 722 722 { 723 723 struct lm3533_led *led = platform_get_drvdata(pdev); 724 724 ··· 726 726 727 727 lm3533_ctrlbank_disable(&led->cb); 728 728 led_classdev_unregister(&led->cdev); 729 - 730 - return 0; 731 729 } 732 730 733 731 static void lm3533_led_shutdown(struct platform_device *pdev) ··· 744 746 .name = "lm3533-leds", 745 747 }, 746 748 .probe = lm3533_led_probe, 747 - .remove = lm3533_led_remove, 749 + .remove_new = lm3533_led_remove, 748 750 .shutdown = lm3533_led_shutdown, 749 751 }; 750 752 module_platform_driver(lm3533_led_driver);
+1 -1
drivers/leds/leds-lm3692x.c
··· 139 139 .max_register = LM3692X_FAULT_FLAGS, 140 140 .reg_defaults = lm3692x_reg_defs, 141 141 .num_reg_defaults = ARRAY_SIZE(lm3692x_reg_defs), 142 - .cache_type = REGCACHE_RBTREE, 142 + .cache_type = REGCACHE_MAPLE, 143 143 }; 144 144 145 145 static int lm3692x_fault_check(struct lm3692x_led *led)
+1 -1
drivers/leds/leds-lm3697.c
··· 89 89 int bank_cfg; 90 90 int num_banks; 91 91 92 - struct lm3697_led leds[]; 92 + struct lm3697_led leds[] __counted_by(num_banks); 93 93 }; 94 94 95 95 static const struct reg_default lm3697_reg_defs[] = {
+2 -2
drivers/leds/leds-lp3952.c
··· 101 101 if (ret) 102 102 return ret; 103 103 104 - strncpy(dest, str, LP3952_LABEL_MAX_LEN); 104 + strscpy(dest, str, LP3952_LABEL_MAX_LEN); 105 105 return 0; 106 106 } 107 107 ··· 204 204 .reg_bits = 8, 205 205 .val_bits = 8, 206 206 .max_register = REG_MAX, 207 - .cache_type = REGCACHE_RBTREE, 207 + .cache_type = REGCACHE_MAPLE, 208 208 }; 209 209 210 210 static int lp3952_probe(struct i2c_client *client)
+2
drivers/leds/leds-lp5521.c
··· 301 301 302 302 /* Set all PWMs to direct control mode */ 303 303 ret = lp55xx_write(chip, LP5521_REG_OP_MODE, LP5521_CMD_DIRECT); 304 + if (ret) 305 + return ret; 304 306 305 307 /* Update configuration for the clock setting */ 306 308 val = LP5521_DEFAULT_CFG;
+2 -2
drivers/leds/leds-lp55xx-common.c
··· 442 442 gpiod_direction_output(pdata->enable_gpiod, 0); 443 443 444 444 gpiod_set_consumer_name(pdata->enable_gpiod, "LP55xx enable"); 445 - gpiod_set_value(pdata->enable_gpiod, 0); 445 + gpiod_set_value_cansleep(pdata->enable_gpiod, 0); 446 446 usleep_range(1000, 2000); /* Keep enable down at least 1ms */ 447 - gpiod_set_value(pdata->enable_gpiod, 1); 447 + gpiod_set_value_cansleep(pdata->enable_gpiod, 1); 448 448 usleep_range(1000, 2000); /* 500us abs min. */ 449 449 } 450 450
+2 -4
drivers/leds/leds-mc13783.c
··· 261 261 return ret; 262 262 } 263 263 264 - static int mc13xxx_led_remove(struct platform_device *pdev) 264 + static void mc13xxx_led_remove(struct platform_device *pdev) 265 265 { 266 266 struct mc13xxx_leds *leds = platform_get_drvdata(pdev); 267 267 int i; 268 268 269 269 for (i = 0; i < leds->num_leds; i++) 270 270 led_classdev_unregister(&leds->led[i].cdev); 271 - 272 - return 0; 273 271 } 274 272 275 273 static const struct mc13xxx_led_devtype mc13783_led_devtype = { ··· 303 305 .driver = { 304 306 .name = "mc13xxx-led", 305 307 }, 306 - .remove = mc13xxx_led_remove, 308 + .remove_new = mc13xxx_led_remove, 307 309 .id_table = mc13xxx_led_id_table, 308 310 }; 309 311 module_platform_driver_probe(mc13xxx_led_driver, mc13xxx_led_probe);
+2 -4
drivers/leds/leds-mlxreg.c
··· 275 275 return mlxreg_led_config(priv); 276 276 } 277 277 278 - static int mlxreg_led_remove(struct platform_device *pdev) 278 + static void mlxreg_led_remove(struct platform_device *pdev) 279 279 { 280 280 struct mlxreg_led_priv_data *priv = dev_get_drvdata(&pdev->dev); 281 281 282 282 mutex_destroy(&priv->access_lock); 283 - 284 - return 0; 285 283 } 286 284 287 285 static struct platform_driver mlxreg_led_driver = { ··· 287 289 .name = "leds-mlxreg", 288 290 }, 289 291 .probe = mlxreg_led_probe, 290 - .remove = mlxreg_led_remove, 292 + .remove_new = mlxreg_led_remove, 291 293 }; 292 294 293 295 module_platform_driver(mlxreg_led_driver);
+2 -4
drivers/leds/leds-mt6323.c
··· 632 632 return ret; 633 633 } 634 634 635 - static int mt6323_led_remove(struct platform_device *pdev) 635 + static void mt6323_led_remove(struct platform_device *pdev) 636 636 { 637 637 struct mt6323_leds *leds = platform_get_drvdata(pdev); 638 638 const struct mt6323_regs *regs = leds->pdata->regs; ··· 647 647 RG_DRV_32K_CK_PDN); 648 648 649 649 mutex_destroy(&leds->lock); 650 - 651 - return 0; 652 650 } 653 651 654 652 static const struct mt6323_regs mt6323_registers = { ··· 721 723 722 724 static struct platform_driver mt6323_led_driver = { 723 725 .probe = mt6323_led_probe, 724 - .remove = mt6323_led_remove, 726 + .remove_new = mt6323_led_remove, 725 727 .driver = { 726 728 .name = "mt6323-led", 727 729 .of_match_table = mt6323_led_dt_match,
+2 -4
drivers/leds/leds-nic78bx.c
··· 167 167 return ret; 168 168 } 169 169 170 - static int nic78bx_remove(struct platform_device *pdev) 170 + static void nic78bx_remove(struct platform_device *pdev) 171 171 { 172 172 struct nic78bx_led_data *led_data = platform_get_drvdata(pdev); 173 173 174 174 /* Lock LED register */ 175 175 outb(NIC78BX_LOCK_VALUE, 176 176 led_data->io_base + NIC78BX_LOCK_REG_OFFSET); 177 - 178 - return 0; 179 177 } 180 178 181 179 static const struct acpi_device_id led_device_ids[] = { ··· 184 186 185 187 static struct platform_driver led_driver = { 186 188 .probe = nic78bx_probe, 187 - .remove = nic78bx_remove, 189 + .remove_new = nic78bx_remove, 188 190 .driver = { 189 191 .name = KBUILD_MODNAME, 190 192 .acpi_match_table = ACPI_PTR(led_device_ids),
+27 -40
drivers/leds/leds-pca955x.c
··· 76 76 int slv_addr_shift; /* Number of bits to ignore */ 77 77 }; 78 78 79 - static struct pca955x_chipdef pca955x_chipdefs[] = { 79 + static const struct pca955x_chipdef pca955x_chipdefs[] = { 80 80 [pca9550] = { 81 81 .bits = 2, 82 82 .slv_addr = /* 110000x */ 0x60, ··· 104 104 }, 105 105 }; 106 106 107 - static const struct i2c_device_id pca955x_id[] = { 108 - { "pca9550", pca9550 }, 109 - { "pca9551", pca9551 }, 110 - { "pca9552", pca9552 }, 111 - { "ibm-pca9552", ibm_pca9552 }, 112 - { "pca9553", pca9553 }, 113 - { } 114 - }; 115 - MODULE_DEVICE_TABLE(i2c, pca955x_id); 116 - 117 107 struct pca955x { 118 108 struct mutex lock; 119 109 struct pca955x_led *leds; 120 - struct pca955x_chipdef *chipdef; 110 + const struct pca955x_chipdef *chipdef; 121 111 struct i2c_client *client; 122 112 unsigned long active_pins; 123 113 #ifdef CONFIG_LEDS_PCA955X_GPIO ··· 405 415 #endif /* CONFIG_LEDS_PCA955X_GPIO */ 406 416 407 417 static struct pca955x_platform_data * 408 - pca955x_get_pdata(struct i2c_client *client, struct pca955x_chipdef *chip) 418 + pca955x_get_pdata(struct i2c_client *client, const struct pca955x_chipdef *chip) 409 419 { 410 420 struct pca955x_platform_data *pdata; 411 421 struct pca955x_led *led; ··· 447 457 return pdata; 448 458 } 449 459 450 - static const struct of_device_id of_pca955x_match[] = { 451 - { .compatible = "nxp,pca9550", .data = (void *)pca9550 }, 452 - { .compatible = "nxp,pca9551", .data = (void *)pca9551 }, 453 - { .compatible = "nxp,pca9552", .data = (void *)pca9552 }, 454 - { .compatible = "ibm,pca9552", .data = (void *)ibm_pca9552 }, 455 - { .compatible = "nxp,pca9553", .data = (void *)pca9553 }, 456 - {}, 457 - }; 458 - MODULE_DEVICE_TABLE(of, of_pca955x_match); 459 - 460 460 static int pca955x_probe(struct i2c_client *client) 461 461 { 462 462 struct pca955x *pca955x; 463 463 struct pca955x_led *pca955x_led; 464 - struct pca955x_chipdef *chip; 464 + const struct pca955x_chipdef *chip; 465 465 struct led_classdev *led; 466 466 struct led_init_data init_data; 467 467 struct i2c_adapter *adapter; ··· 460 480 bool set_default_label = false; 461 481 bool keep_pwm = false; 462 482 char default_label[8]; 463 - enum pca955x_type chip_type; 464 - const void *md = device_get_match_data(&client->dev); 465 483 466 - if (md) { 467 - chip_type = (enum pca955x_type)md; 468 - } else { 469 - const struct i2c_device_id *id = i2c_match_id(pca955x_id, 470 - client); 484 + chip = i2c_get_match_data(client); 485 + if (!chip) 486 + return dev_err_probe(&client->dev, -ENODEV, "unknown chip\n"); 471 487 472 - if (id) { 473 - chip_type = (enum pca955x_type)id->driver_data; 474 - } else { 475 - dev_err(&client->dev, "unknown chip\n"); 476 - return -ENODEV; 477 - } 478 - } 479 - 480 - chip = &pca955x_chipdefs[chip_type]; 481 488 adapter = client->adapter; 482 489 pdata = dev_get_platdata(&client->dev); 483 490 if (!pdata) { ··· 629 662 630 663 return 0; 631 664 } 665 + 666 + static const struct i2c_device_id pca955x_id[] = { 667 + { "pca9550", (kernel_ulong_t)&pca955x_chipdefs[pca9550] }, 668 + { "pca9551", (kernel_ulong_t)&pca955x_chipdefs[pca9551] }, 669 + { "pca9552", (kernel_ulong_t)&pca955x_chipdefs[pca9552] }, 670 + { "ibm-pca9552", (kernel_ulong_t)&pca955x_chipdefs[ibm_pca9552] }, 671 + { "pca9553", (kernel_ulong_t)&pca955x_chipdefs[pca9553] }, 672 + {} 673 + }; 674 + MODULE_DEVICE_TABLE(i2c, pca955x_id); 675 + 676 + static const struct of_device_id of_pca955x_match[] = { 677 + { .compatible = "nxp,pca9550", .data = &pca955x_chipdefs[pca9550] }, 678 + { .compatible = "nxp,pca9551", .data = &pca955x_chipdefs[pca9551] }, 679 + { .compatible = "nxp,pca9552", .data = &pca955x_chipdefs[pca9552] }, 680 + { .compatible = "ibm,pca9552", .data = &pca955x_chipdefs[ibm_pca9552] }, 681 + { .compatible = "nxp,pca9553", .data = &pca955x_chipdefs[pca9553] }, 682 + {} 683 + }; 684 + MODULE_DEVICE_TABLE(of, of_pca955x_match); 632 685 633 686 static struct i2c_driver pca955x_driver = { 634 687 .driver = {
+2 -3
drivers/leds/leds-powernv.c
··· 309 309 } 310 310 311 311 /* Platform driver remove */ 312 - static int powernv_led_remove(struct platform_device *pdev) 312 + static void powernv_led_remove(struct platform_device *pdev) 313 313 { 314 314 struct powernv_led_common *powernv_led_common; 315 315 ··· 321 321 mutex_destroy(&powernv_led_common->lock); 322 322 323 323 dev_info(&pdev->dev, "PowerNV led module unregistered\n"); 324 - return 0; 325 324 } 326 325 327 326 /* Platform driver property match */ ··· 334 335 335 336 static struct platform_driver powernv_led_driver = { 336 337 .probe = powernv_led_probe, 337 - .remove = powernv_led_remove, 338 + .remove_new = powernv_led_remove, 338 339 .driver = { 339 340 .name = "powernv-led-driver", 340 341 .of_match_table = powernv_led_match,
+1 -1
drivers/leds/leds-pwm.c
··· 53 53 duty = led_dat->pwmstate.period - duty; 54 54 55 55 led_dat->pwmstate.duty_cycle = duty; 56 - led_dat->pwmstate.enabled = duty > 0; 56 + led_dat->pwmstate.enabled = true; 57 57 return pwm_apply_state(led_dat->pwm, &led_dat->pwmstate); 58 58 } 59 59
+2 -3
drivers/leds/leds-rb532.c
··· 42 42 return led_classdev_register(&pdev->dev, &rb532_uled); 43 43 } 44 44 45 - static int rb532_led_remove(struct platform_device *pdev) 45 + static void rb532_led_remove(struct platform_device *pdev) 46 46 { 47 47 led_classdev_unregister(&rb532_uled); 48 - return 0; 49 48 } 50 49 51 50 static struct platform_driver rb532_led_driver = { 52 51 .probe = rb532_led_probe, 53 - .remove = rb532_led_remove, 52 + .remove_new = rb532_led_remove, 54 53 .driver = { 55 54 .name = "rb532-led", 56 55 },
+2 -3
drivers/leds/leds-regulator.c
··· 173 173 return 0; 174 174 } 175 175 176 - static int regulator_led_remove(struct platform_device *pdev) 176 + static void regulator_led_remove(struct platform_device *pdev) 177 177 { 178 178 struct regulator_led *led = platform_get_drvdata(pdev); 179 179 180 180 led_classdev_unregister(&led->cdev); 181 181 regulator_led_disable(led); 182 - return 0; 183 182 } 184 183 185 184 static const struct of_device_id regulator_led_of_match[] = { ··· 193 194 .of_match_table = regulator_led_of_match, 194 195 }, 195 196 .probe = regulator_led_probe, 196 - .remove = regulator_led_remove, 197 + .remove_new = regulator_led_remove, 197 198 }; 198 199 199 200 module_platform_driver(regulator_led_driver);
+4 -6
drivers/leds/leds-sc27xx-bltc.c
··· 296 296 return -ENOMEM; 297 297 298 298 platform_set_drvdata(pdev, priv); 299 - mutex_init(&priv->lock); 300 299 priv->base = base; 301 300 priv->regmap = dev_get_regmap(dev->parent, NULL); 302 301 if (!priv->regmap) { ··· 308 309 err = of_property_read_u32(child, "reg", &reg); 309 310 if (err) { 310 311 of_node_put(child); 311 - mutex_destroy(&priv->lock); 312 312 return err; 313 313 } 314 314 315 315 if (reg >= SC27XX_LEDS_MAX || priv->leds[reg].active) { 316 316 of_node_put(child); 317 - mutex_destroy(&priv->lock); 318 317 return -EINVAL; 319 318 } 320 319 321 320 priv->leds[reg].fwnode = of_fwnode_handle(child); 322 321 priv->leds[reg].active = true; 323 322 } 323 + 324 + mutex_init(&priv->lock); 324 325 325 326 err = sc27xx_led_register(dev, priv); 326 327 if (err) ··· 329 330 return err; 330 331 } 331 332 332 - static int sc27xx_led_remove(struct platform_device *pdev) 333 + static void sc27xx_led_remove(struct platform_device *pdev) 333 334 { 334 335 struct sc27xx_led_priv *priv = platform_get_drvdata(pdev); 335 336 336 337 mutex_destroy(&priv->lock); 337 - return 0; 338 338 } 339 339 340 340 static const struct of_device_id sc27xx_led_of_match[] = { ··· 348 350 .of_match_table = sc27xx_led_of_match, 349 351 }, 350 352 .probe = sc27xx_led_probe, 351 - .remove = sc27xx_led_remove, 353 + .remove_new = sc27xx_led_remove, 352 354 }; 353 355 354 356 module_platform_driver(sc27xx_led_driver);
+3 -5
drivers/leds/leds-sunfire.c
··· 163 163 return 0; 164 164 } 165 165 166 - static int sunfire_led_generic_remove(struct platform_device *pdev) 166 + static void sunfire_led_generic_remove(struct platform_device *pdev) 167 167 { 168 168 struct sunfire_drvdata *p = platform_get_drvdata(pdev); 169 169 int i; 170 170 171 171 for (i = 0; i < NUM_LEDS_PER_BOARD; i++) 172 172 led_classdev_unregister(&p->leds[i].led_cdev); 173 - 174 - return 0; 175 173 } 176 174 177 175 static struct led_type clockboard_led_types[NUM_LEDS_PER_BOARD] = { ··· 219 221 220 222 static struct platform_driver sunfire_clockboard_led_driver = { 221 223 .probe = sunfire_clockboard_led_probe, 222 - .remove = sunfire_led_generic_remove, 224 + .remove_new = sunfire_led_generic_remove, 223 225 .driver = { 224 226 .name = "sunfire-clockboard-leds", 225 227 }, ··· 227 229 228 230 static struct platform_driver sunfire_fhc_led_driver = { 229 231 .probe = sunfire_fhc_led_probe, 230 - .remove = sunfire_led_generic_remove, 232 + .remove_new = sunfire_led_generic_remove, 231 233 .driver = { 232 234 .name = "sunfire-fhc-leds", 233 235 },
+1 -7
drivers/leds/leds-tca6507.c
··· 92 92 93 93 struct tca6507_platform_data { 94 94 struct led_platform_data leds; 95 - #ifdef CONFIG_GPIOLIB 96 - int gpio_base; 97 - #endif 98 95 }; 99 96 100 97 #define TCA6507_MAKE_GPIO 1 ··· 633 636 634 637 tca->gpio.label = "gpio-tca6507"; 635 638 tca->gpio.ngpio = gpios; 636 - tca->gpio.base = pdata->gpio_base; 639 + tca->gpio.base = -1; 637 640 tca->gpio.owner = THIS_MODULE; 638 641 tca->gpio.direction_output = tca6507_gpio_direction_output; 639 642 tca->gpio.set = tca6507_gpio_set_value; ··· 712 715 713 716 pdata->leds.leds = tca_leds; 714 717 pdata->leds.num_leds = NUM_LEDS; 715 - #ifdef CONFIG_GPIOLIB 716 - pdata->gpio_base = -1; 717 - #endif 718 718 719 719 return pdata; 720 720 }
+320 -42
drivers/leds/leds-turris-omnia.c
··· 2 2 /* 3 3 * CZ.NIC's Turris Omnia LEDs driver 4 4 * 5 - * 2020 by Marek Behún <kabel@kernel.org> 5 + * 2020, 2023 by Marek Behún <kabel@kernel.org> 6 6 */ 7 7 8 8 #include <linux/i2c.h> ··· 15 15 #define OMNIA_BOARD_LEDS 12 16 16 #define OMNIA_LED_NUM_CHANNELS 3 17 17 18 - #define CMD_LED_MODE 3 19 - #define CMD_LED_MODE_LED(l) ((l) & 0x0f) 20 - #define CMD_LED_MODE_USER 0x10 18 + /* MCU controller commands at I2C address 0x2a */ 19 + #define OMNIA_MCU_I2C_ADDR 0x2a 21 20 22 - #define CMD_LED_STATE 4 23 - #define CMD_LED_STATE_LED(l) ((l) & 0x0f) 24 - #define CMD_LED_STATE_ON 0x10 21 + #define CMD_GET_STATUS_WORD 0x01 22 + #define STS_FEATURES_SUPPORTED BIT(2) 25 23 26 - #define CMD_LED_COLOR 5 27 - #define CMD_LED_SET_BRIGHTNESS 7 28 - #define CMD_LED_GET_BRIGHTNESS 8 24 + #define CMD_GET_FEATURES 0x10 25 + #define FEAT_LED_GAMMA_CORRECTION BIT(5) 26 + 27 + /* LED controller commands at I2C address 0x2b */ 28 + #define CMD_LED_MODE 0x03 29 + #define CMD_LED_MODE_LED(l) ((l) & 0x0f) 30 + #define CMD_LED_MODE_USER 0x10 31 + 32 + #define CMD_LED_STATE 0x04 33 + #define CMD_LED_STATE_LED(l) ((l) & 0x0f) 34 + #define CMD_LED_STATE_ON 0x10 35 + 36 + #define CMD_LED_COLOR 0x05 37 + #define CMD_LED_SET_BRIGHTNESS 0x07 38 + #define CMD_LED_GET_BRIGHTNESS 0x08 39 + 40 + #define CMD_SET_GAMMA_CORRECTION 0x30 41 + #define CMD_GET_GAMMA_CORRECTION 0x31 29 42 30 43 struct omnia_led { 31 44 struct led_classdev_mc mc_cdev; 32 45 struct mc_subled subled_info[OMNIA_LED_NUM_CHANNELS]; 46 + u8 cached_channels[OMNIA_LED_NUM_CHANNELS]; 47 + bool on, hwtrig; 33 48 int reg; 34 49 }; 35 50 ··· 53 38 struct omnia_leds { 54 39 struct i2c_client *client; 55 40 struct mutex lock; 41 + bool has_gamma_correction; 56 42 struct omnia_led leds[]; 57 43 }; 44 + 45 + static int omnia_cmd_write_u8(const struct i2c_client *client, u8 cmd, u8 val) 46 + { 47 + u8 buf[2] = { cmd, val }; 48 + int ret; 49 + 50 + ret = i2c_master_send(client, buf, sizeof(buf)); 51 + 52 + return ret < 0 ? ret : 0; 53 + } 54 + 55 + static int omnia_cmd_read_raw(struct i2c_adapter *adapter, u8 addr, u8 cmd, 56 + void *reply, size_t len) 57 + { 58 + struct i2c_msg msgs[2]; 59 + int ret; 60 + 61 + msgs[0].addr = addr; 62 + msgs[0].flags = 0; 63 + msgs[0].len = 1; 64 + msgs[0].buf = &cmd; 65 + msgs[1].addr = addr; 66 + msgs[1].flags = I2C_M_RD; 67 + msgs[1].len = len; 68 + msgs[1].buf = reply; 69 + 70 + ret = i2c_transfer(adapter, msgs, ARRAY_SIZE(msgs)); 71 + if (likely(ret == ARRAY_SIZE(msgs))) 72 + return 0; 73 + else if (ret < 0) 74 + return ret; 75 + else 76 + return -EIO; 77 + } 78 + 79 + static int omnia_cmd_read_u8(const struct i2c_client *client, u8 cmd) 80 + { 81 + u8 reply; 82 + int err; 83 + 84 + err = omnia_cmd_read_raw(client->adapter, client->addr, cmd, &reply, 1); 85 + if (err) 86 + return err; 87 + 88 + return reply; 89 + } 90 + 91 + static int omnia_led_send_color_cmd(const struct i2c_client *client, 92 + struct omnia_led *led) 93 + { 94 + char cmd[5]; 95 + int ret; 96 + 97 + cmd[0] = CMD_LED_COLOR; 98 + cmd[1] = led->reg; 99 + cmd[2] = led->subled_info[0].brightness; 100 + cmd[3] = led->subled_info[1].brightness; 101 + cmd[4] = led->subled_info[2].brightness; 102 + 103 + /* Send the color change command */ 104 + ret = i2c_master_send(client, cmd, 5); 105 + if (ret < 0) 106 + return ret; 107 + 108 + /* Cache the RGB channel brightnesses */ 109 + for (int i = 0; i < OMNIA_LED_NUM_CHANNELS; ++i) 110 + led->cached_channels[i] = led->subled_info[i].brightness; 111 + 112 + return 0; 113 + } 114 + 115 + /* Determine if the computed RGB channels are different from the cached ones */ 116 + static bool omnia_led_channels_changed(struct omnia_led *led) 117 + { 118 + for (int i = 0; i < OMNIA_LED_NUM_CHANNELS; ++i) 119 + if (led->subled_info[i].brightness != led->cached_channels[i]) 120 + return true; 121 + 122 + return false; 123 + } 58 124 59 125 static int omnia_led_brightness_set_blocking(struct led_classdev *cdev, 60 126 enum led_brightness brightness) ··· 143 47 struct led_classdev_mc *mc_cdev = lcdev_to_mccdev(cdev); 144 48 struct omnia_leds *leds = dev_get_drvdata(cdev->dev->parent); 145 49 struct omnia_led *led = to_omnia_led(mc_cdev); 146 - u8 buf[5], state; 147 - int ret; 50 + int err = 0; 148 51 149 52 mutex_lock(&leds->lock); 150 53 151 - led_mc_calc_color_components(&led->mc_cdev, brightness); 54 + /* 55 + * Only recalculate RGB brightnesses from intensities if brightness is 56 + * non-zero (if it is zero and the LED is in HW blinking mode, we use 57 + * max_brightness as brightness). Otherwise we won't be using them and 58 + * we can save ourselves some software divisions (Omnia's CPU does not 59 + * implement the division instruction). 60 + */ 61 + if (brightness || led->hwtrig) { 62 + led_mc_calc_color_components(mc_cdev, brightness ?: 63 + cdev->max_brightness); 152 64 153 - buf[0] = CMD_LED_COLOR; 154 - buf[1] = led->reg; 155 - buf[2] = mc_cdev->subled_info[0].brightness; 156 - buf[3] = mc_cdev->subled_info[1].brightness; 157 - buf[4] = mc_cdev->subled_info[2].brightness; 65 + /* 66 + * Send color command only if brightness is non-zero and the RGB 67 + * channel brightnesses changed. 68 + */ 69 + if (omnia_led_channels_changed(led)) 70 + err = omnia_led_send_color_cmd(leds->client, led); 71 + } 158 72 159 - state = CMD_LED_STATE_LED(led->reg); 160 - if (buf[2] || buf[3] || buf[4]) 161 - state |= CMD_LED_STATE_ON; 73 + /* 74 + * Send on/off state change only if (bool)brightness changed and the LED 75 + * is not being blinked by HW. 76 + */ 77 + if (!err && !led->hwtrig && !brightness != !led->on) { 78 + u8 state = CMD_LED_STATE_LED(led->reg); 162 79 163 - ret = i2c_smbus_write_byte_data(leds->client, CMD_LED_STATE, state); 164 - if (ret >= 0 && (state & CMD_LED_STATE_ON)) 165 - ret = i2c_master_send(leds->client, buf, 5); 80 + if (brightness) 81 + state |= CMD_LED_STATE_ON; 82 + 83 + err = omnia_cmd_write_u8(leds->client, CMD_LED_STATE, state); 84 + if (!err) 85 + led->on = !!brightness; 86 + } 166 87 167 88 mutex_unlock(&leds->lock); 168 89 169 - return ret; 90 + return err; 170 91 } 92 + 93 + static struct led_hw_trigger_type omnia_hw_trigger_type; 94 + 95 + static int omnia_hwtrig_activate(struct led_classdev *cdev) 96 + { 97 + struct led_classdev_mc *mc_cdev = lcdev_to_mccdev(cdev); 98 + struct omnia_leds *leds = dev_get_drvdata(cdev->dev->parent); 99 + struct omnia_led *led = to_omnia_led(mc_cdev); 100 + int err = 0; 101 + 102 + mutex_lock(&leds->lock); 103 + 104 + if (!led->on) { 105 + /* 106 + * If the LED is off (brightness was set to 0), the last 107 + * configured color was not necessarily sent to the MCU. 108 + * Recompute with max_brightness and send if needed. 109 + */ 110 + led_mc_calc_color_components(mc_cdev, cdev->max_brightness); 111 + 112 + if (omnia_led_channels_changed(led)) 113 + err = omnia_led_send_color_cmd(leds->client, led); 114 + } 115 + 116 + if (!err) { 117 + /* Put the LED into MCU controlled mode */ 118 + err = omnia_cmd_write_u8(leds->client, CMD_LED_MODE, 119 + CMD_LED_MODE_LED(led->reg)); 120 + if (!err) 121 + led->hwtrig = true; 122 + } 123 + 124 + mutex_unlock(&leds->lock); 125 + 126 + return err; 127 + } 128 + 129 + static void omnia_hwtrig_deactivate(struct led_classdev *cdev) 130 + { 131 + struct omnia_leds *leds = dev_get_drvdata(cdev->dev->parent); 132 + struct omnia_led *led = to_omnia_led(lcdev_to_mccdev(cdev)); 133 + int err; 134 + 135 + mutex_lock(&leds->lock); 136 + 137 + led->hwtrig = false; 138 + 139 + /* Put the LED into software mode */ 140 + err = omnia_cmd_write_u8(leds->client, CMD_LED_MODE, 141 + CMD_LED_MODE_LED(led->reg) | 142 + CMD_LED_MODE_USER); 143 + 144 + mutex_unlock(&leds->lock); 145 + 146 + if (err) 147 + dev_err(cdev->dev, "Cannot put LED to software mode: %i\n", 148 + err); 149 + } 150 + 151 + static struct led_trigger omnia_hw_trigger = { 152 + .name = "omnia-mcu", 153 + .activate = omnia_hwtrig_activate, 154 + .deactivate = omnia_hwtrig_deactivate, 155 + .trigger_type = &omnia_hw_trigger_type, 156 + }; 171 157 172 158 static int omnia_led_register(struct i2c_client *client, struct omnia_led *led, 173 159 struct device_node *np) ··· 276 98 } 277 99 278 100 led->subled_info[0].color_index = LED_COLOR_ID_RED; 279 - led->subled_info[0].channel = 0; 280 101 led->subled_info[1].color_index = LED_COLOR_ID_GREEN; 281 - led->subled_info[1].channel = 1; 282 102 led->subled_info[2].color_index = LED_COLOR_ID_BLUE; 283 - led->subled_info[2].channel = 2; 103 + 104 + /* Initial color is white */ 105 + for (int i = 0; i < OMNIA_LED_NUM_CHANNELS; ++i) { 106 + led->subled_info[i].intensity = 255; 107 + led->subled_info[i].brightness = 255; 108 + led->subled_info[i].channel = i; 109 + } 284 110 285 111 led->mc_cdev.subled_info = led->subled_info; 286 112 led->mc_cdev.num_colors = OMNIA_LED_NUM_CHANNELS; ··· 294 112 cdev = &led->mc_cdev.led_cdev; 295 113 cdev->max_brightness = 255; 296 114 cdev->brightness_set_blocking = omnia_led_brightness_set_blocking; 115 + cdev->trigger_type = &omnia_hw_trigger_type; 116 + /* 117 + * Use the omnia-mcu trigger as the default trigger. It may be rewritten 118 + * by LED class from the linux,default-trigger property. 119 + */ 120 + cdev->default_trigger = omnia_hw_trigger.name; 297 121 298 122 /* put the LED into software mode */ 299 - ret = i2c_smbus_write_byte_data(client, CMD_LED_MODE, 300 - CMD_LED_MODE_LED(led->reg) | 301 - CMD_LED_MODE_USER); 302 - if (ret < 0) { 123 + ret = omnia_cmd_write_u8(client, CMD_LED_MODE, 124 + CMD_LED_MODE_LED(led->reg) | 125 + CMD_LED_MODE_USER); 126 + if (ret) { 303 127 dev_err(dev, "Cannot set LED %pOF to software mode: %i\n", np, 304 128 ret); 305 129 return ret; 306 130 } 307 131 308 132 /* disable the LED */ 309 - ret = i2c_smbus_write_byte_data(client, CMD_LED_STATE, 310 - CMD_LED_STATE_LED(led->reg)); 311 - if (ret < 0) { 133 + ret = omnia_cmd_write_u8(client, CMD_LED_STATE, 134 + CMD_LED_STATE_LED(led->reg)); 135 + if (ret) { 312 136 dev_err(dev, "Cannot set LED %pOF brightness: %i\n", np, ret); 137 + return ret; 138 + } 139 + 140 + /* Set initial color and cache it */ 141 + ret = omnia_led_send_color_cmd(client, led); 142 + if (ret < 0) { 143 + dev_err(dev, "Cannot set LED %pOF initial color: %i\n", np, 144 + ret); 313 145 return ret; 314 146 } 315 147 ··· 354 158 struct i2c_client *client = to_i2c_client(dev); 355 159 int ret; 356 160 357 - ret = i2c_smbus_read_byte_data(client, CMD_LED_GET_BRIGHTNESS); 161 + ret = omnia_cmd_read_u8(client, CMD_LED_GET_BRIGHTNESS); 358 162 359 163 if (ret < 0) 360 164 return ret; ··· 367 171 { 368 172 struct i2c_client *client = to_i2c_client(dev); 369 173 unsigned long brightness; 370 - int ret; 174 + int err; 371 175 372 176 if (kstrtoul(buf, 10, &brightness)) 373 177 return -EINVAL; ··· 375 179 if (brightness > 100) 376 180 return -EINVAL; 377 181 378 - ret = i2c_smbus_write_byte_data(client, CMD_LED_SET_BRIGHTNESS, 379 - (u8)brightness); 182 + err = omnia_cmd_write_u8(client, CMD_LED_SET_BRIGHTNESS, brightness); 380 183 381 - return ret < 0 ? ret : count; 184 + return err ?: count; 382 185 } 383 186 static DEVICE_ATTR_RW(brightness); 384 187 188 + static ssize_t gamma_correction_show(struct device *dev, 189 + struct device_attribute *a, char *buf) 190 + { 191 + struct i2c_client *client = to_i2c_client(dev); 192 + struct omnia_leds *leds = i2c_get_clientdata(client); 193 + int ret; 194 + 195 + if (leds->has_gamma_correction) { 196 + ret = omnia_cmd_read_u8(client, CMD_GET_GAMMA_CORRECTION); 197 + if (ret < 0) 198 + return ret; 199 + } else { 200 + ret = 0; 201 + } 202 + 203 + return sysfs_emit(buf, "%d\n", !!ret); 204 + } 205 + 206 + static ssize_t gamma_correction_store(struct device *dev, 207 + struct device_attribute *a, 208 + const char *buf, size_t count) 209 + { 210 + struct i2c_client *client = to_i2c_client(dev); 211 + struct omnia_leds *leds = i2c_get_clientdata(client); 212 + bool val; 213 + int err; 214 + 215 + if (!leds->has_gamma_correction) 216 + return -EOPNOTSUPP; 217 + 218 + if (kstrtobool(buf, &val) < 0) 219 + return -EINVAL; 220 + 221 + err = omnia_cmd_write_u8(client, CMD_SET_GAMMA_CORRECTION, val); 222 + 223 + return err ?: count; 224 + } 225 + static DEVICE_ATTR_RW(gamma_correction); 226 + 385 227 static struct attribute *omnia_led_controller_attrs[] = { 386 228 &dev_attr_brightness.attr, 229 + &dev_attr_gamma_correction.attr, 387 230 NULL, 388 231 }; 389 232 ATTRIBUTE_GROUPS(omnia_led_controller); 233 + 234 + static int omnia_mcu_get_features(const struct i2c_client *client) 235 + { 236 + u16 reply; 237 + int err; 238 + 239 + err = omnia_cmd_read_raw(client->adapter, OMNIA_MCU_I2C_ADDR, 240 + CMD_GET_STATUS_WORD, &reply, sizeof(reply)); 241 + if (err) 242 + return err; 243 + 244 + /* Check whether MCU firmware supports the CMD_GET_FEAUTRES command */ 245 + if (!(le16_to_cpu(reply) & STS_FEATURES_SUPPORTED)) 246 + return 0; 247 + 248 + err = omnia_cmd_read_raw(client->adapter, OMNIA_MCU_I2C_ADDR, 249 + CMD_GET_FEATURES, &reply, sizeof(reply)); 250 + if (err) 251 + return err; 252 + 253 + return le16_to_cpu(reply); 254 + } 390 255 391 256 static int omnia_leds_probe(struct i2c_client *client) 392 257 { ··· 473 216 leds->client = client; 474 217 i2c_set_clientdata(client, leds); 475 218 219 + ret = omnia_mcu_get_features(client); 220 + if (ret < 0) { 221 + dev_err(dev, "Cannot determine MCU supported features: %d\n", 222 + ret); 223 + return ret; 224 + } 225 + 226 + leds->has_gamma_correction = ret & FEAT_LED_GAMMA_CORRECTION; 227 + if (!leds->has_gamma_correction) { 228 + dev_info(dev, 229 + "Your board's MCU firmware does not support the LED gamma correction feature.\n"); 230 + dev_info(dev, 231 + "Consider upgrading MCU firmware with the omnia-mcutool utility.\n"); 232 + } 233 + 476 234 mutex_init(&leds->lock); 235 + 236 + ret = devm_led_trigger_register(dev, &omnia_hw_trigger); 237 + if (ret < 0) { 238 + dev_err(dev, "Cannot register private LED trigger: %d\n", ret); 239 + return ret; 240 + } 477 241 478 242 led = &leds->leds[0]; 479 243 for_each_available_child_of_node(np, child) { ··· 515 237 u8 buf[5]; 516 238 517 239 /* put all LEDs into default (HW triggered) mode */ 518 - i2c_smbus_write_byte_data(client, CMD_LED_MODE, 519 - CMD_LED_MODE_LED(OMNIA_BOARD_LEDS)); 240 + omnia_cmd_write_u8(client, CMD_LED_MODE, 241 + CMD_LED_MODE_LED(OMNIA_BOARD_LEDS)); 520 242 521 243 /* set all LEDs color to [255, 255, 255] */ 522 244 buf[0] = CMD_LED_COLOR;
+2 -4
drivers/leds/leds-wm831x-status.c
··· 280 280 return 0; 281 281 } 282 282 283 - static int wm831x_status_remove(struct platform_device *pdev) 283 + static void wm831x_status_remove(struct platform_device *pdev) 284 284 { 285 285 struct wm831x_status *drvdata = platform_get_drvdata(pdev); 286 286 287 287 led_classdev_unregister(&drvdata->cdev); 288 - 289 - return 0; 290 288 } 291 289 292 290 static struct platform_driver wm831x_status_driver = { ··· 292 294 .name = "wm831x-status", 293 295 }, 294 296 .probe = wm831x_status_probe, 295 - .remove = wm831x_status_remove, 297 + .remove_new = wm831x_status_remove, 296 298 }; 297 299 298 300 module_platform_driver(wm831x_status_driver);
+2 -3
drivers/leds/leds-wm8350.c
··· 242 242 return led_classdev_register(&pdev->dev, &led->cdev); 243 243 } 244 244 245 - static int wm8350_led_remove(struct platform_device *pdev) 245 + static void wm8350_led_remove(struct platform_device *pdev) 246 246 { 247 247 struct wm8350_led *led = platform_get_drvdata(pdev); 248 248 249 249 led_classdev_unregister(&led->cdev); 250 250 wm8350_led_disable(led); 251 - return 0; 252 251 } 253 252 254 253 static struct platform_driver wm8350_led_driver = { ··· 255 256 .name = "wm8350-led", 256 257 }, 257 258 .probe = wm8350_led_probe, 258 - .remove = wm8350_led_remove, 259 + .remove_new = wm8350_led_remove, 259 260 .shutdown = wm8350_led_shutdown, 260 261 }; 261 262
+13
drivers/leds/rgb/Kconfig
··· 14 14 To compile this driver as a module, choose M here: the module 15 15 will be called leds-group-multicolor. 16 16 17 + config LEDS_KTD202X 18 + tristate "LED support for KTD202x Chips" 19 + depends on I2C 20 + depends on OF 21 + select REGMAP_I2C 22 + help 23 + This option enables support for the Kinetic KTD2026/KTD2027 24 + RGB/White LED driver found in different BQ mobile phones. 25 + It is a 3 or 4 channel LED driver programmed via an I2C interface. 26 + 27 + To compile this driver as a module, choose M here: the module 28 + will be called leds-ktd202x. 29 + 17 30 config LEDS_PWM_MULTICOLOR 18 31 tristate "PWM driven multi-color LED Support" 19 32 depends on PWM
+1
drivers/leds/rgb/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0 2 2 3 3 obj-$(CONFIG_LEDS_GROUP_MULTICOLOR) += leds-group-multicolor.o 4 + obj-$(CONFIG_LEDS_KTD202X) += leds-ktd202x.o 4 5 obj-$(CONFIG_LEDS_PWM_MULTICOLOR) += leds-pwm-multicolor.o 5 6 obj-$(CONFIG_LEDS_QCOM_LPG) += leds-qcom-lpg.o 6 7 obj-$(CONFIG_LEDS_MT6370_RGB) += leds-mt6370-rgb.o
+625
drivers/leds/rgb/leds-ktd202x.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * Kinetic KTD2026/7 RGB/White LED driver with I2C interface 4 + * 5 + * Copyright 2023 André Apitzsch <git@apitzsch.eu> 6 + * 7 + * Datasheet: https://www.kinet-ic.com/uploads/KTD2026-7-04h.pdf 8 + */ 9 + 10 + #include <linux/i2c.h> 11 + #include <linux/led-class-multicolor.h> 12 + #include <linux/module.h> 13 + #include <linux/mutex.h> 14 + #include <linux/of.h> 15 + #include <linux/of_device.h> 16 + #include <linux/regmap.h> 17 + #include <linux/regulator/consumer.h> 18 + 19 + #define KTD2026_NUM_LEDS 3 20 + #define KTD2027_NUM_LEDS 4 21 + #define KTD202X_MAX_LEDS 4 22 + 23 + /* Register bank */ 24 + #define KTD202X_REG_RESET_CONTROL 0x00 25 + #define KTD202X_REG_FLASH_PERIOD 0x01 26 + #define KTD202X_REG_PWM1_TIMER 0x02 27 + #define KTD202X_REG_PWM2_TIMER 0x03 28 + #define KTD202X_REG_CHANNEL_CTRL 0x04 29 + #define KTD202X_REG_TRISE_FALL 0x05 30 + #define KTD202X_REG_LED_IOUT(x) (0x06 + (x)) 31 + 32 + /* Register 0 */ 33 + #define KTD202X_TIMER_SLOT_CONTROL_TSLOT1 0x00 34 + #define KTD202X_TIMER_SLOT_CONTROL_TSLOT2 0x01 35 + #define KTD202X_TIMER_SLOT_CONTROL_TSLOT3 0x02 36 + #define KTD202X_TIMER_SLOT_CONTROL_TSLOT4 0x03 37 + #define KTD202X_RSTR_RESET 0x07 38 + 39 + #define KTD202X_ENABLE_CTRL_WAKE 0x00 /* SCL High & SDA High */ 40 + #define KTD202X_ENABLE_CTRL_SLEEP 0x08 /* SCL High & SDA Toggling */ 41 + 42 + #define KTD202X_TRISE_FALL_SCALE_NORMAL 0x00 43 + #define KTD202X_TRISE_FALL_SCALE_SLOW_X2 0x20 44 + #define KTD202X_TRISE_FALL_SCALE_SLOW_X4 0x40 45 + #define KTD202X_TRISE_FALL_SCALE_FAST_X8 0x60 46 + 47 + /* Register 1 */ 48 + #define KTD202X_FLASH_PERIOD_256_MS_LOG_RAMP 0x00 49 + 50 + /* Register 2-3 */ 51 + #define KTD202X_FLASH_ON_TIME_0_4_PERCENT 0x01 52 + 53 + /* Register 4 */ 54 + #define KTD202X_CHANNEL_CTRL_MASK(x) (BIT(2 * (x)) | BIT(2 * (x) + 1)) 55 + #define KTD202X_CHANNEL_CTRL_OFF 0x00 56 + #define KTD202X_CHANNEL_CTRL_ON(x) BIT(2 * (x)) 57 + #define KTD202X_CHANNEL_CTRL_PWM1(x) BIT(2 * (x) + 1) 58 + #define KTD202X_CHANNEL_CTRL_PWM2(x) (BIT(2 * (x)) | BIT(2 * (x) + 1)) 59 + 60 + /* Register 5 */ 61 + #define KTD202X_RAMP_TIMES_2_MS 0x00 62 + 63 + /* Register 6-9 */ 64 + #define KTD202X_LED_CURRENT_10_mA 0x4f 65 + 66 + #define KTD202X_FLASH_PERIOD_MIN_MS 256 67 + #define KTD202X_FLASH_PERIOD_STEP_MS 128 68 + #define KTD202X_FLASH_PERIOD_MAX_STEPS 126 69 + #define KTD202X_FLASH_ON_MAX 256 70 + 71 + #define KTD202X_MAX_BRIGHTNESS 192 72 + 73 + static const struct reg_default ktd202x_reg_defaults[] = { 74 + { KTD202X_REG_RESET_CONTROL, KTD202X_TIMER_SLOT_CONTROL_TSLOT1 | 75 + KTD202X_ENABLE_CTRL_WAKE | KTD202X_TRISE_FALL_SCALE_NORMAL }, 76 + { KTD202X_REG_FLASH_PERIOD, KTD202X_FLASH_PERIOD_256_MS_LOG_RAMP }, 77 + { KTD202X_REG_PWM1_TIMER, KTD202X_FLASH_ON_TIME_0_4_PERCENT }, 78 + { KTD202X_REG_PWM2_TIMER, KTD202X_FLASH_ON_TIME_0_4_PERCENT }, 79 + { KTD202X_REG_CHANNEL_CTRL, KTD202X_CHANNEL_CTRL_OFF }, 80 + { KTD202X_REG_TRISE_FALL, KTD202X_RAMP_TIMES_2_MS }, 81 + { KTD202X_REG_LED_IOUT(0), KTD202X_LED_CURRENT_10_mA }, 82 + { KTD202X_REG_LED_IOUT(1), KTD202X_LED_CURRENT_10_mA }, 83 + { KTD202X_REG_LED_IOUT(2), KTD202X_LED_CURRENT_10_mA }, 84 + { KTD202X_REG_LED_IOUT(3), KTD202X_LED_CURRENT_10_mA }, 85 + }; 86 + 87 + struct ktd202x_led { 88 + struct ktd202x *chip; 89 + union { 90 + struct led_classdev cdev; 91 + struct led_classdev_mc mcdev; 92 + }; 93 + u32 index; 94 + }; 95 + 96 + struct ktd202x { 97 + struct mutex mutex; 98 + struct regulator_bulk_data regulators[2]; 99 + struct device *dev; 100 + struct regmap *regmap; 101 + bool enabled; 102 + int num_leds; 103 + struct ktd202x_led leds[] __counted_by(num_leds); 104 + }; 105 + 106 + static int ktd202x_chip_disable(struct ktd202x *chip) 107 + { 108 + int ret; 109 + 110 + if (!chip->enabled) 111 + return 0; 112 + 113 + regmap_write(chip->regmap, KTD202X_REG_RESET_CONTROL, KTD202X_ENABLE_CTRL_SLEEP); 114 + 115 + ret = regulator_bulk_disable(ARRAY_SIZE(chip->regulators), chip->regulators); 116 + if (ret) { 117 + dev_err(chip->dev, "Failed to disable regulators: %d\n", ret); 118 + return ret; 119 + } 120 + 121 + chip->enabled = false; 122 + return 0; 123 + } 124 + 125 + static int ktd202x_chip_enable(struct ktd202x *chip) 126 + { 127 + int ret; 128 + 129 + if (chip->enabled) 130 + return 0; 131 + 132 + ret = regulator_bulk_enable(ARRAY_SIZE(chip->regulators), chip->regulators); 133 + if (ret) { 134 + dev_err(chip->dev, "Failed to enable regulators: %d\n", ret); 135 + return ret; 136 + } 137 + chip->enabled = true; 138 + 139 + ret = regmap_write(chip->regmap, KTD202X_REG_RESET_CONTROL, KTD202X_ENABLE_CTRL_WAKE); 140 + 141 + if (ret) { 142 + dev_err(chip->dev, "Failed to enable the chip: %d\n", ret); 143 + ktd202x_chip_disable(chip); 144 + } 145 + 146 + return ret; 147 + } 148 + 149 + static bool ktd202x_chip_in_use(struct ktd202x *chip) 150 + { 151 + int i; 152 + 153 + for (i = 0; i < chip->num_leds; i++) { 154 + if (chip->leds[i].cdev.brightness) 155 + return true; 156 + } 157 + 158 + return false; 159 + } 160 + 161 + static int ktd202x_brightness_set(struct ktd202x_led *led, 162 + struct mc_subled *subleds, 163 + unsigned int num_channels) 164 + { 165 + bool mode_blink = false; 166 + int channel; 167 + int state; 168 + int ret; 169 + int i; 170 + 171 + if (ktd202x_chip_in_use(led->chip)) { 172 + ret = ktd202x_chip_enable(led->chip); 173 + if (ret) 174 + return ret; 175 + } 176 + 177 + ret = regmap_read(led->chip->regmap, KTD202X_REG_CHANNEL_CTRL, &state); 178 + if (ret) 179 + return ret; 180 + 181 + /* 182 + * In multicolor case, assume blink mode if PWM is set for at least one 183 + * channel because another channel cannot be in state ON at the same time 184 + */ 185 + for (i = 0; i < num_channels; i++) { 186 + int channel_state; 187 + 188 + channel = subleds[i].channel; 189 + channel_state = (state >> 2 * channel) & KTD202X_CHANNEL_CTRL_MASK(0); 190 + if (channel_state == KTD202X_CHANNEL_CTRL_OFF) 191 + continue; 192 + mode_blink = channel_state == KTD202X_CHANNEL_CTRL_PWM1(0); 193 + break; 194 + } 195 + 196 + for (i = 0; i < num_channels; i++) { 197 + enum led_brightness brightness; 198 + int mode; 199 + 200 + brightness = subleds[i].brightness; 201 + channel = subleds[i].channel; 202 + 203 + if (brightness) { 204 + /* Register expects brightness between 0 and MAX_BRIGHTNESS - 1 */ 205 + ret = regmap_write(led->chip->regmap, KTD202X_REG_LED_IOUT(channel), 206 + brightness - 1); 207 + if (ret) 208 + return ret; 209 + 210 + if (mode_blink) 211 + mode = KTD202X_CHANNEL_CTRL_PWM1(channel); 212 + else 213 + mode = KTD202X_CHANNEL_CTRL_ON(channel); 214 + } else { 215 + mode = KTD202X_CHANNEL_CTRL_OFF; 216 + } 217 + ret = regmap_update_bits(led->chip->regmap, KTD202X_REG_CHANNEL_CTRL, 218 + KTD202X_CHANNEL_CTRL_MASK(channel), mode); 219 + if (ret) 220 + return ret; 221 + } 222 + 223 + if (!ktd202x_chip_in_use(led->chip)) 224 + return ktd202x_chip_disable(led->chip); 225 + 226 + return 0; 227 + } 228 + 229 + static int ktd202x_brightness_single_set(struct led_classdev *cdev, 230 + enum led_brightness value) 231 + { 232 + struct ktd202x_led *led = container_of(cdev, struct ktd202x_led, cdev); 233 + struct mc_subled info; 234 + int ret; 235 + 236 + cdev->brightness = value; 237 + 238 + mutex_lock(&led->chip->mutex); 239 + 240 + info.brightness = value; 241 + info.channel = led->index; 242 + ret = ktd202x_brightness_set(led, &info, 1); 243 + 244 + mutex_unlock(&led->chip->mutex); 245 + 246 + return ret; 247 + } 248 + 249 + static int ktd202x_brightness_mc_set(struct led_classdev *cdev, 250 + enum led_brightness value) 251 + { 252 + struct led_classdev_mc *mc = lcdev_to_mccdev(cdev); 253 + struct ktd202x_led *led = container_of(mc, struct ktd202x_led, mcdev); 254 + int ret; 255 + 256 + cdev->brightness = value; 257 + 258 + mutex_lock(&led->chip->mutex); 259 + 260 + led_mc_calc_color_components(mc, value); 261 + ret = ktd202x_brightness_set(led, mc->subled_info, mc->num_colors); 262 + 263 + mutex_unlock(&led->chip->mutex); 264 + 265 + return ret; 266 + } 267 + 268 + static int ktd202x_blink_set(struct ktd202x_led *led, unsigned long *delay_on, 269 + unsigned long *delay_off, struct mc_subled *subleds, 270 + unsigned int num_channels) 271 + { 272 + unsigned long delay_total_ms; 273 + int ret, num_steps, on; 274 + u8 ctrl_mask = 0; 275 + u8 ctrl_pwm1 = 0; 276 + u8 ctrl_on = 0; 277 + int i; 278 + 279 + mutex_lock(&led->chip->mutex); 280 + 281 + for (i = 0; i < num_channels; i++) { 282 + int channel = subleds[i].channel; 283 + 284 + ctrl_mask |= KTD202X_CHANNEL_CTRL_MASK(channel); 285 + ctrl_on |= KTD202X_CHANNEL_CTRL_ON(channel); 286 + ctrl_pwm1 |= KTD202X_CHANNEL_CTRL_PWM1(channel); 287 + } 288 + 289 + /* Never off - brightness is already set, disable blinking */ 290 + if (!*delay_off) { 291 + ret = regmap_update_bits(led->chip->regmap, KTD202X_REG_CHANNEL_CTRL, 292 + ctrl_mask, ctrl_on); 293 + goto out; 294 + } 295 + 296 + /* Convert into values the HW will understand. */ 297 + 298 + /* Integer representation of time of flash period */ 299 + num_steps = (*delay_on + *delay_off - KTD202X_FLASH_PERIOD_MIN_MS) / 300 + KTD202X_FLASH_PERIOD_STEP_MS; 301 + num_steps = clamp(num_steps, 0, KTD202X_FLASH_PERIOD_MAX_STEPS); 302 + 303 + /* Integer representation of percentage of LED ON time */ 304 + on = (*delay_on * KTD202X_FLASH_ON_MAX) / (*delay_on + *delay_off); 305 + 306 + /* Actually used delay_{on,off} values */ 307 + delay_total_ms = num_steps * KTD202X_FLASH_PERIOD_STEP_MS + KTD202X_FLASH_PERIOD_MIN_MS; 308 + *delay_on = (delay_total_ms * on) / KTD202X_FLASH_ON_MAX; 309 + *delay_off = delay_total_ms - *delay_on; 310 + 311 + /* Set timings */ 312 + ret = regmap_write(led->chip->regmap, KTD202X_REG_FLASH_PERIOD, num_steps); 313 + if (ret) 314 + goto out; 315 + 316 + ret = regmap_write(led->chip->regmap, KTD202X_REG_PWM1_TIMER, on); 317 + if (ret) 318 + goto out; 319 + 320 + ret = regmap_update_bits(led->chip->regmap, KTD202X_REG_CHANNEL_CTRL, 321 + ctrl_mask, ctrl_pwm1); 322 + out: 323 + mutex_unlock(&led->chip->mutex); 324 + return ret; 325 + } 326 + 327 + static int ktd202x_blink_single_set(struct led_classdev *cdev, 328 + unsigned long *delay_on, 329 + unsigned long *delay_off) 330 + { 331 + struct ktd202x_led *led = container_of(cdev, struct ktd202x_led, cdev); 332 + struct mc_subled info; 333 + int ret; 334 + 335 + if (!cdev->brightness) { 336 + ret = ktd202x_brightness_single_set(cdev, KTD202X_MAX_BRIGHTNESS); 337 + if (ret) 338 + return ret; 339 + } 340 + 341 + /* If no blink specified, default to 1 Hz. */ 342 + if (!*delay_off && !*delay_on) { 343 + *delay_off = 500; 344 + *delay_on = 500; 345 + } 346 + 347 + /* Never on - just set to off */ 348 + if (!*delay_on) 349 + return ktd202x_brightness_single_set(cdev, LED_OFF); 350 + 351 + info.channel = led->index; 352 + 353 + return ktd202x_blink_set(led, delay_on, delay_off, &info, 1); 354 + } 355 + 356 + static int ktd202x_blink_mc_set(struct led_classdev *cdev, 357 + unsigned long *delay_on, 358 + unsigned long *delay_off) 359 + { 360 + struct led_classdev_mc *mc = lcdev_to_mccdev(cdev); 361 + struct ktd202x_led *led = container_of(mc, struct ktd202x_led, mcdev); 362 + int ret; 363 + 364 + if (!cdev->brightness) { 365 + ret = ktd202x_brightness_mc_set(cdev, KTD202X_MAX_BRIGHTNESS); 366 + if (ret) 367 + return ret; 368 + } 369 + 370 + /* If no blink specified, default to 1 Hz. */ 371 + if (!*delay_off && !*delay_on) { 372 + *delay_off = 500; 373 + *delay_on = 500; 374 + } 375 + 376 + /* Never on - just set to off */ 377 + if (!*delay_on) 378 + return ktd202x_brightness_mc_set(cdev, LED_OFF); 379 + 380 + return ktd202x_blink_set(led, delay_on, delay_off, mc->subled_info, 381 + mc->num_colors); 382 + } 383 + 384 + static int ktd202x_setup_led_rgb(struct ktd202x *chip, struct device_node *np, 385 + struct ktd202x_led *led, struct led_init_data *init_data) 386 + { 387 + struct led_classdev *cdev; 388 + struct device_node *child; 389 + struct mc_subled *info; 390 + int num_channels; 391 + int i = 0; 392 + 393 + num_channels = of_get_available_child_count(np); 394 + if (!num_channels || num_channels > chip->num_leds) 395 + return -EINVAL; 396 + 397 + info = devm_kcalloc(chip->dev, num_channels, sizeof(*info), GFP_KERNEL); 398 + if (!info) 399 + return -ENOMEM; 400 + 401 + for_each_available_child_of_node(np, child) { 402 + u32 mono_color; 403 + u32 reg; 404 + int ret; 405 + 406 + ret = of_property_read_u32(child, "reg", &reg); 407 + if (ret != 0 || reg >= chip->num_leds) { 408 + dev_err(chip->dev, "invalid 'reg' of %pOFn\n", child); 409 + of_node_put(child); 410 + return -EINVAL; 411 + } 412 + 413 + ret = of_property_read_u32(child, "color", &mono_color); 414 + if (ret < 0 && ret != -EINVAL) { 415 + dev_err(chip->dev, "failed to parse 'color' of %pOF\n", child); 416 + of_node_put(child); 417 + return ret; 418 + } 419 + 420 + info[i].color_index = mono_color; 421 + info[i].channel = reg; 422 + info[i].intensity = KTD202X_MAX_BRIGHTNESS; 423 + i++; 424 + } 425 + 426 + led->mcdev.subled_info = info; 427 + led->mcdev.num_colors = num_channels; 428 + 429 + cdev = &led->mcdev.led_cdev; 430 + cdev->brightness_set_blocking = ktd202x_brightness_mc_set; 431 + cdev->blink_set = ktd202x_blink_mc_set; 432 + 433 + return devm_led_classdev_multicolor_register_ext(chip->dev, &led->mcdev, init_data); 434 + } 435 + 436 + static int ktd202x_setup_led_single(struct ktd202x *chip, struct device_node *np, 437 + struct ktd202x_led *led, struct led_init_data *init_data) 438 + { 439 + struct led_classdev *cdev; 440 + u32 reg; 441 + int ret; 442 + 443 + ret = of_property_read_u32(np, "reg", &reg); 444 + if (ret != 0 || reg >= chip->num_leds) { 445 + dev_err(chip->dev, "invalid 'reg' of %pOFn\n", np); 446 + return -EINVAL; 447 + } 448 + led->index = reg; 449 + 450 + cdev = &led->cdev; 451 + cdev->brightness_set_blocking = ktd202x_brightness_single_set; 452 + cdev->blink_set = ktd202x_blink_single_set; 453 + 454 + return devm_led_classdev_register_ext(chip->dev, &led->cdev, init_data); 455 + } 456 + 457 + static int ktd202x_add_led(struct ktd202x *chip, struct device_node *np, unsigned int index) 458 + { 459 + struct ktd202x_led *led = &chip->leds[index]; 460 + struct led_init_data init_data = {}; 461 + struct led_classdev *cdev; 462 + u32 color; 463 + int ret; 464 + 465 + /* Color property is optional in single color case */ 466 + ret = of_property_read_u32(np, "color", &color); 467 + if (ret < 0 && ret != -EINVAL) { 468 + dev_err(chip->dev, "failed to parse 'color' of %pOF\n", np); 469 + return ret; 470 + } 471 + 472 + led->chip = chip; 473 + init_data.fwnode = of_fwnode_handle(np); 474 + 475 + if (color == LED_COLOR_ID_RGB) { 476 + cdev = &led->mcdev.led_cdev; 477 + ret = ktd202x_setup_led_rgb(chip, np, led, &init_data); 478 + } else { 479 + cdev = &led->cdev; 480 + ret = ktd202x_setup_led_single(chip, np, led, &init_data); 481 + } 482 + 483 + if (ret) { 484 + dev_err(chip->dev, "unable to register %s\n", cdev->name); 485 + return ret; 486 + } 487 + 488 + cdev->max_brightness = KTD202X_MAX_BRIGHTNESS; 489 + 490 + return 0; 491 + } 492 + 493 + static int ktd202x_probe_dt(struct ktd202x *chip) 494 + { 495 + struct device_node *np = dev_of_node(chip->dev), *child; 496 + int count; 497 + int i = 0; 498 + 499 + chip->num_leds = (int)(unsigned long)of_device_get_match_data(chip->dev); 500 + 501 + count = of_get_available_child_count(np); 502 + if (!count || count > chip->num_leds) 503 + return -EINVAL; 504 + 505 + regmap_write(chip->regmap, KTD202X_REG_RESET_CONTROL, KTD202X_RSTR_RESET); 506 + 507 + /* Allow the device to execute the complete reset */ 508 + usleep_range(200, 300); 509 + 510 + for_each_available_child_of_node(np, child) { 511 + int ret = ktd202x_add_led(chip, child, i); 512 + 513 + if (ret) { 514 + of_node_put(child); 515 + return ret; 516 + } 517 + i++; 518 + } 519 + 520 + return 0; 521 + } 522 + 523 + static const struct regmap_config ktd202x_regmap_config = { 524 + .reg_bits = 8, 525 + .val_bits = 8, 526 + .max_register = 0x09, 527 + .cache_type = REGCACHE_FLAT, 528 + .reg_defaults = ktd202x_reg_defaults, 529 + .num_reg_defaults = ARRAY_SIZE(ktd202x_reg_defaults), 530 + }; 531 + 532 + static int ktd202x_probe(struct i2c_client *client) 533 + { 534 + struct device *dev = &client->dev; 535 + struct ktd202x *chip; 536 + int count; 537 + int ret; 538 + 539 + count = device_get_child_node_count(dev); 540 + if (!count || count > KTD202X_MAX_LEDS) 541 + return dev_err_probe(dev, -EINVAL, "Incorrect number of leds (%d)", count); 542 + 543 + chip = devm_kzalloc(dev, struct_size(chip, leds, count), GFP_KERNEL); 544 + if (!chip) 545 + return -ENOMEM; 546 + 547 + chip->dev = dev; 548 + i2c_set_clientdata(client, chip); 549 + 550 + chip->regmap = devm_regmap_init_i2c(client, &ktd202x_regmap_config); 551 + if (IS_ERR(chip->regmap)) { 552 + ret = dev_err_probe(dev, PTR_ERR(chip->regmap), 553 + "Failed to allocate register map.\n"); 554 + return ret; 555 + } 556 + 557 + chip->regulators[0].supply = "vin"; 558 + chip->regulators[1].supply = "vio"; 559 + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(chip->regulators), chip->regulators); 560 + if (ret < 0) { 561 + dev_err_probe(dev, ret, "Failed to request regulators.\n"); 562 + return ret; 563 + } 564 + 565 + ret = regulator_bulk_enable(ARRAY_SIZE(chip->regulators), chip->regulators); 566 + if (ret) { 567 + dev_err_probe(dev, ret, "Failed to enable regulators.\n"); 568 + return ret; 569 + } 570 + 571 + ret = ktd202x_probe_dt(chip); 572 + if (ret < 0) { 573 + regulator_bulk_disable(ARRAY_SIZE(chip->regulators), chip->regulators); 574 + return ret; 575 + } 576 + 577 + ret = regulator_bulk_disable(ARRAY_SIZE(chip->regulators), chip->regulators); 578 + if (ret) { 579 + dev_err_probe(dev, ret, "Failed to disable regulators.\n"); 580 + return ret; 581 + } 582 + 583 + mutex_init(&chip->mutex); 584 + 585 + return 0; 586 + } 587 + 588 + static void ktd202x_remove(struct i2c_client *client) 589 + { 590 + struct ktd202x *chip = i2c_get_clientdata(client); 591 + 592 + ktd202x_chip_disable(chip); 593 + 594 + mutex_destroy(&chip->mutex); 595 + } 596 + 597 + static void ktd202x_shutdown(struct i2c_client *client) 598 + { 599 + struct ktd202x *chip = i2c_get_clientdata(client); 600 + 601 + /* Reset registers to make sure all LEDs are off before shutdown */ 602 + regmap_write(chip->regmap, KTD202X_REG_RESET_CONTROL, KTD202X_RSTR_RESET); 603 + } 604 + 605 + static const struct of_device_id ktd202x_match_table[] = { 606 + { .compatible = "kinetic,ktd2026", .data = (void *)KTD2026_NUM_LEDS }, 607 + { .compatible = "kinetic,ktd2027", .data = (void *)KTD2027_NUM_LEDS }, 608 + {}, 609 + }; 610 + MODULE_DEVICE_TABLE(of, ktd202x_match_table); 611 + 612 + static struct i2c_driver ktd202x_driver = { 613 + .driver = { 614 + .name = "leds-ktd202x", 615 + .of_match_table = ktd202x_match_table, 616 + }, 617 + .probe = ktd202x_probe, 618 + .remove = ktd202x_remove, 619 + .shutdown = ktd202x_shutdown, 620 + }; 621 + module_i2c_driver(ktd202x_driver); 622 + 623 + MODULE_AUTHOR("André Apitzsch <git@apitzsch.eu>"); 624 + MODULE_DESCRIPTION("Kinetic KTD2026/7 LED driver"); 625 + MODULE_LICENSE("GPL");
+1 -1
drivers/leds/rgb/leds-mt6370-rgb.c
··· 153 153 const struct mt6370_pdata *pdata; 154 154 unsigned int leds_count; 155 155 unsigned int leds_active; 156 - struct mt6370_led leds[]; 156 + struct mt6370_led leds[] __counted_by(leds_count); 157 157 }; 158 158 159 159 static const struct reg_field common_reg_fields[F_MAX_FIELDS] = {
+3 -5
drivers/leds/rgb/leds-qcom-lpg.c
··· 173 173 struct led_classdev_mc mcdev; 174 174 175 175 unsigned int num_channels; 176 - struct lpg_channel *channels[]; 176 + struct lpg_channel *channels[] __counted_by(num_channels); 177 177 }; 178 178 179 179 /** ··· 1364 1364 return lpg_add_pwm(lpg); 1365 1365 } 1366 1366 1367 - static int lpg_remove(struct platform_device *pdev) 1367 + static void lpg_remove(struct platform_device *pdev) 1368 1368 { 1369 1369 struct lpg *lpg = platform_get_drvdata(pdev); 1370 1370 1371 1371 pwmchip_remove(&lpg->pwm); 1372 - 1373 - return 0; 1374 1372 } 1375 1373 1376 1374 static const struct lpg_data pm8916_pwm_data = { ··· 1530 1532 1531 1533 static struct platform_driver lpg_driver = { 1532 1534 .probe = lpg_probe, 1533 - .remove = lpg_remove, 1535 + .remove_new = lpg_remove, 1534 1536 .driver = { 1535 1537 .name = "qcom-spmi-lpg", 1536 1538 .of_match_table = lpg_of_table,
+4 -4
drivers/leds/simple/simatic-ipc-leds-gpio-apollolake.c
··· 45 45 &simatic_ipc_led_gpio_table_extra); 46 46 } 47 47 48 - static int simatic_ipc_leds_gpio_apollolake_remove(struct platform_device *pdev) 48 + static void simatic_ipc_leds_gpio_apollolake_remove(struct platform_device *pdev) 49 49 { 50 - return simatic_ipc_leds_gpio_remove(pdev, &simatic_ipc_led_gpio_table, 51 - &simatic_ipc_led_gpio_table_extra); 50 + simatic_ipc_leds_gpio_remove(pdev, &simatic_ipc_led_gpio_table, 51 + &simatic_ipc_led_gpio_table_extra); 52 52 } 53 53 54 54 static struct platform_driver simatic_ipc_led_gpio_apollolake_driver = { 55 55 .probe = simatic_ipc_leds_gpio_apollolake_probe, 56 - .remove = simatic_ipc_leds_gpio_apollolake_remove, 56 + .remove_new = simatic_ipc_leds_gpio_apollolake_remove, 57 57 .driver = { 58 58 .name = KBUILD_MODNAME, 59 59 },
+1 -3
drivers/leds/simple/simatic-ipc-leds-gpio-core.c
··· 33 33 .leds = simatic_ipc_gpio_leds, 34 34 }; 35 35 36 - int simatic_ipc_leds_gpio_remove(struct platform_device *pdev, 36 + void simatic_ipc_leds_gpio_remove(struct platform_device *pdev, 37 37 struct gpiod_lookup_table *table, 38 38 struct gpiod_lookup_table *table_extra) 39 39 { 40 40 gpiod_remove_lookup_table(table); 41 41 gpiod_remove_lookup_table(table_extra); 42 42 platform_device_unregister(simatic_leds_pdev); 43 - 44 - return 0; 45 43 } 46 44 EXPORT_SYMBOL_GPL(simatic_ipc_leds_gpio_remove); 47 45
+3 -4
drivers/leds/simple/simatic-ipc-leds-gpio-elkhartlake.c
··· 36 36 NULL); 37 37 } 38 38 39 - static int simatic_ipc_leds_gpio_elkhartlake_remove(struct platform_device *pdev) 39 + static void simatic_ipc_leds_gpio_elkhartlake_remove(struct platform_device *pdev) 40 40 { 41 - return simatic_ipc_leds_gpio_remove(pdev, &simatic_ipc_led_gpio_table, 42 - NULL); 41 + simatic_ipc_leds_gpio_remove(pdev, &simatic_ipc_led_gpio_table, NULL); 43 42 } 44 43 45 44 static struct platform_driver simatic_ipc_led_gpio_elkhartlake_driver = { 46 45 .probe = simatic_ipc_leds_gpio_elkhartlake_probe, 47 - .remove = simatic_ipc_leds_gpio_elkhartlake_remove, 46 + .remove_new = simatic_ipc_leds_gpio_elkhartlake_remove, 48 47 .driver = { 49 48 .name = KBUILD_MODNAME, 50 49 },
+4 -4
drivers/leds/simple/simatic-ipc-leds-gpio-f7188x.c
··· 45 45 &simatic_ipc_led_gpio_table_extra); 46 46 } 47 47 48 - static int simatic_ipc_leds_gpio_f7188x_remove(struct platform_device *pdev) 48 + static void simatic_ipc_leds_gpio_f7188x_remove(struct platform_device *pdev) 49 49 { 50 - return simatic_ipc_leds_gpio_remove(pdev, &simatic_ipc_led_gpio_table, 51 - &simatic_ipc_led_gpio_table_extra); 50 + simatic_ipc_leds_gpio_remove(pdev, &simatic_ipc_led_gpio_table, 51 + &simatic_ipc_led_gpio_table_extra); 52 52 } 53 53 54 54 static struct platform_driver simatic_ipc_led_gpio_driver = { 55 55 .probe = simatic_ipc_leds_gpio_f7188x_probe, 56 - .remove = simatic_ipc_leds_gpio_f7188x_remove, 56 + .remove_new = simatic_ipc_leds_gpio_f7188x_remove, 57 57 .driver = { 58 58 .name = KBUILD_MODNAME, 59 59 },
+3 -3
drivers/leds/simple/simatic-ipc-leds-gpio.h
··· 15 15 struct gpiod_lookup_table *table, 16 16 struct gpiod_lookup_table *table_extra); 17 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); 18 + void simatic_ipc_leds_gpio_remove(struct platform_device *pdev, 19 + struct gpiod_lookup_table *table, 20 + struct gpiod_lookup_table *table_extra); 21 21 22 22 #endif /* _SIMATIC_IPC_LEDS_GPIO_H */
+1 -4
drivers/leds/trigger/Kconfig
··· 83 83 config LEDS_TRIGGER_GPIO 84 84 tristate "LED GPIO Trigger" 85 85 depends on GPIOLIB || COMPILE_TEST 86 - depends on BROKEN 87 86 help 88 87 This allows LEDs to be controlled by gpio events. It's good 89 88 when using gpios as switches and triggering the needed LEDs 90 - from there. One use case is n810's keypad LEDs that could 91 - be triggered by this trigger when user slides up to show 92 - keypad. 89 + from there. Triggers are defined as device properties. 93 90 94 91 If unsure, say N. 95 92
+2 -2
drivers/leds/trigger/ledtrig-cpu.c
··· 130 130 131 131 static int __init ledtrig_cpu_init(void) 132 132 { 133 - int cpu; 133 + unsigned int cpu; 134 134 int ret; 135 135 136 136 /* Supports up to 9999 cpu cores */ ··· 152 152 if (cpu >= 8) 153 153 continue; 154 154 155 - snprintf(trig->name, MAX_NAME_LEN, "cpu%d", cpu); 155 + snprintf(trig->name, MAX_NAME_LEN, "cpu%u", cpu); 156 156 157 157 led_trigger_register_simple(trig->name, &trig->_trig); 158 158 }
+40 -97
drivers/leds/trigger/ledtrig-gpio.c
··· 3 3 * ledtrig-gio.c - LED Trigger Based on GPIO events 4 4 * 5 5 * Copyright 2009 Felipe Balbi <me@felipebalbi.com> 6 + * Copyright 2023 Linus Walleij <linus.walleij@linaro.org> 6 7 */ 7 8 8 9 #include <linux/module.h> 9 10 #include <linux/kernel.h> 10 11 #include <linux/init.h> 11 - #include <linux/gpio.h> 12 + #include <linux/gpio/consumer.h> 12 13 #include <linux/interrupt.h> 13 14 #include <linux/leds.h> 14 15 #include <linux/slab.h> ··· 17 16 18 17 struct gpio_trig_data { 19 18 struct led_classdev *led; 20 - 21 19 unsigned desired_brightness; /* desired brightness when led is on */ 22 - unsigned inverted; /* true when gpio is inverted */ 23 - unsigned gpio; /* gpio that triggers the leds */ 20 + struct gpio_desc *gpiod; /* gpio that triggers the led */ 24 21 }; 25 22 26 23 static irqreturn_t gpio_trig_irq(int irq, void *_led) ··· 27 28 struct gpio_trig_data *gpio_data = led_get_trigger_data(led); 28 29 int tmp; 29 30 30 - tmp = gpio_get_value_cansleep(gpio_data->gpio); 31 - if (gpio_data->inverted) 32 - tmp = !tmp; 33 - 31 + tmp = gpiod_get_value_cansleep(gpio_data->gpiod); 34 32 if (tmp) { 35 33 if (gpio_data->desired_brightness) 36 34 led_set_brightness_nosleep(gpio_data->led, ··· 69 73 static DEVICE_ATTR(desired_brightness, 0644, gpio_trig_brightness_show, 70 74 gpio_trig_brightness_store); 71 75 72 - static ssize_t gpio_trig_inverted_show(struct device *dev, 73 - struct device_attribute *attr, char *buf) 74 - { 75 - struct gpio_trig_data *gpio_data = led_trigger_get_drvdata(dev); 76 - 77 - return sprintf(buf, "%u\n", gpio_data->inverted); 78 - } 79 - 80 - static ssize_t gpio_trig_inverted_store(struct device *dev, 81 - struct device_attribute *attr, const char *buf, size_t n) 82 - { 83 - struct led_classdev *led = led_trigger_get_led(dev); 84 - struct gpio_trig_data *gpio_data = led_trigger_get_drvdata(dev); 85 - unsigned long inverted; 86 - int ret; 87 - 88 - ret = kstrtoul(buf, 10, &inverted); 89 - if (ret < 0) 90 - return ret; 91 - 92 - if (inverted > 1) 93 - return -EINVAL; 94 - 95 - gpio_data->inverted = inverted; 96 - 97 - /* After inverting, we need to update the LED. */ 98 - if (gpio_is_valid(gpio_data->gpio)) 99 - gpio_trig_irq(0, led); 100 - 101 - return n; 102 - } 103 - static DEVICE_ATTR(inverted, 0644, gpio_trig_inverted_show, 104 - gpio_trig_inverted_store); 105 - 106 - static ssize_t gpio_trig_gpio_show(struct device *dev, 107 - struct device_attribute *attr, char *buf) 108 - { 109 - struct gpio_trig_data *gpio_data = led_trigger_get_drvdata(dev); 110 - 111 - return sprintf(buf, "%u\n", gpio_data->gpio); 112 - } 113 - 114 - static ssize_t gpio_trig_gpio_store(struct device *dev, 115 - struct device_attribute *attr, const char *buf, size_t n) 116 - { 117 - struct led_classdev *led = led_trigger_get_led(dev); 118 - struct gpio_trig_data *gpio_data = led_trigger_get_drvdata(dev); 119 - unsigned gpio; 120 - int ret; 121 - 122 - ret = sscanf(buf, "%u", &gpio); 123 - if (ret < 1) { 124 - dev_err(dev, "couldn't read gpio number\n"); 125 - return -EINVAL; 126 - } 127 - 128 - if (gpio_data->gpio == gpio) 129 - return n; 130 - 131 - if (!gpio_is_valid(gpio)) { 132 - if (gpio_is_valid(gpio_data->gpio)) 133 - free_irq(gpio_to_irq(gpio_data->gpio), led); 134 - gpio_data->gpio = gpio; 135 - return n; 136 - } 137 - 138 - ret = request_threaded_irq(gpio_to_irq(gpio), NULL, gpio_trig_irq, 139 - IRQF_ONESHOT | IRQF_SHARED | IRQF_TRIGGER_RISING 140 - | IRQF_TRIGGER_FALLING, "ledtrig-gpio", led); 141 - if (ret) { 142 - dev_err(dev, "request_irq failed with error %d\n", ret); 143 - } else { 144 - if (gpio_is_valid(gpio_data->gpio)) 145 - free_irq(gpio_to_irq(gpio_data->gpio), led); 146 - gpio_data->gpio = gpio; 147 - /* After changing the GPIO, we need to update the LED. */ 148 - gpio_trig_irq(0, led); 149 - } 150 - 151 - return ret ? ret : n; 152 - } 153 - static DEVICE_ATTR(gpio, 0644, gpio_trig_gpio_show, gpio_trig_gpio_store); 154 - 155 76 static struct attribute *gpio_trig_attrs[] = { 156 77 &dev_attr_desired_brightness.attr, 157 - &dev_attr_inverted.attr, 158 - &dev_attr_gpio.attr, 159 78 NULL 160 79 }; 161 80 ATTRIBUTE_GROUPS(gpio_trig); ··· 78 167 static int gpio_trig_activate(struct led_classdev *led) 79 168 { 80 169 struct gpio_trig_data *gpio_data; 170 + struct device *dev = led->dev; 171 + int ret; 81 172 82 173 gpio_data = kzalloc(sizeof(*gpio_data), GFP_KERNEL); 83 174 if (!gpio_data) 84 175 return -ENOMEM; 85 176 86 - gpio_data->led = led; 87 - gpio_data->gpio = -ENOENT; 177 + /* 178 + * The generic property "trigger-sources" is followed, 179 + * and we hope that this is a GPIO. 180 + */ 181 + gpio_data->gpiod = fwnode_gpiod_get_index(dev->fwnode, 182 + "trigger-sources", 183 + 0, GPIOD_IN, 184 + "led-trigger"); 185 + if (IS_ERR(gpio_data->gpiod)) { 186 + ret = PTR_ERR(gpio_data->gpiod); 187 + kfree(gpio_data); 188 + return ret; 189 + } 190 + if (!gpio_data->gpiod) { 191 + dev_err(dev, "no valid GPIO for the trigger\n"); 192 + kfree(gpio_data); 193 + return -EINVAL; 194 + } 88 195 196 + gpio_data->led = led; 89 197 led_set_trigger_data(led, gpio_data); 198 + 199 + ret = request_threaded_irq(gpiod_to_irq(gpio_data->gpiod), NULL, gpio_trig_irq, 200 + IRQF_ONESHOT | IRQF_SHARED | IRQF_TRIGGER_RISING 201 + | IRQF_TRIGGER_FALLING, "ledtrig-gpio", led); 202 + if (ret) { 203 + dev_err(dev, "request_irq failed with error %d\n", ret); 204 + gpiod_put(gpio_data->gpiod); 205 + kfree(gpio_data); 206 + return ret; 207 + } 208 + 209 + /* Finally update the LED to initial status */ 210 + gpio_trig_irq(0, led); 90 211 91 212 return 0; 92 213 } ··· 127 184 { 128 185 struct gpio_trig_data *gpio_data = led_get_trigger_data(led); 129 186 130 - if (gpio_is_valid(gpio_data->gpio)) 131 - free_irq(gpio_to_irq(gpio_data->gpio), led); 187 + free_irq(gpiod_to_irq(gpio_data->gpiod), led); 188 + gpiod_put(gpio_data->gpiod); 132 189 kfree(gpio_data); 133 190 } 134 191
+3 -3
drivers/leds/trigger/ledtrig-netdev.c
··· 221 221 static int set_device_name(struct led_netdev_data *trigger_data, 222 222 const char *name, size_t size) 223 223 { 224 + if (size >= IFNAMSIZ) 225 + return -EINVAL; 226 + 224 227 cancel_delayed_work_sync(&trigger_data->work); 225 228 226 229 mutex_lock(&trigger_data->lock); ··· 265 262 { 266 263 struct led_netdev_data *trigger_data = led_trigger_get_drvdata(dev); 267 264 int ret; 268 - 269 - if (size >= IFNAMSIZ) 270 - return -EINVAL; 271 265 272 266 ret = set_device_name(trigger_data, buf, size); 273 267