Lines Matching +full:leds +full:- +full:group +full:- +full:multicolor
1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * leds-blinkm.c
4 * (c) Jan-Simon Möller (dl9pf@gmx.de)
17 #include <linux/leds.h>
19 #include <linux/led-class-multicolor.h>
24 /* Addresses to scan - BlinkM is on 0x09 by default*/
30 /* Contains structs for both the color-separated sysfs classes, and the new multicolor class */
34 /* used when multicolor support is disabled */
69 u8 fade_speed; /* fade speed 1 - 255 */
70 s8 time_adjust; /* time adjust -128 - 127 */
83 /* mapping command names to cmd chars - see datasheet */
153 return sysfs_emit(buf, "%02X\n", data->red); in show_color_common()
155 return sysfs_emit(buf, "%02X\n", data->green); in show_color_common()
157 return sysfs_emit(buf, "%02X\n", data->blue); in show_color_common()
159 return -EINVAL; in show_color_common()
161 return -EINVAL; in show_color_common()
182 data->next_red = value; in store_color_common()
185 data->next_green = value; in store_color_common()
188 data->next_blue = value; in store_color_common()
191 return -EINVAL; in store_color_common()
195 data->next_red, data->next_green, data->next_blue); in store_color_common()
309 /* write out cmd to blinkm - always / default step */ in blinkm_write()
344 /* the protocol is simple but non-standard: in blinkm_transfer_hw()
346 * - which defaults to 0x09 - would be the sequence: in blinkm_transfer_hw()
360 if (mutex_lock_interruptible(&data->update_lock) < 0) in blinkm_transfer_hw()
361 return -EAGAIN; in blinkm_transfer_hw()
363 /* switch cmd - usually write before reads */ in blinkm_transfer_hw()
368 data->args[0] = data->next_red; in blinkm_transfer_hw()
369 data->args[1] = data->next_green; in blinkm_transfer_hw()
370 data->args[2] = data->next_blue; in blinkm_transfer_hw()
371 blinkm_write(client, cmd, data->args); in blinkm_transfer_hw()
372 data->red = data->args[0]; in blinkm_transfer_hw()
373 data->green = data->args[1]; in blinkm_transfer_hw()
374 data->blue = data->args[2]; in blinkm_transfer_hw()
378 data->args[0] = data->next_hue; in blinkm_transfer_hw()
379 data->args[1] = data->next_saturation; in blinkm_transfer_hw()
380 data->args[2] = data->next_brightness; in blinkm_transfer_hw()
381 blinkm_write(client, cmd, data->args); in blinkm_transfer_hw()
382 data->hue = data->next_hue; in blinkm_transfer_hw()
383 data->saturation = data->next_saturation; in blinkm_transfer_hw()
384 data->brightness = data->next_brightness; in blinkm_transfer_hw()
387 data->args[0] = data->script_id; in blinkm_transfer_hw()
388 data->args[1] = data->script_repeats; in blinkm_transfer_hw()
389 data->args[2] = data->script_startline; in blinkm_transfer_hw()
390 blinkm_write(client, cmd, data->args); in blinkm_transfer_hw()
396 data->args[0] = data->red; in blinkm_transfer_hw()
397 data->args[1] = data->green; in blinkm_transfer_hw()
398 data->args[2] = data->blue; in blinkm_transfer_hw()
400 blinkm_read(client, cmd, data->args); in blinkm_transfer_hw()
401 data->red = data->args[0]; in blinkm_transfer_hw()
402 data->green = data->args[1]; in blinkm_transfer_hw()
403 data->blue = data->args[2]; in blinkm_transfer_hw()
406 data->args[0] = data->i2c_addr; in blinkm_transfer_hw()
408 blinkm_read(client, cmd, data->args); in blinkm_transfer_hw()
409 data->i2c_addr = data->args[0]; in blinkm_transfer_hw()
419 dev_err(&client->dev, in blinkm_transfer_hw()
423 dev_err(&client->dev, "BlinkM: unknown command %d\n", cmd); in blinkm_transfer_hw()
424 mutex_unlock(&data->update_lock); in blinkm_transfer_hw()
425 return -EINVAL; in blinkm_transfer_hw()
429 mutex_unlock(&data->update_lock); in blinkm_transfer_hw()
438 struct blinkm_data *data = i2c_get_clientdata(led->i2c_client); in blinkm_set_mc_brightness()
442 data->next_red = (u8) mcled_cdev->subled_info[RED].brightness; in blinkm_set_mc_brightness()
443 data->next_green = (u8) mcled_cdev->subled_info[GREEN].brightness; in blinkm_set_mc_brightness()
444 data->next_blue = (u8) mcled_cdev->subled_info[BLUE].brightness; in blinkm_set_mc_brightness()
446 blinkm_transfer_hw(led->i2c_client, BLM_GO_RGB); in blinkm_set_mc_brightness()
454 /* led_brightness is 0, 127 or 255 - we just use it here as-is */ in blinkm_led_common_set()
456 struct blinkm_data *data = i2c_get_clientdata(led->i2c_client); in blinkm_led_common_set()
461 if (data->next_red == (u8) value) in blinkm_led_common_set()
463 data->next_red = (u8) value; in blinkm_led_common_set()
467 if (data->next_green == (u8) value) in blinkm_led_common_set()
469 data->next_green = (u8) value; in blinkm_led_common_set()
473 if (data->next_blue == (u8) value) in blinkm_led_common_set()
475 data->next_blue = (u8) value; in blinkm_led_common_set()
479 dev_err(&led->i2c_client->dev, "BlinkM: unknown color.\n"); in blinkm_led_common_set()
480 return -EINVAL; in blinkm_led_common_set()
483 blinkm_transfer_hw(led->i2c_client, BLM_GO_RGB); in blinkm_led_common_set()
484 dev_dbg(&led->i2c_client->dev, in blinkm_led_common_set()
487 data->next_red, data->next_green, in blinkm_led_common_set()
488 data->next_blue); in blinkm_led_common_set()
521 data->next_red = 0x01; in blinkm_test_run()
522 data->next_green = 0x05; in blinkm_test_run()
523 data->next_blue = 0x10; in blinkm_test_run()
529 data->next_red = 0x25; in blinkm_test_run()
530 data->next_green = 0x10; in blinkm_test_run()
531 data->next_blue = 0x31; in blinkm_test_run()
537 data->next_hue = 0x50; in blinkm_test_run()
538 data->next_saturation = 0x10; in blinkm_test_run()
539 data->next_brightness = 0x20; in blinkm_test_run()
548 /* Return 0 if detection is successful, -ENODEV otherwise */
551 struct i2c_adapter *adapter = client->adapter; in blinkm_detect()
559 return -ENODEV; in blinkm_detect()
576 count--; in blinkm_detect()
579 /* Step 1: Read BlinkM address back - cmd_char 'a' */ in blinkm_detect()
589 dev_err(&client->dev, "enodev DEV ADDR = 0x%02X\n", tmpargs[0]); in blinkm_detect()
590 return -ENODEV; in blinkm_detect()
593 strscpy(info->type, "blinkm", I2C_NAME_SIZE); in blinkm_detect()
600 struct blinkm_led *leds[NUM_LEDS]; in register_separate_colors() local
606 leds[i] = &data->blinkm_leds[i]; in register_separate_colors()
607 leds[i]->i2c_client = client; in register_separate_colors()
608 leds[i]->id = i; in register_separate_colors()
609 leds[i]->cdev.led_cdev.max_brightness = 255; in register_separate_colors()
610 leds[i]->cdev.led_cdev.flags = LED_CORE_SUSPENDRESUME; in register_separate_colors()
614 "blinkm-%d-%d-red", in register_separate_colors()
615 client->adapter->nr, in register_separate_colors()
616 client->addr); in register_separate_colors()
617 leds[i]->cdev.led_cdev.name = blinkm_led_name; in register_separate_colors()
618 leds[i]->cdev.led_cdev.brightness_set_blocking = in register_separate_colors()
620 err = led_classdev_register(&client->dev, in register_separate_colors()
621 &leds[i]->cdev.led_cdev); in register_separate_colors()
623 dev_err(&client->dev, in register_separate_colors()
625 leds[i]->cdev.led_cdev.name); in register_separate_colors()
631 "blinkm-%d-%d-green", in register_separate_colors()
632 client->adapter->nr, in register_separate_colors()
633 client->addr); in register_separate_colors()
634 leds[i]->cdev.led_cdev.name = blinkm_led_name; in register_separate_colors()
635 leds[i]->cdev.led_cdev.brightness_set_blocking = in register_separate_colors()
637 err = led_classdev_register(&client->dev, in register_separate_colors()
638 &leds[i]->cdev.led_cdev); in register_separate_colors()
640 dev_err(&client->dev, in register_separate_colors()
642 leds[i]->cdev.led_cdev.name); in register_separate_colors()
648 "blinkm-%d-%d-blue", in register_separate_colors()
649 client->adapter->nr, in register_separate_colors()
650 client->addr); in register_separate_colors()
651 leds[i]->cdev.led_cdev.name = blinkm_led_name; in register_separate_colors()
652 leds[i]->cdev.led_cdev.brightness_set_blocking = in register_separate_colors()
654 err = led_classdev_register(&client->dev, in register_separate_colors()
655 &leds[i]->cdev.led_cdev); in register_separate_colors()
657 dev_err(&client->dev, in register_separate_colors()
659 leds[i]->cdev.led_cdev.name); in register_separate_colors()
670 led_classdev_unregister(&leds[GREEN]->cdev.led_cdev); in register_separate_colors()
672 led_classdev_unregister(&leds[RED]->cdev.led_cdev); in register_separate_colors()
674 sysfs_remove_group(&client->dev.kobj, &blinkm_group); in register_separate_colors()
686 /* Register multicolor sysfs class */ in register_multicolor()
687 /* The first element of leds is used for multicolor facilities */ in register_multicolor()
688 mc_led = &data->blinkm_leds[RED]; in register_multicolor()
689 mc_led->i2c_client = client; in register_multicolor()
691 mc_led_info = devm_kcalloc(&client->dev, NUM_LEDS, sizeof(*mc_led_info), in register_multicolor()
694 return -ENOMEM; in register_multicolor()
700 mc_led->cdev.mcled_cdev.subled_info = mc_led_info; in register_multicolor()
701 mc_led->cdev.mcled_cdev.num_colors = NUM_LEDS; in register_multicolor()
702 mc_led->cdev.mcled_cdev.led_cdev.brightness = 255; in register_multicolor()
703 mc_led->cdev.mcled_cdev.led_cdev.max_brightness = 255; in register_multicolor()
704 mc_led->cdev.mcled_cdev.led_cdev.flags = LED_CORE_SUSPENDRESUME; in register_multicolor()
707 "blinkm-%d-%d:rgb:indicator", in register_multicolor()
708 client->adapter->nr, in register_multicolor()
709 client->addr); in register_multicolor()
710 mc_led->cdev.mcled_cdev.led_cdev.name = blinkm_led_name; in register_multicolor()
711 mc_led->cdev.mcled_cdev.led_cdev.brightness_set_blocking = blinkm_set_mc_brightness; in register_multicolor()
713 err = led_classdev_multicolor_register(&client->dev, &mc_led->cdev.mcled_cdev); in register_multicolor()
715 dev_err(&client->dev, "couldn't register LED %s\n", in register_multicolor()
716 mc_led->cdev.led_cdev.name); in register_multicolor()
717 sysfs_remove_group(&client->dev.kobj, &blinkm_group); in register_multicolor()
727 data = devm_kzalloc(&client->dev, in blinkm_probe()
730 return -ENOMEM; in blinkm_probe()
732 data->i2c_addr = 0x08; in blinkm_probe()
733 /* i2c addr - use fake addr of 0x08 initially (real is 0x09) */ in blinkm_probe()
734 data->fw_ver = 0xfe; in blinkm_probe()
735 /* firmware version - use fake until we read real value in blinkm_probe()
736 * (currently broken - BlinkM confused!) in blinkm_probe()
738 data->script_id = 0x01; in blinkm_probe()
739 data->i2c_client = client; in blinkm_probe()
742 mutex_init(&data->update_lock); in blinkm_probe()
745 err = sysfs_create_group(&client->dev.kobj, &blinkm_group); in blinkm_probe()
747 dev_err(&client->dev, "couldn't register sysfs group\n"); in blinkm_probe()
774 led_classdev_unregister(&data->blinkm_leds[i].cdev.led_cdev); in blinkm_remove()
777 data->next_red = 0x00; in blinkm_remove()
778 data->next_green = 0x00; in blinkm_remove()
779 data->next_blue = 0x00; in blinkm_remove()
782 dev_err(&client->dev, "Failure in blinkm_remove ignored. Continuing.\n"); in blinkm_remove()
785 data->next_hue = 0x00; in blinkm_remove()
786 data->next_saturation = 0x00; in blinkm_remove()
787 data->next_brightness = 0x00; in blinkm_remove()
790 dev_err(&client->dev, "Failure in blinkm_remove ignored. Continuing.\n"); in blinkm_remove()
793 data->next_red = 0xff; in blinkm_remove()
796 dev_err(&client->dev, "Failure in blinkm_remove ignored. Continuing.\n"); in blinkm_remove()
799 data->next_red = 0x00; in blinkm_remove()
802 dev_err(&client->dev, "Failure in blinkm_remove ignored. Continuing.\n"); in blinkm_remove()
804 sysfs_remove_group(&client->dev.kobj, &blinkm_group); in blinkm_remove()
829 MODULE_AUTHOR("Jan-Simon Moeller <dl9pf@gmx.de>");