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