diff options
| -rw-r--r-- | drivers/leds/leds-bd2802.c | 86 |
1 files changed, 73 insertions, 13 deletions
diff --git a/drivers/leds/leds-bd2802.c b/drivers/leds/leds-bd2802.c index 7a03efd54f69..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); |
| @@ -635,7 +685,7 @@ static int __devinit bd2802_probe(struct i2c_client *client, | |||
| 635 | { | 685 | { |
| 636 | struct bd2802_led *led; | 686 | struct bd2802_led *led; |
| 637 | struct bd2802_led_platform_data *pdata; | 687 | struct bd2802_led_platform_data *pdata; |
| 638 | int ret; | 688 | int ret, i; |
| 639 | 689 | ||
| 640 | led = kzalloc(sizeof(struct bd2802_led), GFP_KERNEL); | 690 | led = kzalloc(sizeof(struct bd2802_led), GFP_KERNEL); |
| 641 | if (!led) { | 691 | if (!led) { |
| @@ -665,13 +715,20 @@ static int __devinit bd2802_probe(struct i2c_client *client, | |||
| 665 | /* To save the power, reset BD2802 after detecting */ | 715 | /* To save the power, reset BD2802 after detecting */ |
| 666 | gpio_set_value(led->pdata->reset_gpio, 0); | 716 | gpio_set_value(led->pdata->reset_gpio, 0); |
| 667 | 717 | ||
| 718 | /* Default attributes */ | ||
| 719 | led->wave_pattern = BD2802_PATTERN_HALF; | ||
| 720 | led->rgb_current = BD2802_CURRENT_032; | ||
| 721 | |||
| 668 | init_rwsem(&led->rwsem); | 722 | init_rwsem(&led->rwsem); |
| 669 | 723 | ||
| 670 | ret = device_create_file(&client->dev, &bd2802_adv_conf_attr); | 724 | for (i = 0; i < ARRAY_SIZE(bd2802_attributes); i++) { |
| 671 | if (ret) { | 725 | ret = device_create_file(&led->client->dev, |
| 672 | dev_err(&client->dev, "failed to create sysfs file %s\n", | 726 | bd2802_attributes[i]); |
| 673 | bd2802_adv_conf_attr.attr.name); | 727 | if (ret) { |
| 674 | 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 | } | ||
| 675 | } | 732 | } |
| 676 | 733 | ||
| 677 | ret = bd2802_register_led_classdev(led); | 734 | ret = bd2802_register_led_classdev(led); |
| @@ -681,7 +738,8 @@ static int __devinit bd2802_probe(struct i2c_client *client, | |||
| 681 | return 0; | 738 | return 0; |
| 682 | 739 | ||
| 683 | failed_unregister_dev_file: | 740 | failed_unregister_dev_file: |
| 684 | 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]); | ||
| 685 | failed_free: | 743 | failed_free: |
| 686 | i2c_set_clientdata(client, NULL); | 744 | i2c_set_clientdata(client, NULL); |
| 687 | kfree(led); | 745 | kfree(led); |
| @@ -692,12 +750,14 @@ failed_free: | |||
| 692 | static int __exit bd2802_remove(struct i2c_client *client) | 750 | static int __exit bd2802_remove(struct i2c_client *client) |
| 693 | { | 751 | { |
| 694 | struct bd2802_led *led = i2c_get_clientdata(client); | 752 | struct bd2802_led *led = i2c_get_clientdata(client); |
| 753 | int i; | ||
| 695 | 754 | ||
| 696 | bd2802_unregister_led_classdev(led); | ||
| 697 | gpio_set_value(led->pdata->reset_gpio, 0); | 755 | gpio_set_value(led->pdata->reset_gpio, 0); |
| 756 | bd2802_unregister_led_classdev(led); | ||
| 698 | if (led->adf_on) | 757 | if (led->adf_on) |
| 699 | bd2802_disable_adv_conf(led); | 758 | bd2802_disable_adv_conf(led); |
| 700 | 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]); | ||
| 701 | i2c_set_clientdata(client, NULL); | 761 | i2c_set_clientdata(client, NULL); |
| 702 | kfree(led); | 762 | kfree(led); |
| 703 | 763 | ||
