diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-06-28 14:02:32 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-06-28 14:02:32 -0400 |
| commit | 61abfd2df8aa43a137ae58446dd0638a2385586e (patch) | |
| tree | 70e54fd22dbe8d7064f8cac47b43c7d5406048ab | |
| parent | 4075ea8c54a7506844a69f674990241e7766357b (diff) | |
| parent | a1dd8c617217322614f0465ae347895c4b58e1ab (diff) | |
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
| -rw-r--r-- | Documentation/leds-lp3944.txt | 50 | ||||
| -rw-r--r-- | Documentation/powerpc/dts-bindings/gpio/led.txt | 17 | ||||
| -rw-r--r-- | drivers/leds/Kconfig | 14 | ||||
| -rw-r--r-- | drivers/leds/Makefile | 1 | ||||
| -rw-r--r-- | drivers/leds/leds-alix2.c | 7 | ||||
| -rw-r--r-- | drivers/leds/leds-bd2802.c | 96 | ||||
| -rw-r--r-- | drivers/leds/leds-gpio.c | 22 | ||||
| -rw-r--r-- | drivers/leds/leds-lp3944.c | 466 | ||||
| -rw-r--r-- | drivers/leds/leds-pca9532.c | 58 | ||||
| -rw-r--r-- | include/linux/leds-lp3944.h | 53 | ||||
| -rw-r--r-- | include/linux/leds.h | 14 |
11 files changed, 733 insertions, 65 deletions
diff --git a/Documentation/leds-lp3944.txt b/Documentation/leds-lp3944.txt new file mode 100644 index 000000000000..c6eda18b15ef --- /dev/null +++ b/Documentation/leds-lp3944.txt | |||
| @@ -0,0 +1,50 @@ | |||
| 1 | Kernel driver lp3944 | ||
| 2 | ==================== | ||
| 3 | |||
| 4 | * National Semiconductor LP3944 Fun-light Chip | ||
| 5 | Prefix: 'lp3944' | ||
| 6 | Addresses scanned: None (see the Notes section below) | ||
| 7 | Datasheet: Publicly available at the National Semiconductor website | ||
| 8 | http://www.national.com/pf/LP/LP3944.html | ||
| 9 | |||
| 10 | Authors: | ||
| 11 | Antonio Ospite <ospite@studenti.unina.it> | ||
| 12 | |||
| 13 | |||
| 14 | Description | ||
| 15 | ----------- | ||
| 16 | The LP3944 is a helper chip that can drive up to 8 leds, with two programmable | ||
| 17 | DIM modes; it could even be used as a gpio expander but this driver assumes it | ||
| 18 | is used as a led controller. | ||
| 19 | |||
| 20 | The DIM modes are used to set _blink_ patterns for leds, the pattern is | ||
| 21 | specified supplying two parameters: | ||
| 22 | - period: from 0s to 1.6s | ||
| 23 | - duty cycle: percentage of the period the led is on, from 0 to 100 | ||
| 24 | |||
| 25 | Setting a led in DIM0 or DIM1 mode makes it blink according to the pattern. | ||
| 26 | See the datasheet for details. | ||
| 27 | |||
| 28 | LP3944 can be found on Motorola A910 smartphone, where it drives the rgb | ||
| 29 | leds, the camera flash light and the lcds power. | ||
| 30 | |||
| 31 | |||
| 32 | Notes | ||
| 33 | ----- | ||
| 34 | The chip is used mainly in embedded contexts, so this driver expects it is | ||
| 35 | registered using the i2c_board_info mechanism. | ||
| 36 | |||
| 37 | To register the chip at address 0x60 on adapter 0, set the platform data | ||
| 38 | according to include/linux/leds-lp3944.h, set the i2c board info: | ||
| 39 | |||
| 40 | static struct i2c_board_info __initdata a910_i2c_board_info[] = { | ||
| 41 | { | ||
| 42 | I2C_BOARD_INFO("lp3944", 0x60), | ||
| 43 | .platform_data = &a910_lp3944_leds, | ||
| 44 | }, | ||
| 45 | }; | ||
| 46 | |||
| 47 | and register it in the platform init function | ||
| 48 | |||
| 49 | i2c_register_board_info(0, a910_i2c_board_info, | ||
| 50 | ARRAY_SIZE(a910_i2c_board_info)); | ||
diff --git a/Documentation/powerpc/dts-bindings/gpio/led.txt b/Documentation/powerpc/dts-bindings/gpio/led.txt index 4fe14deedc0a..064db928c3c1 100644 --- a/Documentation/powerpc/dts-bindings/gpio/led.txt +++ b/Documentation/powerpc/dts-bindings/gpio/led.txt | |||
| @@ -16,10 +16,17 @@ LED sub-node properties: | |||
| 16 | string defining the trigger assigned to the LED. Current triggers are: | 16 | string defining the trigger assigned to the LED. Current triggers are: |
| 17 | "backlight" - LED will act as a back-light, controlled by the framebuffer | 17 | "backlight" - LED will act as a back-light, controlled by the framebuffer |
| 18 | system | 18 | system |
| 19 | "default-on" - LED will turn on | 19 | "default-on" - LED will turn on, but see "default-state" below |
| 20 | "heartbeat" - LED "double" flashes at a load average based rate | 20 | "heartbeat" - LED "double" flashes at a load average based rate |
| 21 | "ide-disk" - LED indicates disk activity | 21 | "ide-disk" - LED indicates disk activity |
| 22 | "timer" - LED flashes at a fixed, configurable rate | 22 | "timer" - LED flashes at a fixed, configurable rate |
| 23 | - default-state: (optional) The initial state of the LED. Valid | ||
| 24 | values are "on", "off", and "keep". If the LED is already on or off | ||
| 25 | and the default-state property is set the to same value, then no | ||
| 26 | glitch should be produced where the LED momentarily turns off (or | ||
| 27 | on). The "keep" setting will keep the LED at whatever its current | ||
| 28 | state is, without producing a glitch. The default is off if this | ||
| 29 | property is not present. | ||
| 23 | 30 | ||
| 24 | Examples: | 31 | Examples: |
| 25 | 32 | ||
| @@ -30,14 +37,22 @@ leds { | |||
| 30 | gpios = <&mcu_pio 0 1>; /* Active low */ | 37 | gpios = <&mcu_pio 0 1>; /* Active low */ |
| 31 | linux,default-trigger = "ide-disk"; | 38 | linux,default-trigger = "ide-disk"; |
| 32 | }; | 39 | }; |
| 40 | |||
| 41 | fault { | ||
| 42 | gpios = <&mcu_pio 1 0>; | ||
| 43 | /* Keep LED on if BIOS detected hardware fault */ | ||
| 44 | default-state = "keep"; | ||
| 45 | }; | ||
| 33 | }; | 46 | }; |
| 34 | 47 | ||
| 35 | run-control { | 48 | run-control { |
| 36 | compatible = "gpio-leds"; | 49 | compatible = "gpio-leds"; |
| 37 | red { | 50 | red { |
| 38 | gpios = <&mpc8572 6 0>; | 51 | gpios = <&mpc8572 6 0>; |
| 52 | default-state = "off"; | ||
| 39 | }; | 53 | }; |
| 40 | green { | 54 | green { |
| 41 | gpios = <&mpc8572 7 0>; | 55 | gpios = <&mpc8572 7 0>; |
| 56 | default-state = "on"; | ||
| 42 | }; | 57 | }; |
| 43 | } | 58 | } |
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 9b60b6b684d9..7c8e7122aaa9 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig | |||
| @@ -75,6 +75,7 @@ config LEDS_ALIX2 | |||
| 75 | depends on LEDS_CLASS && X86 && EXPERIMENTAL | 75 | depends on LEDS_CLASS && X86 && EXPERIMENTAL |
| 76 | help | 76 | help |
| 77 | This option enables support for the PCEngines ALIX.2 and ALIX.3 LEDs. | 77 | This option enables support for the PCEngines ALIX.2 and ALIX.3 LEDs. |
| 78 | You have to set leds-alix2.force=1 for boards with Award BIOS. | ||
| 78 | 79 | ||
| 79 | config LEDS_H1940 | 80 | config LEDS_H1940 |
| 80 | tristate "LED Support for iPAQ H1940 device" | 81 | tristate "LED Support for iPAQ H1940 device" |
| @@ -145,15 +146,16 @@ config LEDS_GPIO_OF | |||
| 145 | of_platform devices. For instance, LEDs which are listed in a "dts" | 146 | of_platform devices. For instance, LEDs which are listed in a "dts" |
| 146 | file. | 147 | file. |
| 147 | 148 | ||
| 148 | config LEDS_LP5521 | 149 | config LEDS_LP3944 |
| 149 | tristate "LED Support for the LP5521 LEDs" | 150 | tristate "LED Support for N.S. LP3944 (Fun Light) I2C chip" |
| 150 | depends on LEDS_CLASS && I2C | 151 | depends on LEDS_CLASS && I2C |
| 151 | help | 152 | help |
| 152 | If you say 'Y' here you get support for the National Semiconductor | 153 | This option enables support for LEDs connected to the National |
| 153 | LP5521 LED driver used in n8x0 boards. | 154 | Semiconductor LP3944 Lighting Management Unit (LMU) also known as |
| 155 | Fun Light Chip. | ||
| 154 | 156 | ||
| 155 | This driver can be built as a module by choosing 'M'. The module | 157 | To compile this driver as a module, choose M here: the |
| 156 | will be called leds-lp5521. | 158 | module will be called leds-lp3944. |
| 157 | 159 | ||
| 158 | config LEDS_CLEVO_MAIL | 160 | config LEDS_CLEVO_MAIL |
| 159 | tristate "Mail LED on Clevo notebook" | 161 | tristate "Mail LED on Clevo notebook" |
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index 2d41c4dcf92f..e8cdcf77a4c3 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile | |||
| @@ -20,6 +20,7 @@ obj-$(CONFIG_LEDS_COBALT_RAQ) += leds-cobalt-raq.o | |||
| 20 | obj-$(CONFIG_LEDS_SUNFIRE) += leds-sunfire.o | 20 | obj-$(CONFIG_LEDS_SUNFIRE) += leds-sunfire.o |
| 21 | obj-$(CONFIG_LEDS_PCA9532) += leds-pca9532.o | 21 | obj-$(CONFIG_LEDS_PCA9532) += leds-pca9532.o |
| 22 | obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o | 22 | obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o |
| 23 | obj-$(CONFIG_LEDS_LP3944) += leds-lp3944.o | ||
| 23 | obj-$(CONFIG_LEDS_CLEVO_MAIL) += leds-clevo-mail.o | 24 | obj-$(CONFIG_LEDS_CLEVO_MAIL) += leds-clevo-mail.o |
| 24 | obj-$(CONFIG_LEDS_HP6XX) += leds-hp6xx.o | 25 | obj-$(CONFIG_LEDS_HP6XX) += leds-hp6xx.o |
| 25 | obj-$(CONFIG_LEDS_FSG) += leds-fsg.o | 26 | obj-$(CONFIG_LEDS_FSG) += leds-fsg.o |
diff --git a/drivers/leds/leds-alix2.c b/drivers/leds/leds-alix2.c index ddbd7730dfc8..731d4eef3425 100644 --- a/drivers/leds/leds-alix2.c +++ b/drivers/leds/leds-alix2.c | |||
| @@ -14,7 +14,7 @@ | |||
| 14 | 14 | ||
| 15 | static int force = 0; | 15 | static int force = 0; |
| 16 | module_param(force, bool, 0444); | 16 | module_param(force, bool, 0444); |
| 17 | MODULE_PARM_DESC(force, "Assume system has ALIX.2 style LEDs"); | 17 | MODULE_PARM_DESC(force, "Assume system has ALIX.2/ALIX.3 style LEDs"); |
| 18 | 18 | ||
| 19 | struct alix_led { | 19 | struct alix_led { |
| 20 | struct led_classdev cdev; | 20 | struct led_classdev cdev; |
| @@ -155,6 +155,11 @@ static int __init alix_led_init(void) | |||
| 155 | goto out; | 155 | goto out; |
| 156 | } | 156 | } |
| 157 | 157 | ||
| 158 | /* enable output on GPIO for LED 1,2,3 */ | ||
| 159 | outl(1 << 6, 0x6104); | ||
| 160 | outl(1 << 9, 0x6184); | ||
| 161 | outl(1 << 11, 0x6184); | ||
| 162 | |||
| 158 | pdev = platform_device_register_simple(KBUILD_MODNAME, -1, NULL, 0); | 163 | pdev = platform_device_register_simple(KBUILD_MODNAME, -1, NULL, 0); |
| 159 | if (!IS_ERR(pdev)) { | 164 | if (!IS_ERR(pdev)) { |
| 160 | ret = platform_driver_probe(&alix_led_driver, alix_led_probe); | 165 | ret = platform_driver_probe(&alix_led_driver, alix_led_probe); |
diff --git a/drivers/leds/leds-bd2802.c b/drivers/leds/leds-bd2802.c index 4149ecb3a9b2..779d7f262c04 100644 --- a/drivers/leds/leds-bd2802.c +++ b/drivers/leds/leds-bd2802.c | |||
| @@ -97,6 +97,10 @@ struct bd2802_led { | |||
| 97 | enum led_ids led_id; | 97 | enum led_ids led_id; |
| 98 | enum led_colors color; | 98 | enum led_colors color; |
| 99 | enum led_bits state; | 99 | enum led_bits state; |
| 100 | |||
| 101 | /* General attributes of RGB LEDs */ | ||
| 102 | int wave_pattern; | ||
| 103 | int rgb_current; | ||
| 100 | }; | 104 | }; |
| 101 | 105 | ||
| 102 | 106 | ||
| @@ -254,7 +258,7 @@ static void bd2802_set_on(struct bd2802_led *led, enum led_ids id, | |||
| 254 | bd2802_reset_cancel(led); | 258 | bd2802_reset_cancel(led); |
| 255 | 259 | ||
| 256 | reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT1SETUP); | 260 | reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT1SETUP); |
| 257 | bd2802_write_byte(led->client, reg, BD2802_CURRENT_032); | 261 | bd2802_write_byte(led->client, reg, led->rgb_current); |
| 258 | reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT2SETUP); | 262 | reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT2SETUP); |
| 259 | bd2802_write_byte(led->client, reg, BD2802_CURRENT_000); | 263 | bd2802_write_byte(led->client, reg, BD2802_CURRENT_000); |
| 260 | reg = bd2802_get_reg_addr(id, color, BD2802_REG_WAVEPATTERN); | 264 | 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 | reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT1SETUP); | 279 | reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT1SETUP); |
| 276 | bd2802_write_byte(led->client, reg, BD2802_CURRENT_000); | 280 | bd2802_write_byte(led->client, reg, BD2802_CURRENT_000); |
| 277 | reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT2SETUP); | 281 | reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT2SETUP); |
| 278 | bd2802_write_byte(led->client, reg, BD2802_CURRENT_032); | 282 | bd2802_write_byte(led->client, reg, led->rgb_current); |
| 279 | reg = bd2802_get_reg_addr(id, color, BD2802_REG_WAVEPATTERN); | 283 | reg = bd2802_get_reg_addr(id, color, BD2802_REG_WAVEPATTERN); |
| 280 | bd2802_write_byte(led->client, reg, BD2802_PATTERN_HALF); | 284 | bd2802_write_byte(led->client, reg, led->wave_pattern); |
| 281 | 285 | ||
| 282 | bd2802_enable(led, id); | 286 | bd2802_enable(led, id); |
| 283 | bd2802_update_state(led, id, color, BD2802_BLINK); | 287 | bd2802_update_state(led, id, color, BD2802_BLINK); |
| @@ -406,7 +410,7 @@ static void bd2802_enable_adv_conf(struct bd2802_led *led) | |||
| 406 | ret = device_create_file(&led->client->dev, | 410 | ret = device_create_file(&led->client->dev, |
| 407 | bd2802_addr_attributes[i]); | 411 | bd2802_addr_attributes[i]); |
| 408 | if (ret) { | 412 | if (ret) { |
| 409 | dev_err(&led->client->dev, "failed to sysfs file %s\n", | 413 | dev_err(&led->client->dev, "failed: sysfs file %s\n", |
| 410 | bd2802_addr_attributes[i]->attr.name); | 414 | bd2802_addr_attributes[i]->attr.name); |
| 411 | goto failed_remove_files; | 415 | goto failed_remove_files; |
| 412 | } | 416 | } |
| @@ -483,6 +487,52 @@ static struct device_attribute bd2802_adv_conf_attr = { | |||
| 483 | .store = bd2802_store_adv_conf, | 487 | .store = bd2802_store_adv_conf, |
| 484 | }; | 488 | }; |
| 485 | 489 | ||
| 490 | #define BD2802_CONTROL_ATTR(attr_name, name_str) \ | ||
| 491 | static ssize_t bd2802_show_##attr_name(struct device *dev, \ | ||
| 492 | struct device_attribute *attr, char *buf) \ | ||
| 493 | { \ | ||
| 494 | struct bd2802_led *led = i2c_get_clientdata(to_i2c_client(dev));\ | ||
| 495 | ssize_t ret; \ | ||
| 496 | down_read(&led->rwsem); \ | ||
| 497 | ret = sprintf(buf, "0x%02x\n", led->attr_name); \ | ||
| 498 | up_read(&led->rwsem); \ | ||
| 499 | return ret; \ | ||
| 500 | } \ | ||
| 501 | static ssize_t bd2802_store_##attr_name(struct device *dev, \ | ||
| 502 | struct device_attribute *attr, const char *buf, size_t count) \ | ||
| 503 | { \ | ||
| 504 | struct bd2802_led *led = i2c_get_clientdata(to_i2c_client(dev));\ | ||
| 505 | unsigned long val; \ | ||
| 506 | int ret; \ | ||
| 507 | if (!count) \ | ||
| 508 | return -EINVAL; \ | ||
| 509 | ret = strict_strtoul(buf, 16, &val); \ | ||
| 510 | if (ret) \ | ||
| 511 | return ret; \ | ||
| 512 | down_write(&led->rwsem); \ | ||
| 513 | led->attr_name = val; \ | ||
| 514 | up_write(&led->rwsem); \ | ||
| 515 | return count; \ | ||
| 516 | } \ | ||
| 517 | static struct device_attribute bd2802_##attr_name##_attr = { \ | ||
| 518 | .attr = { \ | ||
| 519 | .name = name_str, \ | ||
| 520 | .mode = 0644, \ | ||
| 521 | .owner = THIS_MODULE \ | ||
| 522 | }, \ | ||
| 523 | .show = bd2802_show_##attr_name, \ | ||
| 524 | .store = bd2802_store_##attr_name, \ | ||
| 525 | }; | ||
| 526 | |||
| 527 | BD2802_CONTROL_ATTR(wave_pattern, "wave_pattern"); | ||
| 528 | BD2802_CONTROL_ATTR(rgb_current, "rgb_current"); | ||
| 529 | |||
| 530 | static struct device_attribute *bd2802_attributes[] = { | ||
| 531 | &bd2802_adv_conf_attr, | ||
| 532 | &bd2802_wave_pattern_attr, | ||
| 533 | &bd2802_rgb_current_attr, | ||
| 534 | }; | ||
| 535 | |||
| 486 | static void bd2802_led_work(struct work_struct *work) | 536 | static void bd2802_led_work(struct work_struct *work) |
| 487 | { | 537 | { |
| 488 | struct bd2802_led *led = container_of(work, struct bd2802_led, work); | 538 | 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 | led->cdev_led1r.brightness = LED_OFF; | 588 | led->cdev_led1r.brightness = LED_OFF; |
| 539 | led->cdev_led1r.brightness_set = bd2802_set_led1r_brightness; | 589 | led->cdev_led1r.brightness_set = bd2802_set_led1r_brightness; |
| 540 | led->cdev_led1r.blink_set = bd2802_set_led1r_blink; | 590 | led->cdev_led1r.blink_set = bd2802_set_led1r_blink; |
| 541 | led->cdev_led1r.flags |= LED_CORE_SUSPENDRESUME; | ||
| 542 | 591 | ||
| 543 | ret = led_classdev_register(&led->client->dev, &led->cdev_led1r); | 592 | ret = led_classdev_register(&led->client->dev, &led->cdev_led1r); |
| 544 | if (ret < 0) { | 593 | if (ret < 0) { |
| @@ -551,7 +600,6 @@ static int bd2802_register_led_classdev(struct bd2802_led *led) | |||
| 551 | led->cdev_led1g.brightness = LED_OFF; | 600 | led->cdev_led1g.brightness = LED_OFF; |
| 552 | led->cdev_led1g.brightness_set = bd2802_set_led1g_brightness; | 601 | led->cdev_led1g.brightness_set = bd2802_set_led1g_brightness; |
| 553 | led->cdev_led1g.blink_set = bd2802_set_led1g_blink; | 602 | led->cdev_led1g.blink_set = bd2802_set_led1g_blink; |
| 554 | led->cdev_led1g.flags |= LED_CORE_SUSPENDRESUME; | ||
| 555 | 603 | ||
| 556 | ret = led_classdev_register(&led->client->dev, &led->cdev_led1g); | 604 | ret = led_classdev_register(&led->client->dev, &led->cdev_led1g); |
| 557 | if (ret < 0) { | 605 | if (ret < 0) { |
| @@ -564,7 +612,6 @@ static int bd2802_register_led_classdev(struct bd2802_led *led) | |||
| 564 | led->cdev_led1b.brightness = LED_OFF; | 612 | led->cdev_led1b.brightness = LED_OFF; |
| 565 | led->cdev_led1b.brightness_set = bd2802_set_led1b_brightness; | 613 | led->cdev_led1b.brightness_set = bd2802_set_led1b_brightness; |
| 566 | led->cdev_led1b.blink_set = bd2802_set_led1b_blink; | 614 | led->cdev_led1b.blink_set = bd2802_set_led1b_blink; |
| 567 | led->cdev_led1b.flags |= LED_CORE_SUSPENDRESUME; | ||
| 568 | 615 | ||
| 569 | ret = led_classdev_register(&led->client->dev, &led->cdev_led1b); | 616 | ret = led_classdev_register(&led->client->dev, &led->cdev_led1b); |
| 570 | if (ret < 0) { | 617 | if (ret < 0) { |
| @@ -577,7 +624,6 @@ static int bd2802_register_led_classdev(struct bd2802_led *led) | |||
| 577 | led->cdev_led2r.brightness = LED_OFF; | 624 | led->cdev_led2r.brightness = LED_OFF; |
| 578 | led->cdev_led2r.brightness_set = bd2802_set_led2r_brightness; | 625 | led->cdev_led2r.brightness_set = bd2802_set_led2r_brightness; |
| 579 | led->cdev_led2r.blink_set = bd2802_set_led2r_blink; | 626 | led->cdev_led2r.blink_set = bd2802_set_led2r_blink; |
| 580 | led->cdev_led2r.flags |= LED_CORE_SUSPENDRESUME; | ||
| 581 | 627 | ||
| 582 | ret = led_classdev_register(&led->client->dev, &led->cdev_led2r); | 628 | ret = led_classdev_register(&led->client->dev, &led->cdev_led2r); |
| 583 | if (ret < 0) { | 629 | if (ret < 0) { |
| @@ -590,7 +636,6 @@ static int bd2802_register_led_classdev(struct bd2802_led *led) | |||
| 590 | led->cdev_led2g.brightness = LED_OFF; | 636 | led->cdev_led2g.brightness = LED_OFF; |
| 591 | led->cdev_led2g.brightness_set = bd2802_set_led2g_brightness; | 637 | led->cdev_led2g.brightness_set = bd2802_set_led2g_brightness; |
| 592 | led->cdev_led2g.blink_set = bd2802_set_led2g_blink; | 638 | led->cdev_led2g.blink_set = bd2802_set_led2g_blink; |
| 593 | led->cdev_led2g.flags |= LED_CORE_SUSPENDRESUME; | ||
| 594 | 639 | ||
| 595 | ret = led_classdev_register(&led->client->dev, &led->cdev_led2g); | 640 | ret = led_classdev_register(&led->client->dev, &led->cdev_led2g); |
| 596 | if (ret < 0) { | 641 | if (ret < 0) { |
| @@ -640,7 +685,7 @@ static int __devinit bd2802_probe(struct i2c_client *client, | |||
| 640 | { | 685 | { |
| 641 | struct bd2802_led *led; | 686 | struct bd2802_led *led; |
| 642 | struct bd2802_led_platform_data *pdata; | 687 | struct bd2802_led_platform_data *pdata; |
| 643 | int ret; | 688 | int ret, i; |
| 644 | 689 | ||
| 645 | led = kzalloc(sizeof(struct bd2802_led), GFP_KERNEL); | 690 | led = kzalloc(sizeof(struct bd2802_led), GFP_KERNEL); |
| 646 | if (!led) { | 691 | if (!led) { |
| @@ -670,13 +715,20 @@ static int __devinit bd2802_probe(struct i2c_client *client, | |||
| 670 | /* To save the power, reset BD2802 after detecting */ | 715 | /* To save the power, reset BD2802 after detecting */ |
| 671 | gpio_set_value(led->pdata->reset_gpio, 0); | 716 | gpio_set_value(led->pdata->reset_gpio, 0); |
| 672 | 717 | ||
| 718 | /* Default attributes */ | ||
| 719 | led->wave_pattern = BD2802_PATTERN_HALF; | ||
| 720 | led->rgb_current = BD2802_CURRENT_032; | ||
| 721 | |||
| 673 | init_rwsem(&led->rwsem); | 722 | init_rwsem(&led->rwsem); |
| 674 | 723 | ||
| 675 | ret = device_create_file(&client->dev, &bd2802_adv_conf_attr); | 724 | for (i = 0; i < ARRAY_SIZE(bd2802_attributes); i++) { |
| 676 | if (ret) { | 725 | ret = device_create_file(&led->client->dev, |
| 677 | dev_err(&client->dev, "failed to create sysfs file %s\n", | 726 | bd2802_attributes[i]); |
| 678 | bd2802_adv_conf_attr.attr.name); | 727 | if (ret) { |
| 679 | goto failed_free; | 728 | dev_err(&led->client->dev, "failed: sysfs file %s\n", |
| 729 | bd2802_attributes[i]->attr.name); | ||
| 730 | goto failed_unregister_dev_file; | ||
| 731 | } | ||
| 680 | } | 732 | } |
| 681 | 733 | ||
| 682 | ret = bd2802_register_led_classdev(led); | 734 | ret = bd2802_register_led_classdev(led); |
| @@ -686,7 +738,8 @@ static int __devinit bd2802_probe(struct i2c_client *client, | |||
| 686 | return 0; | 738 | return 0; |
| 687 | 739 | ||
| 688 | failed_unregister_dev_file: | 740 | failed_unregister_dev_file: |
| 689 | device_remove_file(&client->dev, &bd2802_adv_conf_attr); | 741 | for (i--; i >= 0; i--) |
| 742 | device_remove_file(&led->client->dev, bd2802_attributes[i]); | ||
| 690 | failed_free: | 743 | failed_free: |
| 691 | i2c_set_clientdata(client, NULL); | 744 | i2c_set_clientdata(client, NULL); |
| 692 | kfree(led); | 745 | kfree(led); |
| @@ -697,12 +750,14 @@ failed_free: | |||
| 697 | static int __exit bd2802_remove(struct i2c_client *client) | 750 | static int __exit bd2802_remove(struct i2c_client *client) |
| 698 | { | 751 | { |
| 699 | struct bd2802_led *led = i2c_get_clientdata(client); | 752 | struct bd2802_led *led = i2c_get_clientdata(client); |
| 753 | int i; | ||
| 700 | 754 | ||
| 701 | bd2802_unregister_led_classdev(led); | ||
| 702 | gpio_set_value(led->pdata->reset_gpio, 0); | 755 | gpio_set_value(led->pdata->reset_gpio, 0); |
| 756 | bd2802_unregister_led_classdev(led); | ||
| 703 | if (led->adf_on) | 757 | if (led->adf_on) |
| 704 | bd2802_disable_adv_conf(led); | 758 | bd2802_disable_adv_conf(led); |
| 705 | device_remove_file(&client->dev, &bd2802_adv_conf_attr); | 759 | for (i = 0; i < ARRAY_SIZE(bd2802_attributes); i++) |
| 760 | device_remove_file(&led->client->dev, bd2802_attributes[i]); | ||
| 706 | i2c_set_clientdata(client, NULL); | 761 | i2c_set_clientdata(client, NULL); |
| 707 | kfree(led); | 762 | kfree(led); |
| 708 | 763 | ||
| @@ -723,8 +778,7 @@ static int bd2802_resume(struct i2c_client *client) | |||
| 723 | struct bd2802_led *led = i2c_get_clientdata(client); | 778 | struct bd2802_led *led = i2c_get_clientdata(client); |
| 724 | 779 | ||
| 725 | if (!bd2802_is_all_off(led) || led->adf_on) { | 780 | if (!bd2802_is_all_off(led) || led->adf_on) { |
| 726 | gpio_set_value(led->pdata->reset_gpio, 1); | 781 | bd2802_reset_cancel(led); |
| 727 | udelay(100); | ||
| 728 | bd2802_restore_state(led); | 782 | bd2802_restore_state(led); |
| 729 | } | 783 | } |
| 730 | 784 | ||
| @@ -762,4 +816,4 @@ module_exit(bd2802_exit); | |||
| 762 | 816 | ||
| 763 | MODULE_AUTHOR("Kim Kyuwon <q1.kim@samsung.com>"); | 817 | MODULE_AUTHOR("Kim Kyuwon <q1.kim@samsung.com>"); |
| 764 | MODULE_DESCRIPTION("BD2802 LED driver"); | 818 | MODULE_DESCRIPTION("BD2802 LED driver"); |
| 765 | MODULE_LICENSE("GPL"); | 819 | MODULE_LICENSE("GPL v2"); |
diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c index d2109054de85..6b06638eb5b4 100644 --- a/drivers/leds/leds-gpio.c +++ b/drivers/leds/leds-gpio.c | |||
| @@ -76,7 +76,7 @@ static int __devinit create_gpio_led(const struct gpio_led *template, | |||
| 76 | struct gpio_led_data *led_dat, struct device *parent, | 76 | struct gpio_led_data *led_dat, struct device *parent, |
| 77 | int (*blink_set)(unsigned, unsigned long *, unsigned long *)) | 77 | int (*blink_set)(unsigned, unsigned long *, unsigned long *)) |
| 78 | { | 78 | { |
| 79 | int ret; | 79 | int ret, state; |
| 80 | 80 | ||
| 81 | /* skip leds that aren't available */ | 81 | /* skip leds that aren't available */ |
| 82 | if (!gpio_is_valid(template->gpio)) { | 82 | if (!gpio_is_valid(template->gpio)) { |
| @@ -99,11 +99,15 @@ static int __devinit create_gpio_led(const struct gpio_led *template, | |||
| 99 | led_dat->cdev.blink_set = gpio_blink_set; | 99 | led_dat->cdev.blink_set = gpio_blink_set; |
| 100 | } | 100 | } |
| 101 | led_dat->cdev.brightness_set = gpio_led_set; | 101 | led_dat->cdev.brightness_set = gpio_led_set; |
| 102 | led_dat->cdev.brightness = LED_OFF; | 102 | if (template->default_state == LEDS_GPIO_DEFSTATE_KEEP) |
| 103 | state = !!gpio_get_value(led_dat->gpio) ^ led_dat->active_low; | ||
| 104 | else | ||
| 105 | state = (template->default_state == LEDS_GPIO_DEFSTATE_ON); | ||
| 106 | led_dat->cdev.brightness = state ? LED_FULL : LED_OFF; | ||
| 103 | if (!template->retain_state_suspended) | 107 | if (!template->retain_state_suspended) |
| 104 | led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME; | 108 | led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME; |
| 105 | 109 | ||
| 106 | ret = gpio_direction_output(led_dat->gpio, led_dat->active_low); | 110 | ret = gpio_direction_output(led_dat->gpio, led_dat->active_low ^ state); |
| 107 | if (ret < 0) | 111 | if (ret < 0) |
| 108 | goto err; | 112 | goto err; |
| 109 | 113 | ||
| @@ -129,7 +133,7 @@ static void delete_gpio_led(struct gpio_led_data *led) | |||
| 129 | } | 133 | } |
| 130 | 134 | ||
| 131 | #ifdef CONFIG_LEDS_GPIO_PLATFORM | 135 | #ifdef CONFIG_LEDS_GPIO_PLATFORM |
| 132 | static int gpio_led_probe(struct platform_device *pdev) | 136 | static int __devinit gpio_led_probe(struct platform_device *pdev) |
| 133 | { | 137 | { |
| 134 | struct gpio_led_platform_data *pdata = pdev->dev.platform_data; | 138 | struct gpio_led_platform_data *pdata = pdev->dev.platform_data; |
| 135 | struct gpio_led_data *leds_data; | 139 | struct gpio_led_data *leds_data; |
| @@ -223,12 +227,22 @@ static int __devinit of_gpio_leds_probe(struct of_device *ofdev, | |||
| 223 | memset(&led, 0, sizeof(led)); | 227 | memset(&led, 0, sizeof(led)); |
| 224 | for_each_child_of_node(np, child) { | 228 | for_each_child_of_node(np, child) { |
| 225 | enum of_gpio_flags flags; | 229 | enum of_gpio_flags flags; |
| 230 | const char *state; | ||
| 226 | 231 | ||
| 227 | led.gpio = of_get_gpio_flags(child, 0, &flags); | 232 | led.gpio = of_get_gpio_flags(child, 0, &flags); |
| 228 | led.active_low = flags & OF_GPIO_ACTIVE_LOW; | 233 | led.active_low = flags & OF_GPIO_ACTIVE_LOW; |
| 229 | led.name = of_get_property(child, "label", NULL) ? : child->name; | 234 | led.name = of_get_property(child, "label", NULL) ? : child->name; |
| 230 | led.default_trigger = | 235 | led.default_trigger = |
| 231 | of_get_property(child, "linux,default-trigger", NULL); | 236 | of_get_property(child, "linux,default-trigger", NULL); |
| 237 | state = of_get_property(child, "default-state", NULL); | ||
| 238 | if (state) { | ||
| 239 | if (!strcmp(state, "keep")) | ||
| 240 | led.default_state = LEDS_GPIO_DEFSTATE_KEEP; | ||
| 241 | else if(!strcmp(state, "on")) | ||
| 242 | led.default_state = LEDS_GPIO_DEFSTATE_ON; | ||
| 243 | else | ||
| 244 | led.default_state = LEDS_GPIO_DEFSTATE_OFF; | ||
| 245 | } | ||
| 232 | 246 | ||
| 233 | ret = create_gpio_led(&led, &pdata->led_data[pdata->num_leds++], | 247 | ret = create_gpio_led(&led, &pdata->led_data[pdata->num_leds++], |
| 234 | &ofdev->dev, NULL); | 248 | &ofdev->dev, NULL); |
diff --git a/drivers/leds/leds-lp3944.c b/drivers/leds/leds-lp3944.c new file mode 100644 index 000000000000..5946208ba26e --- /dev/null +++ b/drivers/leds/leds-lp3944.c | |||
| @@ -0,0 +1,466 @@ | |||
| 1 | /* | ||
| 2 | * leds-lp3944.c - driver for National Semiconductor LP3944 Funlight Chip | ||
| 3 | * | ||
| 4 | * Copyright (C) 2009 Antonio Ospite <ospite@studenti.unina.it> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2 as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | */ | ||
| 11 | |||
| 12 | /* | ||
| 13 | * I2C driver for National Semiconductor LP3944 Funlight Chip | ||
| 14 | * http://www.national.com/pf/LP/LP3944.html | ||
| 15 | * | ||
| 16 | * This helper chip can drive up to 8 leds, with two programmable DIM modes; | ||
| 17 | * it could even be used as a gpio expander but this driver assumes it is used | ||
| 18 | * as a led controller. | ||
| 19 | * | ||
| 20 | * The DIM modes are used to set _blink_ patterns for leds, the pattern is | ||
| 21 | * specified supplying two parameters: | ||
| 22 | * - period: from 0s to 1.6s | ||
| 23 | * - duty cycle: percentage of the period the led is on, from 0 to 100 | ||
| 24 | * | ||
| 25 | * LP3944 can be found on Motorola A910 smartphone, where it drives the rgb | ||
| 26 | * leds, the camera flash light and the displays backlights. | ||
| 27 | */ | ||
| 28 | |||
| 29 | #include <linux/module.h> | ||
| 30 | #include <linux/i2c.h> | ||
| 31 | #include <linux/leds.h> | ||
| 32 | #include <linux/mutex.h> | ||
| 33 | #include <linux/workqueue.h> | ||
| 34 | #include <linux/leds-lp3944.h> | ||
| 35 | |||
| 36 | /* Read Only Registers */ | ||
| 37 | #define LP3944_REG_INPUT1 0x00 /* LEDs 0-7 InputRegister (Read Only) */ | ||
| 38 | #define LP3944_REG_REGISTER1 0x01 /* None (Read Only) */ | ||
| 39 | |||
| 40 | #define LP3944_REG_PSC0 0x02 /* Frequency Prescaler 0 (R/W) */ | ||
| 41 | #define LP3944_REG_PWM0 0x03 /* PWM Register 0 (R/W) */ | ||
| 42 | #define LP3944_REG_PSC1 0x04 /* Frequency Prescaler 1 (R/W) */ | ||
| 43 | #define LP3944_REG_PWM1 0x05 /* PWM Register 1 (R/W) */ | ||
| 44 | #define LP3944_REG_LS0 0x06 /* LEDs 0-3 Selector (R/W) */ | ||
| 45 | #define LP3944_REG_LS1 0x07 /* LEDs 4-7 Selector (R/W) */ | ||
| 46 | |||
| 47 | /* These registers are not used to control leds in LP3944, they can store | ||
| 48 | * arbitrary values which the chip will ignore. | ||
| 49 | */ | ||
| 50 | #define LP3944_REG_REGISTER8 0x08 | ||
| 51 | #define LP3944_REG_REGISTER9 0x09 | ||
| 52 | |||
| 53 | #define LP3944_DIM0 0 | ||
| 54 | #define LP3944_DIM1 1 | ||
| 55 | |||
| 56 | /* period in ms */ | ||
| 57 | #define LP3944_PERIOD_MIN 0 | ||
| 58 | #define LP3944_PERIOD_MAX 1600 | ||
| 59 | |||
| 60 | /* duty cycle is a percentage */ | ||
| 61 | #define LP3944_DUTY_CYCLE_MIN 0 | ||
| 62 | #define LP3944_DUTY_CYCLE_MAX 100 | ||
| 63 | |||
| 64 | #define ldev_to_led(c) container_of(c, struct lp3944_led_data, ldev) | ||
| 65 | |||
| 66 | /* Saved data */ | ||
| 67 | struct lp3944_led_data { | ||
| 68 | u8 id; | ||
| 69 | enum lp3944_type type; | ||
| 70 | enum lp3944_status status; | ||
| 71 | struct led_classdev ldev; | ||
| 72 | struct i2c_client *client; | ||
| 73 | struct work_struct work; | ||
| 74 | }; | ||
| 75 | |||
| 76 | struct lp3944_data { | ||
| 77 | struct mutex lock; | ||
| 78 | struct i2c_client *client; | ||
| 79 | struct lp3944_led_data leds[LP3944_LEDS_MAX]; | ||
| 80 | }; | ||
| 81 | |||
| 82 | static int lp3944_reg_read(struct i2c_client *client, u8 reg, u8 *value) | ||
| 83 | { | ||
| 84 | int tmp; | ||
| 85 | |||
| 86 | tmp = i2c_smbus_read_byte_data(client, reg); | ||
| 87 | if (tmp < 0) | ||
| 88 | return -EINVAL; | ||
| 89 | |||
| 90 | *value = tmp; | ||
| 91 | |||
| 92 | return 0; | ||
| 93 | } | ||
| 94 | |||
| 95 | static int lp3944_reg_write(struct i2c_client *client, u8 reg, u8 value) | ||
| 96 | { | ||
| 97 | return i2c_smbus_write_byte_data(client, reg, value); | ||
| 98 | } | ||
| 99 | |||
| 100 | /** | ||
| 101 | * Set the period for DIM status | ||
| 102 | * | ||
| 103 | * @client: the i2c client | ||
| 104 | * @dim: either LP3944_DIM0 or LP3944_DIM1 | ||
| 105 | * @period: period of a blink, that is a on/off cycle, expressed in ms. | ||
| 106 | */ | ||
| 107 | static int lp3944_dim_set_period(struct i2c_client *client, u8 dim, u16 period) | ||
| 108 | { | ||
| 109 | u8 psc_reg; | ||
| 110 | u8 psc_value; | ||
| 111 | int err; | ||
| 112 | |||
| 113 | if (dim == LP3944_DIM0) | ||
| 114 | psc_reg = LP3944_REG_PSC0; | ||
| 115 | else if (dim == LP3944_DIM1) | ||
| 116 | psc_reg = LP3944_REG_PSC1; | ||
| 117 | else | ||
| 118 | return -EINVAL; | ||
| 119 | |||
| 120 | /* Convert period to Prescaler value */ | ||
| 121 | if (period > LP3944_PERIOD_MAX) | ||
| 122 | return -EINVAL; | ||
| 123 | |||
| 124 | psc_value = (period * 255) / LP3944_PERIOD_MAX; | ||
| 125 | |||
| 126 | err = lp3944_reg_write(client, psc_reg, psc_value); | ||
| 127 | |||
| 128 | return err; | ||
| 129 | } | ||
| 130 | |||
| 131 | /** | ||
| 132 | * Set the duty cycle for DIM status | ||
| 133 | * | ||
| 134 | * @client: the i2c client | ||
| 135 | * @dim: either LP3944_DIM0 or LP3944_DIM1 | ||
| 136 | * @duty_cycle: percentage of a period during which a led is ON | ||
| 137 | */ | ||
| 138 | static int lp3944_dim_set_dutycycle(struct i2c_client *client, u8 dim, | ||
| 139 | u8 duty_cycle) | ||
| 140 | { | ||
| 141 | u8 pwm_reg; | ||
| 142 | u8 pwm_value; | ||
| 143 | int err; | ||
| 144 | |||
| 145 | if (dim == LP3944_DIM0) | ||
| 146 | pwm_reg = LP3944_REG_PWM0; | ||
| 147 | else if (dim == LP3944_DIM1) | ||
| 148 | pwm_reg = LP3944_REG_PWM1; | ||
| 149 | else | ||
| 150 | return -EINVAL; | ||
| 151 | |||
| 152 | /* Convert duty cycle to PWM value */ | ||
| 153 | if (duty_cycle > LP3944_DUTY_CYCLE_MAX) | ||
| 154 | return -EINVAL; | ||
| 155 | |||
| 156 | pwm_value = (duty_cycle * 255) / LP3944_DUTY_CYCLE_MAX; | ||
| 157 | |||
| 158 | err = lp3944_reg_write(client, pwm_reg, pwm_value); | ||
| 159 | |||
| 160 | return err; | ||
| 161 | } | ||
| 162 | |||
| 163 | /** | ||
| 164 | * Set the led status | ||
| 165 | * | ||
| 166 | * @led: a lp3944_led_data structure | ||
| 167 | * @status: one of LP3944_LED_STATUS_OFF | ||
| 168 | * LP3944_LED_STATUS_ON | ||
| 169 | * LP3944_LED_STATUS_DIM0 | ||
| 170 | * LP3944_LED_STATUS_DIM1 | ||
| 171 | */ | ||
| 172 | static int lp3944_led_set(struct lp3944_led_data *led, u8 status) | ||
| 173 | { | ||
| 174 | struct lp3944_data *data = i2c_get_clientdata(led->client); | ||
| 175 | u8 id = led->id; | ||
| 176 | u8 reg; | ||
| 177 | u8 val = 0; | ||
| 178 | int err; | ||
| 179 | |||
| 180 | dev_dbg(&led->client->dev, "%s: %s, status before normalization:%d\n", | ||
| 181 | __func__, led->ldev.name, status); | ||
| 182 | |||
| 183 | switch (id) { | ||
| 184 | case LP3944_LED0: | ||
| 185 | case LP3944_LED1: | ||
| 186 | case LP3944_LED2: | ||
| 187 | case LP3944_LED3: | ||
| 188 | reg = LP3944_REG_LS0; | ||
| 189 | break; | ||
| 190 | case LP3944_LED4: | ||
| 191 | case LP3944_LED5: | ||
| 192 | case LP3944_LED6: | ||
| 193 | case LP3944_LED7: | ||
| 194 | id -= LP3944_LED4; | ||
| 195 | reg = LP3944_REG_LS1; | ||
| 196 | break; | ||
| 197 | default: | ||
| 198 | return -EINVAL; | ||
| 199 | } | ||
| 200 | |||
| 201 | if (status > LP3944_LED_STATUS_DIM1) | ||
| 202 | return -EINVAL; | ||
| 203 | |||
| 204 | /* invert only 0 and 1, leave unchanged the other values, | ||
| 205 | * remember we are abusing status to set blink patterns | ||
| 206 | */ | ||
| 207 | if (led->type == LP3944_LED_TYPE_LED_INVERTED && status < 2) | ||
| 208 | status = 1 - status; | ||
| 209 | |||
| 210 | mutex_lock(&data->lock); | ||
| 211 | lp3944_reg_read(led->client, reg, &val); | ||
| 212 | |||
| 213 | val &= ~(LP3944_LED_STATUS_MASK << (id << 1)); | ||
| 214 | val |= (status << (id << 1)); | ||
| 215 | |||
| 216 | dev_dbg(&led->client->dev, "%s: %s, reg:%d id:%d status:%d val:%#x\n", | ||
| 217 | __func__, led->ldev.name, reg, id, status, val); | ||
| 218 | |||
| 219 | /* set led status */ | ||
| 220 | err = lp3944_reg_write(led->client, reg, val); | ||
| 221 | mutex_unlock(&data->lock); | ||
| 222 | |||
| 223 | return err; | ||
| 224 | } | ||
| 225 | |||
| 226 | static int lp3944_led_set_blink(struct led_classdev *led_cdev, | ||
| 227 | unsigned long *delay_on, | ||
| 228 | unsigned long *delay_off) | ||
| 229 | { | ||
| 230 | struct lp3944_led_data *led = ldev_to_led(led_cdev); | ||
| 231 | u16 period; | ||
| 232 | u8 duty_cycle; | ||
| 233 | int err; | ||
| 234 | |||
| 235 | /* units are in ms */ | ||
| 236 | if (*delay_on + *delay_off > LP3944_PERIOD_MAX) | ||
| 237 | return -EINVAL; | ||
| 238 | |||
| 239 | if (*delay_on == 0 && *delay_off == 0) { | ||
| 240 | /* Special case: the leds subsystem requires a default user | ||
| 241 | * friendly blink pattern for the LED. Let's blink the led | ||
| 242 | * slowly (1Hz). | ||
| 243 | */ | ||
| 244 | *delay_on = 500; | ||
| 245 | *delay_off = 500; | ||
| 246 | } | ||
| 247 | |||
| 248 | period = (*delay_on) + (*delay_off); | ||
| 249 | |||
| 250 | /* duty_cycle is the percentage of period during which the led is ON */ | ||
| 251 | duty_cycle = 100 * (*delay_on) / period; | ||
| 252 | |||
| 253 | /* invert duty cycle for inverted leds, this has the same effect of | ||
| 254 | * swapping delay_on and delay_off | ||
| 255 | */ | ||
| 256 | if (led->type == LP3944_LED_TYPE_LED_INVERTED) | ||
| 257 | duty_cycle = 100 - duty_cycle; | ||
| 258 | |||
| 259 | /* NOTE: using always the first DIM mode, this means that all leds | ||
| 260 | * will have the same blinking pattern. | ||
| 261 | * | ||
| 262 | * We could find a way later to have two leds blinking in hardware | ||
| 263 | * with different patterns at the same time, falling back to software | ||
| 264 | * control for the other ones. | ||
| 265 | */ | ||
| 266 | err = lp3944_dim_set_period(led->client, LP3944_DIM0, period); | ||
| 267 | if (err) | ||
| 268 | return err; | ||
| 269 | |||
| 270 | err = lp3944_dim_set_dutycycle(led->client, LP3944_DIM0, duty_cycle); | ||
| 271 | if (err) | ||
| 272 | return err; | ||
| 273 | |||
| 274 | dev_dbg(&led->client->dev, "%s: OK hardware accelerated blink!\n", | ||
| 275 | __func__); | ||
| 276 | |||
| 277 | led->status = LP3944_LED_STATUS_DIM0; | ||
| 278 | schedule_work(&led->work); | ||
| 279 | |||
| 280 | return 0; | ||
| 281 | } | ||
| 282 | |||
| 283 | static void lp3944_led_set_brightness(struct led_classdev *led_cdev, | ||
| 284 | enum led_brightness brightness) | ||
| 285 | { | ||
| 286 | struct lp3944_led_data *led = ldev_to_led(led_cdev); | ||
| 287 | |||
| 288 | dev_dbg(&led->client->dev, "%s: %s, %d\n", | ||
| 289 | __func__, led_cdev->name, brightness); | ||
| 290 | |||
| 291 | led->status = brightness; | ||
| 292 | schedule_work(&led->work); | ||
| 293 | } | ||
| 294 | |||
| 295 | static void lp3944_led_work(struct work_struct *work) | ||
| 296 | { | ||
| 297 | struct lp3944_led_data *led; | ||
| 298 | |||
| 299 | led = container_of(work, struct lp3944_led_data, work); | ||
| 300 | lp3944_led_set(led, led->status); | ||
| 301 | } | ||
| 302 | |||
| 303 | static int lp3944_configure(struct i2c_client *client, | ||
| 304 | struct lp3944_data *data, | ||
| 305 | struct lp3944_platform_data *pdata) | ||
| 306 | { | ||
| 307 | int i, err = 0; | ||
| 308 | |||
| 309 | for (i = 0; i < pdata->leds_size; i++) { | ||
| 310 | struct lp3944_led *pled = &pdata->leds[i]; | ||
| 311 | struct lp3944_led_data *led = &data->leds[i]; | ||
| 312 | led->client = client; | ||
| 313 | led->id = i; | ||
| 314 | |||
| 315 | switch (pled->type) { | ||
| 316 | |||
| 317 | case LP3944_LED_TYPE_LED: | ||
| 318 | case LP3944_LED_TYPE_LED_INVERTED: | ||
| 319 | led->type = pled->type; | ||
| 320 | led->status = pled->status; | ||
| 321 | led->ldev.name = pled->name; | ||
| 322 | led->ldev.max_brightness = 1; | ||
| 323 | led->ldev.brightness_set = lp3944_led_set_brightness; | ||
| 324 | led->ldev.blink_set = lp3944_led_set_blink; | ||
| 325 | led->ldev.flags = LED_CORE_SUSPENDRESUME; | ||
| 326 | |||
| 327 | INIT_WORK(&led->work, lp3944_led_work); | ||
| 328 | err = led_classdev_register(&client->dev, &led->ldev); | ||
| 329 | if (err < 0) { | ||
| 330 | dev_err(&client->dev, | ||
| 331 | "couldn't register LED %s\n", | ||
| 332 | led->ldev.name); | ||
| 333 | goto exit; | ||
| 334 | } | ||
| 335 | |||
| 336 | /* to expose the default value to userspace */ | ||
| 337 | led->ldev.brightness = led->status; | ||
| 338 | |||
| 339 | /* Set the default led status */ | ||
| 340 | err = lp3944_led_set(led, led->status); | ||
| 341 | if (err < 0) { | ||
| 342 | dev_err(&client->dev, | ||
| 343 | "%s couldn't set STATUS %d\n", | ||
| 344 | led->ldev.name, led->status); | ||
| 345 | goto exit; | ||
| 346 | } | ||
| 347 | break; | ||
| 348 | |||
| 349 | case LP3944_LED_TYPE_NONE: | ||
| 350 | default: | ||
| 351 | break; | ||
| 352 | |||
| 353 | } | ||
| 354 | } | ||
| 355 | return 0; | ||
| 356 | |||
| 357 | exit: | ||
| 358 | if (i > 0) | ||
| 359 | for (i = i - 1; i >= 0; i--) | ||
| 360 | switch (pdata->leds[i].type) { | ||
| 361 | |||
| 362 | case LP3944_LED_TYPE_LED: | ||
| 363 | case LP3944_LED_TYPE_LED_INVERTED: | ||
| 364 | led_classdev_unregister(&data->leds[i].ldev); | ||
| 365 | cancel_work_sync(&data->leds[i].work); | ||
| 366 | break; | ||
| 367 | |||
| 368 | case LP3944_LED_TYPE_NONE: | ||
| 369 | default: | ||
| 370 | break; | ||
| 371 | } | ||
| 372 | |||
| 373 | return err; | ||
| 374 | } | ||
| 375 | |||
| 376 | static int __devinit lp3944_probe(struct i2c_client *client, | ||
| 377 | const struct i2c_device_id *id) | ||
| 378 | { | ||
| 379 | struct lp3944_platform_data *lp3944_pdata = client->dev.platform_data; | ||
| 380 | struct lp3944_data *data; | ||
| 381 | |||
| 382 | if (lp3944_pdata == NULL) { | ||
| 383 | dev_err(&client->dev, "no platform data\n"); | ||
| 384 | return -EINVAL; | ||
| 385 | } | ||
| 386 | |||
| 387 | /* Let's see whether this adapter can support what we need. */ | ||
| 388 | if (!i2c_check_functionality(client->adapter, | ||
| 389 | I2C_FUNC_SMBUS_BYTE_DATA)) { | ||
| 390 | dev_err(&client->dev, "insufficient functionality!\n"); | ||
| 391 | return -ENODEV; | ||
| 392 | } | ||
| 393 | |||
| 394 | data = kzalloc(sizeof(struct lp3944_data), GFP_KERNEL); | ||
| 395 | if (!data) | ||
| 396 | return -ENOMEM; | ||
| 397 | |||
| 398 | data->client = client; | ||
| 399 | i2c_set_clientdata(client, data); | ||
| 400 | |||
| 401 | mutex_init(&data->lock); | ||
| 402 | |||
| 403 | dev_info(&client->dev, "lp3944 enabled\n"); | ||
| 404 | |||
| 405 | lp3944_configure(client, data, lp3944_pdata); | ||
| 406 | return 0; | ||
| 407 | } | ||
| 408 | |||
| 409 | static int __devexit lp3944_remove(struct i2c_client *client) | ||
| 410 | { | ||
| 411 | struct lp3944_platform_data *pdata = client->dev.platform_data; | ||
| 412 | struct lp3944_data *data = i2c_get_clientdata(client); | ||
| 413 | int i; | ||
| 414 | |||
| 415 | for (i = 0; i < pdata->leds_size; i++) | ||
| 416 | switch (data->leds[i].type) { | ||
| 417 | case LP3944_LED_TYPE_LED: | ||
| 418 | case LP3944_LED_TYPE_LED_INVERTED: | ||
| 419 | led_classdev_unregister(&data->leds[i].ldev); | ||
| 420 | cancel_work_sync(&data->leds[i].work); | ||
| 421 | break; | ||
| 422 | |||
| 423 | case LP3944_LED_TYPE_NONE: | ||
| 424 | default: | ||
| 425 | break; | ||
| 426 | } | ||
| 427 | |||
| 428 | kfree(data); | ||
| 429 | i2c_set_clientdata(client, NULL); | ||
| 430 | |||
| 431 | return 0; | ||
| 432 | } | ||
| 433 | |||
| 434 | /* lp3944 i2c driver struct */ | ||
| 435 | static const struct i2c_device_id lp3944_id[] = { | ||
| 436 | {"lp3944", 0}, | ||
| 437 | {} | ||
| 438 | }; | ||
| 439 | |||
| 440 | MODULE_DEVICE_TABLE(i2c, lp3944_id); | ||
| 441 | |||
| 442 | static struct i2c_driver lp3944_driver = { | ||
| 443 | .driver = { | ||
| 444 | .name = "lp3944", | ||
| 445 | }, | ||
| 446 | .probe = lp3944_probe, | ||
| 447 | .remove = __devexit_p(lp3944_remove), | ||
| 448 | .id_table = lp3944_id, | ||
| 449 | }; | ||
| 450 | |||
| 451 | static int __init lp3944_module_init(void) | ||
| 452 | { | ||
| 453 | return i2c_add_driver(&lp3944_driver); | ||
| 454 | } | ||
| 455 | |||
| 456 | static void __exit lp3944_module_exit(void) | ||
| 457 | { | ||
| 458 | i2c_del_driver(&lp3944_driver); | ||
| 459 | } | ||
| 460 | |||
| 461 | module_init(lp3944_module_init); | ||
| 462 | module_exit(lp3944_module_exit); | ||
| 463 | |||
| 464 | MODULE_AUTHOR("Antonio Ospite <ospite@studenti.unina.it>"); | ||
| 465 | MODULE_DESCRIPTION("LP3944 Fun Light Chip"); | ||
| 466 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/leds/leds-pca9532.c b/drivers/leds/leds-pca9532.c index 3937244fdcab..dba8921240f2 100644 --- a/drivers/leds/leds-pca9532.c +++ b/drivers/leds/leds-pca9532.c | |||
| @@ -35,7 +35,7 @@ struct pca9532_data { | |||
| 35 | struct pca9532_led leds[16]; | 35 | struct pca9532_led leds[16]; |
| 36 | struct mutex update_lock; | 36 | struct mutex update_lock; |
| 37 | struct input_dev *idev; | 37 | struct input_dev *idev; |
| 38 | struct work_struct work; | 38 | struct work_struct work; |
| 39 | u8 pwm[2]; | 39 | u8 pwm[2]; |
| 40 | u8 psc[2]; | 40 | u8 psc[2]; |
| 41 | }; | 41 | }; |
| @@ -87,14 +87,14 @@ static int pca9532_calcpwm(struct i2c_client *client, int pwm, int blink, | |||
| 87 | if (b > 0xFF) | 87 | if (b > 0xFF) |
| 88 | return -EINVAL; | 88 | return -EINVAL; |
| 89 | data->pwm[pwm] = b; | 89 | data->pwm[pwm] = b; |
| 90 | data->psc[pwm] = blink; | 90 | data->psc[pwm] = blink; |
| 91 | return 0; | 91 | return 0; |
| 92 | } | 92 | } |
| 93 | 93 | ||
| 94 | static int pca9532_setpwm(struct i2c_client *client, int pwm) | 94 | static int pca9532_setpwm(struct i2c_client *client, int pwm) |
| 95 | { | 95 | { |
| 96 | struct pca9532_data *data = i2c_get_clientdata(client); | 96 | struct pca9532_data *data = i2c_get_clientdata(client); |
| 97 | mutex_lock(&data->update_lock); | 97 | mutex_lock(&data->update_lock); |
| 98 | i2c_smbus_write_byte_data(client, PCA9532_REG_PWM(pwm), | 98 | i2c_smbus_write_byte_data(client, PCA9532_REG_PWM(pwm), |
| 99 | data->pwm[pwm]); | 99 | data->pwm[pwm]); |
| 100 | i2c_smbus_write_byte_data(client, PCA9532_REG_PSC(pwm), | 100 | 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 | led->state = PCA9532_ON; | 132 | led->state = PCA9532_ON; |
| 133 | else { | 133 | else { |
| 134 | led->state = PCA9532_PWM0; /* Thecus: hardcode one pwm */ | 134 | led->state = PCA9532_PWM0; /* Thecus: hardcode one pwm */ |
| 135 | err = pca9532_calcpwm(led->client, 0, 0, value); | 135 | err = pca9532_calcpwm(led->client, 0, 0, value); |
| 136 | if (err) | 136 | if (err) |
| 137 | return; /* XXX: led api doesn't allow error code? */ | 137 | return; /* XXX: led api doesn't allow error code? */ |
| 138 | } | 138 | } |
| 139 | schedule_work(&led->work); | 139 | schedule_work(&led->work); |
| 140 | } | 140 | } |
| 141 | 141 | ||
| 142 | static int pca9532_set_blink(struct led_classdev *led_cdev, | 142 | 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 | struct pca9532_led *led = ldev_to_led(led_cdev); | 145 | struct pca9532_led *led = ldev_to_led(led_cdev); |
| 146 | struct i2c_client *client = led->client; | 146 | struct i2c_client *client = led->client; |
| 147 | int psc; | 147 | int psc; |
| 148 | int err = 0; | 148 | int err = 0; |
| 149 | 149 | ||
| 150 | if (*delay_on == 0 && *delay_off == 0) { | 150 | if (*delay_on == 0 && *delay_off == 0) { |
| 151 | /* led subsystem ask us for a blink rate */ | 151 | /* led subsystem ask us for a blink rate */ |
| @@ -157,11 +157,11 @@ static int pca9532_set_blink(struct led_classdev *led_cdev, | |||
| 157 | 157 | ||
| 158 | /* Thecus specific: only use PSC/PWM 0 */ | 158 | /* Thecus specific: only use PSC/PWM 0 */ |
| 159 | psc = (*delay_on * 152-1)/1000; | 159 | psc = (*delay_on * 152-1)/1000; |
| 160 | err = pca9532_calcpwm(client, 0, psc, led_cdev->brightness); | 160 | err = pca9532_calcpwm(client, 0, psc, led_cdev->brightness); |
| 161 | if (err) | 161 | if (err) |
| 162 | return err; | 162 | return err; |
| 163 | schedule_work(&led->work); | 163 | schedule_work(&led->work); |
| 164 | return 0; | 164 | return 0; |
| 165 | } | 165 | } |
| 166 | 166 | ||
| 167 | static int pca9532_event(struct input_dev *dev, unsigned int type, | 167 | 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 | else | 178 | else |
| 179 | data->pwm[1] = 0; | 179 | data->pwm[1] = 0; |
| 180 | 180 | ||
| 181 | schedule_work(&data->work); | 181 | schedule_work(&data->work); |
| 182 | 182 | ||
| 183 | return 0; | 183 | return 0; |
| 184 | } | 184 | } |
| 185 | 185 | ||
| 186 | static void pca9532_input_work(struct work_struct *work) | 186 | static void pca9532_input_work(struct work_struct *work) |
| 187 | { | 187 | { |
| 188 | struct pca9532_data *data; | 188 | struct pca9532_data *data; |
| 189 | data = container_of(work, struct pca9532_data, work); | 189 | data = container_of(work, struct pca9532_data, work); |
| 190 | mutex_lock(&data->update_lock); | 190 | mutex_lock(&data->update_lock); |
| 191 | i2c_smbus_write_byte_data(data->client, PCA9532_REG_PWM(1), | 191 | i2c_smbus_write_byte_data(data->client, PCA9532_REG_PWM(1), |
| 192 | data->pwm[1]); | 192 | data->pwm[1]); |
| @@ -195,11 +195,11 @@ static void pca9532_input_work(struct work_struct *work) | |||
| 195 | 195 | ||
| 196 | static void pca9532_led_work(struct work_struct *work) | 196 | static void pca9532_led_work(struct work_struct *work) |
| 197 | { | 197 | { |
| 198 | struct pca9532_led *led; | 198 | struct pca9532_led *led; |
| 199 | led = container_of(work, struct pca9532_led, work); | 199 | led = container_of(work, struct pca9532_led, work); |
| 200 | if (led->state == PCA9532_PWM0) | 200 | if (led->state == PCA9532_PWM0) |
| 201 | pca9532_setpwm(led->client, 0); | 201 | pca9532_setpwm(led->client, 0); |
| 202 | pca9532_setled(led); | 202 | pca9532_setled(led); |
| 203 | } | 203 | } |
| 204 | 204 | ||
| 205 | static int pca9532_configure(struct i2c_client *client, | 205 | static int pca9532_configure(struct i2c_client *client, |
| @@ -232,7 +232,7 @@ static int pca9532_configure(struct i2c_client *client, | |||
| 232 | led->ldev.brightness = LED_OFF; | 232 | led->ldev.brightness = LED_OFF; |
| 233 | led->ldev.brightness_set = pca9532_set_brightness; | 233 | led->ldev.brightness_set = pca9532_set_brightness; |
| 234 | led->ldev.blink_set = pca9532_set_blink; | 234 | led->ldev.blink_set = pca9532_set_blink; |
| 235 | INIT_WORK(&led->work, pca9532_led_work); | 235 | INIT_WORK(&led->work, pca9532_led_work); |
| 236 | err = led_classdev_register(&client->dev, &led->ldev); | 236 | err = led_classdev_register(&client->dev, &led->ldev); |
| 237 | if (err < 0) { | 237 | if (err < 0) { |
| 238 | dev_err(&client->dev, | 238 | dev_err(&client->dev, |
| @@ -262,11 +262,11 @@ static int pca9532_configure(struct i2c_client *client, | |||
| 262 | BIT_MASK(SND_TONE); | 262 | BIT_MASK(SND_TONE); |
| 263 | data->idev->event = pca9532_event; | 263 | data->idev->event = pca9532_event; |
| 264 | input_set_drvdata(data->idev, data); | 264 | input_set_drvdata(data->idev, data); |
| 265 | INIT_WORK(&data->work, pca9532_input_work); | 265 | INIT_WORK(&data->work, pca9532_input_work); |
| 266 | err = input_register_device(data->idev); | 266 | err = input_register_device(data->idev); |
| 267 | if (err) { | 267 | if (err) { |
| 268 | input_free_device(data->idev); | 268 | input_free_device(data->idev); |
| 269 | cancel_work_sync(&data->work); | 269 | cancel_work_sync(&data->work); |
| 270 | data->idev = NULL; | 270 | data->idev = NULL; |
| 271 | goto exit; | 271 | goto exit; |
| 272 | } | 272 | } |
| @@ -283,13 +283,13 @@ exit: | |||
| 283 | break; | 283 | break; |
| 284 | case PCA9532_TYPE_LED: | 284 | case PCA9532_TYPE_LED: |
| 285 | led_classdev_unregister(&data->leds[i].ldev); | 285 | led_classdev_unregister(&data->leds[i].ldev); |
| 286 | cancel_work_sync(&data->leds[i].work); | 286 | cancel_work_sync(&data->leds[i].work); |
| 287 | break; | 287 | break; |
| 288 | case PCA9532_TYPE_N2100_BEEP: | 288 | case PCA9532_TYPE_N2100_BEEP: |
| 289 | if (data->idev != NULL) { | 289 | if (data->idev != NULL) { |
| 290 | input_unregister_device(data->idev); | 290 | input_unregister_device(data->idev); |
| 291 | input_free_device(data->idev); | 291 | input_free_device(data->idev); |
| 292 | cancel_work_sync(&data->work); | 292 | cancel_work_sync(&data->work); |
| 293 | data->idev = NULL; | 293 | data->idev = NULL; |
| 294 | } | 294 | } |
| 295 | break; | 295 | break; |
| @@ -340,13 +340,13 @@ static int pca9532_remove(struct i2c_client *client) | |||
| 340 | break; | 340 | break; |
| 341 | case PCA9532_TYPE_LED: | 341 | case PCA9532_TYPE_LED: |
| 342 | led_classdev_unregister(&data->leds[i].ldev); | 342 | led_classdev_unregister(&data->leds[i].ldev); |
| 343 | cancel_work_sync(&data->leds[i].work); | 343 | cancel_work_sync(&data->leds[i].work); |
| 344 | break; | 344 | break; |
| 345 | case PCA9532_TYPE_N2100_BEEP: | 345 | case PCA9532_TYPE_N2100_BEEP: |
| 346 | if (data->idev != NULL) { | 346 | if (data->idev != NULL) { |
| 347 | input_unregister_device(data->idev); | 347 | input_unregister_device(data->idev); |
| 348 | input_free_device(data->idev); | 348 | input_free_device(data->idev); |
| 349 | cancel_work_sync(&data->work); | 349 | cancel_work_sync(&data->work); |
| 350 | data->idev = NULL; | 350 | data->idev = NULL; |
| 351 | } | 351 | } |
| 352 | break; | 352 | break; |
diff --git a/include/linux/leds-lp3944.h b/include/linux/leds-lp3944.h new file mode 100644 index 000000000000..afc9f9fd70f5 --- /dev/null +++ b/include/linux/leds-lp3944.h | |||
| @@ -0,0 +1,53 @@ | |||
| 1 | /* | ||
| 2 | * leds-lp3944.h - platform data structure for lp3944 led controller | ||
| 3 | * | ||
| 4 | * Copyright (C) 2009 Antonio Ospite <ospite@studenti.unina.it> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2 as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | */ | ||
| 11 | |||
| 12 | #ifndef __LINUX_LEDS_LP3944_H | ||
| 13 | #define __LINUX_LEDS_LP3944_H | ||
| 14 | |||
| 15 | #include <linux/leds.h> | ||
| 16 | #include <linux/workqueue.h> | ||
| 17 | |||
| 18 | #define LP3944_LED0 0 | ||
| 19 | #define LP3944_LED1 1 | ||
| 20 | #define LP3944_LED2 2 | ||
| 21 | #define LP3944_LED3 3 | ||
| 22 | #define LP3944_LED4 4 | ||
| 23 | #define LP3944_LED5 5 | ||
| 24 | #define LP3944_LED6 6 | ||
| 25 | #define LP3944_LED7 7 | ||
| 26 | #define LP3944_LEDS_MAX 8 | ||
| 27 | |||
| 28 | #define LP3944_LED_STATUS_MASK 0x03 | ||
| 29 | enum lp3944_status { | ||
| 30 | LP3944_LED_STATUS_OFF = 0x0, | ||
| 31 | LP3944_LED_STATUS_ON = 0x1, | ||
| 32 | LP3944_LED_STATUS_DIM0 = 0x2, | ||
| 33 | LP3944_LED_STATUS_DIM1 = 0x3 | ||
| 34 | }; | ||
| 35 | |||
| 36 | enum lp3944_type { | ||
| 37 | LP3944_LED_TYPE_NONE, | ||
| 38 | LP3944_LED_TYPE_LED, | ||
| 39 | LP3944_LED_TYPE_LED_INVERTED, | ||
| 40 | }; | ||
| 41 | |||
| 42 | struct lp3944_led { | ||
| 43 | char *name; | ||
| 44 | enum lp3944_type type; | ||
| 45 | enum lp3944_status status; | ||
| 46 | }; | ||
| 47 | |||
| 48 | struct lp3944_platform_data { | ||
| 49 | struct lp3944_led leds[LP3944_LEDS_MAX]; | ||
| 50 | u8 leds_size; | ||
| 51 | }; | ||
| 52 | |||
| 53 | #endif /* __LINUX_LEDS_LP3944_H */ | ||
diff --git a/include/linux/leds.h b/include/linux/leds.h index 376fe07732ea..d8bf9665e70c 100644 --- a/include/linux/leds.h +++ b/include/linux/leds.h | |||
| @@ -45,7 +45,10 @@ struct led_classdev { | |||
| 45 | /* Get LED brightness level */ | 45 | /* Get LED brightness level */ |
| 46 | enum led_brightness (*brightness_get)(struct led_classdev *led_cdev); | 46 | enum led_brightness (*brightness_get)(struct led_classdev *led_cdev); |
| 47 | 47 | ||
| 48 | /* Activate hardware accelerated blink */ | 48 | /* Activate hardware accelerated blink, delays are in |
| 49 | * miliseconds and if none is provided then a sensible default | ||
| 50 | * should be chosen. The call can adjust the timings if it can't | ||
| 51 | * match the values specified exactly. */ | ||
| 49 | int (*blink_set)(struct led_classdev *led_cdev, | 52 | int (*blink_set)(struct led_classdev *led_cdev, |
| 50 | unsigned long *delay_on, | 53 | unsigned long *delay_on, |
| 51 | unsigned long *delay_off); | 54 | unsigned long *delay_off); |
| @@ -141,9 +144,14 @@ struct gpio_led { | |||
| 141 | const char *name; | 144 | const char *name; |
| 142 | const char *default_trigger; | 145 | const char *default_trigger; |
| 143 | unsigned gpio; | 146 | unsigned gpio; |
| 144 | u8 active_low : 1; | 147 | unsigned active_low : 1; |
| 145 | u8 retain_state_suspended : 1; | 148 | unsigned retain_state_suspended : 1; |
| 149 | unsigned default_state : 2; | ||
| 150 | /* default_state should be one of LEDS_GPIO_DEFSTATE_(ON|OFF|KEEP) */ | ||
| 146 | }; | 151 | }; |
| 152 | #define LEDS_GPIO_DEFSTATE_OFF 0 | ||
| 153 | #define LEDS_GPIO_DEFSTATE_ON 1 | ||
| 154 | #define LEDS_GPIO_DEFSTATE_KEEP 2 | ||
| 147 | 155 | ||
| 148 | struct gpio_led_platform_data { | 156 | struct gpio_led_platform_data { |
| 149 | int num_leds; | 157 | int num_leds; |
