rt2x00leds.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. Copyright (C) 2004 - 2009 Ivo van Doorn <[email protected]>
  4. <http://rt2x00.serialmonkey.com>
  5. */
  6. /*
  7. Module: rt2x00lib
  8. Abstract: rt2x00 led specific routines.
  9. */
  10. #include <linux/kernel.h>
  11. #include <linux/module.h>
  12. #include "rt2x00.h"
  13. #include "rt2x00lib.h"
  14. void rt2x00leds_led_quality(struct rt2x00_dev *rt2x00dev, int rssi)
  15. {
  16. struct rt2x00_led *led = &rt2x00dev->led_qual;
  17. unsigned int brightness;
  18. if ((led->type != LED_TYPE_QUALITY) || !(led->flags & LED_REGISTERED))
  19. return;
  20. /*
  21. * Led handling requires a positive value for the rssi,
  22. * to do that correctly we need to add the correction.
  23. */
  24. rssi += rt2x00dev->rssi_offset;
  25. /*
  26. * Get the rssi level, this is used to convert the rssi
  27. * to a LED value inside the range LED_OFF - LED_FULL.
  28. */
  29. if (rssi <= 30)
  30. rssi = 0;
  31. else if (rssi <= 39)
  32. rssi = 1;
  33. else if (rssi <= 49)
  34. rssi = 2;
  35. else if (rssi <= 53)
  36. rssi = 3;
  37. else if (rssi <= 63)
  38. rssi = 4;
  39. else
  40. rssi = 5;
  41. /*
  42. * Note that we must _not_ send LED_OFF since the driver
  43. * is going to calculate the value and might use it in a
  44. * division.
  45. */
  46. brightness = ((LED_FULL / 6) * rssi) + 1;
  47. if (brightness != led->led_dev.brightness) {
  48. led->led_dev.brightness_set(&led->led_dev, brightness);
  49. led->led_dev.brightness = brightness;
  50. }
  51. }
  52. static void rt2x00led_led_simple(struct rt2x00_led *led, bool enabled)
  53. {
  54. unsigned int brightness = enabled ? LED_FULL : LED_OFF;
  55. if (!(led->flags & LED_REGISTERED))
  56. return;
  57. led->led_dev.brightness_set(&led->led_dev, brightness);
  58. led->led_dev.brightness = brightness;
  59. }
  60. void rt2x00led_led_activity(struct rt2x00_dev *rt2x00dev, bool enabled)
  61. {
  62. if (rt2x00dev->led_qual.type == LED_TYPE_ACTIVITY)
  63. rt2x00led_led_simple(&rt2x00dev->led_qual, enabled);
  64. }
  65. void rt2x00leds_led_assoc(struct rt2x00_dev *rt2x00dev, bool enabled)
  66. {
  67. if (rt2x00dev->led_assoc.type == LED_TYPE_ASSOC)
  68. rt2x00led_led_simple(&rt2x00dev->led_assoc, enabled);
  69. }
  70. void rt2x00leds_led_radio(struct rt2x00_dev *rt2x00dev, bool enabled)
  71. {
  72. if (rt2x00dev->led_radio.type == LED_TYPE_RADIO)
  73. rt2x00led_led_simple(&rt2x00dev->led_radio, enabled);
  74. }
  75. static int rt2x00leds_register_led(struct rt2x00_dev *rt2x00dev,
  76. struct rt2x00_led *led,
  77. const char *name)
  78. {
  79. struct device *device = wiphy_dev(rt2x00dev->hw->wiphy);
  80. int retval;
  81. led->led_dev.name = name;
  82. led->led_dev.brightness = LED_OFF;
  83. retval = led_classdev_register(device, &led->led_dev);
  84. if (retval) {
  85. rt2x00_err(rt2x00dev, "Failed to register led handler\n");
  86. return retval;
  87. }
  88. led->flags |= LED_REGISTERED;
  89. return 0;
  90. }
  91. void rt2x00leds_register(struct rt2x00_dev *rt2x00dev)
  92. {
  93. char name[36];
  94. int retval;
  95. unsigned long on_period;
  96. unsigned long off_period;
  97. const char *phy_name = wiphy_name(rt2x00dev->hw->wiphy);
  98. if (rt2x00dev->led_radio.flags & LED_INITIALIZED) {
  99. snprintf(name, sizeof(name), "%s-%s::radio",
  100. rt2x00dev->ops->name, phy_name);
  101. retval = rt2x00leds_register_led(rt2x00dev,
  102. &rt2x00dev->led_radio,
  103. name);
  104. if (retval)
  105. goto exit_fail;
  106. }
  107. if (rt2x00dev->led_assoc.flags & LED_INITIALIZED) {
  108. snprintf(name, sizeof(name), "%s-%s::assoc",
  109. rt2x00dev->ops->name, phy_name);
  110. retval = rt2x00leds_register_led(rt2x00dev,
  111. &rt2x00dev->led_assoc,
  112. name);
  113. if (retval)
  114. goto exit_fail;
  115. }
  116. if (rt2x00dev->led_qual.flags & LED_INITIALIZED) {
  117. snprintf(name, sizeof(name), "%s-%s::quality",
  118. rt2x00dev->ops->name, phy_name);
  119. retval = rt2x00leds_register_led(rt2x00dev,
  120. &rt2x00dev->led_qual,
  121. name);
  122. if (retval)
  123. goto exit_fail;
  124. }
  125. /*
  126. * Initialize blink time to default value:
  127. * On period: 70ms
  128. * Off period: 30ms
  129. */
  130. if (rt2x00dev->led_radio.led_dev.blink_set) {
  131. on_period = 70;
  132. off_period = 30;
  133. rt2x00dev->led_radio.led_dev.blink_set(
  134. &rt2x00dev->led_radio.led_dev, &on_period, &off_period);
  135. }
  136. return;
  137. exit_fail:
  138. rt2x00leds_unregister(rt2x00dev);
  139. }
  140. static void rt2x00leds_unregister_led(struct rt2x00_led *led)
  141. {
  142. led_classdev_unregister(&led->led_dev);
  143. /*
  144. * This might look weird, but when we are unregistering while
  145. * suspended the led is already off, and since we haven't
  146. * fully resumed yet, access to the device might not be
  147. * possible yet.
  148. */
  149. if (!(led->led_dev.flags & LED_SUSPENDED))
  150. led->led_dev.brightness_set(&led->led_dev, LED_OFF);
  151. led->flags &= ~LED_REGISTERED;
  152. }
  153. void rt2x00leds_unregister(struct rt2x00_dev *rt2x00dev)
  154. {
  155. if (rt2x00dev->led_qual.flags & LED_REGISTERED)
  156. rt2x00leds_unregister_led(&rt2x00dev->led_qual);
  157. if (rt2x00dev->led_assoc.flags & LED_REGISTERED)
  158. rt2x00leds_unregister_led(&rt2x00dev->led_assoc);
  159. if (rt2x00dev->led_radio.flags & LED_REGISTERED)
  160. rt2x00leds_unregister_led(&rt2x00dev->led_radio);
  161. }
  162. static inline void rt2x00leds_suspend_led(struct rt2x00_led *led)
  163. {
  164. led_classdev_suspend(&led->led_dev);
  165. /* This shouldn't be needed, but just to be safe */
  166. led->led_dev.brightness_set(&led->led_dev, LED_OFF);
  167. led->led_dev.brightness = LED_OFF;
  168. }
  169. void rt2x00leds_suspend(struct rt2x00_dev *rt2x00dev)
  170. {
  171. if (rt2x00dev->led_qual.flags & LED_REGISTERED)
  172. rt2x00leds_suspend_led(&rt2x00dev->led_qual);
  173. if (rt2x00dev->led_assoc.flags & LED_REGISTERED)
  174. rt2x00leds_suspend_led(&rt2x00dev->led_assoc);
  175. if (rt2x00dev->led_radio.flags & LED_REGISTERED)
  176. rt2x00leds_suspend_led(&rt2x00dev->led_radio);
  177. }
  178. static inline void rt2x00leds_resume_led(struct rt2x00_led *led)
  179. {
  180. led_classdev_resume(&led->led_dev);
  181. /* Device might have enabled the LEDS during resume */
  182. led->led_dev.brightness_set(&led->led_dev, LED_OFF);
  183. led->led_dev.brightness = LED_OFF;
  184. }
  185. void rt2x00leds_resume(struct rt2x00_dev *rt2x00dev)
  186. {
  187. if (rt2x00dev->led_radio.flags & LED_REGISTERED)
  188. rt2x00leds_resume_led(&rt2x00dev->led_radio);
  189. if (rt2x00dev->led_assoc.flags & LED_REGISTERED)
  190. rt2x00leds_resume_led(&rt2x00dev->led_assoc);
  191. if (rt2x00dev->led_qual.flags & LED_REGISTERED)
  192. rt2x00leds_resume_led(&rt2x00dev->led_qual);
  193. }