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

Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/cooloney/linux-leds

Pull LED subsystem updates from Bryan Wu:
"In this cycle, we merged some fix and update for LED Flash class
driver. Then the core code of LED Flash class driver is in the kernel
now. Moreover, we also got some bug fixes, code cleanup and new
drivers for LED controllers"

* 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/cooloney/linux-leds:
leds: Don't treat the LED name as a format string
leds: Use log level warn instead of info when telling about a name clash
leds/led-class: Handle LEDs with the same name
leds: lp8860: Fix typo in MODULE_DESCRIPTION in leds-lp8860.c
leds: lp8501: Fix typo in MODULE_DESCRIPTION in leds-lp8501.c
DT: leds: Add uniqueness requirement for 'label' property.
dt-binding: leds: Add common LED DT bindings macros
leds: add Qualcomm PM8941 WLED driver
leds: add DT binding for Qualcomm PM8941 WLED block
leds: pca963x: Add missing initialiation of struct led_info.flags
leds: flash: Fix the size of sysfs_groups array
Documentation: leds: Add description of LED Flash class extension
leds: flash: document sysfs interface
leds: flash: Remove synchronized flash strobe feature
leds: Introduce devres helper for led_classdev_register
leds: lp8860: make use of devm_gpiod_get_optional
leds: Let the binding document example for leds-gpio follow the gpio bindings
leds: flash: remove stray include directive
leds: leds-pwm: drop one pwm_get_period() call

