Commit 2c487121 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull LED subsystem updates from Jacek Anaszewski:
 "Besides regular driver updates, we introduce a portion of LED core
  improvements, that allow to avoid the need for using work queues in
  the LED class drivers, that set brightness in a blocking way.

  Affected LED class drivers are being optimized accordingly.

   - LED core improvements:
        - use EXPORT_SYMBOL_GPL consistently,
        - add two new LED_BLINK_ flags,
        - rename brightness_set_sync op to brightness_set_blocking,
        - add led_set_brightness_nosleep{nopm} functions,
        - use set_brightness_work for the blocking op,
        - drivers shouldn't enforce SYNC/ASYNC brightness setting,
        - turn off the LED and wait for completion on unregistering LED
          class device,
        - add managed version of led_trigger_register,
        - add description of brightness setting API to the LED class doc.

   - Remove work queues from drivers: leds-tlc591xx, leds-88pm860x, leds-adp5520,
        leds-bd2802, leds-blinkm, leds-lm3533, leds-lm3642, leds-pca9532,
        leds-lp3944, leds-lp55xx, leds-lp8788, leds-lp8860, leds-pca955x,
        leds-pca963x, leds-wm831x, leds-da903x, leds-da9052, leds-dac124d085,
        leds-lt3593, leds-max8997, leds-mc13783, leds-regulator, leds-wm8350,
        leds-max77693, leds-aat1290, leds-ktd2692, leds-gpio, leds-pwm,
        leds-lm355x, leds-ns2.

   - Replace brightness_set op with a new brightness_set_blocking op to
     make the drivers compatible with led triggers: leds-ipaq-micro,
     leds-powernv.

   - Add missing of_node_put: leds-ktd2692, leds-aat1290, leds-max77693.

   - Make the driver explicitly non-modular: ledtrig-cpu,
     ledtrig-ide-disk, leds-syscon.

   - Improvements to leds-bcm6328:
        - reuse bcm6328_led_set() instead of copying its functionality,
        - swap LED ON and OFF definitions,
        - improve blink support,
        - simplify duplicated unlock in bcm6328_blink_set,
        - add little endian support,
        - remove unneded lock when checking initial LED status,
        - add HAS_IOMEM dependency,
        - code cleaning.

   - Improvements to leds-bcm6358:
        - use bcm6358_led_set() in order to get rid of the lock,
        - merge bcm6358_led_mode and bcm6358_led_set,
        - add little endian support,
        - remove unneded lock when checking initial LED status,
        - add HAS_IOMEM dependency,
        - remove unneeded busy status check.

   - Call led_pwm_set() in leds-pwm to enforce default LED_OFF.

   - Fix duration to be msec instead of jiffies: ledtrig-transient.

   - Removing NULL check: leds-powernv.

   - Use platform_register/unregister_drivers(): leds-sunfire.

   - Fix module license specification: ledtrig-oneshot.

   - Fix driver description and make license match the header: leds-pwm.

   - Remove checking for state < 1 in flash_strobe_store():
     led-class-flash.

   - Use led_set_brightness_sync for torch brightness:
     v4l2-flash-led-class"

* tag 'leds-for-4.5' of git://git.kernel.org/pub/scm/linux/kernel/git/j.anaszewski/linux-leds: (68 commits)
  leds: add HAS_IOMEM dependency to LEDS_BCM6328/LEDS_BCM6358
  leds: core: add managed version of led_trigger_register
  leds: bcm6358: remove unneeded busy status check
  leds: bcm6328: improve blink support
  leds: bcm6358: merge bcm6358_led_mode and bcm6358_led_set
  leds: bcm6328: simplify duplicated unlock in bcm6328_blink_set
  leds: bcm6358: add little endian support
  leds: bcm6328: add little endian support
  leds: bcm6358: remove unneded lock when checking initial LED status
  leds: bcm6358: Use bcm6358_led_set() in order to get rid of the lock
  leds: bcm6328: remove unneded lock when checking initial LED
  leds: bcm6328: code cleaning
  leds: syscon: Make the driver explicitly non-modular
  leds: ledtrig-ide-disk: Make the driver explicitly non-modular
  leds: ledtrig-cpu: Make the driver explicitly non-modular
  leds: sunfire: Use platform_register/unregister_drivers()
  leds: max77693: Add missing of_node_put
  leds: aat1290: Add missing of_node_put
  leds: powernv: Implement brightness_set_blocking op
  leds: ipaq-micro: Implement brightness_set_blocking op
  ...
