leds-acer-a500.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. // SPDX-License-Identifier: GPL-2.0+
  2. #include <linux/leds.h>
  3. #include <linux/module.h>
  4. #include <linux/platform_device.h>
  5. #include <linux/regmap.h>
  6. #define A500_EC_LED_DELAY_USEC (100 * 1000)
  7. enum {
  8. REG_RESET_LEDS = 0x40,
  9. REG_POWER_LED_ON = 0x42,
  10. REG_CHARGE_LED_ON = 0x43,
  11. REG_ANDROID_LEDS_OFF = 0x5a,
  12. };
  13. struct a500_led {
  14. struct led_classdev cdev;
  15. const struct reg_sequence *enable_seq;
  16. struct a500_led *other;
  17. struct regmap *rmap;
  18. };
  19. static const struct reg_sequence a500_ec_leds_reset_seq[] = {
  20. REG_SEQ(REG_RESET_LEDS, 0x0, A500_EC_LED_DELAY_USEC),
  21. REG_SEQ(REG_ANDROID_LEDS_OFF, 0x0, A500_EC_LED_DELAY_USEC),
  22. };
  23. static const struct reg_sequence a500_ec_white_led_enable_seq[] = {
  24. REG_SEQ(REG_POWER_LED_ON, 0x0, A500_EC_LED_DELAY_USEC),
  25. };
  26. static const struct reg_sequence a500_ec_orange_led_enable_seq[] = {
  27. REG_SEQ(REG_CHARGE_LED_ON, 0x0, A500_EC_LED_DELAY_USEC),
  28. };
  29. static int a500_ec_led_brightness_set(struct led_classdev *led_cdev,
  30. enum led_brightness value)
  31. {
  32. struct a500_led *led = container_of(led_cdev, struct a500_led, cdev);
  33. struct reg_sequence control_seq[2];
  34. unsigned int num_regs = 1;
  35. if (value) {
  36. control_seq[0] = led->enable_seq[0];
  37. } else {
  38. /*
  39. * There is no separate controls which can disable LEDs
  40. * individually, there is only RESET_LEDS command that turns
  41. * off both LEDs.
  42. *
  43. * RESET_LEDS turns off both LEDs, thus restore other LED if
  44. * it's turned ON.
  45. */
  46. if (led->other->cdev.brightness)
  47. num_regs = 2;
  48. control_seq[0] = a500_ec_leds_reset_seq[0];
  49. control_seq[1] = led->other->enable_seq[0];
  50. }
  51. return regmap_multi_reg_write(led->rmap, control_seq, num_regs);
  52. }
  53. static int a500_ec_leds_probe(struct platform_device *pdev)
  54. {
  55. struct a500_led *white_led, *orange_led;
  56. struct regmap *rmap;
  57. int err;
  58. rmap = dev_get_regmap(pdev->dev.parent, "KB930");
  59. if (!rmap)
  60. return -EINVAL;
  61. /* reset and turn off LEDs */
  62. regmap_multi_reg_write(rmap, a500_ec_leds_reset_seq, 2);
  63. white_led = devm_kzalloc(&pdev->dev, sizeof(*white_led), GFP_KERNEL);
  64. if (!white_led)
  65. return -ENOMEM;
  66. white_led->cdev.name = "power:white";
  67. white_led->cdev.brightness_set_blocking = a500_ec_led_brightness_set;
  68. white_led->cdev.flags = LED_CORE_SUSPENDRESUME;
  69. white_led->cdev.max_brightness = 1;
  70. white_led->enable_seq = a500_ec_white_led_enable_seq;
  71. white_led->rmap = rmap;
  72. orange_led = devm_kzalloc(&pdev->dev, sizeof(*orange_led), GFP_KERNEL);
  73. if (!orange_led)
  74. return -ENOMEM;
  75. orange_led->cdev.name = "power:orange";
  76. orange_led->cdev.brightness_set_blocking = a500_ec_led_brightness_set;
  77. orange_led->cdev.flags = LED_CORE_SUSPENDRESUME;
  78. orange_led->cdev.max_brightness = 1;
  79. orange_led->enable_seq = a500_ec_orange_led_enable_seq;
  80. orange_led->rmap = rmap;
  81. white_led->other = orange_led;
  82. orange_led->other = white_led;
  83. err = devm_led_classdev_register(&pdev->dev, &white_led->cdev);
  84. if (err) {
  85. dev_err(&pdev->dev, "failed to register white LED\n");
  86. return err;
  87. }
  88. err = devm_led_classdev_register(&pdev->dev, &orange_led->cdev);
  89. if (err) {
  90. dev_err(&pdev->dev, "failed to register orange LED\n");
  91. return err;
  92. }
  93. return 0;
  94. }
  95. static struct platform_driver a500_ec_leds_driver = {
  96. .driver = {
  97. .name = "acer-a500-iconia-leds",
  98. },
  99. .probe = a500_ec_leds_probe,
  100. };
  101. module_platform_driver(a500_ec_leds_driver);
  102. MODULE_DESCRIPTION("LED driver for Acer Iconia Tab A500 Power Button");
  103. MODULE_AUTHOR("Dmitry Osipenko <digetx@gmail.com>");
  104. MODULE_ALIAS("platform:acer-a500-iconia-leds");
  105. MODULE_LICENSE("GPL");