+735 -120
+80
Documentation/ABI/testing/sysfs-class-led-flash
··· 1 + What: /sys/class/leds/<led>/flash_brightness 2 + Date: March 2015 3 + KernelVersion: 4.0 4 + Contact: Jacek Anaszewski <j.anaszewski@samsung.com> 5 + Description: read/write 6 + Set the brightness of this LED in the flash strobe mode, in 7 + microamperes. The file is created only for the flash LED devices 8 + that support setting flash brightness. 9 + 10 + The value is between 0 and 11 + /sys/class/leds/<led>/max_flash_brightness. 12 + 13 + What: /sys/class/leds/<led>/max_flash_brightness 14 + Date: March 2015 15 + KernelVersion: 4.0 16 + Contact: Jacek Anaszewski <j.anaszewski@samsung.com> 17 + Description: read only 18 + Maximum brightness level for this LED in the flash strobe mode, 19 + in microamperes. 20 + 21 + What: /sys/class/leds/<led>/flash_timeout 22 + Date: March 2015 23 + KernelVersion: 4.0 24 + Contact: Jacek Anaszewski <j.anaszewski@samsung.com> 25 + Description: read/write 26 + Hardware timeout for flash, in microseconds. The flash strobe 27 + is stopped after this period of time has passed from the start 28 + of the strobe. The file is created only for the flash LED 29 + devices that support setting flash timeout. 30 + 31 + What: /sys/class/leds/<led>/max_flash_timeout 32 + Date: March 2015 33 + KernelVersion: 4.0 34 + Contact: Jacek Anaszewski <j.anaszewski@samsung.com> 35 + Description: read only 36 + Maximum flash timeout for this LED, in microseconds. 37 + 38 + What: /sys/class/leds/<led>/flash_strobe 39 + Date: March 2015 40 + KernelVersion: 4.0 41 + Contact: Jacek Anaszewski <j.anaszewski@samsung.com> 42 + Description: read/write 43 + Flash strobe state. When written with 1 it triggers flash strobe 44 + and when written with 0 it turns the flash off. 45 + 46 + On read 1 means that flash is currently strobing and 0 means 47 + that flash is off. 48 + 49 + What: /sys/class/leds/<led>/flash_fault 50 + Date: March 2015 51 + KernelVersion: 4.0 52 + Contact: Jacek Anaszewski <j.anaszewski@samsung.com> 53 + Description: read only 54 + Space separated list of flash faults that may have occurred. 55 + Flash faults are re-read after strobing the flash. Possible 56 + flash faults: 57 + 58 + * led-over-voltage - flash controller voltage to the flash LED 59 + has exceeded the limit specific to the flash controller 60 + * flash-timeout-exceeded - the flash strobe was still on when 61 + the timeout set by the user has expired; not all flash 62 + controllers may set this in all such conditions 63 + * controller-over-temperature - the flash controller has 64 + overheated 65 + * controller-short-circuit - the short circuit protection 66 + of the flash controller has been triggered 67 + * led-power-supply-over-current - current in the LED power 68 + supply has exceeded the limit specific to the flash 69 + controller 70 + * indicator-led-fault - the flash controller has detected 71 + a short or open circuit condition on the indicator LED 72 + * led-under-voltage - flash controller voltage to the flash 73 + LED has been below the minimum limit specific to 74 + the flash 75 + * controller-under-voltage - the input voltage of the flash 76 + controller is below the limit under which strobing the 77 + flash at full current will not be possible; 78 + the condition persists until this flag is no longer set 79 + * led-over-temperature - the temperature of the LED has exceeded 80 + its allowed upper limit
+4 -2
Documentation/devicetree/bindings/leds/common.txt
··· 14 14 - led-sources : List of device current outputs the LED is connected to. The 15 15 outputs are identified by the numbers that must be defined 16 16 in the LED device binding documentation. 17 - - label : The label for this LED. If omitted, the label is 18 - taken from the node name (excluding the unit address). 17 + - label : The label for this LED. If omitted, the label is taken from the node 18 + name (excluding the unit address). It has to uniquely identify 19 + a device, i.e. no other LED class device can be assigned the same 20 + label. 19 21 20 22 - linux,default-trigger : This parameter, if present, is a 21 23 string defining the trigger assigned to the LED. Current triggers are:
+7 -5
Documentation/devicetree/bindings/leds/leds-gpio.txt
··· 26 26 27 27 Examples: 28 28 29 + #include <dt-bindings/gpio/gpio.h> 30 + 29 31 leds { 30 32 compatible = "gpio-leds"; 31 33 hdd { 32 34 label = "IDE Activity"; 33 - gpios = <&mcu_pio 0 1>; /* Active low */ 35 + gpios = <&mcu_pio 0 GPIO_ACTIVE_LOW>; 34 36 linux,default-trigger = "ide-disk"; 35 37 }; 36 38 37 39 fault { 38 - gpios = <&mcu_pio 1 0>; 40 + gpios = <&mcu_pio 1 GPIO_ACTIVE_HIGH>; 39 41 /* Keep LED on if BIOS detected hardware fault */ 40 42 default-state = "keep"; 41 43 }; ··· 46 44 run-control { 47 45 compatible = "gpio-leds"; 48 46 red { 49 - gpios = <&mpc8572 6 0>; 47 + gpios = <&mpc8572 6 GPIO_ACTIVE_HIGH>; 50 48 default-state = "off"; 51 49 }; 52 50 green { 53 - gpios = <&mpc8572 7 0>; 51 + gpios = <&mpc8572 7 GPIO_ACTIVE_HIGH>; 54 52 default-state = "on"; 55 53 }; 56 54 }; ··· 59 57 compatible = "gpio-leds"; 60 58 61 59 charger-led { 62 - gpios = <&gpio1 2 0>; 60 + gpios = <&gpio1 2 GPIO_ACTIVE_HIGH>; 63 61 linux,default-trigger = "max8903-charger-charging"; 64 62 retain-state-suspended; 65 63 };
+43
Documentation/devicetree/bindings/leds/leds-pm8941-wled.txt
··· 1 + Binding for Qualcomm PM8941 WLED driver 2 + 3 + Required properties: 4 + - compatible: should be "qcom,pm8941-wled" 5 + - reg: slave address 6 + 7 + Optional properties: 8 + - label: The label for this led 9 + See Documentation/devicetree/bindings/leds/common.txt 10 + - linux,default-trigger: Default trigger assigned to the LED 11 + See Documentation/devicetree/bindings/leds/common.txt 12 + - qcom,cs-out: bool; enable current sink output 13 + - qcom,cabc: bool; enable content adaptive backlight control 14 + - qcom,ext-gen: bool; use externally generated modulator signal to dim 15 + - qcom,current-limit: mA; per-string current limit; value from 0 to 25 16 + default: 20mA 17 + - qcom,current-boost-limit: mA; boost current limit; one of: 18 + 105, 385, 525, 805, 980, 1260, 1400, 1680 19 + default: 805mA 20 + - qcom,switching-freq: kHz; switching frequency; one of: 21 + 600, 640, 685, 738, 800, 872, 960, 1066, 1200, 1371, 22 + 1600, 1920, 2400, 3200, 4800, 9600, 23 + default: 1600kHz 24 + - qcom,ovp: V; Over-voltage protection limit; one of: 25 + 27, 29, 32, 35 26 + default: 29V 27 + - qcom,num-strings: #; number of led strings attached; value from 1 to 3 28 + default: 2 29 + 30 + Example: 31 + 32 + pm8941-wled@d800 { 33 + compatible = "qcom,pm8941-wled"; 34 + reg = <0xd800>; 35 + label = "backlight"; 36 + 37 + qcom,cs-out; 38 + qcom,current-limit = <20>; 39 + qcom,current-boost-limit = <805>; 40 + qcom,switching-freq = <1600>; 41 + qcom,ovp = <29>; 42 + qcom,num-strings = <2>; 43 + };
+4
Documentation/driver-model/devres.txt
··· 289 289 devm_request_irq() 290 290 devm_request_threaded_irq() 291 291 292 + LED 293 + devm_led_classdev_register() 294 + devm_led_classdev_unregister() 295 + 292 296 MDIO 293 297 devm_mdiobus_alloc() 294 298 devm_mdiobus_alloc_size()
+22
Documentation/leds/leds-class-flash.txt
··· 1 + 2 + Flash LED handling under Linux 3 + ============================== 4 + 5 + Some LED devices provide two modes - torch and flash. In the LED subsystem 6 + those modes are supported by LED class (see Documentation/leds/leds-class.txt) 7 + and LED Flash class respectively. The torch mode related features are enabled 8 + by default and the flash ones only if a driver declares it by setting 9 + LED_DEV_CAP_FLASH flag. 10 + 11 + In order to enable the support for flash LEDs CONFIG_LEDS_CLASS_FLASH symbol 12 + must be defined in the kernel config. A LED Flash class driver must be 13 + registered in the LED subsystem with led_classdev_flash_register function. 14 + 15 + Following sysfs attributes are exposed for controlling flash LED devices: 16 + (see Documentation/ABI/testing/sysfs-class-led-flash) 17 + - flash_brightness 18 + - max_flash_brightness 19 + - flash_timeout 20 + - max_flash_timeout 21 + - flash_strobe 22 + - flash_fault
+8
drivers/leds/Kconfig
··· 526 526 This option enabled support for the LEDs on the ARM Versatile 527 527 and RealView boards. Say Y to enabled these. 528 528 529 + config LEDS_PM8941_WLED 530 + tristate "LED support for the Qualcomm PM8941 WLED block" 531 + depends on LEDS_CLASS 532 + select REGMAP 533 + help 534 + This option enables support for the 'White' LED block 535 + on Qualcomm PM8941 PMICs. 536 + 529 537 comment "LED Triggers" 530 538 source "drivers/leds/trigger/Kconfig" 531 539
+1
drivers/leds/Makefile
··· 58 58 obj-$(CONFIG_LEDS_SYSCON) += leds-syscon.o 59 59 obj-$(CONFIG_LEDS_VERSATILE) += leds-versatile.o 60 60 obj-$(CONFIG_LEDS_MENF21BMC) += leds-menf21bmc.o 61 + obj-$(CONFIG_LEDS_PM8941_WLED) += leds-pm8941-wled.o 61 62 62 63 # LED SPI Drivers 63 64 obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o
-82
drivers/leds/led-class-flash.c
··· 216 216 } 217 217 static DEVICE_ATTR_RO(flash_fault); 218 218 219 - static ssize_t available_sync_leds_show(struct device *dev, 220 - struct device_attribute *attr, char *buf) 221 - { 222 - struct led_classdev *led_cdev = dev_get_drvdata(dev); 223 - struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev); 224 - char *pbuf = buf; 225 - int i, buf_len; 226 - 227 - buf_len = sprintf(pbuf, "[0: none] "); 228 - pbuf += buf_len; 229 - 230 - for (i = 0; i < fled_cdev->num_sync_leds; ++i) { 231 - buf_len = sprintf(pbuf, "[%d: %s] ", i + 1, 232 - fled_cdev->sync_leds[i]->led_cdev.name); 233 - pbuf += buf_len; 234 - } 235 - 236 - return sprintf(buf, "%s\n", buf); 237 - } 238 - static DEVICE_ATTR_RO(available_sync_leds); 239 - 240 - static ssize_t flash_sync_strobe_store(struct device *dev, 241 - struct device_attribute *attr, const char *buf, size_t size) 242 - { 243 - struct led_classdev *led_cdev = dev_get_drvdata(dev); 244 - struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev); 245 - unsigned long led_id; 246 - ssize_t ret; 247 - 248 - mutex_lock(&led_cdev->led_access); 249 - 250 - if (led_sysfs_is_disabled(led_cdev)) { 251 - ret = -EBUSY; 252 - goto unlock; 253 - } 254 - 255 - ret = kstrtoul(buf, 10, &led_id); 256 - if (ret) 257 - goto unlock; 258 - 259 - if (led_id > fled_cdev->num_sync_leds) { 260 - ret = -ERANGE; 261 - goto unlock; 262 - } 263 - 264 - fled_cdev->sync_led_id = led_id; 265 - 266 - ret = size; 267 - unlock: 268 - mutex_unlock(&led_cdev->led_access); 269 - return ret; 270 - } 271 - 272 - static ssize_t flash_sync_strobe_show(struct device *dev, 273 - struct device_attribute *attr, char *buf) 274 - { 275 - struct led_classdev *led_cdev = dev_get_drvdata(dev); 276 - struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev); 277 - int sled_id = fled_cdev->sync_led_id; 278 - char *sync_led_name = "none"; 279 - 280 - if (fled_cdev->sync_led_id > 0) 281 - sync_led_name = (char *) 282 - fled_cdev->sync_leds[sled_id - 1]->led_cdev.name; 283 - 284 - return sprintf(buf, "[%d: %s]\n", sled_id, sync_led_name); 285 - } 286 - static DEVICE_ATTR_RW(flash_sync_strobe); 287 - 288 219 static struct attribute *led_flash_strobe_attrs[] = { 289 220 &dev_attr_flash_strobe.attr, 290 221 NULL, ··· 238 307 NULL, 239 308 }; 240 309 241 - static struct attribute *led_flash_sync_strobe_attrs[] = { 242 - &dev_attr_available_sync_leds.attr, 243 - &dev_attr_flash_sync_strobe.attr, 244 - NULL, 245 - }; 246 - 247 310 static const struct attribute_group led_flash_strobe_group = { 248 311 .attrs = led_flash_strobe_attrs, 249 312 }; ··· 252 327 253 328 static const struct attribute_group led_flash_fault_group = { 254 329 .attrs = led_flash_fault_attrs, 255 - }; 256 - 257 - static const struct attribute_group led_flash_sync_strobe_group = { 258 - .attrs = led_flash_sync_strobe_attrs, 259 330 }; 260 331 261 332 static void led_flash_resume(struct led_classdev *led_cdev) ··· 281 360 282 361 if (ops->fault_get) 283 362 flash_groups[num_sysfs_groups++] = &led_flash_fault_group; 284 - 285 - if (led_cdev->flags & LED_DEV_CAP_SYNC_STROBE) 286 - flash_groups[num_sysfs_groups++] = &led_flash_sync_strobe_group; 287 363 288 364 led_cdev->groups = flash_groups; 289 365 }
+94 -2
drivers/leds/led-class.c
··· 212 212 .resume = led_resume, 213 213 }; 214 214 215 + static int match_name(struct device *dev, const void *data) 216 + { 217 + if (!dev_name(dev)) 218 + return 0; 219 + return !strcmp(dev_name(dev), (char *)data); 220 + } 221 + 222 + static int led_classdev_next_name(const char *init_name, char *name, 223 + size_t len) 224 + { 225 + unsigned int i = 0; 226 + int ret = 0; 227 + 228 + strlcpy(name, init_name, len); 229 + 230 + while (class_find_device(leds_class, NULL, name, match_name) && 231 + (ret < len)) 232 + ret = snprintf(name, len, "%s_%u", init_name, ++i); 233 + 234 + if (ret >= len) 235 + return -ENOMEM; 236 + 237 + return i; 238 + } 239 + 215 240 /** 216 241 * led_classdev_register - register a new object of led_classdev class. 217 242 * @parent: The device to register. ··· 244 219 */ 245 220 int led_classdev_register(struct device *parent, struct led_classdev *led_cdev) 246 221 { 222 + char name[64]; 223 + int ret; 224 + 225 + ret = led_classdev_next_name(led_cdev->name, name, sizeof(name)); 226 + if (ret < 0) 227 + return ret; 228 + 247 229 led_cdev->dev = device_create_with_groups(leds_class, parent, 0, 248 - led_cdev, led_cdev->groups, 249 - "%s", led_cdev->name); 230 + led_cdev, led_cdev->groups, "%s", name); 250 231 if (IS_ERR(led_cdev->dev)) 251 232 return PTR_ERR(led_cdev->dev); 233 + 234 + if (ret) 235 + dev_warn(parent, "Led %s renamed to %s due to name collision", 236 + led_cdev->name, dev_name(led_cdev->dev)); 252 237 253 238 #ifdef CONFIG_LEDS_TRIGGERS 254 239 init_rwsem(&led_cdev->trigger_lock); ··· 322 287 mutex_destroy(&led_cdev->led_access); 323 288 } 324 289 EXPORT_SYMBOL_GPL(led_classdev_unregister); 290 + 291 + static void devm_led_classdev_release(struct device *dev, void *res) 292 + { 293 + led_classdev_unregister(*(struct led_classdev **)res); 294 + } 295 + 296 + /** 297 + * devm_led_classdev_register - resource managed led_classdev_register() 298 + * @parent: The device to register. 299 + * @led_cdev: the led_classdev structure for this device. 300 + */ 301 + int devm_led_classdev_register(struct device *parent, 302 + struct led_classdev *led_cdev) 303 + { 304 + struct led_classdev **dr; 305 + int rc; 306 + 307 + dr = devres_alloc(devm_led_classdev_release, sizeof(*dr), GFP_KERNEL); 308 + if (!dr) 309 + return -ENOMEM; 310 + 311 + rc = led_classdev_register(parent, led_cdev); 312 + if (rc) { 313 + devres_free(dr); 314 + return rc; 315 + } 316 + 317 + *dr = led_cdev; 318 + devres_add(parent, dr); 319 + 320 + return 0; 321 + } 322 + EXPORT_SYMBOL_GPL(devm_led_classdev_register); 323 + 324 + static int devm_led_classdev_match(struct device *dev, void *res, void *data) 325 + { 326 + struct led_cdev **p = res; 327 + 328 + if (WARN_ON(!p || !*p)) 329 + return 0; 330 + 331 + return *p == data; 332 + } 333 + 334 + /** 335 + * devm_led_classdev_unregister() - resource managed led_classdev_unregister() 336 + * @parent: The device to unregister. 337 + * @led_cdev: the led_classdev structure for this device. 338 + */ 339 + void devm_led_classdev_unregister(struct device *dev, 340 + struct led_classdev *led_cdev) 341 + { 342 + WARN_ON(devres_release(dev, 343 + devm_led_classdev_release, 344 + devm_led_classdev_match, led_cdev)); 345 + } 346 + EXPORT_SYMBOL_GPL(devm_led_classdev_unregister); 325 347 326 348 static int __init leds_init(void) 327 349 {
+1 -1
drivers/leds/leds-lp8501.c
··· 406 406 407 407 module_i2c_driver(lp8501_driver); 408 408 409 - MODULE_DESCRIPTION("Texas Instruments LP8501 LED drvier"); 409 + MODULE_DESCRIPTION("Texas Instruments LP8501 LED driver"); 410 410 MODULE_AUTHOR("Milo Kim"); 411 411 MODULE_LICENSE("GPL");
+8 -6
drivers/leds/leds-lp8860.c
··· 391 391 } 392 392 } 393 393 394 - led->enable_gpio = devm_gpiod_get(&client->dev, "enable"); 395 - if (IS_ERR(led->enable_gpio)) 396 - led->enable_gpio = NULL; 397 - else 398 - gpiod_direction_output(led->enable_gpio, 0); 394 + led->enable_gpio = devm_gpiod_get_optional(&client->dev, 395 + "enable", GPIOD_OUT_LOW); 396 + if (IS_ERR(led->enable_gpio)) { 397 + ret = PTR_ERR(led->enable_gpio); 398 + dev_err(&client->dev, "Failed to get enable gpio: %d\n", ret); 399 + return ret; 400 + } 399 401 400 402 led->regulator = devm_regulator_get(&client->dev, "vled"); 401 403 if (IS_ERR(led->regulator)) ··· 488 486 }; 489 487 module_i2c_driver(lp8860_driver); 490 488 491 - MODULE_DESCRIPTION("Texas Instruments LP8860 LED drvier"); 489 + MODULE_DESCRIPTION("Texas Instruments LP8860 LED driver"); 492 490 MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>"); 493 491 MODULE_LICENSE("GPL");
+1 -1
drivers/leds/leds-pca963x.c
··· 289 289 return ERR_PTR(-ENOMEM); 290 290 291 291 for_each_child_of_node(np, child) { 292 - struct led_info led; 292 + struct led_info led = {}; 293 293 u32 reg; 294 294 int res; 295 295
+435
drivers/leds/leds-pm8941-wled.c
··· 1 + /* Copyright (c) 2015, Sony Mobile Communications, AB. 2 + * 3 + * This program is free software; you can redistribute it and/or modify 4 + * it under the terms of the GNU General Public License version 2 and 5 + * only version 2 as published by the Free Software Foundation. 6 + * 7 + * This program is distributed in the hope that it will be useful, 8 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 + * GNU General Public License for more details. 11 + */ 12 + 13 + #include <linux/kernel.h> 14 + #include <linux/leds.h> 15 + #include <linux/module.h> 16 + #include <linux/of.h> 17 + #include <linux/of_device.h> 18 + #include <linux/regmap.h> 19 + 20 + #define PM8941_WLED_REG_VAL_BASE 0x40 21 + #define PM8941_WLED_REG_VAL_MAX 0xFFF 22 + 23 + #define PM8941_WLED_REG_MOD_EN 0x46 24 + #define PM8941_WLED_REG_MOD_EN_BIT BIT(7) 25 + #define PM8941_WLED_REG_MOD_EN_MASK BIT(7) 26 + 27 + #define PM8941_WLED_REG_SYNC 0x47 28 + #define PM8941_WLED_REG_SYNC_MASK 0x07 29 + #define PM8941_WLED_REG_SYNC_LED1 BIT(0) 30 + #define PM8941_WLED_REG_SYNC_LED2 BIT(1) 31 + #define PM8941_WLED_REG_SYNC_LED3 BIT(2) 32 + #define PM8941_WLED_REG_SYNC_ALL 0x07 33 + #define PM8941_WLED_REG_SYNC_CLEAR 0x00 34 + 35 + #define PM8941_WLED_REG_FREQ 0x4c 36 + #define PM8941_WLED_REG_FREQ_MASK 0x0f 37 + 38 + #define PM8941_WLED_REG_OVP 0x4d 39 + #define PM8941_WLED_REG_OVP_MASK 0x03 40 + 41 + #define PM8941_WLED_REG_BOOST 0x4e 42 + #define PM8941_WLED_REG_BOOST_MASK 0x07 43 + 44 + #define PM8941_WLED_REG_SINK 0x4f 45 + #define PM8941_WLED_REG_SINK_MASK 0xe0 46 + #define PM8941_WLED_REG_SINK_SHFT 0x05 47 + 48 + /* Per-'string' registers below */ 49 + #define PM8941_WLED_REG_STR_OFFSET 0x10 50 + 51 + #define PM8941_WLED_REG_STR_MOD_EN_BASE 0x60 52 + #define PM8941_WLED_REG_STR_MOD_MASK BIT(7) 53 + #define PM8941_WLED_REG_STR_MOD_EN BIT(7) 54 + 55 + #define PM8941_WLED_REG_STR_SCALE_BASE 0x62 56 + #define PM8941_WLED_REG_STR_SCALE_MASK 0x1f 57 + 58 + #define PM8941_WLED_REG_STR_MOD_SRC_BASE 0x63 59 + #define PM8941_WLED_REG_STR_MOD_SRC_MASK 0x01 60 + #define PM8941_WLED_REG_STR_MOD_SRC_INT 0x00 61 + #define PM8941_WLED_REG_STR_MOD_SRC_EXT 0x01 62 + 63 + #define PM8941_WLED_REG_STR_CABC_BASE 0x66 64 + #define PM8941_WLED_REG_STR_CABC_MASK BIT(7) 65 + #define PM8941_WLED_REG_STR_CABC_EN BIT(7) 66 + 67 + struct pm8941_wled_config { 68 + u32 i_boost_limit; 69 + u32 ovp; 70 + u32 switch_freq; 71 + u32 num_strings; 72 + u32 i_limit; 73 + bool cs_out_en; 74 + bool ext_gen; 75 + bool cabc_en; 76 + }; 77 + 78 + struct pm8941_wled { 79 + struct regmap *regmap; 80 + u16 addr; 81 + 82 + struct led_classdev cdev; 83 + 84 + struct pm8941_wled_config cfg; 85 + }; 86 + 87 + static int pm8941_wled_set(struct led_classdev *cdev, 88 + enum led_brightness value) 89 + { 90 + struct pm8941_wled *wled; 91 + u8 ctrl = 0; 92 + u16 val; 93 + int rc; 94 + int i; 95 + 96 + wled = container_of(cdev, struct pm8941_wled, cdev); 97 + 98 + if (value != 0) 99 + ctrl = PM8941_WLED_REG_MOD_EN_BIT; 100 + 101 + val = value * PM8941_WLED_REG_VAL_MAX / LED_FULL; 102 + 103 + rc = regmap_update_bits(wled->regmap, 104 + wled->addr + PM8941_WLED_REG_MOD_EN, 105 + PM8941_WLED_REG_MOD_EN_MASK, ctrl); 106 + if (rc) 107 + return rc; 108 + 109 + for (i = 0; i < wled->cfg.num_strings; ++i) { 110 + u8 v[2] = { val & 0xff, (val >> 8) & 0xf }; 111 + 112 + rc = regmap_bulk_write(wled->regmap, 113 + wled->addr + PM8941_WLED_REG_VAL_BASE + 2 * i, 114 + v, 2); 115 + if (rc) 116 + return rc; 117 + } 118 + 119 + rc = regmap_update_bits(wled->regmap, 120 + wled->addr + PM8941_WLED_REG_SYNC, 121 + PM8941_WLED_REG_SYNC_MASK, PM8941_WLED_REG_SYNC_ALL); 122 + if (rc) 123 + return rc; 124 + 125 + rc = regmap_update_bits(wled->regmap, 126 + wled->addr + PM8941_WLED_REG_SYNC, 127 + PM8941_WLED_REG_SYNC_MASK, PM8941_WLED_REG_SYNC_CLEAR); 128 + return rc; 129 + } 130 + 131 + static void pm8941_wled_set_brightness(struct led_classdev *cdev, 132 + enum led_brightness value) 133 + { 134 + if (pm8941_wled_set(cdev, value)) { 135 + dev_err(cdev->dev, "Unable to set brightness\n"); 136 + return; 137 + } 138 + cdev->brightness = value; 139 + } 140 + 141 + static int pm8941_wled_setup(struct pm8941_wled *wled) 142 + { 143 + int rc; 144 + int i; 145 + 146 + rc = regmap_update_bits(wled->regmap, 147 + wled->addr + PM8941_WLED_REG_OVP, 148 + PM8941_WLED_REG_OVP_MASK, wled->cfg.ovp); 149 + if (rc) 150 + return rc; 151 + 152 + rc = regmap_update_bits(wled->regmap, 153 + wled->addr + PM8941_WLED_REG_BOOST, 154 + PM8941_WLED_REG_BOOST_MASK, wled->cfg.i_boost_limit); 155 + if (rc) 156 + return rc; 157 + 158 + rc = regmap_update_bits(wled->regmap, 159 + wled->addr + PM8941_WLED_REG_FREQ, 160 + PM8941_WLED_REG_FREQ_MASK, wled->cfg.switch_freq); 161 + if (rc) 162 + return rc; 163 + 164 + if (wled->cfg.cs_out_en) { 165 + u8 all = (BIT(wled->cfg.num_strings) - 1) 166 + << PM8941_WLED_REG_SINK_SHFT; 167 + 168 + rc = regmap_update_bits(wled->regmap, 169 + wled->addr + PM8941_WLED_REG_SINK, 170 + PM8941_WLED_REG_SINK_MASK, all); 171 + if (rc) 172 + return rc; 173 + } 174 + 175 + for (i = 0; i < wled->cfg.num_strings; ++i) { 176 + u16 addr = wled->addr + PM8941_WLED_REG_STR_OFFSET * i; 177 + 178 + rc = regmap_update_bits(wled->regmap, 179 + addr + PM8941_WLED_REG_STR_MOD_EN_BASE, 180 + PM8941_WLED_REG_STR_MOD_MASK, 181 + PM8941_WLED_REG_STR_MOD_EN); 182 + if (rc) 183 + return rc; 184 + 185 + if (wled->cfg.ext_gen) { 186 + rc = regmap_update_bits(wled->regmap, 187 + addr + PM8941_WLED_REG_STR_MOD_SRC_BASE, 188 + PM8941_WLED_REG_STR_MOD_SRC_MASK, 189 + PM8941_WLED_REG_STR_MOD_SRC_EXT); 190 + if (rc) 191 + return rc; 192 + } 193 + 194 + rc = regmap_update_bits(wled->regmap, 195 + addr + PM8941_WLED_REG_STR_SCALE_BASE, 196 + PM8941_WLED_REG_STR_SCALE_MASK, 197 + wled->cfg.i_limit); 198 + if (rc) 199 + return rc; 200 + 201 + rc = regmap_update_bits(wled->regmap, 202 + addr + PM8941_WLED_REG_STR_CABC_BASE, 203 + PM8941_WLED_REG_STR_CABC_MASK, 204 + wled->cfg.cabc_en ? 205 + PM8941_WLED_REG_STR_CABC_EN : 0); 206 + if (rc) 207 + return rc; 208 + } 209 + 210 + return 0; 211 + } 212 + 213 + static const struct pm8941_wled_config pm8941_wled_config_defaults = { 214 + .i_boost_limit = 3, 215 + .i_limit = 20, 216 + .ovp = 2, 217 + .switch_freq = 5, 218 + .num_strings = 0, 219 + .cs_out_en = false, 220 + .ext_gen = false, 221 + .cabc_en = false, 222 + }; 223 + 224 + struct pm8941_wled_var_cfg { 225 + const u32 *values; 226 + u32 (*fn)(u32); 227 + int size; 228 + }; 229 + 230 + static const u32 pm8941_wled_i_boost_limit_values[] = { 231 + 105, 385, 525, 805, 980, 1260, 1400, 1680, 232 + }; 233 + 234 + static const struct pm8941_wled_var_cfg pm8941_wled_i_boost_limit_cfg = { 235 + .values = pm8941_wled_i_boost_limit_values, 236 + .size = ARRAY_SIZE(pm8941_wled_i_boost_limit_values), 237 + }; 238 + 239 + static const u32 pm8941_wled_ovp_values[] = { 240 + 35, 32, 29, 27, 241 + }; 242 + 243 + static const struct pm8941_wled_var_cfg pm8941_wled_ovp_cfg = { 244 + .values = pm8941_wled_ovp_values, 245 + .size = ARRAY_SIZE(pm8941_wled_ovp_values), 246 + }; 247 + 248 + static u32 pm8941_wled_num_strings_values_fn(u32 idx) 249 + { 250 + return idx + 1; 251 + } 252 + 253 + static const struct pm8941_wled_var_cfg pm8941_wled_num_strings_cfg = { 254 + .fn = pm8941_wled_num_strings_values_fn, 255 + .size = 3, 256 + }; 257 + 258 + static u32 pm8941_wled_switch_freq_values_fn(u32 idx) 259 + { 260 + return 19200 / (2 * (1 + idx)); 261 + } 262 + 263 + static const struct pm8941_wled_var_cfg pm8941_wled_switch_freq_cfg = { 264 + .fn = pm8941_wled_switch_freq_values_fn, 265 + .size = 16, 266 + }; 267 + 268 + static const struct pm8941_wled_var_cfg pm8941_wled_i_limit_cfg = { 269 + .size = 26, 270 + }; 271 + 272 + static u32 pm8941_wled_values(const struct pm8941_wled_var_cfg *cfg, u32 idx) 273 + { 274 + if (idx >= cfg->size) 275 + return UINT_MAX; 276 + if (cfg->fn) 277 + return cfg->fn(idx); 278 + if (cfg->values) 279 + return cfg->values[idx]; 280 + return idx; 281 + } 282 + 283 + static int pm8941_wled_configure(struct pm8941_wled *wled, struct device *dev) 284 + { 285 + struct pm8941_wled_config *cfg = &wled->cfg; 286 + u32 val; 287 + int rc; 288 + u32 c; 289 + int i; 290 + int j; 291 + 292 + const struct { 293 + const char *name; 294 + u32 *val_ptr; 295 + const struct pm8941_wled_var_cfg *cfg; 296 + } u32_opts[] = { 297 + { 298 + "qcom,current-boost-limit", 299 + &cfg->i_boost_limit, 300 + .cfg = &pm8941_wled_i_boost_limit_cfg, 301 + }, 302 + { 303 + "qcom,current-limit", 304 + &cfg->i_limit, 305 + .cfg = &pm8941_wled_i_limit_cfg, 306 + }, 307 + { 308 + "qcom,ovp", 309 + &cfg->ovp, 310 + .cfg = &pm8941_wled_ovp_cfg, 311 + }, 312 + { 313 + "qcom,switching-freq", 314 + &cfg->switch_freq, 315 + .cfg = &pm8941_wled_switch_freq_cfg, 316 + }, 317 + { 318 + "qcom,num-strings", 319 + &cfg->num_strings, 320 + .cfg = &pm8941_wled_num_strings_cfg, 321 + }, 322 + }; 323 + const struct { 324 + const char *name; 325 + bool *val_ptr; 326 + } bool_opts[] = { 327 + { "qcom,cs-out", &cfg->cs_out_en, }, 328 + { "qcom,ext-gen", &cfg->ext_gen, }, 329 + { "qcom,cabc", &cfg->cabc_en, }, 330 + }; 331 + 332 + rc = of_property_read_u32(dev->of_node, "reg", &val); 333 + if (rc || val > 0xffff) { 334 + dev_err(dev, "invalid IO resources\n"); 335 + return rc ? rc : -EINVAL; 336 + } 337 + wled->addr = val; 338 + 339 + rc = of_property_read_string(dev->of_node, "label", &wled->cdev.name); 340 + if (rc) 341 + wled->cdev.name = dev->of_node->name; 342 + 343 + wled->cdev.default_trigger = of_get_property(dev->of_node, 344 + "linux,default-trigger", NULL); 345 + 346 + *cfg = pm8941_wled_config_defaults; 347 + for (i = 0; i < ARRAY_SIZE(u32_opts); ++i) { 348 + rc = of_property_read_u32(dev->of_node, u32_opts[i].name, &val); 349 + if (rc == -EINVAL) { 350 + continue; 351 + } else if (rc) { 352 + dev_err(dev, "error reading '%s'\n", u32_opts[i].name); 353 + return rc; 354 + } 355 + 356 + c = UINT_MAX; 357 + for (j = 0; c != val; j++) { 358 + c = pm8941_wled_values(u32_opts[i].cfg, j); 359 + if (c == UINT_MAX) { 360 + dev_err(dev, "invalid value for '%s'\n", 361 + u32_opts[i].name); 362 + return -EINVAL; 363 + } 364 + } 365 + 366 + dev_dbg(dev, "'%s' = %u\n", u32_opts[i].name, c); 367 + *u32_opts[i].val_ptr = j; 368 + } 369 + 370 + for (i = 0; i < ARRAY_SIZE(bool_opts); ++i) { 371 + if (of_property_read_bool(dev->of_node, bool_opts[i].name)) 372 + *bool_opts[i].val_ptr = true; 373 + } 374 + 375 + cfg->num_strings = cfg->num_strings + 1; 376 + 377 + return 0; 378 + } 379 + 380 + static int pm8941_wled_probe(struct platform_device *pdev) 381 + { 382 + struct pm8941_wled *wled; 383 + struct regmap *regmap; 384 + int rc; 385 + 386 + regmap = dev_get_regmap(pdev->dev.parent, NULL); 387 + if (!regmap) { 388 + dev_err(&pdev->dev, "Unable to get regmap\n"); 389 + return -EINVAL; 390 + } 391 + 392 + wled = devm_kzalloc(&pdev->dev, sizeof(*wled), GFP_KERNEL); 393 + if (!wled) 394 + return -ENOMEM; 395 + 396 + wled->regmap = regmap; 397 + 398 + rc = pm8941_wled_configure(wled, &pdev->dev); 399 + if (rc) 400 + return rc; 401 + 402 + rc = pm8941_wled_setup(wled); 403 + if (rc) 404 + return rc; 405 + 406 + wled->cdev.brightness_set = pm8941_wled_set_brightness; 407 + 408 + rc = devm_led_classdev_register(&pdev->dev, &wled->cdev); 409 + if (rc) 410 + return rc; 411 + 412 + platform_set_drvdata(pdev, wled); 413 + 414 + return 0; 415 + }; 416 + 417 + static const struct of_device_id pm8941_wled_match_table[] = { 418 + { .compatible = "qcom,pm8941-wled" }, 419 + {} 420 + }; 421 + MODULE_DEVICE_TABLE(of, pm8941_wled_match_table); 422 + 423 + static struct platform_driver pm8941_wled_driver = { 424 + .probe = pm8941_wled_probe, 425 + .driver = { 426 + .name = "pm8941-wled", 427 + .of_match_table = pm8941_wled_match_table, 428 + }, 429 + }; 430 + 431 + module_platform_driver(pm8941_wled_driver); 432 + 433 + MODULE_DESCRIPTION("pm8941 wled driver"); 434 + MODULE_LICENSE("GPL v2"); 435 + MODULE_ALIAS("platform:pm8941-wled");
-3
drivers/leds/leds-pwm.c
··· 121 121 return ret; 122 122 } 123 123 124 - if (child) 125 - led_data->period = pwm_get_period(led_data->pwm); 126 - 127 124 led_data->can_sleep = pwm_can_sleep(led_data->pwm); 128 125 if (led_data->can_sleep) 129 126 INIT_WORK(&led_data->work, led_pwm_work);
+21
include/dt-bindings/leds/common.h
··· 1 + /* 2 + * This header provides macros for the common LEDs device tree bindings. 3 + * 4 + * Copyright (C) 2015, Samsung Electronics Co., Ltd. 5 + * 6 + * Author: Jacek Anaszewski <j.anaszewski@samsung.com> 7 + */ 8 + 9 + #ifndef __DT_BINDINGS_LEDS_H__ 10 + #define __DT_BINDINGS_LEDS_H 11 + 12 + /* External trigger type */ 13 + #define LEDS_TRIG_TYPE_EDGE 0 14 + #define LEDS_TRIG_TYPE_LEVEL 1 15 + 16 + /* Boost modes */ 17 + #define LEDS_BOOST_OFF 0 18 + #define LEDS_BOOST_ADAPTIVE 1 19 + #define LEDS_BOOST_FIXED 2 20 + 21 + #endif /* __DT_BINDINGS_LEDS_H */
+2 -17
include/linux/led-class-flash.h
··· 13 13 #define __LINUX_FLASH_LEDS_H_INCLUDED 14 14 15 15 #include <linux/leds.h> 16 - #include <uapi/linux/v4l2-controls.h> 17 16 18 17 struct device_node; 19 18 struct led_classdev_flash; ··· 32 33 #define LED_FAULT_LED_OVER_TEMPERATURE (1 << 8) 33 34 #define LED_NUM_FLASH_FAULTS 9 34 35 35 - #define LED_FLASH_MAX_SYSFS_GROUPS 7 36 + #define LED_FLASH_SYSFS_GROUPS_SIZE 5 36 37 37 38 struct led_flash_ops { 38 39 /* set flash brightness */ ··· 80 81 struct led_flash_setting timeout; 81 82 82 83 /* LED Flash class sysfs groups */ 83 - const struct attribute_group *sysfs_groups[LED_FLASH_MAX_SYSFS_GROUPS]; 84 - 85 - /* LEDs available for flash strobe synchronization */ 86 - struct led_classdev_flash **sync_leds; 87 - 88 - /* Number of LEDs available for flash strobe synchronization */ 89 - int num_sync_leds; 90 - 91 - /* 92 - * The identifier of the sub-led to synchronize the flash strobe with. 93 - * Identifiers start from 1, which reflects the first element from the 94 - * sync_leds array. 0 means that the flash strobe should not be 95 - * synchronized. 96 - */ 97 - u32 sync_led_id; 84 + const struct attribute_group *sysfs_groups[LED_FLASH_SYSFS_GROUPS_SIZE]; 98 85 }; 99 86 100 87 static inline struct led_classdev_flash *lcdev_to_flcdev(
+4 -1
include/linux/leds.h
··· 47 47 #define SET_BRIGHTNESS_ASYNC (1 << 21) 48 48 #define SET_BRIGHTNESS_SYNC (1 << 22) 49 49 #define LED_DEV_CAP_FLASH (1 << 23) 50 - #define LED_DEV_CAP_SYNC_STROBE (1 << 24) 51 50 52 51 /* Set LED brightness level */ 53 52 /* Must not sleep, use a workqueue if needed */ ··· 104 105 105 106 extern int led_classdev_register(struct device *parent, 106 107 struct led_classdev *led_cdev); 108 + extern int devm_led_classdev_register(struct device *parent, 109 + struct led_classdev *led_cdev); 107 110 extern void led_classdev_unregister(struct led_classdev *led_cdev); 111 + extern void devm_led_classdev_unregister(struct device *parent, 112 + struct led_classdev *led_cdev); 108 113 extern void led_classdev_suspend(struct led_classdev *led_cdev); 109 114 extern void led_classdev_resume(struct led_classdev *led_cdev); 110 115