Commit 9256d5a3 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'leds_for_4.6' of git://git.kernel.org/pub/scm/linux/kernel/git/j.anaszewski/linux-leds

Pull LED updates from Jacek Anaszewski:
 "LED core improvements:
   - Fix misleading comment after workqueue removal from drivers
   - Avoid error message when a USB LED device is unplugged
   - Add helpers for calling brightness_set(_blocking)

  LED triggers:
   - Simplify led_trigger_store by using sysfs_streq()

  LED class drivers improvements:
   - Improve wording and formatting in a comment: lp3944
   - Fix return value check in create_gpio_led(): leds-gpio
   - Use GPIOF_OUT_INIT_LOW instead of hardcoded zero: leds-gpio
   - Use devm_led_classdev_register(): leds-lm3533, leds-lm3533,
     leds-lp8788, leds-wm831x-status, leds-s3c24xx, leds-s3c24xx,
     leds-max8997.

  New LED class driver:
   - Add driver for the ISSI IS31FL32xx family of LED controllers.

  Device Tree documentation:
   - of: Add vendor prefixes for Integrated Silicon Solutions Inc.
     (issi) and Si-En Technology (si-en).
   - DT: Add common bindings for Si-En Technology SN3216/18 and
     IS31FL32xx family of LED controllers, since they seem to be the
     same hardware, just rebranded"

* tag 'leds_for_4.6' of git://git.kernel.org/pub/scm/linux/kernel/git/j.anaszewski/linux-leds:
  leds: triggers: simplify led_trigger_store
  leds: max8997: Use devm_led_classdev_register
  leds: da903x: Use devm_led_classdev_register
  leds: s3c24xx: Use devm_led_classdev_register
  leds: wm831x-status: Use devm_led_classdev_register
  leds: lp8788: Use devm_led_classdev_register
  leds: 88pm860x: Use devm_led_classdev_register
  leds: Add SN3218 and SN3216 support to the IS31FL32XX driver
  of: Add vendor prefix for Si-En Technology
  leds: Add driver for the ISSI IS31FL32xx family of LED controllers
  DT: leds: Add binding for the ISSI IS31FL32xx family of LED controllers
  DT: Add vendor prefix for Integrated Silicon Solutions Inc.
  leds: lm3533: Use devm_led_classdev_register
  leds: gpio: Use GPIOF_OUT_INIT_LOW instead of hardcoded zero
  leds: core: add helpers for calling brightness_set(_blocking)
  leds: leds-gpio: Fix return value check in create_gpio_led()
  leds: lp3944: improve wording and formatting in a comment
  leds: core: avoid error message when a USB LED device is unplugged
  leds: core: fix misleading comment after workqueue removal from drivers
parents 13f6f62f 7296c33e
Binding for ISSI IS31FL32xx and Si-En SN32xx LED Drivers
The IS31FL32xx/SN32xx family of LED drivers are I2C devices with multiple
constant-current channels, each with independent 256-level PWM control.
Each LED is represented as a sub-node of the device.
Required properties:
- compatible: one of
issi,is31fl3236
issi,is31fl3235
issi,is31fl3218
issi,is31fl3216
si-en,sn3218
si-en,sn3216
- reg: I2C slave address
- address-cells : must be 1
- size-cells : must be 0
LED sub-node properties:
- reg : LED channel number (1..N)
- label : (optional)
see Documentation/devicetree/bindings/leds/common.txt
- linux,default-trigger : (optional)
see Documentation/devicetree/bindings/leds/common.txt
Example:
is31fl3236: led-controller@3c {
compatible = "issi,is31fl3236";
reg = <0x3c>;
#address-cells = <1>;
#size-cells = <0>;
led@1 {
reg = <1>;
label = "EB:blue:usr0";
};
led@2 {
reg = <2>;
label = "EB:blue:usr1";
};
...
led@36 {
reg = <36>;
label = "EB:blue:usr35";
};
};
For more product information please see the links below:
http://www.issi.com/US/product-analog-fxled-driver.shtml
http://www.si-en.com/product.asp?parentid=890
......@@ -120,6 +120,7 @@ intercontrol Inter Control Group
invensense InvenSense Inc.
isee ISEE 2007 S.L.
isil Intersil
issi Integrated Silicon Solutions Inc.
jedec JEDEC Solid State Technology Association
karo Ka-Ro electronics GmbH
keymile Keymile GmbH
......@@ -204,6 +205,7 @@ seagate Seagate Technology PLC
semtech Semtech Corporation
sgx SGX Sensortech
sharp Sharp Corporation
si-en Si-En Technology Ltd.
sigma Sigma Designs, Inc.
sil Silicon Image
silabs Silicon Laboratories
......
......@@ -568,6 +568,14 @@ config LEDS_SEAD3
This driver can also be built as a module. If so the module
will be called leds-sead3.
config LEDS_IS31FL32XX
tristate "LED support for ISSI IS31FL32XX I2C LED controller family"
depends on LEDS_CLASS && I2C && OF
help
Say Y here to include support for ISSI IS31FL32XX and Si-En SN32xx
LED controllers. They are I2C devices with multiple constant-current
channels, each with independent 256-level PWM control.
comment "LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM)"
config LEDS_BLINKM
......
......@@ -66,6 +66,7 @@ obj-$(CONFIG_LEDS_MENF21BMC) += leds-menf21bmc.o
obj-$(CONFIG_LEDS_KTD2692) += leds-ktd2692.o
obj-$(CONFIG_LEDS_POWERNV) += leds-powernv.o
obj-$(CONFIG_LEDS_SEAD3) += leds-sead3.o
obj-$(CONFIG_LEDS_IS31FL32XX) += leds-is31fl32xx.o
# LED SPI Drivers
obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o
......
......@@ -245,6 +245,8 @@ void led_classdev_unregister(struct led_classdev *led_cdev)
up_write(&led_cdev->trigger_lock);
#endif
led_cdev->flags |= LED_UNREGISTERING;
/* Stop blinking */
led_stop_software_blink(led_cdev);
......
......@@ -25,6 +25,26 @@ EXPORT_SYMBOL_GPL(leds_list_lock);
LIST_HEAD(leds_list);
EXPORT_SYMBOL_GPL(leds_list);
static int __led_set_brightness(struct led_classdev *led_cdev,
enum led_brightness value)
{
if (!led_cdev->brightness_set)
return -ENOTSUPP;
led_cdev->brightness_set(led_cdev, value);
return 0;
}
static int __led_set_brightness_blocking(struct led_classdev *led_cdev,
enum led_brightness value)
{
if (!led_cdev->brightness_set_blocking)
return -ENOTSUPP;
return led_cdev->brightness_set_blocking(led_cdev, value);
}
static void led_timer_function(unsigned long data)
{
struct led_classdev *led_cdev = (void *)data;
......@@ -91,14 +111,14 @@ static void set_brightness_delayed(struct work_struct *ws)
led_cdev->flags &= ~LED_BLINK_DISABLE;
}
if (led_cdev->brightness_set)
led_cdev->brightness_set(led_cdev, led_cdev->delayed_set_value);
else if (led_cdev->brightness_set_blocking)
ret = led_cdev->brightness_set_blocking(led_cdev,
led_cdev->delayed_set_value);
else
ret = -ENOTSUPP;
if (ret < 0)
ret = __led_set_brightness(led_cdev, led_cdev->delayed_set_value);
if (ret == -ENOTSUPP)
ret = __led_set_brightness_blocking(led_cdev,
led_cdev->delayed_set_value);
if (ret < 0 &&
/* LED HW might have been unplugged, therefore don't warn */
!(ret == -ENODEV && (led_cdev->flags & LED_UNREGISTERING) &&
(led_cdev->flags & LED_HW_PLUGGABLE)))
dev_err(led_cdev->dev,
"Setting an LED's brightness failed (%d)\n", ret);
}
......@@ -233,10 +253,8 @@ void led_set_brightness_nopm(struct led_classdev *led_cdev,
enum led_brightness value)
{
/* Use brightness_set op if available, it is guaranteed not to sleep */
if (led_cdev->brightness_set) {
led_cdev->brightness_set(led_cdev, value);
if (!__led_set_brightness(led_cdev, value))
return;
}
/* If brightness setting can sleep, delegate it to a work queue task */
led_cdev->delayed_set_value = value;
......@@ -267,10 +285,7 @@ int led_set_brightness_sync(struct led_classdev *led_cdev,
if (led_cdev->flags & LED_SUSPENDED)
return 0;
if (led_cdev->brightness_set_blocking)
return led_cdev->brightness_set_blocking(led_cdev,
led_cdev->brightness);
return -ENOTSUPP;
return __led_set_brightness_blocking(led_cdev, led_cdev->brightness);
}
EXPORT_SYMBOL_GPL(led_set_brightness_sync);
......
......@@ -34,9 +34,7 @@ ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
char trigger_name[TRIG_NAME_MAX];
struct led_trigger *trig;
size_t len;
int ret = count;
mutex_lock(&led_cdev->led_access);
......@@ -46,21 +44,14 @@ ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr,
goto unlock;
}
trigger_name[sizeof(trigger_name) - 1] = '\0';
strncpy(trigger_name, buf, sizeof(trigger_name) - 1);
len = strlen(trigger_name);
if (len && trigger_name[len - 1] == '\n')
trigger_name[len - 1] = '\0';
if (!strcmp(trigger_name, "none")) {
if (sysfs_streq(buf, "none")) {
led_trigger_remove(led_cdev);
goto unlock;
}
down_read(&triggers_list_lock);
list_for_each_entry(trig, &trigger_list, next_trig) {
if (!strcmp(trigger_name, trig->name)) {
if (sysfs_streq(buf, trig->name)) {
down_write(&led_cdev->trigger_lock);
led_trigger_set(led_cdev, trig);
up_write(&led_cdev->trigger_lock);
......
......@@ -195,7 +195,6 @@ static int pm860x_led_probe(struct platform_device *pdev)
sprintf(data->name, "led1-blue");
break;
}
platform_set_drvdata(pdev, data);
data->chip = chip;
data->i2c = (chip->id == CHIP_PM8606) ? chip->client : chip->companion;
data->port = pdev->id;
......@@ -208,7 +207,7 @@ static int pm860x_led_probe(struct platform_device *pdev)
data->cdev.brightness_set_blocking = pm860x_led_set;
mutex_init(&data->lock);
ret = led_classdev_register(chip->dev, &data->cdev);
ret = devm_led_classdev_register(chip->dev, &data->cdev);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to register LED: %d\n", ret);
return ret;
......@@ -217,21 +216,12 @@ static int pm860x_led_probe(struct platform_device *pdev)
return 0;
}
static int pm860x_led_remove(struct platform_device *pdev)
{
struct pm860x_led *data = platform_get_drvdata(pdev);
led_classdev_unregister(&data->cdev);
return 0;
}
static struct platform_driver pm860x_led_driver = {
.driver = {
.name = "88pm860x-led",
},
.probe = pm860x_led_probe,
.remove = pm860x_led_remove,
};
module_platform_driver(pm860x_led_driver);
......
......@@ -113,21 +113,12 @@ static int da903x_led_probe(struct platform_device *pdev)
led->flags = pdata->flags;
led->master = pdev->dev.parent;
ret = led_classdev_register(led->master, &led->cdev);
ret = devm_led_classdev_register(led->master, &led->cdev);
if (ret) {
dev_err(&pdev->dev, "failed to register LED %d\n", id);
return ret;
}
platform_set_drvdata(pdev, led);
return 0;
}
static int da903x_led_remove(struct platform_device *pdev)
{
struct da903x_led *led = platform_get_drvdata(pdev);
led_classdev_unregister(&led->cdev);
return 0;
}
......@@ -136,7 +127,6 @@ static struct platform_driver da903x_led_driver = {
.name = "da903x-led",
},
.probe = da903x_led_probe,
.remove = da903x_led_remove,
};
module_platform_driver(da903x_led_driver);
......
......@@ -86,7 +86,7 @@ static int create_gpio_led(const struct gpio_led *template,
* still uses GPIO numbers. Ultimately we would like to get
* rid of this block completely.
*/
unsigned long flags = 0;
unsigned long flags = GPIOF_OUT_INIT_LOW;
/* skip leds that aren't available */
if (!gpio_is_valid(template->gpio)) {
......@@ -104,8 +104,8 @@ static int create_gpio_led(const struct gpio_led *template,
return ret;
led_dat->gpiod = gpio_to_desc(template->gpio);
if (IS_ERR(led_dat->gpiod))
return PTR_ERR(led_dat->gpiod);
if (!led_dat->gpiod)
return -EINVAL;
}
led_dat->cdev.name = template->name;
......
This diff is collapsed.
......@@ -698,7 +698,7 @@ static int lm3533_led_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, led);
ret = led_classdev_register(pdev->dev.parent, &led->cdev);
ret = devm_led_classdev_register(pdev->dev.parent, &led->cdev);
if (ret) {
dev_err(&pdev->dev, "failed to register LED %d\n", pdev->id);
return ret;
......@@ -708,18 +708,13 @@ static int lm3533_led_probe(struct platform_device *pdev)
ret = lm3533_led_setup(led, pdata);
if (ret)
goto err_unregister;
return ret;
ret = lm3533_ctrlbank_enable(&led->cb);
if (ret)
goto err_unregister;
return ret;
return 0;
err_unregister:
led_classdev_unregister(&led->cdev);
return ret;
}
static int lm3533_led_remove(struct platform_device *pdev)
......@@ -729,7 +724,6 @@ static int lm3533_led_remove(struct platform_device *pdev)
dev_dbg(&pdev->dev, "%s\n", __func__);
lm3533_ctrlbank_disable(&led->cb);
led_classdev_unregister(&led->cdev);
return 0;
}
......
......@@ -199,8 +199,11 @@ static int lp3944_led_set(struct lp3944_led_data *led, u8 status)
if (status > LP3944_LED_STATUS_DIM1)
return -EINVAL;
/* invert only 0 and 1, leave unchanged the other values,
* remember we are abusing status to set blink patterns
/*
* Invert status only when it's < 2 (i.e. 0 or 1) which means it's
* controlling the on/off state directly.
* When, instead, status is >= 2 don't invert it because it would mean
* to mess with the hardware blinking mode.
*/
if (led->type == LP3944_LED_TYPE_LED_INVERTED && status < 2)
status = 1 - status;
......
......@@ -146,15 +146,13 @@ static int lp8788_led_probe(struct platform_device *pdev)
mutex_init(&led->lock);
platform_set_drvdata(pdev, led);
ret = lp8788_led_init_device(led, led_pdata);
if (ret) {
dev_err(dev, "led init device err: %d\n", ret);
return ret;
}
ret = led_classdev_register(dev, &led->led_dev);
ret = devm_led_classdev_register(dev, &led->led_dev);
if (ret) {
dev_err(dev, "led register err: %d\n", ret);
return ret;
......@@ -163,18 +161,8 @@ static int lp8788_led_probe(struct platform_device *pdev)
return 0;
}
static int lp8788_led_remove(struct platform_device *pdev)
{
struct lp8788_led *led = platform_get_drvdata(pdev);
led_classdev_unregister(&led->led_dev);
return 0;
}
static struct platform_driver lp8788_led_driver = {
.probe = lp8788_led_probe,
.remove = lp8788_led_remove,
.driver = {
.name = LP8788_DEV_KEYLED,
},
......
......@@ -281,30 +281,18 @@ static int max8997_led_probe(struct platform_device *pdev)
mutex_init(&led->mutex);
platform_set_drvdata(pdev, led);
ret = led_classdev_register(&pdev->dev, &led->cdev);
ret = devm_led_classdev_register(&pdev->dev, &led->cdev);
if (ret < 0)
return ret;
return 0;
}
static int max8997_led_remove(struct platform_device *pdev)
{
struct max8997_led *led = platform_get_drvdata(pdev);
led_classdev_unregister(&led->cdev);
return 0;
}
static struct platform_driver max8997_led_driver = {
.driver = {
.name = "max8997-led",
},
.probe = max8997_led_probe,
.remove = max8997_led_remove,
};
module_platform_driver(max8997_led_driver);
......
......@@ -29,11 +29,6 @@ struct s3c24xx_gpio_led {
struct s3c24xx_led_platdata *pdata;
};
static inline struct s3c24xx_gpio_led *pdev_to_gpio(struct platform_device *dev)
{
return platform_get_drvdata(dev);
}
static inline struct s3c24xx_gpio_led *to_gpio(struct led_classdev *led_cdev)
{
return container_of(led_cdev, struct s3c24xx_gpio_led, cdev);
......@@ -59,15 +54,6 @@ static void s3c24xx_led_set(struct led_classdev *led_cdev,
}
}
static int s3c24xx_led_remove(struct platform_device *dev)
{
struct s3c24xx_gpio_led *led = pdev_to_gpio(dev);
led_classdev_unregister(&led->cdev);
return 0;
}
static int s3c24xx_led_probe(struct platform_device *dev)
{
struct s3c24xx_led_platdata *pdata = dev_get_platdata(&dev->dev);
......@@ -79,8 +65,6 @@ static int s3c24xx_led_probe(struct platform_device *dev)
if (!led)
return -ENOMEM;
platform_set_drvdata(dev, led);
led->cdev.brightness_set = s3c24xx_led_set;
led->cdev.default_trigger = pdata->def_trigger;
led->cdev.name = pdata->name;
......@@ -104,7 +88,7 @@ static int s3c24xx_led_probe(struct platform_device *dev)
/* register our new led device */
ret = led_classdev_register(&dev->dev, &led->cdev);
ret = devm_led_classdev_register(&dev->dev, &led->cdev);
if (ret < 0)
dev_err(&dev->dev, "led_classdev_register failed\n");
......@@ -113,7 +97,6 @@ static int s3c24xx_led_probe(struct platform_device *dev)
static struct platform_driver s3c24xx_led_driver = {
.probe = s3c24xx_led_probe,
.remove = s3c24xx_led_remove,
.driver = {
.name = "s3c24xx_led",
},
......
......@@ -239,7 +239,6 @@ static int wm831x_status_probe(struct platform_device *pdev)
GFP_KERNEL);
if (!drvdata)
return -ENOMEM;
platform_set_drvdata(pdev, drvdata);
drvdata->wm831x = wm831x;
drvdata->reg = res->start;
......@@ -284,7 +283,7 @@ static int wm831x_status_probe(struct platform_device *pdev)
drvdata->cdev.blink_set = wm831x_status_blink_set;
drvdata->cdev.groups = wm831x_status_groups;
ret = led_classdev_register(wm831x->dev, &drvdata->cdev);
ret = devm_led_classdev_register(wm831x->dev, &drvdata->cdev);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to register LED: %d\n", ret);
return ret;
......@@ -293,21 +292,11 @@ static int wm831x_status_probe(struct platform_device *pdev)
return 0;
}
static int wm831x_status_remove(struct platform_device *pdev)
{
struct wm831x_status *drvdata = platform_get_drvdata(pdev);
led_classdev_unregister(&drvdata->cdev);
return 0;
}
static struct platform_driver wm831x_status_driver = {
.driver = {
.name = "wm831x-status",
},
.probe = wm831x_status_probe,
.remove = wm831x_status_remove,
};
module_platform_driver(wm831x_status_driver);
......
......@@ -39,6 +39,7 @@ struct led_classdev {
/* Lower 16 bits reflect status */
#define LED_SUSPENDED (1 << 0)
#define LED_UNREGISTERING (1 << 1)
/* Upper 16 bits reflect control information */
#define LED_CORE_SUSPENDRESUME (1 << 16)
#define LED_BLINK_ONESHOT (1 << 17)
......@@ -48,9 +49,12 @@ struct led_classdev {
#define LED_BLINK_DISABLE (1 << 21)
#define LED_SYSFS_DISABLE (1 << 22)
#define LED_DEV_CAP_FLASH (1 << 23)
#define LED_HW_PLUGGABLE (1 << 24)
/* Set LED brightness level */
/* Must not sleep, use a workqueue if needed */
/* Set LED brightness level
* Must not sleep. Use brightness_set_blocking for drivers
* that can sleep while setting brightness.
*/
void (*brightness_set)(struct led_classdev *led_cdev,
enum led_brightness brightness);
/*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment