Commit 61abfd2d authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.o-hand.com/linux-rpurdie-leds

* '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
parents 4075ea8c a1dd8c61
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));
...@@ -16,10 +16,17 @@ LED sub-node properties: ...@@ -16,10 +16,17 @@ LED sub-node properties:
string defining the trigger assigned to the LED. Current triggers are: string defining the trigger assigned to the LED. Current triggers are:
"backlight" - LED will act as a back-light, controlled by the framebuffer "backlight" - LED will act as a back-light, controlled by the framebuffer
system 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 "heartbeat" - LED "double" flashes at a load average based rate
"ide-disk" - LED indicates disk activity "ide-disk" - LED indicates disk activity
"timer" - LED flashes at a fixed, configurable rate "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: Examples:
...@@ -30,14 +37,22 @@ leds { ...@@ -30,14 +37,22 @@ leds {
gpios = <&mcu_pio 0 1>; /* Active low */ gpios = <&mcu_pio 0 1>; /* Active low */
linux,default-trigger = "ide-disk"; linux,default-trigger = "ide-disk";
}; };
fault {
gpios = <&mcu_pio 1 0>;
/* Keep LED on if BIOS detected hardware fault */
default-state = "keep";
};
}; };
run-control { run-control {
compatible = "gpio-leds"; compatible = "gpio-leds";
red { red {
gpios = <&mpc8572 6 0>; gpios = <&mpc8572 6 0>;
default-state = "off";
}; };
green { green {
gpios = <&mpc8572 7 0>; gpios = <&mpc8572 7 0>;
default-state = "on";
}; };
} }
...@@ -75,6 +75,7 @@ config LEDS_ALIX2 ...@@ -75,6 +75,7 @@ config LEDS_ALIX2
depends on LEDS_CLASS && X86 && EXPERIMENTAL depends on LEDS_CLASS && X86 && EXPERIMENTAL
help help
This option enables support for the PCEngines ALIX.2 and ALIX.3 LEDs. 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 config LEDS_H1940
tristate "LED Support for iPAQ H1940 device" tristate "LED Support for iPAQ H1940 device"
...@@ -145,15 +146,16 @@ config LEDS_GPIO_OF ...@@ -145,15 +146,16 @@ config LEDS_GPIO_OF
of_platform devices. For instance, LEDs which are listed in a "dts" of_platform devices. For instance, LEDs which are listed in a "dts"
file. file.
config LEDS_LP5521 config LEDS_LP3944
tristate "LED Support for the LP5521 LEDs" tristate "LED Support for N.S. LP3944 (Fun Light) I2C chip"
depends on LEDS_CLASS && I2C depends on LEDS_CLASS && I2C
help help
If you say 'Y' here you get support for the National Semiconductor This option enables support for LEDs connected to the National
LP5521 LED driver used in n8x0 boards. 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 To compile this driver as a module, choose M here: the
will be called leds-lp5521. module will be called leds-lp3944.
config LEDS_CLEVO_MAIL config LEDS_CLEVO_MAIL
tristate "Mail LED on Clevo notebook" tristate "Mail LED on Clevo notebook"
......
...@@ -20,6 +20,7 @@ obj-$(CONFIG_LEDS_COBALT_RAQ) += leds-cobalt-raq.o ...@@ -20,6 +20,7 @@ obj-$(CONFIG_LEDS_COBALT_RAQ) += leds-cobalt-raq.o
obj-$(CONFIG_LEDS_SUNFIRE) += leds-sunfire.o obj-$(CONFIG_LEDS_SUNFIRE) += leds-sunfire.o
obj-$(CONFIG_LEDS_PCA9532) += leds-pca9532.o obj-$(CONFIG_LEDS_PCA9532) += leds-pca9532.o
obj-$(CONFIG_LEDS_GPIO) += leds-gpio.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_CLEVO_MAIL) += leds-clevo-mail.o
obj-$(CONFIG_LEDS_HP6XX) += leds-hp6xx.o obj-$(CONFIG_LEDS_HP6XX) += leds-hp6xx.o
obj-$(CONFIG_LEDS_FSG) += leds-fsg.o obj-$(CONFIG_LEDS_FSG) += leds-fsg.o
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
static int force = 0; static int force = 0;
module_param(force, bool, 0444); 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 alix_led {
struct led_classdev cdev; struct led_classdev cdev;
...@@ -155,6 +155,11 @@ static int __init alix_led_init(void) ...@@ -155,6 +155,11 @@ static int __init alix_led_init(void)
goto out; 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); pdev = platform_device_register_simple(KBUILD_MODNAME, -1, NULL, 0);
if (!IS_ERR(pdev)) { if (!IS_ERR(pdev)) {
ret = platform_driver_probe(&alix_led_driver, alix_led_probe); ret = platform_driver_probe(&alix_led_driver, alix_led_probe);
......
...@@ -97,6 +97,10 @@ struct bd2802_led { ...@@ -97,6 +97,10 @@ struct bd2802_led {
enum led_ids led_id; enum led_ids led_id;
enum led_colors color; enum led_colors color;
enum led_bits state; enum led_bits state;
/* General attributes of RGB LEDs */
int wave_pattern;
int rgb_current;
}; };
...@@ -254,7 +258,7 @@ static void bd2802_set_on(struct bd2802_led *led, enum led_ids id, ...@@ -254,7 +258,7 @@ static void bd2802_set_on(struct bd2802_led *led, enum led_ids id,
bd2802_reset_cancel(led); bd2802_reset_cancel(led);
reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT1SETUP); 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); reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT2SETUP);
bd2802_write_byte(led->client, reg, BD2802_CURRENT_000); bd2802_write_byte(led->client, reg, BD2802_CURRENT_000);
reg = bd2802_get_reg_addr(id, color, BD2802_REG_WAVEPATTERN); reg = bd2802_get_reg_addr(id, color, BD2802_REG_WAVEPATTERN);
...@@ -275,9 +279,9 @@ static void bd2802_set_blink(struct bd2802_led *led, enum led_ids id, ...@@ -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); reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT1SETUP);
bd2802_write_byte(led->client, reg, BD2802_CURRENT_000); bd2802_write_byte(led->client, reg, BD2802_CURRENT_000);
reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT2SETUP); 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); 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_enable(led, id);
bd2802_update_state(led, id, color, BD2802_BLINK); bd2802_update_state(led, id, color, BD2802_BLINK);
...@@ -406,7 +410,7 @@ static void bd2802_enable_adv_conf(struct bd2802_led *led) ...@@ -406,7 +410,7 @@ static void bd2802_enable_adv_conf(struct bd2802_led *led)
ret = device_create_file(&led->client->dev, ret = device_create_file(&led->client->dev,
bd2802_addr_attributes[i]); bd2802_addr_attributes[i]);
if (ret) { 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); bd2802_addr_attributes[i]->attr.name);
goto failed_remove_files; goto failed_remove_files;
} }
...@@ -483,6 +487,52 @@ static struct device_attribute bd2802_adv_conf_attr = { ...@@ -483,6 +487,52 @@ static struct device_attribute bd2802_adv_conf_attr = {
.store = bd2802_store_adv_conf, .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) static void bd2802_led_work(struct work_struct *work)
{ {
struct bd2802_led *led = container_of(work, struct bd2802_led, work); struct bd2802_led *led = container_of(work, struct bd2802_led, work);
...@@ -538,7 +588,6 @@ static int bd2802_register_led_classdev(struct bd2802_led *led) ...@@ -538,7 +588,6 @@ static int bd2802_register_led_classdev(struct bd2802_led *led)
led->cdev_led1r.brightness = LED_OFF; led->cdev_led1r.brightness = LED_OFF;
led->cdev_led1r.brightness_set = bd2802_set_led1r_brightness; led->cdev_led1r.brightness_set = bd2802_set_led1r_brightness;
led->cdev_led1r.blink_set = bd2802_set_led1r_blink; 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); ret = led_classdev_register(&led->client->dev, &led->cdev_led1r);
if (ret < 0) { if (ret < 0) {
...@@ -551,7 +600,6 @@ static int bd2802_register_led_classdev(struct bd2802_led *led) ...@@ -551,7 +600,6 @@ static int bd2802_register_led_classdev(struct bd2802_led *led)
led->cdev_led1g.brightness = LED_OFF; led->cdev_led1g.brightness = LED_OFF;
led->cdev_led1g.brightness_set = bd2802_set_led1g_brightness; led->cdev_led1g.brightness_set = bd2802_set_led1g_brightness;
led->cdev_led1g.blink_set = bd2802_set_led1g_blink; 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); ret = led_classdev_register(&led->client->dev, &led->cdev_led1g);
if (ret < 0) { if (ret < 0) {
...@@ -564,7 +612,6 @@ static int bd2802_register_led_classdev(struct bd2802_led *led) ...@@ -564,7 +612,6 @@ static int bd2802_register_led_classdev(struct bd2802_led *led)
led->cdev_led1b.brightness = LED_OFF; led->cdev_led1b.brightness = LED_OFF;
led->cdev_led1b.brightness_set = bd2802_set_led1b_brightness; led->cdev_led1b.brightness_set = bd2802_set_led1b_brightness;
led->cdev_led1b.blink_set = bd2802_set_led1b_blink; 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); ret = led_classdev_register(&led->client->dev, &led->cdev_led1b);
if (ret < 0) { if (ret < 0) {
...@@ -577,7 +624,6 @@ static int bd2802_register_led_classdev(struct bd2802_led *led) ...@@ -577,7 +624,6 @@ static int bd2802_register_led_classdev(struct bd2802_led *led)
led->cdev_led2r.brightness = LED_OFF; led->cdev_led2r.brightness = LED_OFF;
led->cdev_led2r.brightness_set = bd2802_set_led2r_brightness; led->cdev_led2r.brightness_set = bd2802_set_led2r_brightness;
led->cdev_led2r.blink_set = bd2802_set_led2r_blink; 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); ret = led_classdev_register(&led->client->dev, &led->cdev_led2r);
if (ret < 0) { if (ret < 0) {
...@@ -590,7 +636,6 @@ static int bd2802_register_led_classdev(struct bd2802_led *led) ...@@ -590,7 +636,6 @@ static int bd2802_register_led_classdev(struct bd2802_led *led)
led->cdev_led2g.brightness = LED_OFF; led->cdev_led2g.brightness = LED_OFF;
led->cdev_led2g.brightness_set = bd2802_set_led2g_brightness; led->cdev_led2g.brightness_set = bd2802_set_led2g_brightness;
led->cdev_led2g.blink_set = bd2802_set_led2g_blink; 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); ret = led_classdev_register(&led->client->dev, &led->cdev_led2g);
if (ret < 0) { if (ret < 0) {
...@@ -640,7 +685,7 @@ static int __devinit bd2802_probe(struct i2c_client *client, ...@@ -640,7 +685,7 @@ static int __devinit bd2802_probe(struct i2c_client *client,
{ {
struct bd2802_led *led; struct bd2802_led *led;
struct bd2802_led_platform_data *pdata; struct bd2802_led_platform_data *pdata;
int ret; int ret, i;
led = kzalloc(sizeof(struct bd2802_led), GFP_KERNEL); led = kzalloc(sizeof(struct bd2802_led), GFP_KERNEL);
if (!led) { if (!led) {
...@@ -670,13 +715,20 @@ static int __devinit bd2802_probe(struct i2c_client *client, ...@@ -670,13 +715,20 @@ static int __devinit bd2802_probe(struct i2c_client *client,
/* To save the power, reset BD2802 after detecting */ /* To save the power, reset BD2802 after detecting */
gpio_set_value(led->pdata->reset_gpio, 0); 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); init_rwsem(&led->rwsem);
ret = device_create_file(&client->dev, &bd2802_adv_conf_attr); for (i = 0; i < ARRAY_SIZE(bd2802_attributes); i++) {
if (ret) { ret = device_create_file(&led->client->dev,
dev_err(&client->dev, "failed to create sysfs file %s\n", bd2802_attributes[i]);
bd2802_adv_conf_attr.attr.name); if (ret) {
goto failed_free; 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); ret = bd2802_register_led_classdev(led);
...@@ -686,7 +738,8 @@ static int __devinit bd2802_probe(struct i2c_client *client, ...@@ -686,7 +738,8 @@ static int __devinit bd2802_probe(struct i2c_client *client,
return 0; return 0;
failed_unregister_dev_file: 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: failed_free:
i2c_set_clientdata(client, NULL); i2c_set_clientdata(client, NULL);
kfree(led); kfree(led);
...@@ -697,12 +750,14 @@ static int __devinit bd2802_probe(struct i2c_client *client, ...@@ -697,12 +750,14 @@ static int __devinit bd2802_probe(struct i2c_client *client,
static int __exit bd2802_remove(struct i2c_client *client) static int __exit bd2802_remove(struct i2c_client *client)
{ {
struct bd2802_led *led = i2c_get_clientdata(client); struct bd2802_led *led = i2c_get_clientdata(client);
int i;
bd2802_unregister_led_classdev(led);
gpio_set_value(led->pdata->reset_gpio, 0); gpio_set_value(led->pdata->reset_gpio, 0);
bd2802_unregister_led_classdev(led);
if (led->adf_on) if (led->adf_on)
bd2802_disable_adv_conf(led); 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); i2c_set_clientdata(client, NULL);
kfree(led); kfree(led);
...@@ -723,8 +778,7 @@ static int bd2802_resume(struct i2c_client *client) ...@@ -723,8 +778,7 @@ static int bd2802_resume(struct i2c_client *client)
struct bd2802_led *led = i2c_get_clientdata(client); struct bd2802_led *led = i2c_get_clientdata(client);
if (!bd2802_is_all_off(led) || led->adf_on) { if (!bd2802_is_all_off(led) || led->adf_on) {
gpio_set_value(led->pdata->reset_gpio, 1); bd2802_reset_cancel(led);
udelay(100);
bd2802_restore_state(led); bd2802_restore_state(led);
} }
...@@ -762,4 +816,4 @@ module_exit(bd2802_exit); ...@@ -762,4 +816,4 @@ module_exit(bd2802_exit);
MODULE_AUTHOR("Kim Kyuwon <q1.kim@samsung.com>"); MODULE_AUTHOR("Kim Kyuwon <q1.kim@samsung.com>");
MODULE_DESCRIPTION("BD2802 LED driver"); MODULE_DESCRIPTION("BD2802 LED driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL v2");
...@@ -76,7 +76,7 @@ static int __devinit create_gpio_led(const struct gpio_led *template, ...@@ -76,7 +76,7 @@ static int __devinit create_gpio_led(const struct gpio_led *template,
struct gpio_led_data *led_dat, struct device *parent, struct gpio_led_data *led_dat, struct device *parent,
int (*blink_set)(unsigned, unsigned long *, unsigned long *)) int (*blink_set)(unsigned, unsigned long *, unsigned long *))
{ {
int ret; int ret, state;
/* skip leds that aren't available */ /* skip leds that aren't available */
if (!gpio_is_valid(template->gpio)) { if (!gpio_is_valid(template->gpio)) {
...@@ -99,11 +99,15 @@ static int __devinit create_gpio_led(const struct gpio_led *template, ...@@ -99,11 +99,15 @@ static int __devinit create_gpio_led(const struct gpio_led *template,
led_dat->cdev.blink_set = gpio_blink_set; led_dat->cdev.blink_set = gpio_blink_set;
} }
led_dat->cdev.brightness_set = gpio_led_set; led_dat->cdev.brightness_set = gpio_led_set;
led_dat->cdev.brightness = LED_OFF; if (template->default_state == LEDS_GPIO_DEFSTATE_KEEP)
state = !!gpio_get_value(led_dat->gpio) ^ led_dat->active_low;
else
state = (template->default_state == LEDS_GPIO_DEFSTATE_ON);
led_dat->cdev.brightness = state ? LED_FULL : LED_OFF;
if (!template->retain_state_suspended) if (!template->retain_state_suspended)
led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME; led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
ret = gpio_direction_output(led_dat->gpio, led_dat->active_low); ret = gpio_direction_output(led_dat->gpio, led_dat->active_low ^ state);
if (ret < 0) if (ret < 0)
goto err; goto err;
...@@ -129,7 +133,7 @@ static void delete_gpio_led(struct gpio_led_data *led) ...@@ -129,7 +133,7 @@ static void delete_gpio_led(struct gpio_led_data *led)
} }
#ifdef CONFIG_LEDS_GPIO_PLATFORM #ifdef CONFIG_LEDS_GPIO_PLATFORM
static int gpio_led_probe(struct platform_device *pdev) static int __devinit gpio_led_probe(struct platform_device *pdev)
{ {
struct gpio_led_platform_data *pdata = pdev->dev.platform_data; struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
struct gpio_led_data *leds_data; struct gpio_led_data *leds_data;
...@@ -223,12 +227,22 @@ static int __devinit of_gpio_leds_probe(struct of_device *ofdev, ...@@ -223,12 +227,22 @@ static int __devinit of_gpio_leds_probe(struct of_device *ofdev,
memset(&led, 0, sizeof(led)); memset(&led, 0, sizeof(led));
for_each_child_of_node(np, child) { for_each_child_of_node(np, child) {
enum of_gpio_flags flags; enum of_gpio_flags flags;
const char *state;
led.gpio = of_get_gpio_flags(child, 0, &flags); led.gpio = of_get_gpio_flags(child, 0, &flags);
led.active_low = flags & OF_GPIO_ACTIVE_LOW; led.active_low = flags & OF_GPIO_ACTIVE_LOW;
led.name = of_get_property(child, "label", NULL) ? : child->name; led.name = of_get_property(child, "label", NULL) ? : child->name;
led.default_trigger = led.default_trigger =
of_get_property(child, "linux,default-trigger", NULL); of_get_property(child, "linux,default-trigger", NULL);
state = of_get_property(child, "default-state", NULL);
if (state) {
if (!strcmp(state, "keep"))
led.default_state = LEDS_GPIO_DEFSTATE_KEEP;
else if(!strcmp(state, "on"))
led.default_state = LEDS_GPIO_DEFSTATE_ON;
else
led.default_state = LEDS_GPIO_DEFSTATE_OFF;
}
ret = create_gpio_led(&led, &pdata->led_data[pdata->num_leds++], ret = create_gpio_led(&led, &pdata->led_data[pdata->num_leds++],
&ofdev->dev, NULL); &ofdev->dev, NULL);
......
This diff is collapsed.
...@@ -35,7 +35,7 @@ struct pca9532_data { ...@@ -35,7 +35,7 @@ struct pca9532_data {
struct pca9532_led leds[16]; struct pca9532_led leds[16];
struct mutex update_lock; struct mutex update_lock;
struct input_dev *idev; struct input_dev *idev;
struct work_struct work; struct work_struct work;
u8 pwm[2]; u8 pwm[2];
u8 psc[2]; u8 psc[2];
}; };
...@@ -87,14 +87,14 @@ static int pca9532_calcpwm(struct i2c_client *client, int pwm, int blink, ...@@ -87,14 +87,14 @@ static int pca9532_calcpwm(struct i2c_client *client, int pwm, int blink,
if (b > 0xFF) if (b > 0xFF)
return -EINVAL; return -EINVAL;
data->pwm[pwm] = b; data->pwm[pwm] = b;
data->psc[pwm] = blink; data->psc[pwm] = blink;
return 0; return 0;
} }
static int pca9532_setpwm(struct i2c_client *client, int pwm) static int pca9532_setpwm(struct i2c_client *client, int pwm)
{ {
struct pca9532_data *data = i2c_get_clientdata(client); struct pca9532_data *data = i2c_get_clientdata(client);
mutex_lock(&data->update_lock); mutex_lock(&data->update_lock);
i2c_smbus_write_byte_data(client, PCA9532_REG_PWM(pwm), i2c_smbus_write_byte_data(client, PCA9532_REG_PWM(pwm),
data->pwm[pwm]); data->pwm[pwm]);
i2c_smbus_write_byte_data(client, PCA9532_REG_PSC(pwm), i2c_smbus_write_byte_data(client, PCA9532_REG_PSC(pwm),
...@@ -132,11 +132,11 @@ static void pca9532_set_brightness(struct led_classdev *led_cdev, ...@@ -132,11 +132,11 @@ static void pca9532_set_brightness(struct led_classdev *led_cdev,
led->state = PCA9532_ON; led->state = PCA9532_ON;
else { else {
led->state = PCA9532_PWM0; /* Thecus: hardcode one pwm */ led->state = PCA9532_PWM0; /* Thecus: hardcode one pwm */
err = pca9532_calcpwm(led->client, 0, 0, value); err = pca9532_calcpwm(led->client, 0, 0, value);
if (err) if (err)
return; /* XXX: led api doesn't allow error code? */ return; /* XXX: led api doesn't allow error code? */
} }
schedule_work(&led->work); schedule_work(&led->work);
} }
static int pca9532_set_blink(struct led_classdev *led_cdev, static int pca9532_set_blink(struct led_classdev *led_cdev,
...@@ -145,7 +145,7 @@ static int pca9532_set_blink(struct led_classdev *led_cdev, ...@@ -145,7 +145,7 @@ static int pca9532_set_blink(struct led_classdev *led_cdev,
struct pca9532_led *led = ldev_to_led(led_cdev); struct pca9532_led *led = ldev_to_led(led_cdev);
struct i2c_client *client = led->client; struct i2c_client *client = led->client;
int psc; int psc;
int err = 0; int err = 0;
if (*delay_on == 0 && *delay_off == 0) { if (*delay_on == 0 && *delay_off == 0) {
/* led subsystem ask us for a blink rate */ /* led subsystem ask us for a blink rate */
...@@ -157,11 +157,11 @@ static int pca9532_set_blink(struct led_classdev *led_cdev, ...@@ -157,11 +157,11 @@ static int pca9532_set_blink(struct led_classdev *led_cdev,
/* Thecus specific: only use PSC/PWM 0 */ /* Thecus specific: only use PSC/PWM 0 */
psc = (*delay_on * 152-1)/1000; psc = (*delay_on * 152-1)/1000;
err = pca9532_calcpwm(client, 0, psc, led_cdev->brightness); err = pca9532_calcpwm(client, 0, psc, led_cdev->brightness);
if (err) if (err)
return err; return err;
schedule_work(&led->work); schedule_work(&led->work);
return 0; return 0;
} }
static int pca9532_event(struct input_dev *dev, unsigned int type, static int pca9532_event(struct input_dev *dev, unsigned int type,
...@@ -178,15 +178,15 @@ static int pca9532_event(struct input_dev *dev, unsigned int type, ...@@ -178,15 +178,15 @@ static int pca9532_event(struct input_dev *dev, unsigned int type,
else else
data->pwm[1] = 0; data->pwm[1] = 0;
schedule_work(&data->work); schedule_work(&data->work);
return 0; return 0;
} }
static void pca9532_input_work(struct work_struct *work) static void pca9532_input_work(struct work_struct *work)
{ {
struct pca9532_data *data; struct pca9532_data *data;
data = container_of(work, struct pca9532_data, work); data = container_of(work, struct pca9532_data, work);
mutex_lock(&data->update_lock); mutex_lock(&data->update_lock);
i2c_smbus_write_byte_data(data->client, PCA9532_REG_PWM(1), i2c_smbus_write_byte_data(data->client, PCA9532_REG_PWM(1),
data->pwm[1]); data->pwm[1]);
...@@ -195,11 +195,11 @@ static void pca9532_input_work(struct work_struct *work) ...@@ -195,11 +195,11 @@ static void pca9532_input_work(struct work_struct *work)
static void pca9532_led_work(struct work_struct *work) static void pca9532_led_work(struct work_struct *work)
{ {
struct pca9532_led *led; struct pca9532_led *led;
led = container_of(work, struct pca9532_led, work); led = container_of(work, struct pca9532_led, work);
if (led->state == PCA9532_PWM0) if (led->state == PCA9532_PWM0)
pca9532_setpwm(led->client, 0); pca9532_setpwm(led->client, 0);
pca9532_setled(led); pca9532_setled(led);
} }
static int pca9532_configure(struct i2c_client *client, static int pca9532_configure(struct i2c_client *client,
...@@ -232,7 +232,7 @@ static int pca9532_configure(struct i2c_client *client, ...@@ -232,7 +232,7 @@ static int pca9532_configure(struct i2c_client *client,
led->ldev.brightness = LED_OFF; led->ldev.brightness = LED_OFF;
led->ldev.brightness_set = pca9532_set_brightness; led->ldev.brightness_set = pca9532_set_brightness;
led->ldev.blink_set = pca9532_set_blink; led->ldev.blink_set = pca9532_set_blink;
INIT_WORK(&led->work, pca9532_led_work); INIT_WORK(&led->work, pca9532_led_work);
err = led_classdev_register(&client->dev, &led->ldev); err = led_classdev_register(&client->dev, &led->ldev);
if (err < 0) { if (err < 0) {
dev_err(&client->dev, dev_err(&client->dev,
...@@ -262,11 +262,11 @@ static int pca9532_configure(struct i2c_client *client, ...@@ -262,11 +262,11 @@ static int pca9532_configure(struct i2c_client *client,
BIT_MASK(SND_TONE); BIT_MASK(SND_TONE);
data->idev->event = pca9532_event; data->idev->event = pca9532_event;
input_set_drvdata(data->idev, data); input_set_drvdata(data->idev, data);
INIT_WORK(&data->work, pca9532_input_work); INIT_WORK(&data->work, pca9532_input_work);
err = input_register_device(data->idev); err = input_register_device(data->idev);
if (err) { if (err) {
input_free_device(data->idev); input_free_device(data->idev);
cancel_work_sync(&data->work); cancel_work_sync(&data->work);
data->idev = NULL; data->idev = NULL;
goto exit; goto exit;
} }
...@@ -283,13 +283,13 @@ static int pca9532_configure(struct i2c_client *client, ...@@ -283,13 +283,13 @@ static int pca9532_configure(struct i2c_client *client,
break; break;
case PCA9532_TYPE_LED: case PCA9532_TYPE_LED:
led_classdev_unregister(&data->leds[i].ldev); led_classdev_unregister(&data->leds[i].ldev);
cancel_work_sync(&data->leds[i].work); cancel_work_sync(&data->leds[i].work);
break; break;
case PCA9532_TYPE_N2100_BEEP: case PCA9532_TYPE_N2100_BEEP:
if (data->idev != NULL) { if (data->idev != NULL) {
input_unregister_device(data->idev); input_unregister_device(data->idev);
input_free_device(data->idev); input_free_device(data->idev);
cancel_work_sync(&data->work); cancel_work_sync(&data->work);
data->idev = NULL; data->idev = NULL;
} }
break; break;
...@@ -340,13 +340,13 @@ static int pca9532_remove(struct i2c_client *client) ...@@ -340,13 +340,13 @@ static int pca9532_remove(struct i2c_client *client)
break; break;
case PCA9532_TYPE_LED: case PCA9532_TYPE_LED:
led_classdev_unregister(&data->leds[i].ldev); led_classdev_unregister(&data->leds[i].ldev);
cancel_work_sync(&data->leds[i].work); cancel_work_sync(&data->leds[i].work);
break; break;
case PCA9532_TYPE_N2100_BEEP: case PCA9532_TYPE_N2100_BEEP:
if (data->idev != NULL) { if (data->idev != NULL) {
input_unregister_device(data->idev); input_unregister_device(data->idev);
input_free_device(data->idev); input_free_device(data->idev);
cancel_work_sync(&data->work); cancel_work_sync(&data->work);
data->idev = NULL; data->idev = NULL;
} }
break; break;
......
/*
* leds-lp3944.h - platform data structure for lp3944 led controller
*
* Copyright (C) 2009 Antonio Ospite <ospite@studenti.unina.it>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#ifndef __LINUX_LEDS_LP3944_H
#define __LINUX_LEDS_LP3944_H
#include <linux/leds.h>
#include <linux/workqueue.h>
#define LP3944_LED0 0
#define LP3944_LED1 1
#define LP3944_LED2 2
#define LP3944_LED3 3
#define LP3944_LED4 4
#define LP3944_LED5 5
#define LP3944_LED6 6
#define LP3944_LED7 7
#define LP3944_LEDS_MAX 8
#define LP3944_LED_STATUS_MASK 0x03
enum lp3944_status {
LP3944_LED_STATUS_OFF = 0x0,
LP3944_LED_STATUS_ON = 0x1,
LP3944_LED_STATUS_DIM0 = 0x2,
LP3944_LED_STATUS_DIM1 = 0x3
};
enum lp3944_type {
LP3944_LED_TYPE_NONE,
LP3944_LED_TYPE_LED,
LP3944_LED_TYPE_LED_INVERTED,
};
struct lp3944_led {
char *name;
enum lp3944_type type;
enum lp3944_status status;
};
struct lp3944_platform_data {
struct lp3944_led leds[LP3944_LEDS_MAX];
u8 leds_size;
};
#endif /* __LINUX_LEDS_LP3944_H */
...@@ -45,7 +45,10 @@ struct led_classdev { ...@@ -45,7 +45,10 @@ struct led_classdev {
/* Get LED brightness level */ /* Get LED brightness level */
enum led_brightness (*brightness_get)(struct led_classdev *led_cdev); enum led_brightness (*brightness_get)(struct led_classdev *led_cdev);
/* Activate hardware accelerated blink */ /* Activate hardware accelerated blink, delays are in
* miliseconds and if none is provided then a sensible default
* should be chosen. The call can adjust the timings if it can't
* match the values specified exactly. */
int (*blink_set)(struct led_classdev *led_cdev, int (*blink_set)(struct led_classdev *led_cdev,
unsigned long *delay_on, unsigned long *delay_on,
unsigned long *delay_off); unsigned long *delay_off);
...@@ -141,9 +144,14 @@ struct gpio_led { ...@@ -141,9 +144,14 @@ struct gpio_led {
const char *name; const char *name;
const char *default_trigger; const char *default_trigger;
unsigned gpio; unsigned gpio;
u8 active_low : 1; unsigned active_low : 1;
u8 retain_state_suspended : 1; unsigned retain_state_suspended : 1;
unsigned default_state : 2;
/* default_state should be one of LEDS_GPIO_DEFSTATE_(ON|OFF|KEEP) */
}; };
#define LEDS_GPIO_DEFSTATE_OFF 0
#define LEDS_GPIO_DEFSTATE_ON 1
#define LEDS_GPIO_DEFSTATE_KEEP 2
struct gpio_led_platform_data { struct gpio_led_platform_data {
int num_leds; int num_leds;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment