Skip to content

Commit

Permalink
Merge branch 'for-linus' of git://git.o-hand.com/linux-rpurdie-leds
Browse files Browse the repository at this point in the history
* 'for-linus' of git://git.o-hand.com/linux-rpurdie-leds:
  leds: Futher document blink_set
  leds: Add options to have GPIO LEDs start on or keep their state
  leds: LED driver for National Semiconductor LP3944 Funlight Chip
  leds: pca9532 - Indent using tabs, not spaces.
  leds: Remove an orphan Kconfig entry
  leds: Further document parameters for blink_set()
  leds: alix-leds2 fixed for Award BIOS
  leds: leds-gpio - fix a section mismatch
  leds: add the sysfs interface into the leds-bd2802 driver for changing wave pattern and led current.
  leds: change the license information
  leds: fix led-bd2802 errors while resuming
  • Loading branch information
torvalds committed Jun 28, 2009
2 parents 4075ea8 + a1dd8c6 commit 61abfd2
Show file tree
Hide file tree
Showing 11 changed files with 733 additions and 65 deletions.
50 changes: 50 additions & 0 deletions Documentation/leds-lp3944.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
Kernel driver lp3944
====================

* National Semiconductor LP3944 Fun-light Chip
Prefix: 'lp3944'
Addresses scanned: None (see the Notes section below)
Datasheet: Publicly available at the National Semiconductor website
http://www.national.com/pf/LP/LP3944.html

Authors:
Antonio Ospite <ospite@studenti.unina.it>


Description
-----------
The LP3944 is a helper chip that can drive up to 8 leds, with two programmable
DIM modes; it could even be used as a gpio expander but this driver assumes it
is used as a led controller.

The DIM modes are used to set _blink_ patterns for leds, the pattern is
specified supplying two parameters:
- period: from 0s to 1.6s
- duty cycle: percentage of the period the led is on, from 0 to 100

Setting a led in DIM0 or DIM1 mode makes it blink according to the pattern.
See the datasheet for details.

LP3944 can be found on Motorola A910 smartphone, where it drives the rgb
leds, the camera flash light and the lcds power.


Notes
-----
The chip is used mainly in embedded contexts, so this driver expects it is
registered using the i2c_board_info mechanism.

To register the chip at address 0x60 on adapter 0, set the platform data
according to include/linux/leds-lp3944.h, set the i2c board info:

static struct i2c_board_info __initdata a910_i2c_board_info[] = {
{
I2C_BOARD_INFO("lp3944", 0x60),
.platform_data = &a910_lp3944_leds,
},
};

and register it in the platform init function

i2c_register_board_info(0, a910_i2c_board_info,
ARRAY_SIZE(a910_i2c_board_info));
17 changes: 16 additions & 1 deletion Documentation/powerpc/dts-bindings/gpio/led.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,17 @@ LED sub-node properties:
string defining the trigger assigned to the LED. Current triggers are:
"backlight" - LED will act as a back-light, controlled by the framebuffer
system
"default-on" - LED will turn on
"default-on" - LED will turn on, but see "default-state" below
"heartbeat" - LED "double" flashes at a load average based rate
"ide-disk" - LED indicates disk activity
"timer" - LED flashes at a fixed, configurable rate
- default-state: (optional) The initial state of the LED. Valid
values are "on", "off", and "keep". If the LED is already on or off
and the default-state property is set the to same value, then no
glitch should be produced where the LED momentarily turns off (or
on). The "keep" setting will keep the LED at whatever its current
state is, without producing a glitch. The default is off if this
property is not present.

Examples:

Expand All @@ -30,14 +37,22 @@ leds {
gpios = <&mcu_pio 0 1>; /* Active low */
linux,default-trigger = "ide-disk";
};

fault {
gpios = <&mcu_pio 1 0>;
/* Keep LED on if BIOS detected hardware fault */
default-state = "keep";
};
};

run-control {
compatible = "gpio-leds";
red {
gpios = <&mpc8572 6 0>;
default-state = "off";
};
green {
gpios = <&mpc8572 7 0>;
default-state = "on";
};
}
14 changes: 8 additions & 6 deletions drivers/leds/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ config LEDS_ALIX2
depends on LEDS_CLASS && X86 && EXPERIMENTAL
help
This option enables support for the PCEngines ALIX.2 and ALIX.3 LEDs.
You have to set leds-alix2.force=1 for boards with Award BIOS.

config LEDS_H1940
tristate "LED Support for iPAQ H1940 device"
Expand Down Expand Up @@ -145,15 +146,16 @@ config LEDS_GPIO_OF
of_platform devices. For instance, LEDs which are listed in a "dts"
file.

config LEDS_LP5521
tristate "LED Support for the LP5521 LEDs"
config LEDS_LP3944
tristate "LED Support for N.S. LP3944 (Fun Light) I2C chip"
depends on LEDS_CLASS && I2C
help
If you say 'Y' here you get support for the National Semiconductor
LP5521 LED driver used in n8x0 boards.
This option enables support for LEDs connected to the National
Semiconductor LP3944 Lighting Management Unit (LMU) also known as
Fun Light Chip.

This driver can be built as a module by choosing 'M'. The module
will be called leds-lp5521.
To compile this driver as a module, choose M here: the
module will be called leds-lp3944.

config LEDS_CLEVO_MAIL
tristate "Mail LED on Clevo notebook"
Expand Down
1 change: 1 addition & 0 deletions drivers/leds/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ obj-$(CONFIG_LEDS_COBALT_RAQ) += leds-cobalt-raq.o
obj-$(CONFIG_LEDS_SUNFIRE) += leds-sunfire.o
obj-$(CONFIG_LEDS_PCA9532) += leds-pca9532.o
obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o
obj-$(CONFIG_LEDS_LP3944) += leds-lp3944.o
obj-$(CONFIG_LEDS_CLEVO_MAIL) += leds-clevo-mail.o
obj-$(CONFIG_LEDS_HP6XX) += leds-hp6xx.o
obj-$(CONFIG_LEDS_FSG) += leds-fsg.o
Expand Down
7 changes: 6 additions & 1 deletion drivers/leds/leds-alix2.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

static int force = 0;
module_param(force, bool, 0444);
MODULE_PARM_DESC(force, "Assume system has ALIX.2 style LEDs");
MODULE_PARM_DESC(force, "Assume system has ALIX.2/ALIX.3 style LEDs");

struct alix_led {
struct led_classdev cdev;
Expand Down Expand Up @@ -155,6 +155,11 @@ static int __init alix_led_init(void)
goto out;
}

/* enable output on GPIO for LED 1,2,3 */
outl(1 << 6, 0x6104);
outl(1 << 9, 0x6184);
outl(1 << 11, 0x6184);

pdev = platform_device_register_simple(KBUILD_MODNAME, -1, NULL, 0);
if (!IS_ERR(pdev)) {
ret = platform_driver_probe(&alix_led_driver, alix_led_probe);
Expand Down
96 changes: 75 additions & 21 deletions drivers/leds/leds-bd2802.c
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ struct bd2802_led {
enum led_ids led_id;
enum led_colors color;
enum led_bits state;

/* General attributes of RGB LEDs */
int wave_pattern;
int rgb_current;
};


Expand Down Expand Up @@ -254,7 +258,7 @@ static void bd2802_set_on(struct bd2802_led *led, enum led_ids id,
bd2802_reset_cancel(led);

reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT1SETUP);
bd2802_write_byte(led->client, reg, BD2802_CURRENT_032);
bd2802_write_byte(led->client, reg, led->rgb_current);
reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT2SETUP);
bd2802_write_byte(led->client, reg, BD2802_CURRENT_000);
reg = bd2802_get_reg_addr(id, color, BD2802_REG_WAVEPATTERN);
Expand All @@ -275,9 +279,9 @@ static void bd2802_set_blink(struct bd2802_led *led, enum led_ids id,
reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT1SETUP);
bd2802_write_byte(led->client, reg, BD2802_CURRENT_000);
reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT2SETUP);
bd2802_write_byte(led->client, reg, BD2802_CURRENT_032);
bd2802_write_byte(led->client, reg, led->rgb_current);
reg = bd2802_get_reg_addr(id, color, BD2802_REG_WAVEPATTERN);
bd2802_write_byte(led->client, reg, BD2802_PATTERN_HALF);
bd2802_write_byte(led->client, reg, led->wave_pattern);

