/arch/powerpc/platforms/powermac/backlight.c

http://github.com/mirrors/linux · C · 221 lines · 139 code · 45 blank · 37 comment · 22 complexity · 8df7b62a66ef4d2acaa368b526179c15 MD5 · raw file

  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Miscellaneous procedures for dealing with the PowerMac hardware.
  4. * Contains support for the backlight.
  5. *
  6. * Copyright (C) 2000 Benjamin Herrenschmidt
  7. * Copyright (C) 2006 Michael Hanselmann <linux-kernel@hansmi.ch>
  8. *
  9. */
  10. #include <linux/kernel.h>
  11. #include <linux/fb.h>
  12. #include <linux/backlight.h>
  13. #include <linux/adb.h>
  14. #include <linux/pmu.h>
  15. #include <linux/atomic.h>
  16. #include <linux/export.h>
  17. #include <asm/prom.h>
  18. #include <asm/backlight.h>
  19. #define OLD_BACKLIGHT_MAX 15
  20. static void pmac_backlight_key_worker(struct work_struct *work);
  21. static void pmac_backlight_set_legacy_worker(struct work_struct *work);
  22. static DECLARE_WORK(pmac_backlight_key_work, pmac_backlight_key_worker);
  23. static DECLARE_WORK(pmac_backlight_set_legacy_work, pmac_backlight_set_legacy_worker);
  24. /* Although these variables are used in interrupt context, it makes no sense to
  25. * protect them. No user is able to produce enough key events per second and
  26. * notice the errors that might happen.
  27. */
  28. static int pmac_backlight_key_queued;
  29. static int pmac_backlight_set_legacy_queued;
  30. /* The via-pmu code allows the backlight to be grabbed, in which case the
  31. * in-kernel control of the brightness needs to be disabled. This should
  32. * only be used by really old PowerBooks.
  33. */
  34. static atomic_t kernel_backlight_disabled = ATOMIC_INIT(0);
  35. /* Protect the pmac_backlight variable below.
  36. You should hold this lock when using the pmac_backlight pointer to
  37. prevent its potential removal. */
  38. DEFINE_MUTEX(pmac_backlight_mutex);
  39. /* Main backlight storage
  40. *
  41. * Backlight drivers in this variable are required to have the "ops"
  42. * attribute set and to have an update_status function.
  43. *
  44. * We can only store one backlight here, but since Apple laptops have only one
  45. * internal display, it doesn't matter. Other backlight drivers can be used
  46. * independently.
  47. *
  48. */
  49. struct backlight_device *pmac_backlight;
  50. int pmac_has_backlight_type(const char *type)
  51. {
  52. struct device_node* bk_node = of_find_node_by_name(NULL, "backlight");
  53. if (bk_node) {
  54. const char *prop = of_get_property(bk_node,
  55. "backlight-control", NULL);
  56. if (prop && strncmp(prop, type, strlen(type)) == 0) {
  57. of_node_put(bk_node);
  58. return 1;
  59. }
  60. of_node_put(bk_node);
  61. }
  62. return 0;
  63. }
  64. int pmac_backlight_curve_lookup(struct fb_info *info, int value)
  65. {
  66. int level = (FB_BACKLIGHT_LEVELS - 1);
  67. if (info && info->bl_dev) {
  68. int i, max = 0;
  69. /* Look for biggest value */
  70. for (i = 0; i < FB_BACKLIGHT_LEVELS; i++)
  71. max = max((int)info->bl_curve[i], max);
  72. /* Look for nearest value */
  73. for (i = 0; i < FB_BACKLIGHT_LEVELS; i++) {
  74. int diff = abs(info->bl_curve[i] - value);
  75. if (diff < max) {
  76. max = diff;
  77. level = i;
  78. }
  79. }
  80. }
  81. return level;
  82. }
  83. static void pmac_backlight_key_worker(struct work_struct *work)
  84. {
  85. if (atomic_read(&kernel_backlight_disabled))
  86. return;
  87. mutex_lock(&pmac_backlight_mutex);
  88. if (pmac_backlight) {
  89. struct backlight_properties *props;
  90. int brightness;
  91. props = &pmac_backlight->props;
  92. brightness = props->brightness +
  93. ((pmac_backlight_key_queued?-1:1) *
  94. (props->max_brightness / 15));
  95. if (brightness < 0)
  96. brightness = 0;
  97. else if (brightness > props->max_brightness)
  98. brightness = props->max_brightness;
  99. props->brightness = brightness;
  100. backlight_update_status(pmac_backlight);
  101. }
  102. mutex_unlock(&pmac_backlight_mutex);
  103. }
  104. /* This function is called in interrupt context */
  105. void pmac_backlight_key(int direction)
  106. {
  107. if (atomic_read(&kernel_backlight_disabled))
  108. return;
  109. /* we can receive multiple interrupts here, but the scheduled work
  110. * will run only once, with the last value
  111. */
  112. pmac_backlight_key_queued = direction;
  113. schedule_work(&pmac_backlight_key_work);
  114. }
  115. static int __pmac_backlight_set_legacy_brightness(int brightness)
  116. {
  117. int error = -ENXIO;
  118. mutex_lock(&pmac_backlight_mutex);
  119. if (pmac_backlight) {
  120. struct backlight_properties *props;
  121. props = &pmac_backlight->props;
  122. props->brightness = brightness *
  123. (props->max_brightness + 1) /
  124. (OLD_BACKLIGHT_MAX + 1);
  125. if (props->brightness > props->max_brightness)
  126. props->brightness = props->max_brightness;
  127. else if (props->brightness < 0)
  128. props->brightness = 0;
  129. backlight_update_status(pmac_backlight);
  130. error = 0;
  131. }
  132. mutex_unlock(&pmac_backlight_mutex);
  133. return error;
  134. }
  135. static void pmac_backlight_set_legacy_worker(struct work_struct *work)
  136. {
  137. if (atomic_read(&kernel_backlight_disabled))
  138. return;
  139. __pmac_backlight_set_legacy_brightness(pmac_backlight_set_legacy_queued);
  140. }
  141. /* This function is called in interrupt context */
  142. void pmac_backlight_set_legacy_brightness_pmu(int brightness) {
  143. if (atomic_read(&kernel_backlight_disabled))
  144. return;
  145. pmac_backlight_set_legacy_queued = brightness;
  146. schedule_work(&pmac_backlight_set_legacy_work);
  147. }
  148. int pmac_backlight_set_legacy_brightness(int brightness)
  149. {
  150. return __pmac_backlight_set_legacy_brightness(brightness);
  151. }
  152. int pmac_backlight_get_legacy_brightness(void)
  153. {
  154. int result = -ENXIO;
  155. mutex_lock(&pmac_backlight_mutex);
  156. if (pmac_backlight) {
  157. struct backlight_properties *props;
  158. props = &pmac_backlight->props;
  159. result = props->brightness *
  160. (OLD_BACKLIGHT_MAX + 1) /
  161. (props->max_brightness + 1);
  162. }
  163. mutex_unlock(&pmac_backlight_mutex);
  164. return result;
  165. }
  166. void pmac_backlight_disable(void)
  167. {
  168. atomic_inc(&kernel_backlight_disabled);
  169. }
  170. void pmac_backlight_enable(void)
  171. {
  172. atomic_dec(&kernel_backlight_disabled);
  173. }
  174. EXPORT_SYMBOL_GPL(pmac_backlight);
  175. EXPORT_SYMBOL_GPL(pmac_backlight_mutex);
  176. EXPORT_SYMBOL_GPL(pmac_has_backlight_type);