parents d870a9d5 522f17e1
......@@ -52,6 +52,19 @@ above leaves scope for further attributes should they be needed. If sections
of the name don't apply, just leave that section blank.
Brightness setting API
======================
LED subsystem core exposes following API for setting brightness:
- led_set_brightness : it is guaranteed not to sleep, passing LED_OFF stops
blinking,
- led_set_brightness_sync : for use cases when immediate effect is desired -
it can block the caller for the time required for accessing
device registers and can sleep, passing LED_OFF stops hardware
blinking, returns -EBUSY if software blink fallback is enabled.
Hardware accelerated blink of LEDs
==================================
......
......@@ -52,6 +52,7 @@ config LEDS_AAT1290
config LEDS_BCM6328
tristate "LED Support for Broadcom BCM6328"
depends on LEDS_CLASS
depends on HAS_IOMEM
depends on OF
help
This option enables support for LEDs connected to the BCM6328
......@@ -60,6 +61,7 @@ config LEDS_BCM6328
config LEDS_BCM6358
tristate "LED Support for Broadcom BCM6358"
depends on LEDS_CLASS
depends on HAS_IOMEM
depends on OF
help
This option enables support for LEDs connected to the BCM6358
......
......@@ -108,7 +108,7 @@ static ssize_t flash_strobe_store(struct device *dev,
if (ret)
goto unlock;
if (state < 0 || state > 1) {
if (state > 1) {
ret = -EINVAL;
goto unlock;
}
......@@ -298,7 +298,7 @@ int led_classdev_flash_register(struct device *parent,
led_cdev = &fled_cdev->led_cdev;
if (led_cdev->flags & LED_DEV_CAP_FLASH) {
if (!led_cdev->brightness_set_sync)
if (!led_cdev->brightness_set_blocking)
return -EINVAL;
ops = fled_cdev->ops;
......@@ -316,10 +316,6 @@ int led_classdev_flash_register(struct device *parent,
if (ret < 0)
return ret;
/* Setting a torch brightness needs to have immediate effect */
led_cdev->flags &= ~SET_BRIGHTNESS_ASYNC;
led_cdev->flags |= SET_BRIGHTNESS_SYNC;
return 0;
}
EXPORT_SYMBOL_GPL(led_classdev_flash_register);
......
......@@ -109,7 +109,7 @@ static const struct attribute_group *led_groups[] = {
void led_classdev_suspend(struct led_classdev *led_cdev)
{
led_cdev->flags |= LED_SUSPENDED;
led_cdev->brightness_set(led_cdev, 0);
led_set_brightness_nopm(led_cdev, 0);
}
EXPORT_SYMBOL_GPL(led_classdev_suspend);
......@@ -119,7 +119,7 @@ EXPORT_SYMBOL_GPL(led_classdev_suspend);
*/
void led_classdev_resume(struct led_classdev *led_cdev)
{
led_cdev->brightness_set(led_cdev, led_cdev->brightness);
led_set_brightness_nopm(led_cdev, led_cdev->brightness);
if (led_cdev->flash_resume)
led_cdev->flash_resume(led_cdev);
......@@ -215,8 +215,6 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
if (!led_cdev->max_brightness)
led_cdev->max_brightness = LED_FULL;
led_cdev->flags |= SET_BRIGHTNESS_ASYNC;
led_update_brightness(led_cdev);
led_init_core(led_cdev);
......@@ -247,12 +245,13 @@ void led_classdev_unregister(struct led_classdev *led_cdev)
up_write(&led_cdev->trigger_lock);
#endif
cancel_work_sync(&led_cdev->set_brightness_work);
/* Stop blinking */
led_stop_software_blink(led_cdev);
led_set_brightness(led_cdev, LED_OFF);
flush_work(&led_cdev->set_brightness_work);
device_unregister(led_cdev->dev);
down_write(&leds_list_lock);
......
......@@ -32,7 +32,7 @@ static void led_timer_function(unsigned long data)
unsigned long delay;
if (!led_cdev->blink_delay_on || !led_cdev->blink_delay_off) {
led_set_brightness_async(led_cdev, LED_OFF);
led_set_brightness_nosleep(led_cdev, LED_OFF);
return;
}
......@@ -44,23 +44,23 @@ static void led_timer_function(unsigned long data)
brightness = led_get_brightness(led_cdev);
if (!brightness) {
/* Time to switch the LED on. */
if (led_cdev->delayed_set_value) {
led_cdev->blink_brightness =
led_cdev->delayed_set_value;
led_cdev->delayed_set_value = 0;
}
brightness = led_cdev->blink_brightness;
delay = led_cdev->blink_delay_on;
} else {
/* Store the current brightness value to be able
* to restore it when the delay_off period is over.
* Do it only if there is no pending blink brightness
* change, to avoid overwriting the new value.
*/
if (!(led_cdev->flags & LED_BLINK_BRIGHTNESS_CHANGE))
led_cdev->blink_brightness = brightness;
else
led_cdev->flags &= ~LED_BLINK_BRIGHTNESS_CHANGE;
brightness = LED_OFF;
delay = led_cdev->blink_delay_off;
}
led_set_brightness_async(led_cdev, brightness);
led_set_brightness_nosleep(led_cdev, brightness);
/* Return in next iteration if led is in one-shot mode and we are in
* the final blink state so that the led is toggled each delay_on +
......@@ -83,10 +83,24 @@ static void set_brightness_delayed(struct work_struct *ws)
{
struct led_classdev *led_cdev =
container_of(ws, struct led_classdev, set_brightness_work);
int ret = 0;
if (led_cdev->flags & LED_BLINK_DISABLE) {
led_cdev->delayed_set_value = LED_OFF;
led_stop_software_blink(led_cdev);
led_cdev->flags &= ~LED_BLINK_DISABLE;
}
led_set_brightness_async(led_cdev, led_cdev->delayed_set_value);
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)
dev_err(led_cdev->dev,
"Setting an LED's brightness failed (%d)\n", ret);
}
static void led_set_software_blink(struct led_classdev *led_cdev,
......@@ -106,13 +120,14 @@ static void led_set_software_blink(struct led_classdev *led_cdev,
/* never on - just set to off */
if (!delay_on) {
led_set_brightness_async(led_cdev, LED_OFF);
led_set_brightness_nosleep(led_cdev, LED_OFF);
return;
}
/* never off - just set to brightness */
if (!delay_off) {
led_set_brightness_async(led_cdev, led_cdev->blink_brightness);
led_set_brightness_nosleep(led_cdev,
led_cdev->blink_brightness);
return;
}
......@@ -156,7 +171,7 @@ void led_blink_set(struct led_classdev *led_cdev,
led_blink_setup(led_cdev, delay_on, delay_off);
}
EXPORT_SYMBOL(led_blink_set);
EXPORT_SYMBOL_GPL(led_blink_set);
void led_blink_set_oneshot(struct led_classdev *led_cdev,
unsigned long *delay_on,
......@@ -177,7 +192,7 @@ void led_blink_set_oneshot(struct led_classdev *led_cdev,
led_blink_setup(led_cdev, delay_on, delay_off);
}
EXPORT_SYMBOL(led_blink_set_oneshot);
EXPORT_SYMBOL_GPL(led_blink_set_oneshot);
void led_stop_software_blink(struct led_classdev *led_cdev)
{
......@@ -190,29 +205,74 @@ EXPORT_SYMBOL_GPL(led_stop_software_blink);
void led_set_brightness(struct led_classdev *led_cdev,
enum led_brightness brightness)
{
int ret = 0;
/* delay brightness if soft-blink is active */
/*
* In case blinking is on delay brightness setting
* until the next timer tick.
*/
if (led_cdev->blink_delay_on || led_cdev->blink_delay_off) {
led_cdev->delayed_set_value = brightness;
if (brightness == LED_OFF)
/*
* If we need to disable soft blinking delegate this to the
* work queue task to avoid problems in case we are called
* from hard irq context.
*/
if (brightness == LED_OFF) {
led_cdev->flags |= LED_BLINK_DISABLE;
schedule_work(&led_cdev->set_brightness_work);
} else {
led_cdev->flags |= LED_BLINK_BRIGHTNESS_CHANGE;
led_cdev->blink_brightness = brightness;
}
return;
}
if (led_cdev->flags & SET_BRIGHTNESS_ASYNC) {
led_set_brightness_async(led_cdev, brightness);
led_set_brightness_nosleep(led_cdev, brightness);
}
EXPORT_SYMBOL_GPL(led_set_brightness);
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);
return;
} else if (led_cdev->flags & SET_BRIGHTNESS_SYNC)
ret = led_set_brightness_sync(led_cdev, brightness);
else
ret = -EINVAL;
}
if (ret < 0)
dev_dbg(led_cdev->dev, "Setting LED brightness failed (%d)\n",
ret);
/* If brightness setting can sleep, delegate it to a work queue task */
led_cdev->delayed_set_value = value;
schedule_work(&led_cdev->set_brightness_work);
}
EXPORT_SYMBOL_GPL(led_set_brightness_nopm);
void led_set_brightness_nosleep(struct led_classdev *led_cdev,
enum led_brightness value)
{
led_cdev->brightness = min(value, led_cdev->max_brightness);
if (led_cdev->flags & LED_SUSPENDED)
return;
led_set_brightness_nopm(led_cdev, led_cdev->brightness);
}
EXPORT_SYMBOL_GPL(led_set_brightness_nosleep);
int led_set_brightness_sync(struct led_classdev *led_cdev,
enum led_brightness value)
{
if (led_cdev->blink_delay_on || led_cdev->blink_delay_off)
return -EBUSY;
led_cdev->brightness = min(value, led_cdev->max_brightness);
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;
}
EXPORT_SYMBOL(led_set_brightness);
EXPORT_SYMBOL_GPL(led_set_brightness_sync);
int led_update_brightness(struct led_classdev *led_cdev)
{
......@@ -228,7 +288,7 @@ int led_update_brightness(struct led_classdev *led_cdev)
return ret;
}
EXPORT_SYMBOL(led_update_brightness);
EXPORT_SYMBOL_GPL(led_update_brightness);
/* Caller must ensure led_cdev->led_access held */
void led_sysfs_disable(struct led_classdev *led_cdev)
......
......@@ -249,6 +249,34 @@ void led_trigger_unregister(struct led_trigger *trig)
}
EXPORT_SYMBOL_GPL(led_trigger_unregister);
static void devm_led_trigger_release(struct device *dev, void *res)
{
led_trigger_unregister(*(struct led_trigger **)res);
}
int devm_led_trigger_register(struct device *dev,
struct led_trigger *trig)
{
struct led_trigger **dr;
int rc;
dr = devres_alloc(devm_led_trigger_release, sizeof(*dr),
GFP_KERNEL);
if (!dr)
return -ENOMEM;
*dr = trig;
rc = led_trigger_register(trig);
if (rc)
devres_free(dr);
else
devres_add(dev, dr);
return rc;
}
EXPORT_SYMBOL_GPL(devm_led_trigger_register);
/* Simple LED Tigger Interface */
void led_trigger_event(struct led_trigger *trig,
......
......@@ -16,7 +16,6 @@
#include <linux/i2c.h>
#include <linux/leds.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <linux/mfd/88pm860x.h>
#include <linux/module.h>
......@@ -33,7 +32,6 @@
struct pm860x_led {
struct led_classdev cdev;
struct i2c_client *i2c;
struct work_struct work;
struct pm860x_chip *chip;
struct mutex lock;
char name[MFD_NAME_SIZE];
......@@ -69,17 +67,18 @@ static int led_power_set(struct pm860x_chip *chip, int port, int on)
return ret;
}
static void pm860x_led_work(struct work_struct *work)
static int pm860x_led_set(struct led_classdev *cdev,
enum led_brightness value)
{
struct pm860x_led *led;
struct pm860x_led *led = container_of(cdev, struct pm860x_led, cdev);
struct pm860x_chip *chip;
unsigned char buf[3];
int ret;
led = container_of(work, struct pm860x_led, work);
chip = led->chip;
mutex_lock(&led->lock);
led->brightness = value >> 3;
if ((led->current_brightness == 0) && led->brightness) {
led_power_set(chip, led->port, 1);
if (led->iset) {
......@@ -112,15 +111,8 @@ static void pm860x_led_work(struct work_struct *work)
dev_dbg(chip->dev, "Update LED. (reg:%d, brightness:%d)\n",
led->reg_control, led->brightness);
mutex_unlock(&led->lock);
}
static void pm860x_led_set(struct led_classdev *cdev,
enum led_brightness value)
{
struct pm860x_led *data = container_of(cdev, struct pm860x_led, cdev);
data->brightness = value >> 3;
schedule_work(&data->work);
return 0;
}
#ifdef CONFIG_OF
......@@ -213,9 +205,8 @@ static int pm860x_led_probe(struct platform_device *pdev)
data->current_brightness = 0;
data->cdev.name = data->name;
data->cdev.brightness_set = pm860x_led_set;
data->cdev.brightness_set_blocking = pm860x_led_set;
mutex_init(&data->lock);
INIT_WORK(&data->work, pm860x_led_work);
ret = led_classdev_register(chip->dev, &data->cdev);
if (ret < 0) {
......
......@@ -20,7 +20,6 @@
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <media/v4l2-flash-led-class.h>
#define AAT1290_MOVIE_MODE_CURRENT_ADDR 17
......@@ -82,8 +81,6 @@ struct aat1290_led {
/* brightness cache */
unsigned int torch_brightness;
/* assures led-triggers compatibility */
struct work_struct work_brightness_set;
};
static struct aat1290_led *fled_cdev_to_led(
......@@ -92,6 +89,12 @@ static struct aat1290_led *fled_cdev_to_led(
return container_of(fled_cdev, struct aat1290_led, fled_cdev);
}
static struct led_classdev_flash *led_cdev_to_fled_cdev(
struct led_classdev *led_cdev)
{
return container_of(led_cdev, struct led_classdev_flash, led_cdev);
}
static void aat1290_as2cwire_write(struct aat1290_led *led, int addr, int value)
{
int i;
......@@ -134,9 +137,14 @@ static void aat1290_set_flash_safety_timer(struct aat1290_led *led,
flash_tm_reg);
}
static void aat1290_brightness_set(struct aat1290_led *led,
/* LED subsystem callbacks */
static int aat1290_led_brightness_set(struct led_classdev *led_cdev,
enum led_brightness brightness)
{
struct led_classdev_flash *fled_cdev = led_cdev_to_fled_cdev(led_cdev);
struct aat1290_led *led = fled_cdev_to_led(fled_cdev);
mutex_lock(&led->lock);
if (brightness == 0) {
......@@ -158,35 +166,6 @@ static void aat1290_brightness_set(struct aat1290_led *led,
}
mutex_unlock(&led->lock);
}
/* LED subsystem callbacks */
static void aat1290_brightness_set_work(struct work_struct *work)
{
struct aat1290_led *led =
container_of(work, struct aat1290_led, work_brightness_set);
aat1290_brightness_set(led, led->torch_brightness);
}
static void aat1290_led_brightness_set(struct led_classdev *led_cdev,
enum led_brightness brightness)
{
struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
struct aat1290_led *led = fled_cdev_to_led(fled_cdev);
led->torch_brightness = brightness;
schedule_work(&led->work_brightness_set);
}
static int aat1290_led_brightness_set_sync(struct led_classdev *led_cdev,
enum led_brightness brightness)
{
struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
struct aat1290_led *led = fled_cdev_to_led(fled_cdev);
aat1290_brightness_set(led, brightness);
return 0;
}
......@@ -296,7 +275,7 @@ static int aat1290_led_parse_dt(struct aat1290_led *led,
if (ret < 0) {
dev_err(dev,
"flash-max-microamp DT property missing\n");
return ret;
goto err_parse_dt;
}
ret = of_property_read_u32(child_node, "flash-max-timeout-us",
......@@ -304,13 +283,14 @@ static int aat1290_led_parse_dt(struct aat1290_led *led,
if (ret < 0) {
dev_err(dev,
"flash-max-timeout-us DT property missing\n");
return ret;
goto err_parse_dt;
}
of_node_put(child_node);
*sub_node = child_node;
err_parse_dt:
of_node_put(child_node);
return ret;
}
......@@ -509,11 +489,9 @@ static int aat1290_led_probe(struct platform_device *pdev)
mutex_init(&led->lock);
/* Initialize LED Flash class device */
led_cdev->brightness_set = aat1290_led_brightness_set;
led_cdev->brightness_set_sync = aat1290_led_brightness_set_sync;
led_cdev->brightness_set_blocking = aat1290_led_brightness_set;
led_cdev->max_brightness = led_cfg.max_brightness;
led_cdev->flags |= LED_DEV_CAP_FLASH;
INIT_WORK(&led->work_brightness_set, aat1290_brightness_set_work);
aat1290_init_flash_timeout(led, &led_cfg);
......@@ -548,7 +526,6 @@ static int aat1290_led_remove(struct platform_device *pdev)
v4l2_flash_release(led->v4l2_flash);
led_classdev_flash_unregister(&led->fled_cdev);
cancel_work_sync(&led->work_brightness_set);
mutex_destroy(&led->lock);
......
......@@ -17,34 +17,24 @@
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/leds.h>
#include <linux/workqueue.h>
#include <linux/mfd/adp5520.h>
#include <linux/slab.h>
struct adp5520_led {
struct led_classdev cdev;
struct work_struct work;
struct device *master;
enum led_brightness new_brightness;
int id;
int flags;
};
static void adp5520_led_work(struct work_struct *work)
{
struct adp5520_led *led = container_of(work, struct adp5520_led, work);
adp5520_write(led->master, ADP5520_LED1_CURRENT + led->id - 1,
led->new_brightness >> 2);
}
static void adp5520_led_set(struct led_classdev *led_cdev,
static int adp5520_led_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
struct adp5520_led *led;
led = container_of(led_cdev, struct adp5520_led, cdev);
led->new_brightness = value;
schedule_work(&led->work);
return adp5520_write(led->master, ADP5520_LED1_CURRENT + led->id - 1,
value >> 2);
}
static int adp5520_led_setup(struct adp5520_led *led)
......@@ -135,7 +125,7 @@ static int adp5520_led_probe(struct platform_device *pdev)
led_dat->cdev.name = cur_led->name;
led_dat->cdev.default_trigger = cur_led->default_trigger;
led_dat->cdev.brightness_set = adp5520_led_set;
led_dat->cdev.brightness_set_blocking = adp5520_led_set;
led_dat->cdev.brightness = LED_OFF;
if (cur_led->flags & ADP5520_FLAG_LED_MASK)
......@@ -146,9 +136,6 @@ static int adp5520_led_probe(struct platform_device *pdev)
led_dat->id = led_dat->flags & ADP5520_FLAG_LED_MASK;
led_dat->master = pdev->dev.parent;
led_dat->new_brightness = LED_OFF;
INIT_WORK(&led_dat->work, adp5520_led_work);
ret = led_classdev_register(led_dat->master, &led_dat->cdev);
if (ret) {
......@@ -170,10 +157,8 @@ static int adp5520_led_probe(struct platform_device *pdev)
err:
if (i > 0) {
for (i = i - 1; i >= 0; i--) {
for (i = i - 1; i >= 0; i--)
led_classdev_unregister(&led[i].cdev);
cancel_work_sync(&led[i].work);
}
}
return ret;
......@@ -192,7 +177,6 @@ static int adp5520_led_remove(struct platform_device *pdev)
for (i = 0; i < pdata->num_leds; i++) {
led_classdev_unregister(&led[i].cdev);
cancel_work_sync(&led[i].work);
}
return 0;
......
......@@ -48,10 +48,10 @@
BCM6328_SERIAL_LED_SHIFT_DIR)
#define BCM6328_LED_MODE_MASK 3
#define BCM6328_LED_MODE_OFF 0
#define BCM6328_LED_MODE_ON 0
#define BCM6328_LED_MODE_FAST 1
#define BCM6328_LED_MODE_BLINK 2
#define BCM6328_LED_MODE_ON 3
#define BCM6328_LED_MODE_OFF 3
#define BCM6328_LED_SHIFT(X) ((X) << 1)
/**
......@@ -76,12 +76,20 @@ struct bcm6328_led {
static void bcm6328_led_write(void __iomem *reg, unsigned long data)
{
#ifdef CONFIG_CPU_BIG_ENDIAN
iowrite32be(data, reg);
#else
writel(data, reg);
#endif
}
static unsigned long bcm6328_led_read(void __iomem *reg)
{
#ifdef CONFIG_CPU_BIG_ENDIAN
return ioread32be(reg);
#else
return readl(reg);
#endif
}
/**
......@@ -126,34 +134,45 @@ static void bcm6328_led_set(struct led_classdev *led_cdev,
*(led->blink_leds) &= ~BIT(led->pin);
if ((led->active_low && value == LED_OFF) ||
(!led->active_low && value != LED_OFF))
bcm6328_led_mode(led, BCM6328_LED_MODE_OFF);
else
bcm6328_led_mode(led, BCM6328_LED_MODE_ON);
else
bcm6328_led_mode(led, BCM6328_LED_MODE_OFF);
spin_unlock_irqrestore(led->lock, flags);
}
static unsigned long bcm6328_blink_delay(unsigned long delay)
{
unsigned long bcm6328_delay;
bcm6328_delay = delay + BCM6328_LED_INTERVAL_MS / 2;
bcm6328_delay = bcm6328_delay / BCM6328_LED_INTERVAL_MS;
if (bcm6328_delay == 0)
bcm6328_delay = 1;
return bcm6328_delay;
}
static int bcm6328_blink_set(struct led_classdev *led_cdev,
unsigned long *delay_on, unsigned long *delay_off)
{
struct bcm6328_led *led =
container_of(led_cdev, struct bcm6328_led, cdev);
unsigned long delay, flags;
int rc;
if (!*delay_on)
*delay_on = BCM6328_LED_DEF_DELAY;
if (!*delay_off)
*delay_off = BCM6328_LED_DEF_DELAY;
if (*delay_on != *delay_off) {
delay = bcm6328_blink_delay(*delay_on);
if (delay != bcm6328_blink_delay(*delay_off)) {
dev_dbg(led_cdev->dev,
"fallback to soft blinking (delay_on != delay_off)\n");
return -EINVAL;
}
delay = *delay_on / BCM6328_LED_INTERVAL_MS;
if (delay == 0)
delay = 1;
else if (delay > BCM6328_LED_INTV_MASK) {
if (delay > BCM6328_LED_INTV_MASK) {
dev_dbg(led_cdev->dev,
"fallback to soft blinking (delay > %ums)\n",
BCM6328_LED_INTV_MASK * BCM6328_LED_INTERVAL_MS);
......@@ -175,16 +194,15 @@ static int bcm6328_blink_set(struct led_classdev *led_cdev,
bcm6328_led_write(led->mem + BCM6328_REG_INIT, val);
bcm6328_led_mode(led, BCM6328_LED_MODE_BLINK);
spin_unlock_irqrestore(led->lock, flags);
rc = 0;
} else {
spin_unlock_irqrestore(led->lock, flags);
dev_dbg(led_cdev->dev,
"fallback to soft blinking (delay already set)\n");
return -EINVAL;
rc = -EINVAL;
}
spin_unlock_irqrestore(led->lock, flags);
return 0;
return rc;
}
static int bcm6328_hwled(struct device *dev, struct device_node *nc, u32 reg,
......@@ -264,7 +282,6 @@ static int bcm6328_led(struct device *dev, struct device_node *nc, u32 reg,
unsigned long *blink_leds, unsigned long *blink_delay)
{
struct bcm6328_led *led;
unsigned long flags;
const char *state;
int rc;
......@@ -286,7 +303,6 @@ static int bcm6328_led(struct device *dev, struct device_node *nc, u32 reg,
"linux,default-trigger",
NULL);
spin_lock_irqsave(lock, flags);
if (!of_property_read_string(nc, "default-state", &state)) {
if (!strcmp(state, "on")) {
led->cdev.brightness = LED_FULL;
......@@ -303,8 +319,8 @@ static int bcm6328_led(struct device *dev, struct device_node *nc, u32 reg,
val = bcm6328_led_read(mode) >>
BCM6328_LED_SHIFT(shift % 16);
val &= BCM6328_LED_MODE_MASK;
if ((led->active_low && val == BCM6328_LED_MODE_ON) ||
(!led->active_low && val == BCM6328_LED_MODE_OFF))
if ((led->active_low && val == BCM6328_LED_MODE_OFF) ||
(!led->active_low && val == BCM6328_LED_MODE_ON))
led->cdev.brightness = LED_FULL;
else
led->cdev.brightness = LED_OFF;
......@@ -315,12 +331,7 @@ static int bcm6328_led(struct device *dev, struct device_node *nc, u32 reg,
led->cdev.brightness = LED_OFF;
}
if ((led->active_low && led->cdev.brightness == LED_FULL) ||
(!led->active_low && led->cdev.brightness == LED_OFF))
bcm6328_led_mode(led, BCM6328_LED_MODE_ON);
else
bcm6328_led_mode(led, BCM6328_LED_MODE_OFF);
spin_unlock_irqrestore(lock, flags);
bcm6328_led_set(&led->cdev, led->cdev.brightness);
led->cdev.brightness_set = bcm6328_led_set;
led->cdev.blink_set = bcm6328_blink_set;
......@@ -341,7 +352,7 @@ static int bcm6328_leds_probe(struct platform_device *pdev)
struct device_node *child;
struct resource *mem_r;
void __iomem *mem;
spinlock_t *lock;
spinlock_t *lock; /* memory lock */
unsigned long val, *blink_leds, *blink_delay;
mem_r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
......
......@@ -49,12 +49,20 @@ struct bcm6358_led {
static void bcm6358_led_write(void __iomem *reg, unsigned long data)
{
#ifdef CONFIG_CPU_BIG_ENDIAN
iowrite32be(data, reg);
#else
writel(data, reg);
#endif
}
static unsigned long bcm6358_led_read(void __iomem *reg)
{
#ifdef CONFIG_CPU_BIG_ENDIAN
return ioread32be(reg);
#else
return readl(reg);
#endif
}
static unsigned long bcm6358_led_busy(void __iomem *mem)
......@@ -68,12 +76,15 @@ static unsigned long bcm6358_led_busy(void __iomem *mem)
return val;
}
static void bcm6358_led_mode(struct bcm6358_led *led, unsigned long value)
static void bcm6358_led_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
unsigned long val;
struct bcm6358_led *led =
container_of(led_cdev, struct bcm6358_led, cdev);
unsigned long flags, val;
spin_lock_irqsave(led->lock, flags);
bcm6358_led_busy(led->mem);
val = bcm6358_led_read(led->mem + BCM6358_REG_MODE);
if ((led->active_low && value == LED_OFF) ||
(!led->active_low && value != LED_OFF))
......@@ -81,17 +92,6 @@ static void bcm6358_led_mode(struct bcm6358_led *led, unsigned long value)
else
val &= ~(BIT(led->pin));
bcm6358_led_write(led->mem + BCM6358_REG_MODE, val);
}
static void bcm6358_led_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
struct bcm6358_led *led =
container_of(led_cdev, struct bcm6358_led, cdev);
unsigned long flags;
spin_lock_irqsave(led->lock, flags);
bcm6358_led_mode(led, value);
spin_unlock_irqrestore(led->lock, flags);
}
......@@ -99,7 +99,6 @@ static int bcm6358_led(struct device *dev, struct device_node *nc, u32 reg,
void __iomem *mem, spinlock_t *lock)
{
struct bcm6358_led *led;
unsigned long flags;
const char *state;
int rc;
......@@ -119,15 +118,11 @@ static int bcm6358_led(struct device *dev, struct device_node *nc, u32 reg,
"linux,default-trigger",
NULL);
spin_lock_irqsave(lock, flags);
if (!of_property_read_string(nc, "default-state", &state)) {
if (!strcmp(state, "on")) {
led->cdev.brightness = LED_FULL;
} else if (!strcmp(state, "keep")) {
unsigned long val;
bcm6358_led_busy(led->mem);
val = bcm6358_led_read(led->mem + BCM6358_REG_MODE);
val &= BIT(led->pin);
if ((led->active_low && !val) ||
......@@ -141,8 +136,8 @@ static int bcm6358_led(struct device *dev, struct device_node *nc, u32 reg,
} else {
led->cdev.brightness = LED_OFF;
}
bcm6358_led_mode(led, led->cdev.brightness);
spin_unlock_irqrestore(lock, flags);
bcm6358_led_set(&led->cdev, led->cdev.brightness);
led->cdev.brightness_set = bcm6358_led_set;
......
......@@ -72,7 +72,6 @@ struct bd2802_led {
struct bd2802_led_platform_data *pdata;
struct i2c_client *client;
struct rw_semaphore rwsem;
struct work_struct work;
struct led_state led[2];
......@@ -518,29 +517,22 @@ static struct device_attribute *bd2802_attributes[] = {
&bd2802_rgb_current_attr,
};
static void bd2802_led_work(struct work_struct *work)
{
struct bd2802_led *led = container_of(work, struct bd2802_led, work);
if (led->state)
bd2802_turn_on(led, led->led_id, led->color, led->state);
else
bd2802_turn_off(led, led->led_id, led->color);
}
#define BD2802_CONTROL_RGBS(name, id, clr) \
static void bd2802_set_##name##_brightness(struct led_classdev *led_cdev,\
static int bd2802_set_##name##_brightness(struct led_classdev *led_cdev,\
enum led_brightness value) \
{ \
struct bd2802_led *led = \
container_of(led_cdev, struct bd2802_led, cdev_##name); \
led->led_id = id; \
led->color = clr; \
if (value == LED_OFF) \
if (value == LED_OFF) { \
led->state = BD2802_OFF; \
else \
bd2802_turn_off(led, led->led_id, led->color); \
} else { \
led->state = BD2802_ON; \
schedule_work(&led->work); \
bd2802_turn_on(led, led->led_id, led->color, BD2802_ON);\
} \
return 0; \
} \
static int bd2802_set_##name##_blink(struct led_classdev *led_cdev, \
unsigned long *delay_on, unsigned long *delay_off) \
......@@ -552,7 +544,7 @@ static int bd2802_set_##name##_blink(struct led_classdev *led_cdev, \
led->led_id = id; \
led->color = clr; \
led->state = BD2802_BLINK; \
schedule_work(&led->work); \
bd2802_turn_on(led, led->led_id, led->color, BD2802_BLINK); \
return 0; \
}
......@@ -567,11 +559,9 @@ static int bd2802_register_led_classdev(struct bd2802_led *led)
{
int ret;
INIT_WORK(&led->work, bd2802_led_work);
led->cdev_led1r.name = "led1_R";
led->cdev_led1r.brightness = LED_OFF;
led->cdev_led1r.brightness_set = bd2802_set_led1r_brightness;
led->cdev_led1r.brightness_set_blocking = bd2802_set_led1r_brightness;
led->cdev_led1r.blink_set = bd2802_set_led1r_blink;
ret = led_classdev_register(&led->client->dev, &led->cdev_led1r);
......@@ -583,7 +573,7 @@ static int bd2802_register_led_classdev(struct bd2802_led *led)
led->cdev_led1g.name = "led1_G";
led->cdev_led1g.brightness = LED_OFF;
led->cdev_led1g.brightness_set = bd2802_set_led1g_brightness;
led->cdev_led1g.brightness_set_blocking = bd2802_set_led1g_brightness;
led->cdev_led1g.blink_set = bd2802_set_led1g_blink;
ret = led_classdev_register(&led->client->dev, &led->cdev_led1g);
......@@ -595,7 +585,7 @@ static int bd2802_register_led_classdev(struct bd2802_led *led)
led->cdev_led1b.name = "led1_B";
led->cdev_led1b.brightness = LED_OFF;
led->cdev_led1b.brightness_set = bd2802_set_led1b_brightness;
led->cdev_led1b.brightness_set_blocking = bd2802_set_led1b_brightness;
led->cdev_led1b.blink_set = bd2802_set_led1b_blink;
ret = led_classdev_register(&led->client->dev, &led->cdev_led1b);
......@@ -607,7 +597,7 @@ static int bd2802_register_led_classdev(struct bd2802_led *led)
led->cdev_led2r.name = "led2_R";
led->cdev_led2r.brightness = LED_OFF;
led->cdev_led2r.brightness_set = bd2802_set_led2r_brightness;
led->cdev_led2r.brightness_set_blocking = bd2802_set_led2r_brightness;
led->cdev_led2r.blink_set = bd2802_set_led2r_blink;
ret = led_classdev_register(&led->client->dev, &led->cdev_led2r);
......@@ -619,7 +609,7 @@ static int bd2802_register_led_classdev(struct bd2802_led *led)
led->cdev_led2g.name = "led2_G";
led->cdev_led2g.brightness = LED_OFF;
led->cdev_led2g.brightness_set = bd2802_set_led2g_brightness;
led->cdev_led2g.brightness_set_blocking = bd2802_set_led2g_brightness;
led->cdev_led2g.blink_set = bd2802_set_led2g_blink;
ret = led_classdev_register(&led->client->dev, &led->cdev_led2g);
......@@ -631,7 +621,7 @@ static int bd2802_register_led_classdev(struct bd2802_led *led)
led->cdev_led2b.name = "led2_B";
led->cdev_led2b.brightness = LED_OFF;
led->cdev_led2b.brightness_set = bd2802_set_led2b_brightness;
led->cdev_led2b.brightness_set_blocking = bd2802_set_led2b_brightness;
led->cdev_led2b.blink_set = bd2802_set_led2b_blink;
led->cdev_led2b.flags |= LED_CORE_SUSPENDRESUME;
......@@ -661,7 +651,6 @@ static int bd2802_register_led_classdev(struct bd2802_led *led)
static void bd2802_unregister_led_classdev(struct bd2802_led *led)
{
cancel_work_sync(&led->work);
led_classdev_unregister(&led->cdev_led2b);
led_classdev_unregister(&led->cdev_led2g);
led_classdev_unregister(&led->cdev_led2r);
......
......@@ -39,16 +39,9 @@ struct blinkm_led {
struct i2c_client *i2c_client;
struct led_classdev led_cdev;
int id;
atomic_t active;
};
struct blinkm_work {
struct blinkm_led *blinkm_led;
struct work_struct work;
};
#define cdev_to_blmled(c) container_of(c, struct blinkm_led, led_cdev)
#define work_to_blmwork(c) container_of(c, struct blinkm_work, work)
struct blinkm_data {
struct i2c_client *i2c_client;
......@@ -439,65 +432,30 @@ static int blinkm_transfer_hw(struct i2c_client *client, int cmd)
return 0;
}
static void led_work(struct work_struct *work)
{
int ret;
struct blinkm_led *led;
struct blinkm_data *data;
struct blinkm_work *blm_work = work_to_blmwork(work);
led = blm_work->blinkm_led;
data = i2c_get_clientdata(led->i2c_client);
ret = blinkm_transfer_hw(led->i2c_client, BLM_GO_RGB);
atomic_dec(&led->active);
dev_dbg(&led->i2c_client->dev,
"# DONE # next_red = %d, next_green = %d,"
" next_blue = %d, active = %d\n",
data->next_red, data->next_green,
data->next_blue, atomic_read(&led->active));
kfree(blm_work);
}
static int blinkm_led_common_set(struct led_classdev *led_cdev,
enum led_brightness value, int color)
{
/* led_brightness is 0, 127 or 255 - we just use it here as-is */
struct blinkm_led *led = cdev_to_blmled(led_cdev);
struct blinkm_data *data = i2c_get_clientdata(led->i2c_client);
struct blinkm_work *bl_work;
switch (color) {
case RED:
/* bail out if there's no change */
if (data->next_red == (u8) value)
return 0;
/* we assume a quite fast sequence here ([off]->on->off)
* think of network led trigger - we cannot blink that fast, so
* in case we already have a off->on->off transition queued up,
* we refuse to queue up more.
* Revisit: fast-changing brightness. */
if (atomic_read(&led->active) > 1)
return 0;
data->next_red = (u8) value;
break;
case GREEN:
/* bail out if there's no change */
if (data->next_green == (u8) value)
return 0;
/* we assume a quite fast sequence here ([off]->on->off)
* Revisit: fast-changing brightness. */
if (atomic_read(&led->active) > 1)
return 0;
data->next_green = (u8) value;
break;
case BLUE:
/* bail out if there's no change */
if (data->next_blue == (u8) value)
return 0;
/* we assume a quite fast sequence here ([off]->on->off)
* Revisit: fast-changing brightness. */
if (atomic_read(&led->active) > 1)
return 0;
data->next_blue = (u8) value;
break;
......@@ -506,42 +464,31 @@ static int blinkm_led_common_set(struct led_classdev *led_cdev,
return -EINVAL;
}
bl_work = kzalloc(sizeof(*bl_work), GFP_ATOMIC);
if (!bl_work)
return -ENOMEM;
atomic_inc(&led->active);
blinkm_transfer_hw(led->i2c_client, BLM_GO_RGB);
dev_dbg(&led->i2c_client->dev,
"#TO_SCHED# next_red = %d, next_green = %d,"
" next_blue = %d, active = %d\n",
"# DONE # next_red = %d, next_green = %d,"
" next_blue = %d\n",
data->next_red, data->next_green,
data->next_blue, atomic_read(&led->active));
/* a fresh work _item_ for each change */
bl_work->blinkm_led = led;
INIT_WORK(&bl_work->work, led_work);
/* queue work in own queue for easy sync on exit*/
schedule_work(&bl_work->work);
data->next_blue);
return 0;
}
static void blinkm_led_red_set(struct led_classdev *led_cdev,
static int blinkm_led_red_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
blinkm_led_common_set(led_cdev, value, RED);
return blinkm_led_common_set(led_cdev, value, RED);
}
static void blinkm_led_green_set(struct led_classdev *led_cdev,
static int blinkm_led_green_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
blinkm_led_common_set(led_cdev, value, GREEN);
return blinkm_led_common_set(led_cdev, value, GREEN);
}
static void blinkm_led_blue_set(struct led_classdev *led_cdev,
static int blinkm_led_blue_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
blinkm_led_common_set(led_cdev, value, BLUE);
return blinkm_led_common_set(led_cdev, value, BLUE);
}
static void blinkm_init_hw(struct i2c_client *client)
......@@ -669,7 +616,6 @@ static int blinkm_probe(struct i2c_client *client,
led[i]->id = i;
led[i]->led_cdev.max_brightness = 255;
led[i]->led_cdev.flags = LED_CORE_SUSPENDRESUME;
atomic_set(&led[i]->active, 0);
switch (i) {
case RED:
snprintf(blinkm_led_name, sizeof(blinkm_led_name),
......@@ -677,7 +623,8 @@ static int blinkm_probe(struct i2c_client *client,
client->adapter->nr,
client->addr);
led[i]->led_cdev.name = blinkm_led_name;
led[i]->led_cdev.brightness_set = blinkm_led_red_set;
led[i]->led_cdev.brightness_set_blocking =
blinkm_led_red_set;
err = led_classdev_register(&client->dev,
&led[i]->led_cdev);
if (err < 0) {
......@@ -693,7 +640,8 @@ static int blinkm_probe(struct i2c_client *client,
client->adapter->nr,
client->addr);
led[i]->led_cdev.name = blinkm_led_name;
led[i]->led_cdev.brightness_set = blinkm_led_green_set;
led[i]->led_cdev.brightness_set_blocking =
blinkm_led_green_set;
err = led_classdev_register(&client->dev,
&led[i]->led_cdev);
if (err < 0) {
......@@ -709,7 +657,8 @@ static int blinkm_probe(struct i2c_client *client,
client->adapter->nr,
client->addr);
led[i]->led_cdev.name = blinkm_led_name;
led[i]->led_cdev.brightness_set = blinkm_led_blue_set;
led[i]->led_cdev.brightness_set_blocking =
blinkm_led_blue_set;
err = led_classdev_register(&client->dev,
&led[i]->led_cdev);
if (err < 0) {
......@@ -746,10 +695,8 @@ static int blinkm_remove(struct i2c_client *client)
int i;
/* make sure no workqueue entries are pending */
for (i = 0; i < 3; i++) {
flush_scheduled_work();
for (i = 0; i < 3; i++)
led_classdev_unregister(&data->blinkm_leds[i].led_cdev);
}
/* reset rgb */
data->next_red = 0x00;
......
......@@ -16,7 +16,6 @@
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/leds.h>
#include <linux/workqueue.h>
#include <linux/mfd/da903x.h>
#include <linux/slab.h>
......@@ -33,9 +32,7 @@
struct da903x_led {
struct led_classdev cdev;
struct work_struct work;
struct device *master;
enum led_brightness new_brightness;
int id;
int flags;
};
......@@ -43,11 +40,13 @@ struct da903x_led {
#define DA9030_LED_OFFSET(id) ((id) - DA9030_ID_LED_1)
#define DA9034_LED_OFFSET(id) ((id) - DA9034_ID_LED_1)
static void da903x_led_work(struct work_struct *work)
static int da903x_led_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
struct da903x_led *led = container_of(work, struct da903x_led, work);
struct da903x_led *led =
container_of(led_cdev, struct da903x_led, cdev);
uint8_t val;
int offset;
int offset, ret = -EINVAL;
switch (led->id) {
case DA9030_ID_LED_1:
......@@ -57,37 +56,31 @@ static void da903x_led_work(struct work_struct *work)
case DA9030_ID_LED_PC:
offset = DA9030_LED_OFFSET(led->id);
val = led->flags & ~0x87;
val |= (led->new_brightness) ? 0x80 : 0; /* EN bit */
val |= (0x7 - (led->new_brightness >> 5)) & 0x7; /* PWM<2:0> */
da903x_write(led->master, DA9030_LED1_CONTROL + offset, val);
val |= value ? 0x80 : 0; /* EN bit */
val |= (0x7 - (value >> 5)) & 0x7; /* PWM<2:0> */
ret = da903x_write(led->master, DA9030_LED1_CONTROL + offset,
val);
break;
case DA9030_ID_VIBRA:
val = led->flags & ~0x80;
val |= (led->new_brightness) ? 0x80 : 0; /* EN bit */
da903x_write(led->master, DA9030_MISC_CONTROL_A, val);
val |= value ? 0x80 : 0; /* EN bit */
ret = da903x_write(led->master, DA9030_MISC_CONTROL_A, val);
break;
case DA9034_ID_LED_1:
case DA9034_ID_LED_2:
offset = DA9034_LED_OFFSET(led->id);
val = (led->new_brightness * 0x5f / LED_FULL) & 0x7f;
val = (value * 0x5f / LED_FULL) & 0x7f;
val |= (led->flags & DA9034_LED_RAMP) ? 0x80 : 0;
da903x_write(led->master, DA9034_LED1_CONTROL + offset, val);
ret = da903x_write(led->master, DA9034_LED1_CONTROL + offset,
val);
break;
case DA9034_ID_VIBRA:
val = led->new_brightness & 0xfe;
da903x_write(led->master, DA9034_VIBRA, val);
val = value & 0xfe;
ret = da903x_write(led->master, DA9034_VIBRA, val);
break;
}
}
static void da903x_led_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
struct da903x_led *led;
led = container_of(led_cdev, struct da903x_led, cdev);
led->new_brightness = value;
schedule_work(&led->work);
return ret;
}
static int da903x_led_probe(struct platform_device *pdev)
......@@ -113,15 +106,12 @@ static int da903x_led_probe(struct platform_device *pdev)
led->cdev.name = pdata->name;
led->cdev.default_trigger = pdata->default_trigger;
led->cdev.brightness_set = da903x_led_set;
led->cdev.brightness_set_blocking = da903x_led_set;
led->cdev.brightness = LED_OFF;
led->id = id;
led->flags = pdata->flags;
led->master = pdev->dev.parent;
led->new_brightness = LED_OFF;
INIT_WORK(&led->work, da903x_led_work);
ret = led_classdev_register(led->master, &led->cdev);
if (ret) {
......
......@@ -16,7 +16,6 @@
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/leds.h>
#include <linux/workqueue.h>
#include <linux/slab.h>
#include <linux/mfd/da9052/reg.h>
......@@ -32,11 +31,9 @@
struct da9052_led {
struct led_classdev cdev;
struct work_struct work;
struct da9052 *da9052;
unsigned char led_index;
unsigned char id;
int brightness;
};
static unsigned char led_reg[] = {
......@@ -44,12 +41,13 @@ static unsigned char led_reg[] = {
DA9052_LED_CONT_5_REG,
};
static int da9052_set_led_brightness(struct da9052_led *led)
static int da9052_set_led_brightness(struct da9052_led *led,
enum led_brightness brightness)
{
u8 val;
int error;
val = (led->brightness & 0x7f) | DA9052_LED_CONT_DIM;
val = (brightness & 0x7f) | DA9052_LED_CONT_DIM;
error = da9052_reg_write(led->da9052, led_reg[led->led_index], val);
if (error < 0)
......@@ -58,21 +56,13 @@ static int da9052_set_led_brightness(struct da9052_led *led)
return error;
}
static void da9052_led_work(struct work_struct *work)
{
struct da9052_led *led = container_of(work, struct da9052_led, work);
da9052_set_led_brightness(led);
}
static void da9052_led_set(struct led_classdev *led_cdev,
static int da9052_led_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
struct da9052_led *led;
struct da9052_led *led =
container_of(led_cdev, struct da9052_led, cdev);
led = container_of(led_cdev, struct da9052_led, cdev);
led->brightness = value;
schedule_work(&led->work);
return da9052_set_led_brightness(led, value);
}
static int da9052_configure_leds(struct da9052 *da9052)
......@@ -133,13 +123,11 @@ static int da9052_led_probe(struct platform_device *pdev)
for (i = 0; i < pled->num_leds; i++) {
led[i].cdev.name = pled->leds[i].name;
led[i].cdev.brightness_set = da9052_led_set;
led[i].cdev.brightness_set_blocking = da9052_led_set;
led[i].cdev.brightness = LED_OFF;
led[i].cdev.max_brightness = DA9052_MAX_BRIGHTNESS;
led[i].brightness = LED_OFF;
led[i].led_index = pled->leds[i].flags;
led[i].da9052 = dev_get_drvdata(pdev->dev.parent);
INIT_WORK(&led[i].work, da9052_led_work);
error = led_classdev_register(pdev->dev.parent, &led[i].cdev);
if (error) {
......@@ -148,7 +136,8 @@ static int da9052_led_probe(struct platform_device *pdev)
goto err_register;
}
error = da9052_set_led_brightness(&led[i]);
error = da9052_set_led_brightness(&led[i],
led[i].cdev.brightness);
if (error) {
dev_err(&pdev->dev, "Unable to init led %d\n",
led[i].led_index);
......@@ -166,10 +155,8 @@ static int da9052_led_probe(struct platform_device *pdev)
return 0;
err_register:
for (i = i - 1; i >= 0; i--) {
for (i = i - 1; i >= 0; i--)
led_classdev_unregister(&led[i].cdev);
cancel_work_sync(&led[i].work);
}
err:
return error;
}
......@@ -187,10 +174,8 @@ static int da9052_led_remove(struct platform_device *pdev)
pled = pdata->pled;
for (i = 0; i < pled->num_leds; i++) {
led[i].brightness = 0;
da9052_set_led_brightness(&led[i]);
da9052_set_led_brightness(&led[i], LED_OFF);
led_classdev_unregister(&led[i].cdev);
cancel_work_sync(&led[i].work);
}
return 0;
......
......@@ -13,20 +13,15 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <linux/spi/spi.h>
struct dac124s085_led {
struct led_classdev ldev;
struct spi_device *spi;
int id;
int brightness;
char name[sizeof("dac124s085-3")];
struct mutex mutex;
struct work_struct work;
spinlock_t lock;
};
struct dac124s085 {
......@@ -38,29 +33,21 @@ struct dac124s085 {
#define ALL_WRITE_UPDATE (2 << 12)
#define POWER_DOWN_OUTPUT (3 << 12)
static void dac124s085_led_work(struct work_struct *work)
static int dac124s085_set_brightness(struct led_classdev *ldev,
enum led_brightness brightness)
{
struct dac124s085_led *led = container_of(work, struct dac124s085_led,
work);
struct dac124s085_led *led = container_of(ldev, struct dac124s085_led,
ldev);
u16 word;
int ret;
mutex_lock(&led->mutex);
word = cpu_to_le16(((led->id) << 14) | REG_WRITE_UPDATE |
(led->brightness & 0xfff));
spi_write(led->spi, (const u8 *)&word, sizeof(word));
(brightness & 0xfff));
ret = spi_write(led->spi, (const u8 *)&word, sizeof(word));
mutex_unlock(&led->mutex);
}
static void dac124s085_set_brightness(struct led_classdev *ldev,
enum led_brightness brightness)
{
struct dac124s085_led *led = container_of(ldev, struct dac124s085_led,
ldev);
spin_lock(&led->lock);
led->brightness = brightness;
schedule_work(&led->work);
spin_unlock(&led->lock);
return ret;
}
static int dac124s085_probe(struct spi_device *spi)
......@@ -78,16 +65,13 @@ static int dac124s085_probe(struct spi_device *spi)
for (i = 0; i < ARRAY_SIZE(dac->leds); i++) {
led = dac->leds + i;
led->id = i;
led->brightness = LED_OFF;
led->spi = spi;
snprintf(led->name, sizeof(led->name), "dac124s085-%d", i);
spin_lock_init(&led->lock);
INIT_WORK(&led->work, dac124s085_led_work);
mutex_init(&led->mutex);
led->ldev.name = led->name;
led->ldev.brightness = LED_OFF;
led->ldev.max_brightness = 0xfff;
led->ldev.brightness_set = dac124s085_set_brightness;
led->ldev.brightness_set_blocking = dac124s085_set_brightness;
ret = led_classdev_register(&spi->dev, &led->ldev);
if (ret < 0)
goto eledcr;
......@@ -109,10 +93,8 @@ static int dac124s085_remove(struct spi_device *spi)
struct dac124s085 *dac = spi_get_drvdata(spi);
int i;
for (i = 0; i < ARRAY_SIZE(dac->leds); i++) {
for (i = 0; i < ARRAY_SIZE(dac->leds); i++)
led_classdev_unregister(&dac->leds[i].ldev);
cancel_work_sync(&dac->leds[i].work);
}
return 0;
}
......
......@@ -20,32 +20,16 @@
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
struct gpio_led_data {
struct led_classdev cdev;
struct gpio_desc *gpiod;
struct work_struct work;
u8 new_level;
u8 can_sleep;
u8 blinking;
int (*platform_gpio_blink_set)(struct gpio_desc *desc, int state,
unsigned long *delay_on, unsigned long *delay_off);
};
static void gpio_led_work(struct work_struct *work)
{
struct gpio_led_data *led_dat =
container_of(work, struct gpio_led_data, work);
if (led_dat->blinking) {
led_dat->platform_gpio_blink_set(led_dat->gpiod,
led_dat->new_level, NULL, NULL);
led_dat->blinking = 0;
} else
gpiod_set_value_cansleep(led_dat->gpiod, led_dat->new_level);
}
static void gpio_led_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
......@@ -58,23 +42,25 @@ static void gpio_led_set(struct led_classdev *led_cdev,
else
level = 1;
/* Setting GPIOs with I2C/etc requires a task context, and we don't
* seem to have a reliable way to know if we're already in one; so
* let's just assume the worst.
*/
if (led_dat->can_sleep) {
led_dat->new_level = level;
schedule_work(&led_dat->work);
} else {
if (led_dat->blinking) {
led_dat->platform_gpio_blink_set(led_dat->gpiod, level,
NULL, NULL);
led_dat->blinking = 0;
} else
} else {
if (led_dat->can_sleep)
gpiod_set_value_cansleep(led_dat->gpiod, level);
else
gpiod_set_value(led_dat->gpiod, level);
}
}
static int gpio_led_set_blocking(struct led_classdev *led_cdev,
enum led_brightness value)
{
gpio_led_set(led_cdev, value);
return 0;
}
static int gpio_blink_set(struct led_classdev *led_cdev,
unsigned long *delay_on, unsigned long *delay_off)
{
......@@ -125,12 +111,15 @@ static int create_gpio_led(const struct gpio_led *template,
led_dat->cdev.name = template->name;
led_dat->cdev.default_trigger = template->default_trigger;
led_dat->can_sleep = gpiod_cansleep(led_dat->gpiod);
if (!led_dat->can_sleep)
led_dat->cdev.brightness_set = gpio_led_set;
else
led_dat->cdev.brightness_set_blocking = gpio_led_set_blocking;
led_dat->blinking = 0;
if (blink_set) {
led_dat->platform_gpio_blink_set = blink_set;
led_dat->cdev.blink_set = gpio_blink_set;
}
led_dat->cdev.brightness_set = gpio_led_set;
if (template->default_state == LEDS_GPIO_DEFSTATE_KEEP)
state = !!gpiod_get_value_cansleep(led_dat->gpiod);
else
......@@ -143,17 +132,9 @@ static int create_gpio_led(const struct gpio_led *template,
if (ret < 0)
return ret;
INIT_WORK(&led_dat->work, gpio_led_work);
return led_classdev_register(parent, &led_dat->cdev);
}
static void delete_gpio_led(struct gpio_led_data *led)
{
led_classdev_unregister(&led->cdev);
cancel_work_sync(&led->work);
}
struct gpio_leds_priv {
int num_leds;
struct gpio_led_data leds[];
......@@ -233,7 +214,7 @@ static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev)
err:
for (count = priv->num_leds - 1; count >= 0; count--)
delete_gpio_led(&priv->leds[count]);
led_classdev_unregister(&priv->leds[count].cdev);
return ERR_PTR(ret);
}
......@@ -265,7 +246,8 @@ static int gpio_led_probe(struct platform_device *pdev)
if (ret < 0) {
/* On failure: unwind the led creations */
for (i = i - 1; i >= 0; i--)
delete_gpio_led(&priv->leds[i]);
led_classdev_unregister(
&priv->leds[i].cdev);
return ret;
}
}
......@@ -286,7 +268,7 @@ static int gpio_led_remove(struct platform_device *pdev)
int i;
for (i = 0; i < priv->num_leds; i++)
delete_gpio_led(&priv->leds[i]);
led_classdev_unregister(&priv->leds[i].cdev);
return 0;
}
......
......@@ -20,7 +20,7 @@
#define LED_AUTOSTOP (1 << 5) /* LED ON/OFF auto stop set 0:disable, 1:enable */
#define LED_ALWAYS (1 << 6) /* LED Interrupt Mask 0:No mask, 1:mask */
static void micro_leds_brightness_set(struct led_classdev *led_cdev,
static int micro_leds_brightness_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
struct ipaq_micro *micro = dev_get_drvdata(led_cdev->dev->parent->parent);
......@@ -50,7 +50,7 @@ static void micro_leds_brightness_set(struct led_classdev *led_cdev,
msg.tx_data[2] = 1;
msg.tx_data[3] = 0; /* Duty cycle 256 */
}
ipaq_micro_tx_msg_sync(micro, &msg);
return ipaq_micro_tx_msg_sync(micro, &msg);
}
/* Maximum duty cycle in ms 256/10 sec = 25600 ms */
......@@ -102,7 +102,7 @@ static int micro_leds_blink_set(struct led_classdev *led_cdev,
static struct led_classdev micro_led = {
.name = "led-ipaq-micro",
.brightness_set = micro_leds_brightness_set,
.brightness_set_blocking = micro_leds_brightness_set,
.blink_set = micro_leds_blink_set,
.flags = LED_CORE_SUSPENDRESUME,
};
......
......@@ -18,7 +18,6 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/workqueue.h>
/* Value related the movie mode */
#define KTD2692_MOVIE_MODE_CURRENT_LEVELS 16
......@@ -82,7 +81,6 @@ struct ktd2692_context {
/* secures access to the device */
struct mutex lock;
struct regulator *regulator;
struct work_struct work_brightness_set;
struct gpio_desc *aux_gpio;
struct gpio_desc *ctrl_gpio;
......@@ -158,9 +156,12 @@ static void ktd2692_expresswire_write(struct ktd2692_context *led, u8 value)
ktd2692_expresswire_end(led);
}
static void ktd2692_brightness_set(struct ktd2692_context *led,
static int ktd2692_led_brightness_set(struct led_classdev *led_cdev,
enum led_brightness brightness)
{
struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
struct ktd2692_context *led = fled_cdev_to_led(fled_cdev);
mutex_lock(&led->lock);
if (brightness == LED_OFF) {
......@@ -174,33 +175,6 @@ static void ktd2692_brightness_set(struct ktd2692_context *led,
ktd2692_expresswire_write(led, led->mode | KTD2692_REG_MODE_BASE);
mutex_unlock(&led->lock);
}
static void ktd2692_brightness_set_work(struct work_struct *work)
{
struct ktd2692_context *led =
container_of(work, struct ktd2692_context, work_brightness_set);
ktd2692_brightness_set(led, led->torch_brightness);
}
static void ktd2692_led_brightness_set(struct led_classdev *led_cdev,
enum led_brightness brightness)
{
struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
struct ktd2692_context *led = fled_cdev_to_led(fled_cdev);
led->torch_brightness = brightness;
schedule_work(&led->work_brightness_set);
}
static int ktd2692_led_brightness_set_sync(struct led_classdev *led_cdev,
enum led_brightness brightness)
{
struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
struct ktd2692_context *led = fled_cdev_to_led(fled_cdev);
ktd2692_brightness_set(led, brightness);
return 0;
}
......@@ -332,21 +306,24 @@ static int ktd2692_parse_dt(struct ktd2692_context *led, struct device *dev,
&cfg->movie_max_microamp);
if (ret) {
dev_err(dev, "failed to parse led-max-microamp\n");
return ret;
goto err_parse_dt;
}
ret = of_property_read_u32(child_node, "flash-max-microamp",
&cfg->flash_max_microamp);
if (ret) {
dev_err(dev, "failed to parse flash-max-microamp\n");
return ret;
goto err_parse_dt;
}
ret = of_property_read_u32(child_node, "flash-max-timeout-us",
&cfg->flash_max_timeout);
if (ret)
if (ret) {
dev_err(dev, "failed to parse flash-max-timeout-us\n");
goto err_parse_dt;
}
err_parse_dt:
of_node_put(child_node);
return ret;
}
......@@ -381,12 +358,10 @@ static int ktd2692_probe(struct platform_device *pdev)
fled_cdev->ops = &flash_ops;
led_cdev->max_brightness = led_cfg.max_brightness;
led_cdev->brightness_set = ktd2692_led_brightness_set;
led_cdev->brightness_set_sync = ktd2692_led_brightness_set_sync;
led_cdev->brightness_set_blocking = ktd2692_led_brightness_set;
led_cdev->flags |= LED_CORE_SUSPENDRESUME | LED_DEV_CAP_FLASH;
mutex_init(&led->lock);
INIT_WORK(&led->work_brightness_set, ktd2692_brightness_set_work);
platform_set_drvdata(pdev, led);
......@@ -408,7 +383,6 @@ static int ktd2692_remove(struct platform_device *pdev)
int ret;
led_classdev_flash_unregister(&led->fled_cdev);
cancel_work_sync(&led->work_brightness_set);
if (led->regulator) {
ret = regulator_disable(led->regulator);
......
......@@ -17,7 +17,6 @@
#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <linux/mfd/lm3533.h>
......@@ -53,9 +52,6 @@ struct lm3533_led {
struct mutex mutex;
unsigned long flags;
struct work_struct work;
u8 new_brightness;
};
......@@ -123,27 +119,17 @@ static int lm3533_led_pattern_enable(struct lm3533_led *led, int enable)
return ret;
}
static void lm3533_led_work(struct work_struct *work)
{
struct lm3533_led *led = container_of(work, struct lm3533_led, work);
dev_dbg(led->cdev.dev, "%s - %u\n", __func__, led->new_brightness);
if (led->new_brightness == 0)
lm3533_led_pattern_enable(led, 0); /* disable blink */
lm3533_ctrlbank_set_brightness(&led->cb, led->new_brightness);
}
static void lm3533_led_set(struct led_classdev *cdev,
static int lm3533_led_set(struct led_classdev *cdev,
enum led_brightness value)
{
struct lm3533_led *led = to_lm3533_led(cdev);
dev_dbg(led->cdev.dev, "%s - %d\n", __func__, value);
led->new_brightness = value;
schedule_work(&led->work);
if (value == 0)
lm3533_led_pattern_enable(led, 0); /* disable blink */
return lm3533_ctrlbank_set_brightness(&led->cb, value);
}
static enum led_brightness lm3533_led_get(struct led_classdev *cdev)
......@@ -693,7 +679,7 @@ static int lm3533_led_probe(struct platform_device *pdev)
led->lm3533 = lm3533;
led->cdev.name = pdata->name;
led->cdev.default_trigger = pdata->default_trigger;
led->cdev.brightness_set = lm3533_led_set;
led->cdev.brightness_set_blocking = lm3533_led_set;
led->cdev.brightness_get = lm3533_led_get;
led->cdev.blink_set = lm3533_led_blink_set;
led->cdev.brightness = LED_OFF;
......@@ -701,7 +687,6 @@ static int lm3533_led_probe(struct platform_device *pdev)
led->id = pdev->id;
mutex_init(&led->mutex);
INIT_WORK(&led->work, lm3533_led_work);
/* The class framework makes a callback to get brightness during
* registration so use parent device (for error reporting) until
......@@ -733,7 +718,6 @@ static int lm3533_led_probe(struct platform_device *pdev)
err_unregister:
led_classdev_unregister(&led->cdev);
flush_work(&led->work);
return ret;
}
......@@ -746,7 +730,6 @@ static int lm3533_led_remove(struct platform_device *pdev)
lm3533_ctrlbank_disable(&led->cb);
led_classdev_unregister(&led->cdev);
flush_work(&led->work);
return 0;
}
......@@ -760,7 +743,6 @@ static void lm3533_led_shutdown(struct platform_device *pdev)
lm3533_ctrlbank_disable(&led->cb);
lm3533_led_set(&led->cdev, LED_OFF); /* disable blink */
flush_work(&led->work);
}
static struct platform_driver lm3533_led_driver = {
......
......@@ -16,7 +16,6 @@
#include <linux/platform_device.h>
#include <linux/fs.h>
#include <linux/regmap.h>
#include <linux/workqueue.h>
#include <linux/platform_data/leds-lm355x.h>
enum lm355x_type {
......@@ -59,14 +58,6 @@ struct lm355x_chip_data {
struct led_classdev cdev_torch;
struct led_classdev cdev_indicator;
struct work_struct work_flash;
struct work_struct work_torch;
struct work_struct work_indicator;
u8 br_flash;
u8 br_torch;
u8 br_indicator;
struct lm355x_platform_data *pdata;
struct regmap *regmap;
struct mutex lock;
......@@ -204,7 +195,7 @@ static int lm355x_chip_init(struct lm355x_chip_data *chip)
}
/* chip control */
static void lm355x_control(struct lm355x_chip_data *chip,
static int lm355x_control(struct lm355x_chip_data *chip,
u8 brightness, enum lm355x_mode opmode)
{
int ret;
......@@ -301,7 +292,7 @@ static void lm355x_control(struct lm355x_chip_data *chip,
case MODE_SHDN:
break;
default:
return;
return -EINVAL;
}
/* operation mode control */
ret = regmap_update_bits(chip->regmap, preg[REG_OPMODE].regno,
......@@ -309,73 +300,55 @@ static void lm355x_control(struct lm355x_chip_data *chip,
opmode << preg[REG_OPMODE].shift);
if (ret < 0)
goto out;
return;
return ret;
out:
dev_err(chip->dev, "%s:i2c access fail to register\n", __func__);
return;
return ret;
}
/* torch */
static void lm355x_deferred_torch_brightness_set(struct work_struct *work)
{
struct lm355x_chip_data *chip =
container_of(work, struct lm355x_chip_data, work_torch);
mutex_lock(&chip->lock);
lm355x_control(chip, chip->br_torch, MODE_TORCH);
mutex_unlock(&chip->lock);
}
static void lm355x_torch_brightness_set(struct led_classdev *cdev,
static int lm355x_torch_brightness_set(struct led_classdev *cdev,
enum led_brightness brightness)
{
struct lm355x_chip_data *chip =
container_of(cdev, struct lm355x_chip_data, cdev_torch);
chip->br_torch = brightness;
schedule_work(&chip->work_torch);
}
/* flash */
static void lm355x_deferred_strobe_brightness_set(struct work_struct *work)
{
struct lm355x_chip_data *chip =
container_of(work, struct lm355x_chip_data, work_flash);
int ret;
mutex_lock(&chip->lock);
lm355x_control(chip, chip->br_flash, MODE_FLASH);
ret = lm355x_control(chip, brightness, MODE_TORCH);
mutex_unlock(&chip->lock);
return ret;
}
static void lm355x_strobe_brightness_set(struct led_classdev *cdev,
/* flash */
static int lm355x_strobe_brightness_set(struct led_classdev *cdev,
enum led_brightness brightness)
{
struct lm355x_chip_data *chip =
container_of(cdev, struct lm355x_chip_data, cdev_flash);
chip->br_flash = brightness;
schedule_work(&chip->work_flash);
}
/* indicator */
static void lm355x_deferred_indicator_brightness_set(struct work_struct *work)
{
struct lm355x_chip_data *chip =
container_of(work, struct lm355x_chip_data, work_indicator);
int ret;
mutex_lock(&chip->lock);
lm355x_control(chip, chip->br_indicator, MODE_INDIC);
ret = lm355x_control(chip, brightness, MODE_FLASH);
mutex_unlock(&chip->lock);
return ret;
}
static void lm355x_indicator_brightness_set(struct led_classdev *cdev,
/* indicator */
static int lm355x_indicator_brightness_set(struct led_classdev *cdev,
enum led_brightness brightness)
{
struct lm355x_chip_data *chip =
container_of(cdev, struct lm355x_chip_data, cdev_indicator);
int ret;
chip->br_indicator = brightness;
schedule_work(&chip->work_indicator);
mutex_lock(&chip->lock);
ret = lm355x_control(chip, brightness, MODE_INDIC);
mutex_unlock(&chip->lock);
return ret;
}
/* indicator pattern only for lm3556*/
......@@ -479,34 +452,31 @@ static int lm355x_probe(struct i2c_client *client,
goto err_out;
/* flash */
INIT_WORK(&chip->work_flash, lm355x_deferred_strobe_brightness_set);
chip->cdev_flash.name = "flash";
chip->cdev_flash.max_brightness = 16;
chip->cdev_flash.brightness_set = lm355x_strobe_brightness_set;
chip->cdev_flash.brightness_set_blocking = lm355x_strobe_brightness_set;
chip->cdev_flash.default_trigger = "flash";
err = led_classdev_register((struct device *)
&client->dev, &chip->cdev_flash);
if (err < 0)
goto err_out;
/* torch */
INIT_WORK(&chip->work_torch, lm355x_deferred_torch_brightness_set);
chip->cdev_torch.name = "torch";
chip->cdev_torch.max_brightness = 8;
chip->cdev_torch.brightness_set = lm355x_torch_brightness_set;
chip->cdev_torch.brightness_set_blocking = lm355x_torch_brightness_set;
chip->cdev_torch.default_trigger = "torch";
err = led_classdev_register((struct device *)
&client->dev, &chip->cdev_torch);
if (err < 0)
goto err_create_torch_file;
/* indicator */
INIT_WORK(&chip->work_indicator,
lm355x_deferred_indicator_brightness_set);
chip->cdev_indicator.name = "indicator";
if (id->driver_data == CHIP_LM3554)
chip->cdev_indicator.max_brightness = 4;
else
chip->cdev_indicator.max_brightness = 8;
chip->cdev_indicator.brightness_set = lm355x_indicator_brightness_set;
chip->cdev_indicator.brightness_set_blocking =
lm355x_indicator_brightness_set;
/* indicator pattern control only for LM3556 */
if (id->driver_data == CHIP_LM3556)
chip->cdev_indicator.groups = lm355x_indicator_groups;
......@@ -534,11 +504,8 @@ static int lm355x_remove(struct i2c_client *client)
regmap_write(chip->regmap, preg[REG_OPMODE].regno, 0);
led_classdev_unregister(&chip->cdev_indicator);
flush_work(&chip->work_indicator);
led_classdev_unregister(&chip->cdev_torch);
flush_work(&chip->work_torch);
led_classdev_unregister(&chip->cdev_flash);
flush_work(&chip->work_flash);
dev_info(&client->dev, "%s is removed\n", lm355x_name[chip->type]);
return 0;
......
......@@ -15,7 +15,6 @@
#include <linux/platform_device.h>
#include <linux/fs.h>
#include <linux/regmap.h>
#include <linux/workqueue.h>
#include <linux/platform_data/leds-lm3642.h>
#define REG_FILT_TIME (0x0)
......@@ -73,10 +72,6 @@ struct lm3642_chip_data {
struct led_classdev cdev_torch;
struct led_classdev cdev_indicator;
struct work_struct work_flash;
struct work_struct work_torch;
struct work_struct work_indicator;
u8 br_flash;
u8 br_torch;
u8 br_indicator;
......@@ -209,24 +204,18 @@ static ssize_t lm3642_torch_pin_store(struct device *dev,
static DEVICE_ATTR(torch_pin, S_IWUSR, NULL, lm3642_torch_pin_store);
static void lm3642_deferred_torch_brightness_set(struct work_struct *work)
{
struct lm3642_chip_data *chip =
container_of(work, struct lm3642_chip_data, work_torch);
mutex_lock(&chip->lock);
lm3642_control(chip, chip->br_torch, MODES_TORCH);
mutex_unlock(&chip->lock);
}
static void lm3642_torch_brightness_set(struct led_classdev *cdev,
static int lm3642_torch_brightness_set(struct led_classdev *cdev,
enum led_brightness brightness)
{
struct lm3642_chip_data *chip =
container_of(cdev, struct lm3642_chip_data, cdev_torch);
int ret;
mutex_lock(&chip->lock);
chip->br_torch = brightness;
schedule_work(&chip->work_torch);
ret = lm3642_control(chip, chip->br_torch, MODES_TORCH);
mutex_unlock(&chip->lock);
return ret;
}
/* flash */
......@@ -266,45 +255,33 @@ static ssize_t lm3642_strobe_pin_store(struct device *dev,
static DEVICE_ATTR(strobe_pin, S_IWUSR, NULL, lm3642_strobe_pin_store);
static void lm3642_deferred_strobe_brightness_set(struct work_struct *work)
{
struct lm3642_chip_data *chip =
container_of(work, struct lm3642_chip_data, work_flash);
mutex_lock(&chip->lock);
lm3642_control(chip, chip->br_flash, MODES_FLASH);
mutex_unlock(&chip->lock);
}
static void lm3642_strobe_brightness_set(struct led_classdev *cdev,
static int lm3642_strobe_brightness_set(struct led_classdev *cdev,
enum led_brightness brightness)
{
struct lm3642_chip_data *chip =
container_of(cdev, struct lm3642_chip_data, cdev_flash);
chip->br_flash = brightness;
schedule_work(&chip->work_flash);
}
/* indicator */
static void lm3642_deferred_indicator_brightness_set(struct work_struct *work)
{
struct lm3642_chip_data *chip =
container_of(work, struct lm3642_chip_data, work_indicator);
int ret;
mutex_lock(&chip->lock);
lm3642_control(chip, chip->br_indicator, MODES_INDIC);
chip->br_flash = brightness;
ret = lm3642_control(chip, chip->br_flash, MODES_FLASH);
mutex_unlock(&chip->lock);
return ret;
}
static void lm3642_indicator_brightness_set(struct led_classdev *cdev,
/* indicator */
static int lm3642_indicator_brightness_set(struct led_classdev *cdev,
enum led_brightness brightness)
{
struct lm3642_chip_data *chip =
container_of(cdev, struct lm3642_chip_data, cdev_indicator);
int ret;
mutex_lock(&chip->lock);
chip->br_indicator = brightness;
schedule_work(&chip->work_indicator);
ret = lm3642_control(chip, chip->br_indicator, MODES_INDIC);
mutex_unlock(&chip->lock);
return ret;
}
static const struct regmap_config lm3642_regmap = {
......@@ -371,10 +348,9 @@ static int lm3642_probe(struct i2c_client *client,
goto err_out;
/* flash */
INIT_WORK(&chip->work_flash, lm3642_deferred_strobe_brightness_set);
chip->cdev_flash.name = "flash";
chip->cdev_flash.max_brightness = 16;
chip->cdev_flash.brightness_set = lm3642_strobe_brightness_set;
chip->cdev_flash.brightness_set_blocking = lm3642_strobe_brightness_set;
chip->cdev_flash.default_trigger = "flash";
chip->cdev_flash.groups = lm3642_flash_groups,
err = led_classdev_register((struct device *)
......@@ -385,10 +361,9 @@ static int lm3642_probe(struct i2c_client *client,
}
/* torch */
INIT_WORK(&chip->work_torch, lm3642_deferred_torch_brightness_set);
chip->cdev_torch.name = "torch";
chip->cdev_torch.max_brightness = 8;
chip->cdev_torch.brightness_set = lm3642_torch_brightness_set;
chip->cdev_torch.brightness_set_blocking = lm3642_torch_brightness_set;
chip->cdev_torch.default_trigger = "torch";
chip->cdev_torch.groups = lm3642_torch_groups,
err = led_classdev_register((struct device *)
......@@ -399,11 +374,10 @@ static int lm3642_probe(struct i2c_client *client,
}
/* indicator */
INIT_WORK(&chip->work_indicator,
lm3642_deferred_indicator_brightness_set);
chip->cdev_indicator.name = "indicator";
chip->cdev_indicator.max_brightness = 8;
chip->cdev_indicator.brightness_set = lm3642_indicator_brightness_set;
chip->cdev_indicator.brightness_set_blocking =
lm3642_indicator_brightness_set;
err = led_classdev_register((struct device *)
&client->dev, &chip->cdev_indicator);
if (err < 0) {
......@@ -427,11 +401,8 @@ static int lm3642_remove(struct i2c_client *client)
struct lm3642_chip_data *chip = i2c_get_clientdata(client);
led_classdev_unregister(&chip->cdev_indicator);
flush_work(&chip->work_indicator);
led_classdev_unregister(&chip->cdev_torch);
flush_work(&chip->work_torch);
led_classdev_unregister(&chip->cdev_flash);
flush_work(&chip->work_flash);
regmap_write(chip->regmap, REG_ENABLE, 0);
return 0;
}
......
......@@ -31,7 +31,6 @@
#include <linux/slab.h>
#include <linux/leds.h>
#include <linux/mutex.h>
#include <linux/workqueue.h>
#include <linux/leds-lp3944.h>
/* Read Only Registers */
......@@ -68,10 +67,8 @@
struct lp3944_led_data {
u8 id;
enum lp3944_type type;
enum lp3944_status status;
struct led_classdev ldev;
struct i2c_client *client;
struct work_struct work;
};
struct lp3944_data {
......@@ -275,13 +272,12 @@ static int lp3944_led_set_blink(struct led_classdev *led_cdev,
dev_dbg(&led->client->dev, "%s: OK hardware accelerated blink!\n",
__func__);
led->status = LP3944_LED_STATUS_DIM0;
schedule_work(&led->work);
lp3944_led_set(led, LP3944_LED_STATUS_DIM0);
return 0;
}
static void lp3944_led_set_brightness(struct led_classdev *led_cdev,
static int lp3944_led_set_brightness(struct led_classdev *led_cdev,
enum led_brightness brightness)
{
struct lp3944_led_data *led = ldev_to_led(led_cdev);
......@@ -289,16 +285,7 @@ static void lp3944_led_set_brightness(struct led_classdev *led_cdev,
dev_dbg(&led->client->dev, "%s: %s, %d\n",
__func__, led_cdev->name, brightness);
led->status = !!brightness;
schedule_work(&led->work);
}
static void lp3944_led_work(struct work_struct *work)
{
struct lp3944_led_data *led;
led = container_of(work, struct lp3944_led_data, work);
lp3944_led_set(led, led->status);
return lp3944_led_set(led, !!brightness);
}
static int lp3944_configure(struct i2c_client *client,
......@@ -318,14 +305,13 @@ static int lp3944_configure(struct i2c_client *client,
case LP3944_LED_TYPE_LED:
case LP3944_LED_TYPE_LED_INVERTED:
led->type = pled->type;
led->status = pled->status;
led->ldev.name = pled->name;
led->ldev.max_brightness = 1;
led->ldev.brightness_set = lp3944_led_set_brightness;
led->ldev.brightness_set_blocking =
lp3944_led_set_brightness;
led->ldev.blink_set = lp3944_led_set_blink;
led->ldev.flags = LED_CORE_SUSPENDRESUME;
INIT_WORK(&led->work, lp3944_led_work);
err = led_classdev_register(&client->dev, &led->ldev);
if (err < 0) {
dev_err(&client->dev,
......@@ -336,14 +322,14 @@ static int lp3944_configure(struct i2c_client *client,
/* to expose the default value to userspace */
led->ldev.brightness =
(enum led_brightness) led->status;
(enum led_brightness) pled->status;
/* Set the default led status */
err = lp3944_led_set(led, led->status);
err = lp3944_led_set(led, pled->status);
if (err < 0) {
dev_err(&client->dev,
"%s couldn't set STATUS %d\n",
led->ldev.name, led->status);
led->ldev.name, pled->status);
goto exit;
}
break;
......@@ -364,7 +350,6 @@ static int lp3944_configure(struct i2c_client *client,
case LP3944_LED_TYPE_LED:
case LP3944_LED_TYPE_LED_INVERTED:
led_classdev_unregister(&data->leds[i].ldev);
cancel_work_sync(&data->leds[i].work);
break;
case LP3944_LED_TYPE_NONE:
......@@ -424,7 +409,6 @@ static int lp3944_remove(struct i2c_client *client)
case LP3944_LED_TYPE_LED:
case LP3944_LED_TYPE_LED_INVERTED:
led_classdev_unregister(&data->leds[i].ldev);
cancel_work_sync(&data->leds[i].work);
break;
case LP3944_LED_TYPE_NONE:
......
......@@ -362,16 +362,17 @@ static int lp5521_run_selftest(struct lp55xx_chip *chip, char *buf)
return 0;
}
static void lp5521_led_brightness_work(struct work_struct *work)
static int lp5521_led_brightness(struct lp55xx_led *led)
{
struct lp55xx_led *led = container_of(work, struct lp55xx_led,
brightness_work);
struct lp55xx_chip *chip = led->chip;
int ret;
mutex_lock(&chip->lock);
lp55xx_write(chip, LP5521_REG_LED_PWM_BASE + led->chan_nr,
ret = lp55xx_write(chip, LP5521_REG_LED_PWM_BASE + led->chan_nr,
led->brightness);
mutex_unlock(&chip->lock);
return ret;
}
static ssize_t show_engine_mode(struct device *dev,
......@@ -501,7 +502,7 @@ static struct lp55xx_device_config lp5521_cfg = {
},
.max_channel = LP5521_MAX_LEDS,
.post_init_device = lp5521_post_init_device,
.brightness_work_fn = lp5521_led_brightness_work,
.brightness_fn = lp5521_led_brightness,
.set_led_current = lp5521_set_led_current,
.firmware_cb = lp5521_firmware_loaded,
.run_engine = lp5521_run_engine,
......
......@@ -802,16 +802,16 @@ static ssize_t store_master_fader_leds(struct device *dev,
return ret;
}
static void lp5523_led_brightness_work(struct work_struct *work)
static int lp5523_led_brightness(struct lp55xx_led *led)
{
struct lp55xx_led *led = container_of(work, struct lp55xx_led,
brightness_work);
struct lp55xx_chip *chip = led->chip;
int ret;
mutex_lock(&chip->lock);
lp55xx_write(chip, LP5523_REG_LED_PWM_BASE + led->chan_nr,
ret = lp55xx_write(chip, LP5523_REG_LED_PWM_BASE + led->chan_nr,
led->brightness);
mutex_unlock(&chip->lock);
return ret;
}
static LP55XX_DEV_ATTR_RW(engine1_mode, show_engine1_mode, store_engine1_mode);
......@@ -867,7 +867,7 @@ static struct lp55xx_device_config lp5523_cfg = {
},
.max_channel = LP5523_MAX_LEDS,
.post_init_device = lp5523_post_init_device,
.brightness_work_fn = lp5523_led_brightness_work,
.brightness_fn = lp5523_led_brightness,
.set_led_current = lp5523_set_led_current,
.firmware_cb = lp5523_firmware_loaded,
.run_engine = lp5523_run_engine,
......
......@@ -311,10 +311,8 @@ static int lp5562_post_init_device(struct lp55xx_chip *chip)
return 0;
}
static void lp5562_led_brightness_work(struct work_struct *work)
static int lp5562_led_brightness(struct lp55xx_led *led)
{
struct lp55xx_led *led = container_of(work, struct lp55xx_led,
brightness_work);
struct lp55xx_chip *chip = led->chip;
u8 addr[] = {
LP5562_REG_R_PWM,
......@@ -322,10 +320,13 @@ static void lp5562_led_brightness_work(struct work_struct *work)
LP5562_REG_B_PWM,
LP5562_REG_W_PWM,
};
int ret;
mutex_lock(&chip->lock);
lp55xx_write(chip, addr[led->chan_nr], led->brightness);
ret = lp55xx_write(chip, addr[led->chan_nr], led->brightness);
mutex_unlock(&chip->lock);
return ret;
}
static void lp5562_write_program_memory(struct lp55xx_chip *chip,
......@@ -503,7 +504,7 @@ static struct lp55xx_device_config lp5562_cfg = {
},
.post_init_device = lp5562_post_init_device,
.set_led_current = lp5562_set_led_current,
.brightness_work_fn = lp5562_led_brightness_work,
.brightness_fn = lp5562_led_brightness,
.run_engine = lp5562_run_engine,
.firmware_cb = lp5562_firmware_loaded,
.dev_attr_group = &lp5562_group,
......
......@@ -134,13 +134,14 @@ static struct attribute *lp55xx_led_attrs[] = {
};
ATTRIBUTE_GROUPS(lp55xx_led);
static void lp55xx_set_brightness(struct led_classdev *cdev,
static int lp55xx_set_brightness(struct led_classdev *cdev,
enum led_brightness brightness)
{
struct lp55xx_led *led = cdev_to_lp55xx_led(cdev);
struct lp55xx_device_config *cfg = led->chip->cfg;
led->brightness = (u8)brightness;
schedule_work(&led->brightness_work);
return cfg->brightness_fn(led);
}
static int lp55xx_init_led(struct lp55xx_led *led,
......@@ -172,7 +173,7 @@ static int lp55xx_init_led(struct lp55xx_led *led,
return -EINVAL;
}
led->cdev.brightness_set = lp55xx_set_brightness;
led->cdev.brightness_set_blocking = lp55xx_set_brightness;
led->cdev.groups = lp55xx_led_groups;
if (pdata->led_config[chan].name) {
......@@ -464,7 +465,7 @@ int lp55xx_register_leds(struct lp55xx_led *led, struct lp55xx_chip *chip)
int ret;
int i;
if (!cfg->brightness_work_fn) {
if (!cfg->brightness_fn) {
dev_err(&chip->cl->dev, "empty brightness configuration\n");
return -EINVAL;
}
......@@ -481,8 +482,6 @@ int lp55xx_register_leds(struct lp55xx_led *led, struct lp55xx_chip *chip)
if (ret)
goto err_init_led;
INIT_WORK(&each->brightness_work, cfg->brightness_work_fn);
chip->num_leds++;
each->chip = chip;
......@@ -507,7 +506,6 @@ void lp55xx_unregister_leds(struct lp55xx_led *led, struct lp55xx_chip *chip)
for (i = 0; i < chip->num_leds; i++) {
each = led + i;
led_classdev_unregister(&each->cdev);
flush_work(&each->brightness_work);
}
}
EXPORT_SYMBOL_GPL(lp55xx_unregister_leds);
......
......@@ -95,7 +95,7 @@ struct lp55xx_reg {
* @enable : Chip specific enable command
* @max_channel : Maximum number of channels
* @post_init_device : Chip specific initialization code
* @brightness_work_fn : Brightness work function
* @brightness_fn : Brightness function
* @set_led_current : LED current set function
* @firmware_cb : Call function when the firmware is loaded
* @run_engine : Run internal engine for pattern
......@@ -110,7 +110,7 @@ struct lp55xx_device_config {
int (*post_init_device) (struct lp55xx_chip *chip);
/* access brightness register */
void (*brightness_work_fn)(struct work_struct *work);
int (*brightness_fn)(struct lp55xx_led *led);
/* current setting function */
void (*set_led_current) (struct lp55xx_led *led, u8 led_current);
......@@ -164,7 +164,6 @@ struct lp55xx_chip {
* @cdev : LED class device
* @led_current : Current setting at each led channel
* @max_current : Maximun current at each led channel
* @brightness_work : Workqueue for brightness control
* @brightness : Brightness value
* @chip : The lp55xx chip data
*/
......@@ -173,7 +172,6 @@ struct lp55xx_led {
struct led_classdev cdev;
u8 led_current;
u8 max_current;
struct work_struct brightness_work;
u8 brightness;
struct lp55xx_chip *chip;
};
......
......@@ -272,16 +272,17 @@ static void lp8501_firmware_loaded(struct lp55xx_chip *chip)
lp8501_update_program_memory(chip, fw->data, fw->size);
}
static void lp8501_led_brightness_work(struct work_struct *work)
static int lp8501_led_brightness(struct lp55xx_led *led)
{
struct lp55xx_led *led = container_of(work, struct lp55xx_led,
brightness_work);
struct lp55xx_chip *chip = led->chip;
int ret;
mutex_lock(&chip->lock);
lp55xx_write(chip, LP8501_REG_LED_PWM_BASE + led->chan_nr,
ret = lp55xx_write(chip, LP8501_REG_LED_PWM_BASE + led->chan_nr,
led->brightness);
mutex_unlock(&chip->lock);
return ret;
}
/* Chip specific configurations */
......@@ -296,7 +297,7 @@ static struct lp55xx_device_config lp8501_cfg = {
},
.max_channel = LP8501_MAX_LEDS,
.post_init_device = lp8501_post_init_device,
.brightness_work_fn = lp8501_led_brightness_work,
.brightness_fn = lp8501_led_brightness,
.set_led_current = lp8501_set_led_current,
.firmware_cb = lp8501_firmware_loaded,
.run_engine = lp8501_run_engine,
......
......@@ -26,10 +26,8 @@
struct lp8788_led {
struct lp8788 *lp;
struct mutex lock;
struct work_struct work;
struct led_classdev led_dev;
enum lp8788_isink_number isink_num;
enum led_brightness brightness;
int on;
};
......@@ -76,24 +74,29 @@ static int lp8788_led_init_device(struct lp8788_led *led,
return lp8788_update_bits(led->lp, addr, mask, val);
}
static void lp8788_led_enable(struct lp8788_led *led,
static int lp8788_led_enable(struct lp8788_led *led,
enum lp8788_isink_number num, int on)
{
int ret;
u8 mask = 1 << num;
u8 val = on << num;
if (lp8788_update_bits(led->lp, LP8788_ISINK_CTRL, mask, val))
return;
ret = lp8788_update_bits(led->lp, LP8788_ISINK_CTRL, mask, val);
if (ret == 0)
led->on = on;
return ret;
}
static void lp8788_led_work(struct work_struct *work)
static int lp8788_brightness_set(struct led_classdev *led_cdev,
enum led_brightness val)
{
struct lp8788_led *led = container_of(work, struct lp8788_led, work);
struct lp8788_led *led =
container_of(led_cdev, struct lp8788_led, led_dev);
enum lp8788_isink_number num = led->isink_num;
int enable;
u8 val = led->brightness;
int enable, ret;
mutex_lock(&led->lock);
......@@ -101,28 +104,21 @@ static void lp8788_led_work(struct work_struct *work)
case LP8788_ISINK_1:
case LP8788_ISINK_2:
case LP8788_ISINK_3:
lp8788_write_byte(led->lp, lp8788_pwm_addr[num], val);
ret = lp8788_write_byte(led->lp, lp8788_pwm_addr[num], val);
if (ret < 0)
goto unlock;
break;
default:
mutex_unlock(&led->lock);
return;
return -EINVAL;
}
enable = (val > 0) ? 1 : 0;
if (enable != led->on)
lp8788_led_enable(led, num, enable);
ret = lp8788_led_enable(led, num, enable);
unlock:
mutex_unlock(&led->lock);
}
static void lp8788_brightness_set(struct led_classdev *led_cdev,
enum led_brightness brt_val)
{
struct lp8788_led *led =
container_of(led_cdev, struct lp8788_led, led_dev);
led->brightness = brt_val;
schedule_work(&led->work);
return ret;
}
static int lp8788_led_probe(struct platform_device *pdev)
......@@ -139,7 +135,7 @@ static int lp8788_led_probe(struct platform_device *pdev)
led->lp = lp;
led->led_dev.max_brightness = MAX_BRIGHTNESS;
led->led_dev.brightness_set = lp8788_brightness_set;
led->led_dev.brightness_set_blocking = lp8788_brightness_set;
led_pdata = lp->pdata ? lp->pdata->led_pdata : NULL;
......@@ -149,7 +145,6 @@ static int lp8788_led_probe(struct platform_device *pdev)
led->led_dev.name = led_pdata->name;
mutex_init(&led->lock);
INIT_WORK(&led->work, lp8788_led_work);
platform_set_drvdata(pdev, led);
......@@ -173,7 +168,6 @@ static int lp8788_led_remove(struct platform_device *pdev)
struct lp8788_led *led = platform_get_drvdata(pdev);
led_classdev_unregister(&led->led_dev);
flush_work(&led->work);
return 0;
}
......
......@@ -91,26 +91,22 @@
/**
* struct lp8860_led -
* @lock - Lock for reading/writing the device
* @work - Work item used to off load the brightness register writes
* @client - Pointer to the I2C client
* @led_dev - led class device pointer
* @regmap - Devices register map
* @eeprom_regmap - EEPROM register map
* @enable_gpio - VDDIO/EN gpio to enable communication interface
* @regulator - LED supply regulator pointer
* @brightness - Current brightness value requested
* @label - LED label
**/
struct lp8860_led {
struct mutex lock;
struct work_struct work;
struct i2c_client *client;
struct led_classdev led_dev;
struct regmap *regmap;
struct regmap *eeprom_regmap;
struct gpio_desc *enable_gpio;
struct regulator *regulator;
enum led_brightness brightness;
const char *label;
};
......@@ -212,11 +208,13 @@ static int lp8860_fault_check(struct lp8860_led *led)
return ret;
}
static void lp8860_led_brightness_work(struct work_struct *work)
static int lp8860_brightness_set(struct led_classdev *led_cdev,
enum led_brightness brt_val)
{
struct lp8860_led *led = container_of(work, struct lp8860_led, work);
struct lp8860_led *led =
container_of(led_cdev, struct lp8860_led, led_dev);
int disp_brightness = brt_val * 255;
int ret;
int disp_brightness = led->brightness * 255;
mutex_lock(&led->lock);
......@@ -241,16 +239,7 @@ static void lp8860_led_brightness_work(struct work_struct *work)
}
out:
mutex_unlock(&led->lock);
}
static void lp8860_brightness_set(struct led_classdev *led_cdev,
enum led_brightness brt_val)
{
struct lp8860_led *led =
container_of(led_cdev, struct lp8860_led, led_dev);
led->brightness = brt_val;
schedule_work(&led->work);
return ret;
}
static int lp8860_init(struct lp8860_led *led)
......@@ -406,10 +395,9 @@ static int lp8860_probe(struct i2c_client *client,
led->client = client;
led->led_dev.name = led->label;
led->led_dev.max_brightness = LED_FULL;
led->led_dev.brightness_set = lp8860_brightness_set;
led->led_dev.brightness_set_blocking = lp8860_brightness_set;
mutex_init(&led->lock);
INIT_WORK(&led->work, lp8860_led_brightness_work);
i2c_set_clientdata(client, led);
......@@ -448,7 +436,6 @@ static int lp8860_remove(struct i2c_client *client)
int ret;
led_classdev_unregister(&led->led_dev);
cancel_work_sync(&led->work);
if (led->enable_gpio)
gpiod_direction_output(led->enable_gpio, 0);
......
......@@ -19,7 +19,6 @@
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/leds.h>
#include <linux/workqueue.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/slab.h>
......@@ -28,15 +27,14 @@
struct lt3593_led_data {
struct led_classdev cdev;
unsigned gpio;
struct work_struct work;
u8 new_level;
};
static void lt3593_led_work(struct work_struct *work)
static int lt3593_led_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
int pulses;
struct lt3593_led_data *led_dat =
container_of(work, struct lt3593_led_data, work);
container_of(led_cdev, struct lt3593_led_data, cdev);
int pulses;
/*
* The LT3593 resets its internal current level register to the maximum
......@@ -47,18 +45,18 @@ static void lt3593_led_work(struct work_struct *work)
* applied is to the output driver.
*/
if (led_dat->new_level == 0) {
if (value == 0) {
gpio_set_value_cansleep(led_dat->gpio, 0);
return;
return 0;
}
pulses = 32 - (led_dat->new_level * 32) / 255;
pulses = 32 - (value * 32) / 255;
if (pulses == 0) {
gpio_set_value_cansleep(led_dat->gpio, 0);
mdelay(1);
gpio_set_value_cansleep(led_dat->gpio, 1);
return;
return 0;
}
gpio_set_value_cansleep(led_dat->gpio, 1);
......@@ -69,16 +67,8 @@ static void lt3593_led_work(struct work_struct *work)
gpio_set_value_cansleep(led_dat->gpio, 1);
udelay(1);
}
}
static void lt3593_led_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
struct lt3593_led_data *led_dat =
container_of(led_cdev, struct lt3593_led_data, cdev);
led_dat->new_level = value;
schedule_work(&led_dat->work);
return 0;
}
static int create_lt3593_led(const struct gpio_led *template,
......@@ -97,7 +87,7 @@ static int create_lt3593_led(const struct gpio_led *template,
led_dat->cdev.default_trigger = template->default_trigger;
led_dat->gpio = template->gpio;
led_dat->cdev.brightness_set = lt3593_led_set;
led_dat->cdev.brightness_set_blocking = lt3593_led_set;
state = (template->default_state == LEDS_GPIO_DEFSTATE_ON);
led_dat->cdev.brightness = state ? LED_FULL : LED_OFF;
......@@ -111,8 +101,6 @@ static int create_lt3593_led(const struct gpio_led *template,
if (ret < 0)
return ret;
INIT_WORK(&led_dat->work, lt3593_led_work);
ret = led_classdev_register(parent, &led_dat->cdev);
if (ret < 0)
return ret;
......@@ -129,7 +117,6 @@ static void delete_lt3593_led(struct lt3593_led_data *led)
return;
led_classdev_unregister(&led->cdev);
cancel_work_sync(&led->work);
}
static int lt3593_led_probe(struct platform_device *pdev)
......
......@@ -20,7 +20,6 @@
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <media/v4l2-flash-led-class.h>
#define MODE_OFF 0
......@@ -62,8 +61,6 @@ struct max77693_sub_led {
int fled_id;
/* corresponding LED Flash class device */
struct led_classdev_flash fled_cdev;
/* assures led-triggers compatibility */
struct work_struct work_brightness_set;
/* V4L2 Flash device */
struct v4l2_flash *v4l2_flash;
......@@ -463,10 +460,14 @@ static int max77693_setup(struct max77693_led_device *led,
return max77693_set_mode_reg(led, MODE_OFF);
}
static int __max77693_led_brightness_set(struct max77693_led_device *led,
int fled_id, enum led_brightness value)
/* LED subsystem callbacks */
static int max77693_led_brightness_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
int ret;
struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
struct max77693_sub_led *sub_led = flcdev_to_sub_led(fled_cdev);
struct max77693_led_device *led = sub_led_to_led(sub_led);
int fled_id = sub_led->fled_id, ret;
mutex_lock(&led->lock);
......@@ -494,43 +495,8 @@ static int __max77693_led_brightness_set(struct max77693_led_device *led,
ret);
unlock:
mutex_unlock(&led->lock);
return ret;
}
static void max77693_led_brightness_set_work(
struct work_struct *work)
{
struct max77693_sub_led *sub_led =
container_of(work, struct max77693_sub_led,
work_brightness_set);
struct max77693_led_device *led = sub_led_to_led(sub_led);
__max77693_led_brightness_set(led, sub_led->fled_id,
sub_led->torch_brightness);
}
/* LED subsystem callbacks */
static int max77693_led_brightness_set_sync(
struct led_classdev *led_cdev,
enum led_brightness value)
{
struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
struct max77693_sub_led *sub_led = flcdev_to_sub_led(fled_cdev);
struct max77693_led_device *led = sub_led_to_led(sub_led);
return __max77693_led_brightness_set(led, sub_led->fled_id, value);
}
static void max77693_led_brightness_set(
struct led_classdev *led_cdev,
enum led_brightness value)
{
struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
struct max77693_sub_led *sub_led = flcdev_to_sub_led(fled_cdev);
sub_led->torch_brightness = value;
schedule_work(&sub_led->work_brightness_set);
return ret;
}
static int max77693_led_flash_brightness_set(
......@@ -682,6 +648,7 @@ static int max77693_led_parse_dt(struct max77693_led_device *led,
if (sub_nodes[fled_id]) {
dev_err(dev,
"Conflicting \"led-sources\" DT properties\n");
of_node_put(child_node);
return -EINVAL;
}
......@@ -931,16 +898,13 @@ static void max77693_init_fled_cdev(struct max77693_sub_led *sub_led,
led_cdev->name = led_cfg->label[fled_id];
led_cdev->brightness_set = max77693_led_brightness_set;
led_cdev->brightness_set_sync = max77693_led_brightness_set_sync;
led_cdev->brightness_set_blocking = max77693_led_brightness_set;
led_cdev->max_brightness = (led->iout_joint ?
led_cfg->iout_torch_max[FLED1] +
led_cfg->iout_torch_max[FLED2] :
led_cfg->iout_torch_max[fled_id]) /
TORCH_IOUT_STEP;
led_cdev->flags |= LED_DEV_CAP_FLASH;
INIT_WORK(&sub_led->work_brightness_set,
max77693_led_brightness_set_work);
max77693_init_flash_settings(sub_led, led_cfg);
......@@ -1062,13 +1026,11 @@ static int max77693_led_remove(struct platform_device *pdev)
if (led->iout_joint || max77693_fled_used(led, FLED1)) {
v4l2_flash_release(sub_leds[FLED1].v4l2_flash);
led_classdev_flash_unregister(&sub_leds[FLED1].fled_cdev);
cancel_work_sync(&sub_leds[FLED1].work_brightness_set);
}
if (!led->iout_joint && max77693_fled_used(led, FLED2)) {
v4l2_flash_release(sub_leds[FLED2].v4l2_flash);
led_classdev_flash_unregister(&sub_leds[FLED2].fled_cdev);
cancel_work_sync(&sub_leds[FLED2].work_brightness_set);
}
mutex_destroy(&led->lock);
......
......@@ -13,7 +13,6 @@
#include <linux/module.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <linux/leds.h>
#include <linux/mfd/max8997.h>
#include <linux/mfd/max8997-private.h>
......
......@@ -20,7 +20,6 @@
#include <linux/platform_device.h>
#include <linux/leds.h>
#include <linux/of.h>
#include <linux/workqueue.h>
#include <linux/mfd/mc13xxx.h>
struct mc13xxx_led_devtype {
......@@ -32,8 +31,6 @@ struct mc13xxx_led_devtype {
struct mc13xxx_led {
struct led_classdev cdev;
struct work_struct work;
enum led_brightness new_brightness;
int id;
struct mc13xxx_leds *leds;
};
......@@ -55,9 +52,11 @@ static unsigned int mc13xxx_max_brightness(int id)
return 0x3f;
}
static void mc13xxx_led_work(struct work_struct *work)
static int mc13xxx_led_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
struct mc13xxx_led *led = container_of(work, struct mc13xxx_led, work);
struct mc13xxx_led *led =
container_of(led_cdev, struct mc13xxx_led, cdev);
struct mc13xxx_leds *leds = led->leds;
unsigned int reg, bank, off, shift;
......@@ -105,19 +104,9 @@ static void mc13xxx_led_work(struct work_struct *work)
BUG();
}
mc13xxx_reg_rmw(leds->master, leds->devtype->ledctrl_base + reg,
return mc13xxx_reg_rmw(leds->master, leds->devtype->ledctrl_base + reg,
mc13xxx_max_brightness(led->id) << shift,
led->new_brightness << shift);
}
static void mc13xxx_led_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
struct mc13xxx_led *led =
container_of(led_cdev, struct mc13xxx_led, cdev);
led->new_brightness = value;
schedule_work(&led->work);
value << shift);
}
#ifdef CONFIG_OF
......@@ -257,11 +246,9 @@ static int __init mc13xxx_led_probe(struct platform_device *pdev)
leds->led[i].cdev.name = name;
leds->led[i].cdev.default_trigger = trig;
leds->led[i].cdev.flags = LED_CORE_SUSPENDRESUME;
leds->led[i].cdev.brightness_set = mc13xxx_led_set;
leds->led[i].cdev.brightness_set_blocking = mc13xxx_led_set;
leds->led[i].cdev.max_brightness = mc13xxx_max_brightness(id);
INIT_WORK(&leds->led[i].work, mc13xxx_led_work);
ret = led_classdev_register(dev->parent, &leds->led[i].cdev);
if (ret) {
dev_err(dev, "Failed to register LED %i\n", id);
......@@ -270,10 +257,8 @@ static int __init mc13xxx_led_probe(struct platform_device *pdev)
}
if (ret)
while (--i >= 0) {
while (--i >= 0)
led_classdev_unregister(&leds->led[i].cdev);
cancel_work_sync(&leds->led[i].work);
}
return ret;
}
......@@ -283,10 +268,8 @@ static int mc13xxx_led_remove(struct platform_device *pdev)
struct mc13xxx_leds *leds = platform_get_drvdata(pdev);
int i;
for (i = 0; i < leds->num_leds; i++) {
for (i = 0; i < leds->num_leds; i++)
led_classdev_unregister(&leds->led[i].cdev);
cancel_work_sync(&leds->led[i].work);
}
return 0;
}
......
......@@ -45,24 +45,12 @@ struct ns2_led_data {
unsigned cmd;
unsigned slow;
bool can_sleep;
int mode_index;
unsigned char sata; /* True when SATA mode active. */
rwlock_t rw_lock; /* Lock GPIOs. */
struct work_struct work;
int num_modes;
struct ns2_led_modval *modval;
};
static void ns2_led_work(struct work_struct *work)
{
struct ns2_led_data *led_dat =
container_of(work, struct ns2_led_data, work);
int i = led_dat->mode_index;
gpio_set_value_cansleep(led_dat->cmd, led_dat->modval[i].cmd_level);
gpio_set_value_cansleep(led_dat->slow, led_dat->modval[i].slow_level);
}
static int ns2_led_get_mode(struct ns2_led_data *led_dat,
enum ns2_led_modes *mode)
{
......@@ -112,8 +100,8 @@ static void ns2_led_set_mode(struct ns2_led_data *led_dat,
goto exit_unlock;
}
led_dat->mode_index = i;
schedule_work(&led_dat->work);
gpio_set_value_cansleep(led_dat->cmd, led_dat->modval[i].cmd_level);
gpio_set_value_cansleep(led_dat->slow, led_dat->modval[i].slow_level);
exit_unlock:
write_unlock_irqrestore(&led_dat->rw_lock, flags);
......@@ -136,6 +124,13 @@ static void ns2_led_set(struct led_classdev *led_cdev,
ns2_led_set_mode(led_dat, mode);
}
static int ns2_led_set_blocking(struct led_classdev *led_cdev,
enum led_brightness value)
{
ns2_led_set(led_cdev, value);
return 0;
}
static ssize_t ns2_led_sata_store(struct device *dev,
struct device_attribute *attr,
const char *buff, size_t count)
......@@ -219,13 +214,16 @@ create_ns2_led(struct platform_device *pdev, struct ns2_led_data *led_dat,
led_dat->cdev.name = template->name;
led_dat->cdev.default_trigger = template->default_trigger;
led_dat->cdev.blink_set = NULL;
led_dat->cdev.brightness_set = ns2_led_set;
led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
led_dat->cdev.groups = ns2_led_groups;
led_dat->cmd = template->cmd;
led_dat->slow = template->slow;
led_dat->can_sleep = gpio_cansleep(led_dat->cmd) |
gpio_cansleep(led_dat->slow);
if (led_dat->can_sleep)
led_dat->cdev.brightness_set_blocking = ns2_led_set_blocking;
else
led_dat->cdev.brightness_set = ns2_led_set;
led_dat->modval = template->modval;
led_dat->num_modes = template->num_modes;
......@@ -238,8 +236,6 @@ create_ns2_led(struct platform_device *pdev, struct ns2_led_data *led_dat,
led_dat->cdev.brightness =
(mode == NS_V2_LED_OFF) ? LED_OFF : LED_FULL;
INIT_WORK(&led_dat->work, ns2_led_work);
ret = led_classdev_register(&pdev->dev, &led_dat->cdev);
if (ret < 0)
return ret;
......@@ -250,7 +246,6 @@ create_ns2_led(struct platform_device *pdev, struct ns2_led_data *led_dat,
static void delete_ns2_led(struct ns2_led_data *led_dat)
{
led_classdev_unregister(&led_dat->cdev);
cancel_work_sync(&led_dat->work);
}
#ifdef CONFIG_OF_GPIO
......
......@@ -158,7 +158,7 @@ static void pca9532_setled(struct pca9532_led *led)
mutex_unlock(&data->update_lock);
}
static void pca9532_set_brightness(struct led_classdev *led_cdev,
static int pca9532_set_brightness(struct led_classdev *led_cdev,
enum led_brightness value)
{
int err = 0;
......@@ -172,9 +172,12 @@ static void pca9532_set_brightness(struct led_classdev *led_cdev,
led->state = PCA9532_PWM0; /* Thecus: hardcode one pwm */
err = pca9532_calcpwm(led->client, 0, 0, value);
if (err)
return; /* XXX: led api doesn't allow error code? */
return err;
}
schedule_work(&led->work);
if (led->state == PCA9532_PWM0)
pca9532_setpwm(led->client, 0);
pca9532_setled(led);
return err;
}
static int pca9532_set_blink(struct led_classdev *led_cdev,
......@@ -198,7 +201,10 @@ static int pca9532_set_blink(struct led_classdev *led_cdev,
err = pca9532_calcpwm(client, 0, psc, led_cdev->brightness);
if (err)
return err;
schedule_work(&led->work);
if (led->state == PCA9532_PWM0)
pca9532_setpwm(led->client, 0);
pca9532_setled(led);
return 0;
}
......@@ -233,15 +239,6 @@ static void pca9532_input_work(struct work_struct *work)
mutex_unlock(&data->update_lock);
}
static void pca9532_led_work(struct work_struct *work)
{
struct pca9532_led *led;
led = container_of(work, struct pca9532_led, work);
if (led->state == PCA9532_PWM0)
pca9532_setpwm(led->client, 0);
pca9532_setled(led);
}
#ifdef CONFIG_LEDS_PCA9532_GPIO
static int pca9532_gpio_request_pin(struct gpio_chip *gc, unsigned offset)
{
......@@ -307,7 +304,6 @@ static int pca9532_destroy_devices(struct pca9532_data *data, int n_devs)
break;
case PCA9532_TYPE_LED:
led_classdev_unregister(&data->leds[i].ldev);
cancel_work_sync(&data->leds[i].work);
break;
case PCA9532_TYPE_N2100_BEEP:
if (data->idev != NULL) {
......@@ -359,9 +355,9 @@ static int pca9532_configure(struct i2c_client *client,
led->name = pled->name;
led->ldev.name = led->name;
led->ldev.brightness = LED_OFF;
led->ldev.brightness_set = pca9532_set_brightness;
led->ldev.brightness_set_blocking =
pca9532_set_brightness;
led->ldev.blink_set = pca9532_set_blink;
INIT_WORK(&led->work, pca9532_led_work);
err = led_classdev_register(&client->dev, &led->ldev);
if (err < 0) {
dev_err(&client->dev,
......
......@@ -47,7 +47,6 @@
#include <linux/leds.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/workqueue.h>
#include <linux/slab.h>
/* LED select registers determine the source that drives LED outputs */
......@@ -110,8 +109,6 @@ struct pca955x {
struct pca955x_led {
struct pca955x *pca955x;
struct work_struct work;
enum led_brightness brightness;
struct led_classdev led_cdev;
int led_num; /* 0 .. 15 potentially */
char name[32];
......@@ -193,7 +190,8 @@ static u8 pca955x_read_ls(struct i2c_client *client, int n)
pca95xx_num_input_regs(pca955x->chipdef->bits) + 4 + n);
}
static void pca955x_led_work(struct work_struct *work)
static int pca955x_led_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
struct pca955x_led *pca955x_led;
struct pca955x *pca955x;
......@@ -201,7 +199,7 @@ static void pca955x_led_work(struct work_struct *work)
int chip_ls; /* which LSx to use (0-3 potentially) */
int ls_led; /* which set of bits within LSx to use (0-3) */
pca955x_led = container_of(work, struct pca955x_led, work);
pca955x_led = container_of(led_cdev, struct pca955x_led, led_cdev);
pca955x = pca955x_led->pca955x;
chip_ls = pca955x_led->led_num / 4;
......@@ -211,7 +209,7 @@ static void pca955x_led_work(struct work_struct *work)
ls = pca955x_read_ls(pca955x->client, chip_ls);
switch (pca955x_led->brightness) {
switch (value) {
case LED_FULL:
ls = pca955x_ledsel(ls, ls_led, PCA955X_LS_LED_ON);
break;
......@@ -230,7 +228,7 @@ static void pca955x_led_work(struct work_struct *work)
* just turning off for all other values.
*/
pca955x_write_pwm(pca955x->client, 1,
255 - pca955x_led->brightness);
255 - value);
ls = pca955x_ledsel(ls, ls_led, PCA955X_LS_BLINK1);
break;
}
......@@ -238,21 +236,8 @@ static void pca955x_led_work(struct work_struct *work)
pca955x_write_ls(pca955x->client, chip_ls, ls);
mutex_unlock(&pca955x->lock);
}
static void pca955x_led_set(struct led_classdev *led_cdev, enum led_brightness value)
{
struct pca955x_led *pca955x;
pca955x = container_of(led_cdev, struct pca955x_led, led_cdev);
pca955x->brightness = value;
/*
* Must use workqueue for the actual I/O since I2C operations
* can sleep.
*/
schedule_work(&pca955x->work);
return 0;
}
static int pca955x_probe(struct i2c_client *client,
......@@ -328,9 +313,7 @@ static int pca955x_probe(struct i2c_client *client,
}
pca955x_led->led_cdev.name = pca955x_led->name;
pca955x_led->led_cdev.brightness_set = pca955x_led_set;
INIT_WORK(&pca955x_led->work, pca955x_led_work);
pca955x_led->led_cdev.brightness_set_blocking = pca955x_led_set;
err = led_classdev_register(&client->dev,
&pca955x_led->led_cdev);
......@@ -355,10 +338,8 @@ static int pca955x_probe(struct i2c_client *client,
return 0;
exit:
while (i--) {
while (i--)
led_classdev_unregister(&pca955x->leds[i].led_cdev);
cancel_work_sync(&pca955x->leds[i].work);
}
return err;
}
......@@ -368,10 +349,8 @@ static int pca955x_remove(struct i2c_client *client)
struct pca955x *pca955x = i2c_get_clientdata(client);
int i;
for (i = 0; i < pca955x->chipdef->bits; i++) {
for (i = 0; i < pca955x->chipdef->bits; i++)
led_classdev_unregister(&pca955x->leds[i].led_cdev);
cancel_work_sync(&pca955x->leds[i].work);
}
return 0;
}
......
......@@ -32,7 +32,6 @@
#include <linux/leds.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/workqueue.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/platform_data/leds-pca963x.h>
......@@ -96,11 +95,6 @@ static const struct i2c_device_id pca963x_id[] = {
};
MODULE_DEVICE_TABLE(i2c, pca963x_id);
enum pca963x_cmd {
BRIGHTNESS_SET,
BLINK_SET,
};
struct pca963x_led;
struct pca963x {
......@@ -112,47 +106,52 @@ struct pca963x {
struct pca963x_led {
struct pca963x *chip;
struct work_struct work;
enum led_brightness brightness;
struct led_classdev led_cdev;
int led_num; /* 0 .. 15 potentially */
enum pca963x_cmd cmd;
char name[32];
u8 gdc;
u8 gfrq;
};
static void pca963x_brightness_work(struct pca963x_led *pca963x)
static int pca963x_brightness(struct pca963x_led *pca963x,
enum led_brightness brightness)
{
u8 ledout_addr = pca963x->chip->chipdef->ledout_base
+ (pca963x->led_num / 4);
u8 ledout;
int shift = 2 * (pca963x->led_num % 4);
u8 mask = 0x3 << shift;
int ret;
mutex_lock(&pca963x->chip->mutex);
ledout = i2c_smbus_read_byte_data(pca963x->chip->client, ledout_addr);
switch (pca963x->brightness) {
switch (brightness) {
case LED_FULL:
i2c_smbus_write_byte_data(pca963x->chip->client, ledout_addr,
ret = i2c_smbus_write_byte_data(pca963x->chip->client,
ledout_addr,
(ledout & ~mask) | (PCA963X_LED_ON << shift));
break;
case LED_OFF:
i2c_smbus_write_byte_data(pca963x->chip->client, ledout_addr,
ledout & ~mask);
ret = i2c_smbus_write_byte_data(pca963x->chip->client,
ledout_addr, ledout & ~mask);
break;
default:
i2c_smbus_write_byte_data(pca963x->chip->client,
ret = i2c_smbus_write_byte_data(pca963x->chip->client,
PCA963X_PWM_BASE + pca963x->led_num,
pca963x->brightness);
i2c_smbus_write_byte_data(pca963x->chip->client, ledout_addr,
brightness);
if (ret < 0)
goto unlock;
ret = i2c_smbus_write_byte_data(pca963x->chip->client,
ledout_addr,
(ledout & ~mask) | (PCA963X_LED_PWM << shift));
break;
}
unlock:
mutex_unlock(&pca963x->chip->mutex);
return ret;
}
static void pca963x_blink_work(struct pca963x_led *pca963x)
static void pca963x_blink(struct pca963x_led *pca963x)
{
u8 ledout_addr = pca963x->chip->chipdef->ledout_base +
(pca963x->led_num / 4);
......@@ -180,36 +179,14 @@ static void pca963x_blink_work(struct pca963x_led *pca963x)
mutex_unlock(&pca963x->chip->mutex);
}
static void pca963x_work(struct work_struct *work)
{
struct pca963x_led *pca963x = container_of(work,
struct pca963x_led, work);
switch (pca963x->cmd) {
case BRIGHTNESS_SET:
pca963x_brightness_work(pca963x);
break;
case BLINK_SET:
pca963x_blink_work(pca963x);
break;
}
}
static void pca963x_led_set(struct led_classdev *led_cdev,
static int pca963x_led_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
struct pca963x_led *pca963x;
pca963x = container_of(led_cdev, struct pca963x_led, led_cdev);
pca963x->cmd = BRIGHTNESS_SET;
pca963x->brightness = value;
/*
* Must use workqueue for the actual I/O since I2C operations
* can sleep.
*/
schedule_work(&pca963x->work);
return pca963x_brightness(pca963x, value);
}
static int pca963x_blink_set(struct led_classdev *led_cdev,
......@@ -254,15 +231,10 @@ static int pca963x_blink_set(struct led_classdev *led_cdev,
*/
gfrq = (period * 24 / 1000) - 1;
pca963x->cmd = BLINK_SET;
pca963x->gdc = gdc;
pca963x->gfrq = gfrq;
/*
* Must use workqueue for the actual I/O since I2C operations
* can sleep.
*/
schedule_work(&pca963x->work);
pca963x_blink(pca963x);
*delay_on = time_on;
*delay_off = time_off;
......@@ -409,13 +381,11 @@ static int pca963x_probe(struct i2c_client *client,
client->addr, i);
pca963x[i].led_cdev.name = pca963x[i].name;
pca963x[i].led_cdev.brightness_set = pca963x_led_set;
pca963x[i].led_cdev.brightness_set_blocking = pca963x_led_set;
if (pdata && pdata->blink_type == PCA963X_HW_BLINK)
pca963x[i].led_cdev.blink_set = pca963x_blink_set;
INIT_WORK(&pca963x[i].work, pca963x_work);
err = led_classdev_register(&client->dev, &pca963x[i].led_cdev);
if (err < 0)
goto exit;
......@@ -435,10 +405,8 @@ static int pca963x_probe(struct i2c_client *client,
return 0;
exit:
while (i--) {
while (i--)
led_classdev_unregister(&pca963x[i].led_cdev);
cancel_work_sync(&pca963x[i].work);
}
return err;
}
......@@ -448,10 +416,8 @@ static int pca963x_remove(struct i2c_client *client)
struct pca963x *pca963x = i2c_get_clientdata(client);
int i;
for (i = 0; i < pca963x->chipdef->n_leds; i++) {
for (i = 0; i < pca963x->chipdef->n_leds; i++)
led_classdev_unregister(&pca963x->leds[i].led_cdev);
cancel_work_sync(&pca963x->leds[i].work);
}
return 0;
}
......
......@@ -77,7 +77,7 @@ static int powernv_get_led_type(const char *led_type_desc)
* This function is called from work queue task context when ever it gets
* scheduled. This function can sleep at opal_async_wait_response call.
*/
static void powernv_led_set(struct powernv_led_data *powernv_led,
static int powernv_led_set(struct powernv_led_data *powernv_led,
enum led_brightness value)
{
int rc, token;
......@@ -99,7 +99,7 @@ static void powernv_led_set(struct powernv_led_data *powernv_led,
if (token != -ERESTARTSYS)
dev_err(dev, "%s: Couldn't get OPAL async token\n",
__func__);
return;
return token;
}
rc = opal_leds_set_ind(token, powernv_led->loc_code,
......@@ -125,6 +125,7 @@ static void powernv_led_set(struct powernv_led_data *powernv_led,
out_token:
opal_async_release_token(token);
return rc;
}
/*
......@@ -173,20 +174,23 @@ static enum led_brightness powernv_led_get(struct powernv_led_data *powernv_led)
* LED classdev 'brightness_get' function. This schedules work
* to update LED state.
*/
static void powernv_brightness_set(struct led_classdev *led_cdev,
static int powernv_brightness_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
struct powernv_led_data *powernv_led =
container_of(led_cdev, struct powernv_led_data, cdev);
struct powernv_led_common *powernv_led_common = powernv_led->common;
int rc;
/* Do not modify LED in unload path */
if (powernv_led_common->led_disabled)
return;
return 0;
mutex_lock(&powernv_led_common->lock);
powernv_led_set(powernv_led, value);
rc = powernv_led_set(powernv_led, value);
mutex_unlock(&powernv_led_common->lock);
return rc;
}
/* LED classdev 'brightness_get' function */
......@@ -227,7 +231,7 @@ static int powernv_led_create(struct device *dev,
return -ENOMEM;
}
powernv_led->cdev.brightness_set = powernv_brightness_set;
powernv_led->cdev.brightness_set_blocking = powernv_brightness_set;
powernv_led->cdev.brightness_get = powernv_brightness_get;
powernv_led->cdev.brightness = LED_OFF;
powernv_led->cdev.max_brightness = LED_FULL;
......@@ -256,8 +260,6 @@ static int powernv_led_classdev(struct platform_device *pdev,
for_each_child_of_node(led_node, np) {
p = of_find_property(np, "led-types", NULL);
if (!p)
continue;
while ((cur = of_prop_next_string(p, cur)) != NULL) {
powernv_led = devm_kzalloc(dev, sizeof(*powernv_led),
......
......@@ -22,12 +22,10 @@
#include <linux/pwm.h>
#include <linux/leds_pwm.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
struct led_pwm_data {
struct led_classdev cdev;
struct pwm_device *pwm;
struct work_struct work;
unsigned int active_low;
unsigned int period;
int duty;
......@@ -51,14 +49,6 @@ static void __led_pwm_set(struct led_pwm_data *led_dat)
pwm_enable(led_dat->pwm);
}
static void led_pwm_work(struct work_struct *work)
{
struct led_pwm_data *led_dat =
container_of(work, struct led_pwm_data, work);
__led_pwm_set(led_dat);
}
static void led_pwm_set(struct led_classdev *led_cdev,
enum led_brightness brightness)
{
......@@ -75,12 +65,16 @@ static void led_pwm_set(struct led_classdev *led_cdev,
led_dat->duty = duty;
if (led_dat->can_sleep)
schedule_work(&led_dat->work);
else
__led_pwm_set(led_dat);
}
static int led_pwm_set_blocking(struct led_classdev *led_cdev,
enum led_brightness brightness)
{
led_pwm_set(led_cdev, brightness);
return 0;
}
static inline size_t sizeof_pwm_leds_priv(int num_leds)
{
return sizeof(struct led_pwm_priv) +
......@@ -89,11 +83,8 @@ static inline size_t sizeof_pwm_leds_priv(int num_leds)
static void led_pwm_cleanup(struct led_pwm_priv *priv)
{
while (priv->num_leds--) {
while (priv->num_leds--)
led_classdev_unregister(&priv->leds[priv->num_leds].cdev);
if (priv->leds[priv->num_leds].can_sleep)
cancel_work_sync(&priv->leds[priv->num_leds].work);
}
}
static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv,
......@@ -105,7 +96,6 @@ static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv,
led_data->active_low = led->active_low;
led_data->cdev.name = led->name;
led_data->cdev.default_trigger = led->default_trigger;
led_data->cdev.brightness_set = led_pwm_set;
led_data->cdev.brightness = LED_OFF;
led_data->cdev.max_brightness = led->max_brightness;
led_data->cdev.flags = LED_CORE_SUSPENDRESUME;
......@@ -122,8 +112,10 @@ static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv,
}
led_data->can_sleep = pwm_can_sleep(led_data->pwm);
if (led_data->can_sleep)
INIT_WORK(&led_data->work, led_pwm_work);
if (!led_data->can_sleep)
led_data->cdev.brightness_set = led_pwm_set;
else
led_data->cdev.brightness_set_blocking = led_pwm_set_blocking;
led_data->period = pwm_get_period(led_data->pwm);
if (!led_data->period && (led->pwm_period_ns > 0))
......@@ -132,6 +124,7 @@ static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv,
ret = led_classdev_register(dev, &led_data->cdev);
if (ret == 0) {
priv->num_leds++;
led_pwm_set(&led_data->cdev, led_data->cdev.brightness);
} else {
dev_err(dev, "failed to register PWM led for %s: %d\n",
led->name, ret);
......@@ -236,6 +229,6 @@ static struct platform_driver led_pwm_driver = {
module_platform_driver(led_pwm_driver);
MODULE_AUTHOR("Luotao Fu <l.fu@pengutronix.de>");
MODULE_DESCRIPTION("PWM LED driver for PXA");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("generic PWM LED driver");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:leds-pwm");
......@@ -14,7 +14,6 @@
#include <linux/module.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <linux/leds.h>
#include <linux/leds-regulator.h>
#include <linux/platform_device.h>
......@@ -25,10 +24,8 @@
struct regulator_led {
struct led_classdev cdev;
enum led_brightness value;
int enabled;
struct mutex mutex;
struct work_struct work;
struct regulator *vcc;
};
......@@ -94,22 +91,24 @@ static void regulator_led_disable(struct regulator_led *led)
led->enabled = 0;
}
static void regulator_led_set_value(struct regulator_led *led)
static int regulator_led_brightness_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
struct regulator_led *led = to_regulator_led(led_cdev);
int voltage;
int ret;
int ret = 0;
mutex_lock(&led->mutex);
if (led->value == LED_OFF) {
if (value == LED_OFF) {
regulator_led_disable(led);
goto out;
}
if (led->cdev.max_brightness > 1) {
voltage = led_regulator_get_voltage(led->vcc, led->value);
voltage = led_regulator_get_voltage(led->vcc, value);
dev_dbg(led->cdev.dev, "brightness: %d voltage: %d\n",
led->value, voltage);
value, voltage);
ret = regulator_set_voltage(led->vcc, voltage, voltage);
if (ret != 0)
......@@ -121,23 +120,7 @@ static void regulator_led_set_value(struct regulator_led *led)
out:
mutex_unlock(&led->mutex);
}
static void led_work(struct work_struct *work)
{
struct regulator_led *led;
led = container_of(work, struct regulator_led, work);
regulator_led_set_value(led);
}
static void regulator_led_brightness_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
struct regulator_led *led = to_regulator_led(led_cdev);
led->value = value;
schedule_work(&led->work);
return ret;
}
static int regulator_led_probe(struct platform_device *pdev)
......@@ -169,9 +152,8 @@ static int regulator_led_probe(struct platform_device *pdev)
pdata->brightness);
return -EINVAL;
}
led->value = pdata->brightness;
led->cdev.brightness_set = regulator_led_brightness_set;
led->cdev.brightness_set_blocking = regulator_led_brightness_set;
led->cdev.name = pdata->name;
led->cdev.flags |= LED_CORE_SUSPENDRESUME;
led->vcc = vcc;
......@@ -181,21 +163,18 @@ static int regulator_led_probe(struct platform_device *pdev)
led->enabled = 1;
mutex_init(&led->mutex);
INIT_WORK(&led->work, led_work);
platform_set_drvdata(pdev, led);
ret = led_classdev_register(&pdev->dev, &led->cdev);
if (ret < 0) {
cancel_work_sync(&led->work);
if (ret < 0)
return ret;
}
/* to expose the default value to userspace */
led->cdev.brightness = led->value;
led->cdev.brightness = pdata->brightness;
/* Set the default led status */
regulator_led_set_value(led);
regulator_led_brightness_set(&led->cdev, led->cdev.brightness);
return 0;
}
......@@ -205,7 +184,6 @@ static int regulator_led_remove(struct platform_device *pdev)
struct regulator_led *led = platform_get_drvdata(pdev);
led_classdev_unregister(&led->cdev);
cancel_work_sync(&led->work);
regulator_led_disable(led);
return 0;
}
......
......@@ -234,28 +234,19 @@ static struct platform_driver sunfire_fhc_led_driver = {
},
};
static struct platform_driver * const drivers[] = {
&sunfire_clockboard_led_driver,
&sunfire_fhc_led_driver,
};
static int __init sunfire_leds_init(void)
{
int err = platform_driver_register(&sunfire_clockboard_led_driver);
if (err) {
pr_err("Could not register clock board LED driver\n");
return err;
}
err = platform_driver_register(&sunfire_fhc_led_driver);
if (err) {
pr_err("Could not register FHC LED driver\n");
platform_driver_unregister(&sunfire_clockboard_led_driver);
}
return err;
return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
}
static void __exit sunfire_leds_exit(void)
{
platform_driver_unregister(&sunfire_clockboard_led_driver);
platform_driver_unregister(&sunfire_fhc_led_driver);
platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
}
module_init(sunfire_leds_init);
......
......@@ -20,7 +20,7 @@
* MA 02111-1307 USA
*/
#include <linux/io.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/of_device.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
......@@ -139,29 +139,17 @@ static int syscon_led_probe(struct platform_device *pdev)
return 0;
}
static int syscon_led_remove(struct platform_device *pdev)
{
struct syscon_led *sled = platform_get_drvdata(pdev);
led_classdev_unregister(&sled->cdev);
/* Turn it off */
regmap_update_bits(sled->map, sled->offset, sled->mask, 0);
return 0;
}
static const struct of_device_id of_syscon_leds_match[] = {
{ .compatible = "register-bit-led", },
{},
};
MODULE_DEVICE_TABLE(of, of_syscon_leds_match);
static struct platform_driver syscon_led_driver = {
.probe = syscon_led_probe,
.remove = syscon_led_remove,
.driver = {
.name = "leds-syscon",
.of_match_table = of_syscon_leds_match,
.suppress_bind_attrs = true,
},
};
module_platform_driver(syscon_led_driver);
builtin_platform_driver(syscon_led_driver);
......@@ -14,7 +14,6 @@
#include <linux/of_device.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#define TLC591XX_MAX_LEDS 16
......@@ -42,13 +41,11 @@
#define LEDOUT_MASK 0x3
#define ldev_to_led(c) container_of(c, struct tlc591xx_led, ldev)
#define work_to_led(work) container_of(work, struct tlc591xx_led, work)
struct tlc591xx_led {
bool active;
unsigned int led_no;
struct led_classdev ldev;
struct work_struct work;
struct tlc591xx_priv *priv;
};
......@@ -110,12 +107,12 @@ tlc591xx_set_pwm(struct tlc591xx_priv *priv, struct tlc591xx_led *led,
return regmap_write(priv->regmap, pwm, brightness);
}
static void
tlc591xx_led_work(struct work_struct *work)
static int
tlc591xx_brightness_set(struct led_classdev *led_cdev,
enum led_brightness brightness)
{
struct tlc591xx_led *led = work_to_led(work);
struct tlc591xx_led *led = ldev_to_led(led_cdev);
struct tlc591xx_priv *priv = led->priv;
enum led_brightness brightness = led->ldev.brightness;
int err;
switch (brightness) {
......@@ -131,18 +128,7 @@ tlc591xx_led_work(struct work_struct *work)
err = tlc591xx_set_pwm(priv, led, brightness);
}
if (err)
dev_err(led->ldev.dev, "Failed setting brightness\n");
}
static void
tlc591xx_brightness_set(struct led_classdev *led_cdev,
enum led_brightness brightness)
{
struct tlc591xx_led *led = ldev_to_led(led_cdev);
led->ldev.brightness = brightness;
schedule_work(&led->work);
return err;
}
static void
......@@ -151,10 +137,8 @@ tlc591xx_destroy_devices(struct tlc591xx_priv *priv, unsigned int j)
int i = j;
while (--i >= 0) {
if (priv->leds[i].active) {
if (priv->leds[i].active)
led_classdev_unregister(&priv->leds[i].ldev);
cancel_work_sync(&priv->leds[i].work);
}
}
}
......@@ -175,9 +159,8 @@ tlc591xx_configure(struct device *dev,
led->priv = priv;
led->led_no = i;
led->ldev.brightness_set = tlc591xx_brightness_set;
led->ldev.brightness_set_blocking = tlc591xx_brightness_set;
led->ldev.max_brightness = LED_FULL;
INIT_WORK(&led->work, tlc591xx_led_work);
err = led_classdev_register(dev, &led->ldev);
if (err < 0) {
dev_err(dev, "couldn't register LED %s\n",
......
......@@ -23,7 +23,6 @@
struct wm831x_status {
struct led_classdev cdev;
struct wm831x *wm831x;
struct work_struct work;
struct mutex mutex;
spinlock_t value_lock;
......@@ -40,10 +39,8 @@ struct wm831x_status {
#define to_wm831x_status(led_cdev) \
container_of(led_cdev, struct wm831x_status, cdev)
static void wm831x_status_work(struct work_struct *work)
static void wm831x_status_set(struct wm831x_status *led)
{
struct wm831x_status *led = container_of(work, struct wm831x_status,
work);
unsigned long flags;
mutex_lock(&led->mutex);
......@@ -70,7 +67,7 @@ static void wm831x_status_work(struct work_struct *work)
mutex_unlock(&led->mutex);
}
static void wm831x_status_set(struct led_classdev *led_cdev,
static int wm831x_status_brightness_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
struct wm831x_status *led = to_wm831x_status(led_cdev);
......@@ -80,8 +77,10 @@ static void wm831x_status_set(struct led_classdev *led_cdev,
led->brightness = value;
if (value == LED_OFF)
led->blink = 0;
schedule_work(&led->work);
spin_unlock_irqrestore(&led->value_lock, flags);
wm831x_status_set(led);
return 0;
}
static int wm831x_status_blink_set(struct led_classdev *led_cdev,
......@@ -147,11 +146,8 @@ static int wm831x_status_blink_set(struct led_classdev *led_cdev,
else
led->blink = 0;
/* Always update; if we fail turn off blinking since we expect
* a software fallback. */
schedule_work(&led->work);
spin_unlock_irqrestore(&led->value_lock, flags);
wm831x_status_set(led);
return ret;
}
......@@ -206,11 +202,9 @@ static ssize_t wm831x_status_src_store(struct device *dev,
for (i = 0; i < ARRAY_SIZE(led_src_texts); i++) {
if (!strcmp(name, led_src_texts[i])) {
mutex_lock(&led->mutex);
led->src = i;
schedule_work(&led->work);
mutex_unlock(&led->mutex);
wm831x_status_set(led);
}
}
......@@ -262,7 +256,6 @@ static int wm831x_status_probe(struct platform_device *pdev)
pdata.name = dev_name(&pdev->dev);
mutex_init(&drvdata->mutex);
INIT_WORK(&drvdata->work, wm831x_status_work);
spin_lock_init(&drvdata->value_lock);
/* We cache the configuration register and read startup values
......@@ -287,7 +280,7 @@ static int wm831x_status_probe(struct platform_device *pdev)
drvdata->cdev.name = pdata.name;
drvdata->cdev.default_trigger = pdata.default_trigger;
drvdata->cdev.brightness_set = wm831x_status_set;
drvdata->cdev.brightness_set_blocking = wm831x_status_brightness_set;
drvdata->cdev.blink_set = wm831x_status_blink_set;
drvdata->cdev.groups = wm831x_status_groups;
......
......@@ -89,40 +89,42 @@ static const int isink_cur[] = {
#define to_wm8350_led(led_cdev) \
container_of(led_cdev, struct wm8350_led, cdev)
static void wm8350_led_enable(struct wm8350_led *led)
static int wm8350_led_enable(struct wm8350_led *led)
{
int ret;
int ret = 0;
if (led->enabled)
return;
return ret;
ret = regulator_enable(led->isink);
if (ret != 0) {
dev_err(led->cdev.dev, "Failed to enable ISINK: %d\n", ret);
return;
return ret;
}
ret = regulator_enable(led->dcdc);
if (ret != 0) {
dev_err(led->cdev.dev, "Failed to enable DCDC: %d\n", ret);
regulator_disable(led->isink);
return;
return ret;
}
led->enabled = 1;
return ret;
}
static void wm8350_led_disable(struct wm8350_led *led)
static int wm8350_led_disable(struct wm8350_led *led)
{
int ret;
int ret = 0;
if (!led->enabled)
return;
return ret;
ret = regulator_disable(led->dcdc);
if (ret != 0) {
dev_err(led->cdev.dev, "Failed to disable DCDC: %d\n", ret);
return;
return ret;
}
ret = regulator_disable(led->isink);
......@@ -132,27 +134,29 @@ static void wm8350_led_disable(struct wm8350_led *led)
if (ret != 0)
dev_err(led->cdev.dev, "Failed to reenable DCDC: %d\n",
ret);
return;
return ret;
}
led->enabled = 0;
return ret;
}
static void led_work(struct work_struct *work)
static int wm8350_led_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
struct wm8350_led *led = container_of(work, struct wm8350_led, work);
struct wm8350_led *led = to_wm8350_led(led_cdev);
unsigned long flags;
int ret;
int uA;
unsigned long flags;
mutex_lock(&led->mutex);
led->value = value;
spin_lock_irqsave(&led->value_lock, flags);
if (led->value == LED_OFF) {
spin_unlock_irqrestore(&led->value_lock, flags);
wm8350_led_disable(led);
goto out;
return wm8350_led_disable(led);
}
/* This scales linearly into the index of valid current
......@@ -166,36 +170,21 @@ static void led_work(struct work_struct *work)
ret = regulator_set_current_limit(led->isink, isink_cur[uA],
isink_cur[uA]);
if (ret != 0)
if (ret != 0) {
dev_err(led->cdev.dev, "Failed to set %duA: %d\n",
isink_cur[uA], ret);
return ret;
}
wm8350_led_enable(led);
out:
mutex_unlock(&led->mutex);
}
static void wm8350_led_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
struct wm8350_led *led = to_wm8350_led(led_cdev);
unsigned long flags;
spin_lock_irqsave(&led->value_lock, flags);
led->value = value;
schedule_work(&led->work);
spin_unlock_irqrestore(&led->value_lock, flags);
return wm8350_led_enable(led);
}
static void wm8350_led_shutdown(struct platform_device *pdev)
{
struct wm8350_led *led = platform_get_drvdata(pdev);
mutex_lock(&led->mutex);
led->value = LED_OFF;
wm8350_led_disable(led);
mutex_unlock(&led->mutex);
}
static int wm8350_led_probe(struct platform_device *pdev)
......@@ -232,7 +221,7 @@ static int wm8350_led_probe(struct platform_device *pdev)
if (led == NULL)
return -ENOMEM;
led->cdev.brightness_set = wm8350_led_set;
led->cdev.brightness_set_blocking = wm8350_led_set;
led->cdev.default_trigger = pdata->default_trigger;
led->cdev.name = pdata->name;
led->cdev.flags |= LED_CORE_SUSPENDRESUME;
......@@ -251,8 +240,6 @@ static int wm8350_led_probe(struct platform_device *pdev)
pdata->max_uA);
spin_lock_init(&led->value_lock);
mutex_init(&led->mutex);
INIT_WORK(&led->work, led_work);
led->value = LED_OFF;
platform_set_drvdata(pdev, led);
......@@ -264,7 +251,6 @@ static int wm8350_led_remove(struct platform_device *pdev)
struct wm8350_led *led = platform_get_drvdata(pdev);
led_classdev_unregister(&led->cdev);
flush_work(&led->work);
wm8350_led_disable(led);
return 0;
}
......
......@@ -16,29 +16,6 @@
#include <linux/rwsem.h>
#include <linux/leds.h>
static inline void led_set_brightness_async(struct led_classdev *led_cdev,
enum led_brightness value)
{
value = min(value, led_cdev->max_brightness);
led_cdev->brightness = value;
if (!(led_cdev->flags & LED_SUSPENDED))
led_cdev->brightness_set(led_cdev, value);
}
static inline int led_set_brightness_sync(struct led_classdev *led_cdev,
enum led_brightness value)
{
int ret = 0;
led_cdev->brightness = min(value, led_cdev->max_brightness);
if (!(led_cdev->flags & LED_SUSPENDED))
ret = led_cdev->brightness_set_sync(led_cdev,
led_cdev->brightness);
return ret;
}
static inline int led_get_brightness(struct led_classdev *led_cdev)
{
return led_cdev->brightness;
......@@ -46,6 +23,10 @@ static inline int led_get_brightness(struct led_classdev *led_cdev)
void led_init_core(struct led_classdev *led_cdev);
void led_stop_software_blink(struct led_classdev *led_cdev);
void led_set_brightness_nopm(struct led_classdev *led_cdev,
enum led_brightness value);
void led_set_brightness_nosleep(struct led_classdev *led_cdev,
enum led_brightness value);
extern struct rw_semaphore leds_list_lock;
extern struct list_head leds_list;
......
......@@ -51,9 +51,9 @@ static int fb_notifier_callback(struct notifier_block *p,
if ((n->old_status == UNBLANK) ^ n->invert) {
n->brightness = led->brightness;
led_set_brightness_async(led, LED_OFF);
led_set_brightness_nosleep(led, LED_OFF);
} else {
led_set_brightness_async(led, n->brightness);
led_set_brightness_nosleep(led, n->brightness);
}
n->old_status = new_status;
......@@ -89,9 +89,9 @@ static ssize_t bl_trig_invert_store(struct device *dev,
/* After inverting, we need to update the LED. */
if ((n->old_status == BLANK) ^ n->invert)
led_set_brightness_async(led, LED_OFF);
led_set_brightness_nosleep(led, LED_OFF);
else
led_set_brightness_async(led, n->brightness);
led_set_brightness_nosleep(led, n->brightness);
return num;
}
......
......@@ -19,7 +19,6 @@
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>
......@@ -140,27 +139,4 @@ static int __init ledtrig_cpu_init(void)
return 0;
}
module_init(ledtrig_cpu_init);
static void __exit ledtrig_cpu_exit(void)
{
int cpu;
unregister_cpu_notifier(&ledtrig_cpu_nb);
for_each_possible_cpu(cpu) {
struct led_trigger_cpu *trig = &per_cpu(cpu_trig, cpu);
led_trigger_unregister_simple(trig->_trig);
trig->_trig = NULL;
memset(trig->name, 0, MAX_NAME_LEN);
}
unregister_syscore_ops(&ledtrig_cpu_syscore_ops);
}
module_exit(ledtrig_cpu_exit);
MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
MODULE_AUTHOR("Bryan Wu <bryan.wu@canonical.com>");
MODULE_DESCRIPTION("CPU LED trigger");
MODULE_LICENSE("GPL");
device_initcall(ledtrig_cpu_init);
......@@ -19,7 +19,7 @@
static void defon_trig_activate(struct led_classdev *led_cdev)
{
led_set_brightness_async(led_cdev, led_cdev->max_brightness);
led_set_brightness_nosleep(led_cdev, led_cdev->max_brightness);
}
static struct led_trigger defon_led_trigger = {
......
......@@ -54,12 +54,12 @@ static void gpio_trig_work(struct work_struct *work)
if (tmp) {
if (gpio_data->desired_brightness)
led_set_brightness_async(gpio_data->led,
led_set_brightness_nosleep(gpio_data->led,
gpio_data->desired_brightness);
else
led_set_brightness_async(gpio_data->led, LED_FULL);
led_set_brightness_nosleep(gpio_data->led, LED_FULL);
} else {
led_set_brightness_async(gpio_data->led, LED_OFF);
led_set_brightness_nosleep(gpio_data->led, LED_OFF);
}
}
......
......@@ -38,7 +38,7 @@ static void led_heartbeat_function(unsigned long data)
unsigned long delay = 0;
if (unlikely(panic_heartbeats)) {
led_set_brightness(led_cdev, LED_OFF);
led_set_brightness_nosleep(led_cdev, LED_OFF);
return;
}
......@@ -81,7 +81,7 @@ static void led_heartbeat_function(unsigned long data)
break;
}
led_set_brightness_async(led_cdev, brightness);
led_set_brightness_nosleep(led_cdev, brightness);
mod_timer(&heartbeat_data->timer, jiffies + delay);
}
......
......@@ -11,7 +11,6 @@
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/leds.h>
......@@ -33,15 +32,4 @@ static int __init ledtrig_ide_init(void)
led_trigger_register_simple("ide-disk", &ledtrig_ide);
return 0;
}
static void __exit ledtrig_ide_exit(void)
{
led_trigger_unregister_simple(ledtrig_ide);
}
module_init(ledtrig_ide_init);
module_exit(ledtrig_ide_exit);
MODULE_AUTHOR("Richard Purdie <rpurdie@openedhand.com>");
MODULE_DESCRIPTION("LED IDE Disk Activity Trigger");
MODULE_LICENSE("GPL");
device_initcall(ledtrig_ide_init);
......@@ -63,9 +63,9 @@ static ssize_t led_invert_store(struct device *dev,
oneshot_data->invert = !!state;
if (oneshot_data->invert)
led_set_brightness_async(led_cdev, LED_FULL);
led_set_brightness_nosleep(led_cdev, LED_FULL);
else
led_set_brightness_async(led_cdev, LED_OFF);
led_set_brightness_nosleep(led_cdev, LED_OFF);
return size;
}
......@@ -201,4 +201,4 @@ module_exit(oneshot_trig_exit);
MODULE_AUTHOR("Fabio Baltieri <fabio.baltieri@gmail.com>");
MODULE_DESCRIPTION("One-shot LED trigger");
MODULE_LICENSE("GPL");
MODULE_LICENSE("GPL v2");
......@@ -41,7 +41,7 @@ static void transient_timer_function(unsigned long data)
struct transient_trig_data *transient_data = led_cdev->trigger_data;
transient_data->activate = 0;
led_set_brightness_async(led_cdev, transient_data->restore_state);
led_set_brightness_nosleep(led_cdev, transient_data->restore_state);
}
static ssize_t transient_activate_show(struct device *dev,
......@@ -72,7 +72,7 @@ static ssize_t transient_activate_store(struct device *dev,
if (state == 0 && transient_data->activate == 1) {
del_timer(&transient_data->timer);
transient_data->activate = state;
led_set_brightness_async(led_cdev,
led_set_brightness_nosleep(led_cdev,
transient_data->restore_state);
return size;
}
......@@ -81,11 +81,11 @@ static ssize_t transient_activate_store(struct device *dev,
if (state == 1 && transient_data->activate == 0 &&
transient_data->duration != 0) {
transient_data->activate = state;
led_set_brightness_async(led_cdev, transient_data->state);
led_set_brightness_nosleep(led_cdev, transient_data->state);
transient_data->restore_state =
(transient_data->state == LED_FULL) ? LED_OFF : LED_FULL;
mod_timer(&transient_data->timer,
jiffies + transient_data->duration);
jiffies + msecs_to_jiffies(transient_data->duration));
}
/* state == 0 && transient_data->activate == 0
......@@ -204,7 +204,7 @@ static void transient_trig_deactivate(struct led_classdev *led_cdev)
if (led_cdev->activated) {
del_timer_sync(&transient_data->timer);
led_set_brightness_async(led_cdev,
led_set_brightness_nosleep(led_cdev,
transient_data->restore_state);
device_remove_file(led_cdev->dev, &dev_attr_activate);
device_remove_file(led_cdev->dev, &dev_attr_duration);
......
......@@ -107,10 +107,10 @@ static void v4l2_flash_set_led_brightness(struct v4l2_flash *v4l2_flash,
if (ctrls[LED_MODE]->val != V4L2_FLASH_LED_MODE_TORCH)
return;
led_set_brightness(&v4l2_flash->fled_cdev->led_cdev,
led_set_brightness_sync(&v4l2_flash->fled_cdev->led_cdev,
brightness);
} else {
led_set_brightness(&v4l2_flash->iled_cdev->led_cdev,
led_set_brightness_sync(&v4l2_flash->iled_cdev->led_cdev,
brightness);
}
}
......@@ -206,11 +206,11 @@ static int v4l2_flash_s_ctrl(struct v4l2_ctrl *c)
case V4L2_CID_FLASH_LED_MODE:
switch (c->val) {
case V4L2_FLASH_LED_MODE_NONE:
led_set_brightness(led_cdev, LED_OFF);
led_set_brightness_sync(led_cdev, LED_OFF);
return led_set_flash_strobe(fled_cdev, false);
case V4L2_FLASH_LED_MODE_FLASH:
/* Turn the torch LED off */
led_set_brightness(led_cdev, LED_OFF);
led_set_brightness_sync(led_cdev, LED_OFF);
if (ctrls[STROBE_SOURCE]) {
external_strobe = (ctrls[STROBE_SOURCE]->val ==
V4L2_FLASH_STROBE_SOURCE_EXTERNAL);
......
......@@ -44,9 +44,9 @@ struct led_classdev {
#define LED_BLINK_ONESHOT (1 << 17)
#define LED_BLINK_ONESHOT_STOP (1 << 18)
#define LED_BLINK_INVERT (1 << 19)
#define LED_SYSFS_DISABLE (1 << 20)
#define SET_BRIGHTNESS_ASYNC (1 << 21)
#define SET_BRIGHTNESS_SYNC (1 << 22)
#define LED_BLINK_BRIGHTNESS_CHANGE (1 << 20)
#define LED_BLINK_DISABLE (1 << 21)
#define LED_SYSFS_DISABLE (1 << 22)
#define LED_DEV_CAP_FLASH (1 << 23)
/* Set LED brightness level */
......@@ -57,7 +57,7 @@ struct led_classdev {
* Set LED brightness level immediately - it can block the caller for
* the time required for accessing a LED device register.
*/
int (*brightness_set_sync)(struct led_classdev *led_cdev,
int (*brightness_set_blocking)(struct led_classdev *led_cdev,
enum led_brightness brightness);
/* Get LED brightness level */
enum led_brightness (*brightness_get)(struct led_classdev *led_cdev);
......@@ -156,10 +156,25 @@ extern void led_blink_set_oneshot(struct led_classdev *led_cdev,
*
* Set an LED's brightness, and, if necessary, cancel the
* software blink timer that implements blinking when the
* hardware doesn't.
* hardware doesn't. This function is guaranteed not to sleep.
*/
extern void led_set_brightness(struct led_classdev *led_cdev,
enum led_brightness brightness);
/**
* led_set_brightness_sync - set LED brightness synchronously
* @led_cdev: the LED to set
* @brightness: the brightness to set it to
*
* Set an LED's brightness immediately. This function will block
* the caller for the time required for accessing device registers,
* and it can sleep.
*
* Returns: 0 on success or negative error value on failure
*/
extern int led_set_brightness_sync(struct led_classdev *led_cdev,
enum led_brightness value);
/**
* led_update_brightness - update LED brightness
* @led_cdev: the LED to query
......@@ -231,6 +246,8 @@ ssize_t led_trigger_show(struct device *dev, struct device_attribute *attr,
/* Registration functions for complex triggers */
extern int led_trigger_register(struct led_trigger *trigger);
extern void led_trigger_unregister(struct led_trigger *trigger);
extern int devm_led_trigger_register(struct device *dev,
struct led_trigger *trigger);
extern void led_trigger_register_simple(const char *name,
struct led_trigger **trigger);
......
......@@ -715,7 +715,6 @@ struct wm8350_led_platform_data {
struct wm8350_led {
struct platform_device *pdev;
struct mutex mutex;
struct work_struct work;
spinlock_t value_lock;
enum led_brightness value;
......
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