aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/leds/leds-bd2802.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/leds/leds-bd2802.c')
-rw-r--r--drivers/leds/leds-bd2802.c96
1 files changed, 75 insertions, 21 deletions
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) \
491static 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} \
501static 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} \
517static 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
527BD2802_CONTROL_ATTR(wave_pattern, "wave_pattern");
528BD2802_CONTROL_ATTR(rgb_current, "rgb_current");
529
530static struct device_attribute *bd2802_attributes[] = {
531 &bd2802_adv_conf_attr,
532 &bd2802_wave_pattern_attr,
533 &bd2802_rgb_current_attr,
534};
535
486static void bd2802_led_work(struct work_struct *work) 536static 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
688failed_unregister_dev_file: 740failed_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]);
690failed_free: 743failed_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:
697static int __exit bd2802_remove(struct i2c_client *client) 750static 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
763MODULE_AUTHOR("Kim Kyuwon <q1.kim@samsung.com>"); 817MODULE_AUTHOR("Kim Kyuwon <q1.kim@samsung.com>");
764MODULE_DESCRIPTION("BD2802 LED driver"); 818MODULE_DESCRIPTION("BD2802 LED driver");
765MODULE_LICENSE("GPL"); 819MODULE_LICENSE("GPL v2");