Lines Matching +full:led +full:-
1 // SPDX-License-Identifier: GPL-2.0-only
3 * leds-bd2802.c - RGB LED Driver
8 * Datasheet: http://www.rohm.com/products/databook/driver/pdf/bd2802gu-e.pdf
16 #include <linux/leds-bd2802.h>
73 struct led_state led[2]; member
104 /*--------------------------------------------------------------*/
106 /*--------------------------------------------------------------*/
108 static inline int bd2802_is_rgb_off(struct bd2802_led *led, enum led_ids id, in bd2802_is_rgb_off() argument
113 return !led->led[id].r; in bd2802_is_rgb_off()
115 return !led->led[id].g; in bd2802_is_rgb_off()
117 return !led->led[id].b; in bd2802_is_rgb_off()
119 dev_err(&led->client->dev, "%s: Invalid color\n", __func__); in bd2802_is_rgb_off()
120 return -EINVAL; in bd2802_is_rgb_off()
124 static inline int bd2802_is_led_off(struct bd2802_led *led, enum led_ids id) in bd2802_is_led_off() argument
126 if (led->led[id].r || led->led[id].g || led->led[id].b) in bd2802_is_led_off()
132 static inline int bd2802_is_all_off(struct bd2802_led *led) in bd2802_is_all_off() argument
137 if (!bd2802_is_led_off(led, i)) in bd2802_is_all_off()
155 /*--------------------------------------------------------------*/
157 /*--------------------------------------------------------------*/
165 dev_err(&client->dev, "%s: reg 0x%x, val 0x%x, err %d\n", in bd2802_write_byte()
171 static void bd2802_update_state(struct bd2802_led *led, enum led_ids id, in bd2802_update_state() argument
181 led->led[i].r = led_bit; in bd2802_update_state()
184 led->led[i].g = led_bit; in bd2802_update_state()
187 led->led[i].b = led_bit; in bd2802_update_state()
190 dev_err(&led->client->dev, in bd2802_update_state()
200 if (!bd2802_is_led_off(led, id)) in bd2802_update_state()
203 if (bd2802_is_all_off(led) && !led->adf_on) { in bd2802_update_state()
204 gpiod_set_value(led->reset, 1); in bd2802_update_state()
209 * In this case, other led is turned on, and current led is turned in bd2802_update_state()
210 * off. So set RGB LED Control register to stop the current RGB LED in bd2802_update_state()
213 bd2802_write_byte(led->client, BD2802_REG_CONTROL, value); in bd2802_update_state()
216 static void bd2802_configure(struct bd2802_led *led) in bd2802_configure() argument
218 struct bd2802_led_platform_data *pdata = led->pdata; in bd2802_configure()
222 bd2802_write_byte(led->client, reg, pdata->rgb_time); in bd2802_configure()
225 bd2802_write_byte(led->client, reg, pdata->rgb_time); in bd2802_configure()
228 static void bd2802_reset_cancel(struct bd2802_led *led) in bd2802_reset_cancel() argument
230 gpiod_set_value(led->reset, 0); in bd2802_reset_cancel()
232 bd2802_configure(led); in bd2802_reset_cancel()
235 static void bd2802_enable(struct bd2802_led *led, enum led_ids id) in bd2802_enable() argument
240 other_led_on = !bd2802_is_led_off(led, other_led); in bd2802_enable()
246 bd2802_write_byte(led->client, BD2802_REG_CONTROL, value); in bd2802_enable()
249 static void bd2802_set_on(struct bd2802_led *led, enum led_ids id, in bd2802_set_on() argument
254 if (bd2802_is_all_off(led) && !led->adf_on) in bd2802_set_on()
255 bd2802_reset_cancel(led); in bd2802_set_on()
258 bd2802_write_byte(led->client, reg, led->rgb_current); in bd2802_set_on()
260 bd2802_write_byte(led->client, reg, BD2802_CURRENT_000); in bd2802_set_on()
262 bd2802_write_byte(led->client, reg, BD2802_PATTERN_FULL); in bd2802_set_on()
264 bd2802_enable(led, id); in bd2802_set_on()
265 bd2802_update_state(led, id, color, BD2802_ON); in bd2802_set_on()
268 static void bd2802_set_blink(struct bd2802_led *led, enum led_ids id, in bd2802_set_blink() argument
273 if (bd2802_is_all_off(led) && !led->adf_on) in bd2802_set_blink()
274 bd2802_reset_cancel(led); in bd2802_set_blink()
277 bd2802_write_byte(led->client, reg, BD2802_CURRENT_000); in bd2802_set_blink()
279 bd2802_write_byte(led->client, reg, led->rgb_current); in bd2802_set_blink()
281 bd2802_write_byte(led->client, reg, led->wave_pattern); in bd2802_set_blink()
283 bd2802_enable(led, id); in bd2802_set_blink()
284 bd2802_update_state(led, id, color, BD2802_BLINK); in bd2802_set_blink()
287 static void bd2802_turn_on(struct bd2802_led *led, enum led_ids id, in bd2802_turn_on() argument
291 dev_err(&led->client->dev, in bd2802_turn_on()
297 bd2802_set_blink(led, id, color); in bd2802_turn_on()
299 bd2802_set_on(led, id, color); in bd2802_turn_on()
302 static void bd2802_turn_off(struct bd2802_led *led, enum led_ids id, in bd2802_turn_off() argument
307 if (bd2802_is_rgb_off(led, id, color)) in bd2802_turn_off()
311 bd2802_write_byte(led->client, reg, BD2802_CURRENT_000); in bd2802_turn_off()
313 bd2802_write_byte(led->client, reg, BD2802_CURRENT_000); in bd2802_turn_off()
315 bd2802_update_state(led, id, color, BD2802_OFF); in bd2802_turn_off()
322 struct bd2802_led *led = i2c_get_clientdata(to_i2c_client(dev));\
326 return -EINVAL; \
330 down_write(&led->rwsem); \
331 bd2802_write_byte(led->client, reg_addr, (u8) val); \
332 up_write(&led->rwsem); \
388 static void bd2802_enable_adv_conf(struct bd2802_led *led) in bd2802_enable_adv_conf() argument
393 ret = device_create_file(&led->client->dev, in bd2802_enable_adv_conf()
396 dev_err(&led->client->dev, "failed: sysfs file %s\n", in bd2802_enable_adv_conf()
397 bd2802_addr_attributes[i]->attr.name); in bd2802_enable_adv_conf()
402 if (bd2802_is_all_off(led)) in bd2802_enable_adv_conf()
403 bd2802_reset_cancel(led); in bd2802_enable_adv_conf()
405 led->adf_on = 1; in bd2802_enable_adv_conf()
410 for (i--; i >= 0; i--) in bd2802_enable_adv_conf()
411 device_remove_file(&led->client->dev, in bd2802_enable_adv_conf()
415 static void bd2802_disable_adv_conf(struct bd2802_led *led) in bd2802_disable_adv_conf() argument
420 device_remove_file(&led->client->dev, in bd2802_disable_adv_conf()
423 if (bd2802_is_all_off(led)) in bd2802_disable_adv_conf()
424 gpiod_set_value(led->reset, 1); in bd2802_disable_adv_conf()
426 led->adf_on = 0; in bd2802_disable_adv_conf()
432 struct bd2802_led *led = i2c_get_clientdata(to_i2c_client(dev)); in bd2802_show_adv_conf() local
435 down_read(&led->rwsem); in bd2802_show_adv_conf()
436 if (led->adf_on) in bd2802_show_adv_conf()
440 up_read(&led->rwsem); in bd2802_show_adv_conf()
448 struct bd2802_led *led = i2c_get_clientdata(to_i2c_client(dev)); in bd2802_store_adv_conf() local
451 return -EINVAL; in bd2802_store_adv_conf()
453 down_write(&led->rwsem); in bd2802_store_adv_conf()
454 if (!led->adf_on && !strncmp(buf, "on", 2)) in bd2802_store_adv_conf()
455 bd2802_enable_adv_conf(led); in bd2802_store_adv_conf()
456 else if (led->adf_on && !strncmp(buf, "off", 3)) in bd2802_store_adv_conf()
457 bd2802_disable_adv_conf(led); in bd2802_store_adv_conf()
458 up_write(&led->rwsem); in bd2802_store_adv_conf()
476 struct bd2802_led *led = i2c_get_clientdata(to_i2c_client(dev));\
478 down_read(&led->rwsem); \
479 ret = sprintf(buf, "0x%02x\n", led->attr_name); \
480 up_read(&led->rwsem); \
486 struct bd2802_led *led = i2c_get_clientdata(to_i2c_client(dev));\
490 return -EINVAL; \
494 down_write(&led->rwsem); \
495 led->attr_name = val; \
496 up_write(&led->rwsem); \
521 struct bd2802_led *led = \
523 led->led_id = id; \
524 led->color = clr; \
526 led->state = BD2802_OFF; \
527 bd2802_turn_off(led, led->led_id, led->color); \
529 led->state = BD2802_ON; \
530 bd2802_turn_on(led, led->led_id, led->color, BD2802_ON);\
537 struct bd2802_led *led = \
540 return -EINVAL; \
541 led->led_id = id; \
542 led->color = clr; \
543 led->state = BD2802_BLINK; \
544 bd2802_turn_on(led, led->led_id, led->color, BD2802_BLINK); \
555 static int bd2802_register_led_classdev(struct bd2802_led *led) in bd2802_register_led_classdev() argument
559 led->cdev_led1r.name = "led1_R"; in bd2802_register_led_classdev()
560 led->cdev_led1r.brightness = LED_OFF; in bd2802_register_led_classdev()
561 led->cdev_led1r.brightness_set_blocking = bd2802_set_led1r_brightness; in bd2802_register_led_classdev()
562 led->cdev_led1r.blink_set = bd2802_set_led1r_blink; in bd2802_register_led_classdev()
564 ret = led_classdev_register(&led->client->dev, &led->cdev_led1r); in bd2802_register_led_classdev()
566 dev_err(&led->client->dev, "couldn't register LED %s\n", in bd2802_register_led_classdev()
567 led->cdev_led1r.name); in bd2802_register_led_classdev()
571 led->cdev_led1g.name = "led1_G"; in bd2802_register_led_classdev()
572 led->cdev_led1g.brightness = LED_OFF; in bd2802_register_led_classdev()
573 led->cdev_led1g.brightness_set_blocking = bd2802_set_led1g_brightness; in bd2802_register_led_classdev()
574 led->cdev_led1g.blink_set = bd2802_set_led1g_blink; in bd2802_register_led_classdev()
576 ret = led_classdev_register(&led->client->dev, &led->cdev_led1g); in bd2802_register_led_classdev()
578 dev_err(&led->client->dev, "couldn't register LED %s\n", in bd2802_register_led_classdev()
579 led->cdev_led1g.name); in bd2802_register_led_classdev()
583 led->cdev_led1b.name = "led1_B"; in bd2802_register_led_classdev()
584 led->cdev_led1b.brightness = LED_OFF; in bd2802_register_led_classdev()
585 led->cdev_led1b.brightness_set_blocking = bd2802_set_led1b_brightness; in bd2802_register_led_classdev()
586 led->cdev_led1b.blink_set = bd2802_set_led1b_blink; in bd2802_register_led_classdev()
588 ret = led_classdev_register(&led->client->dev, &led->cdev_led1b); in bd2802_register_led_classdev()
590 dev_err(&led->client->dev, "couldn't register LED %s\n", in bd2802_register_led_classdev()
591 led->cdev_led1b.name); in bd2802_register_led_classdev()
595 led->cdev_led2r.name = "led2_R"; in bd2802_register_led_classdev()
596 led->cdev_led2r.brightness = LED_OFF; in bd2802_register_led_classdev()
597 led->cdev_led2r.brightness_set_blocking = bd2802_set_led2r_brightness; in bd2802_register_led_classdev()
598 led->cdev_led2r.blink_set = bd2802_set_led2r_blink; in bd2802_register_led_classdev()
600 ret = led_classdev_register(&led->client->dev, &led->cdev_led2r); in bd2802_register_led_classdev()
602 dev_err(&led->client->dev, "couldn't register LED %s\n", in bd2802_register_led_classdev()
603 led->cdev_led2r.name); in bd2802_register_led_classdev()
607 led->cdev_led2g.name = "led2_G"; in bd2802_register_led_classdev()
608 led->cdev_led2g.brightness = LED_OFF; in bd2802_register_led_classdev()
609 led->cdev_led2g.brightness_set_blocking = bd2802_set_led2g_brightness; in bd2802_register_led_classdev()
610 led->cdev_led2g.blink_set = bd2802_set_led2g_blink; in bd2802_register_led_classdev()
612 ret = led_classdev_register(&led->client->dev, &led->cdev_led2g); in bd2802_register_led_classdev()
614 dev_err(&led->client->dev, "couldn't register LED %s\n", in bd2802_register_led_classdev()
615 led->cdev_led2g.name); in bd2802_register_led_classdev()
619 led->cdev_led2b.name = "led2_B"; in bd2802_register_led_classdev()
620 led->cdev_led2b.brightness = LED_OFF; in bd2802_register_led_classdev()
621 led->cdev_led2b.brightness_set_blocking = bd2802_set_led2b_brightness; in bd2802_register_led_classdev()
622 led->cdev_led2b.blink_set = bd2802_set_led2b_blink; in bd2802_register_led_classdev()
623 led->cdev_led2b.flags |= LED_CORE_SUSPENDRESUME; in bd2802_register_led_classdev()
625 ret = led_classdev_register(&led->client->dev, &led->cdev_led2b); in bd2802_register_led_classdev()
627 dev_err(&led->client->dev, "couldn't register LED %s\n", in bd2802_register_led_classdev()
628 led->cdev_led2b.name); in bd2802_register_led_classdev()
635 led_classdev_unregister(&led->cdev_led2g); in bd2802_register_led_classdev()
637 led_classdev_unregister(&led->cdev_led2r); in bd2802_register_led_classdev()
639 led_classdev_unregister(&led->cdev_led1b); in bd2802_register_led_classdev()
641 led_classdev_unregister(&led->cdev_led1g); in bd2802_register_led_classdev()
643 led_classdev_unregister(&led->cdev_led1r); in bd2802_register_led_classdev()
649 static void bd2802_unregister_led_classdev(struct bd2802_led *led) in bd2802_unregister_led_classdev() argument
651 led_classdev_unregister(&led->cdev_led2b); in bd2802_unregister_led_classdev()
652 led_classdev_unregister(&led->cdev_led2g); in bd2802_unregister_led_classdev()
653 led_classdev_unregister(&led->cdev_led2r); in bd2802_unregister_led_classdev()
654 led_classdev_unregister(&led->cdev_led1b); in bd2802_unregister_led_classdev()
655 led_classdev_unregister(&led->cdev_led1g); in bd2802_unregister_led_classdev()
656 led_classdev_unregister(&led->cdev_led1r); in bd2802_unregister_led_classdev()
661 struct bd2802_led *led; in bd2802_probe() local
664 led = devm_kzalloc(&client->dev, sizeof(struct bd2802_led), GFP_KERNEL); in bd2802_probe()
665 if (!led) in bd2802_probe()
666 return -ENOMEM; in bd2802_probe()
668 led->client = client; in bd2802_probe()
669 i2c_set_clientdata(client, led); in bd2802_probe()
674 * We request the reset GPIO as OUT_LOW which means de-asserted, in bd2802_probe()
678 led->reset = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_LOW); in bd2802_probe()
679 if (IS_ERR(led->reset)) in bd2802_probe()
680 return PTR_ERR(led->reset); in bd2802_probe()
688 dev_err(&client->dev, "failed to detect device\n"); in bd2802_probe()
691 dev_info(&client->dev, "return 0x%02x\n", ret); in bd2802_probe()
694 gpiod_set_value(led->reset, 1); in bd2802_probe()
697 led->wave_pattern = BD2802_PATTERN_HALF; in bd2802_probe()
698 led->rgb_current = BD2802_CURRENT_032; in bd2802_probe()
700 init_rwsem(&led->rwsem); in bd2802_probe()
703 ret = device_create_file(&led->client->dev, in bd2802_probe()
706 dev_err(&led->client->dev, "failed: sysfs file %s\n", in bd2802_probe()
707 bd2802_attributes[i]->attr.name); in bd2802_probe()
712 ret = bd2802_register_led_classdev(led); in bd2802_probe()
719 for (i--; i >= 0; i--) in bd2802_probe()
720 device_remove_file(&led->client->dev, bd2802_attributes[i]); in bd2802_probe()
726 struct bd2802_led *led = i2c_get_clientdata(client); in bd2802_remove() local
729 gpiod_set_value(led->reset, 1); in bd2802_remove()
730 bd2802_unregister_led_classdev(led); in bd2802_remove()
731 if (led->adf_on) in bd2802_remove()
732 bd2802_disable_adv_conf(led); in bd2802_remove()
734 device_remove_file(&led->client->dev, bd2802_attributes[i]); in bd2802_remove()
738 static void bd2802_restore_state(struct bd2802_led *led) in bd2802_restore_state() argument
743 if (led->led[i].r) in bd2802_restore_state()
744 bd2802_turn_on(led, i, RED, led->led[i].r); in bd2802_restore_state()
745 if (led->led[i].g) in bd2802_restore_state()
746 bd2802_turn_on(led, i, GREEN, led->led[i].g); in bd2802_restore_state()
747 if (led->led[i].b) in bd2802_restore_state()
748 bd2802_turn_on(led, i, BLUE, led->led[i].b); in bd2802_restore_state()
755 struct bd2802_led *led = i2c_get_clientdata(client); in bd2802_suspend() local
757 gpiod_set_value(led->reset, 1); in bd2802_suspend()
765 struct bd2802_led *led = i2c_get_clientdata(client); in bd2802_resume() local
767 if (!bd2802_is_all_off(led) || led->adf_on) { in bd2802_resume()
768 bd2802_reset_cancel(led); in bd2802_resume()
769 bd2802_restore_state(led); in bd2802_resume()
797 MODULE_DESCRIPTION("BD2802 LED driver");