You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
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:
@@ -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);
|
||||
|
||||
+92
-32
@@ -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) {
|
||||
|
||||
+18
-41
@@ -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;
|
||||
|
||||
+37
-26
@@ -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);
|
||||
|
||||
+16
-21
@@ -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;
|
||||
|
||||
|
||||
+14
-25
@@ -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);
|
||||
|
||||
+17
-70
@@ -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;
|
||||
|
||||
+18
-28
@@ -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) {
|
||||
|
||||
+12
-27
@@ -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;
|
||||
}
|
||||
|
||||
+22
-40
@@ -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,
|
||||
};
|
||||
|
||||
+12
-38
@@ -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 = {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user