forked from Minki/linux
- 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 -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJWkpEGAAoJEL1qUBy3i3wmwKgP/inH3kQ6RZgKw5g2sZtyLYbf W9eEXsGNIKGPmkgRXi3JauY5RiWK2vGAWmBLZCeOfnl/TKzOVvotUweT68dPpC9/ sd4R5aVNJ6o8lOWuZHWvql5HPc99ou8YUquoPZuHsG/JecB+7uIJUqTszq12+s7c Y6RY5KyGD/rMmw3QBWxIKxOMqDl9TvywUZp1LMmD2NP1hdWRuN4R3pnJxQbtPQMg F/OnXcu4UN+dzgFpNlqBOdoTXypNP8uJhVWWRuzBaDI1UXc1cHeNWyQc4aMM0FOm +U3csu/eUNClIIliN6rswXVR/Bi5VJGIj9VfnShf0CpW9ZaNUKTYvk0usHMH/tMQ 8mBVY84+XE5cLrRgohiuh0kcF+NqepYDRrte7XBFOFq4W14/l09cYWhA4N563y3N 18beRbNULVFHSk4IKBelnWuCwp2eG3K2JzOkaYay2U3Uxq5eJEK4xiNT36Ay30dK +vzEXSX998f/3ZRKHtBm6RYd8aaH2iSs0Z3dA9AjXxea58qc8lRu5/9DfSBFz1jo We4Wq7HOIMYJ6taNqfik8N7nIeWPVtOnfZxRGaZESezGR023LFCSLqe3wMkMfNVz 63Jd6RA81jlaCNV2h0IVZvKyvIaJ8Dp2jCEQViuPEbsYBYmIDkAr+BUK0VpZodwl t977bJDXp4ss1NXeT3kC =MW8D -----END PGP SIGNATURE----- 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 ...
This commit is contained in:
commit
2c487121e3
@ -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.
|
||||
*/
|
||||
led_cdev->blink_brightness = brightness;
|
||||
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;
|
||||
|
||||
led_stop_software_blink(led_cdev);
|
||||
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);
|
||||
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);
|
||||
led_set_brightness_nosleep(led_cdev, brightness);
|
||||
}
|
||||
EXPORT_SYMBOL(led_set_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;
|
||||
}
|
||||
|
||||
/* 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_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;
|
||||
|
@ -42,16 +42,16 @@
|
||||
#define BCM6328_LED_SHIFT_TEST BIT(30)
|
||||
#define BCM6328_LED_TEST BIT(31)
|
||||
#define BCM6328_INIT_MASK (BCM6328_SERIAL_LED_EN | \
|
||||
BCM6328_SERIAL_LED_MUX | \
|
||||
BCM6328_SERIAL_LED_MUX | \
|
||||
BCM6328_SERIAL_LED_CLK_NPOL | \
|
||||
BCM6328_SERIAL_LED_DATA_PPOL | \
|
||||
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 @@ failed_unregister_led1_R:
|
||||
|
||||
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)
|
||||
{
|
||||
struct dac124s085_led *led = container_of(work, struct dac124s085_led,
|
||||
work);
|
||||
u16 word;
|
||||
|
||||
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));
|
||||
mutex_unlock(&led->mutex);
|
||||
}
|
||||
|
||||
static void dac124s085_set_brightness(struct led_classdev *ldev,
|
||||
static int dac124s085_set_brightness(struct led_classdev *ldev,
|
||||
enum led_brightness brightness)
|
||||
{
|
||||
struct dac124s085_led *led = container_of(ldev, struct dac124s085_led,
|
||||
ldev);
|
||||
u16 word;
|
||||
int ret;
|
||||
|
||||
spin_lock(&led->lock);
|
||||
led->brightness = brightness;
|
||||
schedule_work(&led->work);
|
||||
spin_unlock(&led->lock);
|
||||
mutex_lock(&led->mutex);
|
||||
word = cpu_to_le16(((led->id) << 14) | REG_WRITE_UPDATE |
|
||||
(brightness & 0xfff));
|
||||
ret = spi_write(led->spi, (const u8 *)&word, sizeof(word));
|
||||
mutex_unlock(&led->mutex);
|
||||
|
||||
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);
|
||||
if (led_dat->blinking) {
|
||||
led_dat->platform_gpio_blink_set(led_dat->gpiod, level,
|
||||
NULL, NULL);
|
||||
led_dat->blinking = 0;
|
||||
} else {
|
||||
if (led_dat->blinking) {
|
||||
led_dat->platform_gpio_blink_set(led_dat->gpiod, level,
|
||||
NULL, NULL);
|
||||
led_dat->blinking = 0;
|
||||
} 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,
|
||||
enum led_brightness brightness)
|
||||
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 @@ out:
|
||||
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 @@ out:
|
||||
}
|
||||
|
||||
/* 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);
|
||||
int ret;
|
||||
|
||||
chip->br_torch = brightness;
|
||||
schedule_work(&chip->work_torch);
|
||||
mutex_lock(&chip->lock);
|
||||
ret = lm355x_control(chip, brightness, MODE_TORCH);
|
||||
mutex_unlock(&chip->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
mutex_lock(&chip->lock);
|
||||
lm355x_control(chip, chip->br_flash, MODE_FLASH);
|
||||
mutex_unlock(&chip->lock);
|
||||
}
|
||||
|
||||
static void lm355x_strobe_brightness_set(struct led_classdev *cdev,
|
||||
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);
|
||||
int ret;
|
||||
|
||||
chip->br_flash = brightness;
|
||||
schedule_work(&chip->work_flash);
|
||||
mutex_lock(&chip->lock);
|
||||
ret = lm355x_control(chip, brightness, MODE_FLASH);
|
||||
mutex_unlock(&chip->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
mutex_lock(&chip->lock);
|
||||
lm355x_control(chip, chip->br_indicator, MODE_INDIC);
|
||||
mutex_unlock(&chip->lock);
|
||||
}
|
||||
|
||||
static void lm355x_indicator_brightness_set(struct led_classdev *cdev,
|
||||
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 @@ out_strtoint:
|
||||
|
||||
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 @@ out_strtoint:
|
||||
|
||||
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);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&chip->lock);
|
||||
chip->br_flash = brightness;
|
||||
schedule_work(&chip->work_flash);
|
||||
ret = lm3642_control(chip, chip->br_flash, MODES_FLASH);
|
||||
mutex_unlock(&chip->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
mutex_lock(&chip->lock);
|
||||
lm3642_control(chip, chip->br_indicator, MODES_INDIC);
|
||||
mutex_unlock(&chip->lock);
|
||||
}
|
||||
|
||||
static void lm3642_indicator_brightness_set(struct led_classdev *cdev,
|
||||
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 @@ exit:
|
||||
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 @@ leave:
|
||||
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;
|
||||
|
||||
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 @@ out:
|
||||
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,45 +495,10 @@ 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);
|
||||
}
|
||||
|
||||
static int max77693_led_flash_brightness_set(
|
||||
struct led_classdev_flash *fled_cdev,
|
||||
u32 brightness)
|
||||
@ -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,10 +65,14 @@ 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);
|
||||
__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)
|
||||
@ -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,8 +67,8 @@ static void wm831x_status_work(struct work_struct *work)
|
||||
mutex_unlock(&led->mutex);
|
||||
}
|
||||
|
||||
static void wm831x_status_set(struct led_classdev *led_cdev,
|
||||
enum led_brightness value)
|
||||
static int wm831x_status_brightness_set(struct led_classdev *led_cdev,
|
||||
enum led_brightness value)
|
||||
{
|
||||
struct wm831x_status *led = to_wm831x_status(led_cdev);
|
||||
unsigned long flags;
|
||||
@ -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,8 +57,8 @@ 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,
|
||||
enum led_brightness brightness);
|
||||
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;
|
||||
|
Loading…
Reference in New Issue
Block a user