bd2802_enable(led, id);
bd2802_update_state(led, id, color, BD2802_BLINK);
Expand Down Expand Up @@ -406,7 +410,7 @@ static void bd2802_enable_adv_conf(struct bd2802_led *led)
ret = device_create_file(&led->client->dev,
bd2802_addr_attributes[i]);
if (ret) {
dev_err(&led->client->dev, "failed to sysfs file %s\n",
dev_err(&led->client->dev, "failed: sysfs file %s\n",
bd2802_addr_attributes[i]->attr.name);
goto failed_remove_files;
}
Expand Down Expand Up @@ -483,6 +487,52 @@ static struct device_attribute bd2802_adv_conf_attr = {
.store = bd2802_store_adv_conf,
};

#define BD2802_CONTROL_ATTR(attr_name, name_str) \
static ssize_t bd2802_show_##attr_name(struct device *dev, \
struct device_attribute *attr, char *buf) \
{ \
struct bd2802_led *led = i2c_get_clientdata(to_i2c_client(dev));\
ssize_t ret; \
down_read(&led->rwsem); \
ret = sprintf(buf, "0x%02x\n", led->attr_name); \
up_read(&led->rwsem); \
return ret; \
} \
static ssize_t bd2802_store_##attr_name(struct device *dev, \
struct device_attribute *attr, const char *buf, size_t count) \
{ \
struct bd2802_led *led = i2c_get_clientdata(to_i2c_client(dev));\
unsigned long val; \
int ret; \
if (!count) \
return -EINVAL; \
ret = strict_strtoul(buf, 16, &val); \
if (ret) \
return ret; \
down_write(&led->rwsem); \
led->attr_name = val; \
up_write(&led->rwsem); \
return count; \
} \
static struct device_attribute bd2802_##attr_name##_attr = { \
.attr = { \
.name = name_str, \
.mode = 0644, \
.owner = THIS_MODULE \
}, \
.show = bd2802_show_##attr_name, \
.store = bd2802_store_##attr_name, \
};

BD2802_CONTROL_ATTR(wave_pattern, "wave_pattern");
BD2802_CONTROL_ATTR(rgb_current, "rgb_current");

static struct device_attribute *bd2802_attributes[] = {
&bd2802_adv_conf_attr,
&bd2802_wave_pattern_attr,
&bd2802_rgb_current_attr,
};

