leds.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. /*
  2. * Driver for the 4 user LEDs found on the Integrator AP/CP baseboard
  3. * Based on Versatile and RealView machine LED code
  4. *
  5. * License terms: GNU General Public License (GPL) version 2
  6. * Author: Bryan Wu <bryan.wu@canonical.com>
  7. */
  8. #include <linux/kernel.h>
  9. #include <linux/init.h>
  10. #include <linux/io.h>
  11. #include <linux/slab.h>
  12. #include <linux/leds.h>
  13. #include "hardware.h"
  14. #include "cm.h"
  15. #if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS)
  16. #define ALPHA_REG __io_address(INTEGRATOR_DBG_BASE)
  17. #define LEDREG (__io_address(INTEGRATOR_DBG_BASE) + INTEGRATOR_DBG_LEDS_OFFSET)
  18. struct integrator_led {
  19. struct led_classdev cdev;
  20. u8 mask;
  21. };
  22. /*
  23. * The triggers lines up below will only be used if the
  24. * LED triggers are compiled in.
  25. */
  26. static const struct {
  27. const char *name;
  28. const char *trigger;
  29. } integrator_leds[] = {
  30. { "integrator:green0", "heartbeat", },
  31. { "integrator:yellow", },
  32. { "integrator:red", },
  33. { "integrator:green1", },
  34. { "integrator:core_module", "cpu0", },
  35. };
  36. static void integrator_led_set(struct led_classdev *cdev,
  37. enum led_brightness b)
  38. {
  39. struct integrator_led *led = container_of(cdev,
  40. struct integrator_led, cdev);
  41. u32 reg = __raw_readl(LEDREG);
  42. if (b != LED_OFF)
  43. reg |= led->mask;
  44. else
  45. reg &= ~led->mask;
  46. while (__raw_readl(ALPHA_REG) & 1)
  47. cpu_relax();
  48. __raw_writel(reg, LEDREG);
  49. }
  50. static enum led_brightness integrator_led_get(struct led_classdev *cdev)
  51. {
  52. struct integrator_led *led = container_of(cdev,
  53. struct integrator_led, cdev);
  54. u32 reg = __raw_readl(LEDREG);
  55. return (reg & led->mask) ? LED_FULL : LED_OFF;
  56. }
  57. static void cm_led_set(struct led_classdev *cdev,
  58. enum led_brightness b)
  59. {
  60. if (b != LED_OFF)
  61. cm_control(CM_CTRL_LED, CM_CTRL_LED);
  62. else
  63. cm_control(CM_CTRL_LED, 0);
  64. }
  65. static enum led_brightness cm_led_get(struct led_classdev *cdev)
  66. {
  67. u32 reg = cm_get();
  68. return (reg & CM_CTRL_LED) ? LED_FULL : LED_OFF;
  69. }
  70. static int __init integrator_leds_init(void)
  71. {
  72. int i;
  73. for (i = 0; i < ARRAY_SIZE(integrator_leds); i++) {
  74. struct integrator_led *led;
  75. led = kzalloc(sizeof(*led), GFP_KERNEL);
  76. if (!led)
  77. break;
  78. led->cdev.name = integrator_leds[i].name;
  79. if (i == 4) { /* Setting for LED in core module */
  80. led->cdev.brightness_set = cm_led_set;
  81. led->cdev.brightness_get = cm_led_get;
  82. } else {
  83. led->cdev.brightness_set = integrator_led_set;
  84. led->cdev.brightness_get = integrator_led_get;
  85. }
  86. led->cdev.default_trigger = integrator_leds[i].trigger;
  87. led->mask = BIT(i);
  88. if (led_classdev_register(NULL, &led->cdev) < 0) {
  89. kfree(led);
  90. break;
  91. }
  92. }
  93. return 0;
  94. }
  95. /*
  96. * Since we may have triggers on any subsystem, defer registration
  97. * until after subsystem_init.
  98. */
  99. fs_initcall(integrator_leds_init);
  100. #endif