static void bd2802_led_work(struct work_struct *work)
{
struct bd2802_led *led = container_of(work, struct bd2802_led, work);
Expand Down Expand Up @@ -538,7 +588,6 @@ static int bd2802_register_led_classdev(struct bd2802_led *led)
led->cdev_led1r.brightness = LED_OFF;
led->cdev_led1r.brightness_set = bd2802_set_led1r_brightness;
led->cdev_led1r.blink_set = bd2802_set_led1r_blink;
led->cdev_led1r.flags |= LED_CORE_SUSPENDRESUME;

ret = led_classdev_register(&led->client->dev, &led->cdev_led1r);
if (ret < 0) {
Expand All @@ -551,7 +600,6 @@ static int bd2802_register_led_classdev(struct bd2802_led *led)
led->cdev_led1g.brightness = LED_OFF;
led->cdev_led1g.brightness_set = bd2802_set_led1g_brightness;
led->cdev_led1g.blink_set = bd2802_set_led1g_blink;
led->cdev_led1g.flags |= LED_CORE_SUSPENDRESUME;

ret = led_classdev_register(&led->client->dev, &led->cdev_led1g);
if (ret < 0) {
Expand All @@ -564,7 +612,6 @@ static int bd2802_register_led_classdev(struct bd2802_led *led)
led->cdev_led1b.brightness = LED_OFF;
led->cdev_led1b.brightness_set = bd2802_set_led1b_brightness;
led->cdev_led1b.blink_set = bd2802_set_led1b_blink;
led->cdev_led1b.flags |= LED_CORE_SUSPENDRESUME;

ret = led_classdev_register(&led->client->dev, &led->cdev_led1b);
if (ret < 0) {
Expand All @@ -577,7 +624,6 @@ static int bd2802_register_led_classdev(struct bd2802_led *led)
led->cdev_led2r.brightness = LED_OFF;
led->cdev_led2r.brightness_set = bd2802_set_led2r_brightness;
led->cdev_led2r.blink_set = bd2802_set_led2r_blink;
led->cdev_led2r.flags |= LED_CORE_SUSPENDRESUME;

ret = led_classdev_register(&led->client->dev, &led->cdev_led2r);
if (ret < 0) {
Expand All @@ -590,7 +636,6 @@ static int bd2802_register_led_classdev(struct bd2802_led *led)
led->cdev_led2g.brightness = LED_OFF;
led->cdev_led2g.brightness_set = bd2802_set_led2g_brightness;
led->cdev_led2g.blink_set = bd2802_set_led2g_blink;
led->cdev_led2g.flags |= LED_CORE_SUSPENDRESUME;

ret = led_classdev_register(&led->client->dev, &led->cdev_led2g);
if (ret < 0) {
Expand Down Expand Up @@ -640,7 +685,7 @@ static int __devinit bd2802_probe(struct i2c_client *client,
{
struct bd2802_led *led;
struct bd2802_led_platform_data *pdata;
int ret;
int ret, i;

led = kzalloc(sizeof(struct bd2802_led), GFP_KERNEL);
if (!led) {
Expand Down Expand Up @@ -670,13 +715,20 @@ static int __devinit bd2802_probe(struct i2c_client *client,
/* To save the power, reset BD2802 after detecting */
gpio_set_value(led->pdata->reset_gpio, 0);

/* Default attributes */
led->wave_pattern = BD2802_PATTERN_HALF;
led->rgb_current = BD2802_CURRENT_032;

init_rwsem(&led->rwsem);

ret = device_create_file(&client->dev, &bd2802_adv_conf_attr);
if (ret) {
dev_err(&client->dev, "failed to create sysfs file %s\n",
bd2802_adv_conf_attr.attr.name);
goto failed_free;
for (i = 0; i < ARRAY_SIZE(bd2802_attributes); i++) {
ret = device_create_file(&led->client->dev,
bd2802_attributes[i]);
if (ret) {
dev_err(&led->client->dev, "failed: sysfs file %s\n",
bd2802_attributes[i]->attr.name);
goto failed_unregister_dev_file;
}
}

ret = bd2802_register_led_classdev(led);
Expand All @@ -686,7 +738,8 @@ static int __devinit bd2802_probe(struct i2c_client *client,
return 0;

failed_unregister_dev_file:
device_remove_file(&client->dev, &bd2802_adv_conf_attr);
for (i--; i >= 0; i--)
device_remove_file(&led->client->dev, bd2802_attributes[i]);
failed_free:
i2c_set_clientdata(client, NULL);
kfree(led);
Expand All @@ -697,12 +750,14 @@ static int __devinit bd2802_probe(struct i2c_client *client,
static int __exit bd2802_remove(struct i2c_client *client)
{
struct bd2802_led *led = i2c_get_clientdata(client);
int i;

bd2802_unregister_led_classdev(led);
gpio_set_value(led->pdata->reset_gpio, 0);
bd2802_unregister_led_classdev(led);
if (led->adf_on)
bd2802_disable_adv_conf(led);
device_remove_file(&client->dev, &bd2802_adv_conf_attr);
for (i = 0; i < ARRAY_SIZE(bd2802_attributes); i++)
device_remove_file(&led->client->dev, bd2802_attributes[i]);
i2c_set_clientdata(client, NULL);
kfree(led);

Expand All @@ -723,8 +778,7 @@ static int bd2802_resume(struct i2c_client *client)
struct bd2802_led *led = i2c_get_clientdata(client);

if (!bd2802_is_all_off(led) || led->adf_on) {
gpio_set_value(led->pdata->reset_gpio, 1);
udelay(100);
bd2802_reset_cancel(led);
bd2802_restore_state(led);
}

Expand Down Expand Up @@ -762,4 +816,4 @@ module_exit(bd2802_exit);

MODULE_AUTHOR("Kim Kyuwon <q1.kim@samsung.com>");
MODULE_DESCRIPTION("BD2802 LED driver");
MODULE_LICENSE("GPL");
MODULE_LICENSE("GPL v2");
Loading

0 comments on commit 61abfd2

Please sign in to comment.