1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40#include "carl9170.h"
41#include "cmd.h"
42
43int carl9170_led_set_state(struct ar9170 *ar, const u32 led_state)
44{
45 return carl9170_write_reg(ar, AR9170_GPIO_REG_PORT_DATA, led_state);
46}
47
48int carl9170_led_init(struct ar9170 *ar)
49{
50 int err;
51
52
53
54 err = carl9170_write_reg(ar, AR9170_GPIO_REG_PORT_TYPE, 3);
55 if (err)
56 goto out;
57
58
59 err = carl9170_led_set_state(ar, 0);
60
61out:
62 return err;
63}
64
65#ifdef CONFIG_CARL9170_LEDS
66static void carl9170_led_update(struct work_struct *work)
67{
68 struct ar9170 *ar = container_of(work, struct ar9170, led_work.work);
69 int i, tmp = 300, blink_delay = 1000;
70 u32 led_val = 0;
71 bool rerun = false;
72
73 if (!IS_ACCEPTING_CMD(ar))
74 return;
75
76 mutex_lock(&ar->mutex);
77 for (i = 0; i < AR9170_NUM_LEDS; i++) {
78 if (ar->leds[i].registered) {
79 if (ar->leds[i].last_state ||
80 ar->leds[i].toggled) {
81
82 if (ar->leds[i].toggled)
83 tmp = 70 + 200 / (ar->leds[i].toggled);
84
85 if (tmp < blink_delay)
86 blink_delay = tmp;
87
88 led_val |= 1 << i;
89 ar->leds[i].toggled = 0;
90 rerun = true;
91 }
92 }
93 }
94
95 carl9170_led_set_state(ar, led_val);
96 mutex_unlock(&ar->mutex);
97
98 if (!rerun)
99 return;
100
101 ieee80211_queue_delayed_work(ar->hw,
102 &ar->led_work,
103 msecs_to_jiffies(blink_delay));
104}
105
106static void carl9170_led_set_brightness(struct led_classdev *led,
107 enum led_brightness brightness)
108{
109 struct carl9170_led *arl = container_of(led, struct carl9170_led, l);
110 struct ar9170 *ar = arl->ar;
111
112 if (!arl->registered)
113 return;
114
115 if (arl->last_state != !!brightness) {
116 arl->toggled++;
117 arl->last_state = !!brightness;
118 }
119
120 if (likely(IS_ACCEPTING_CMD(ar) && arl->toggled))
121 ieee80211_queue_delayed_work(ar->hw, &ar->led_work, HZ / 10);
122}
123
124static int carl9170_led_register_led(struct ar9170 *ar, int i, char *name,
125 char *trigger)
126{
127 int err;
128
129 snprintf(ar->leds[i].name, sizeof(ar->leds[i].name),
130 "carl9170-%s::%s", wiphy_name(ar->hw->wiphy), name);
131
132 ar->leds[i].ar = ar;
133 ar->leds[i].l.name = ar->leds[i].name;
134 ar->leds[i].l.brightness_set = carl9170_led_set_brightness;
135 ar->leds[i].l.brightness = 0;
136 ar->leds[i].l.default_trigger = trigger;
137
138 err = led_classdev_register(wiphy_dev(ar->hw->wiphy),
139 &ar->leds[i].l);
140 if (err) {
141 wiphy_err(ar->hw->wiphy, "failed to register %s LED (%d).\n",
142 ar->leds[i].name, err);
143 } else {
144 ar->leds[i].registered = true;
145 }
146
147 return err;
148}
149
150void carl9170_led_unregister(struct ar9170 *ar)
151{
152 int i;
153
154 for (i = 0; i < AR9170_NUM_LEDS; i++)
155 if (ar->leds[i].registered) {
156 led_classdev_unregister(&ar->leds[i].l);
157 ar->leds[i].registered = false;
158 ar->leds[i].toggled = 0;
159 }
160
161 cancel_delayed_work_sync(&ar->led_work);
162}
163
164int carl9170_led_register(struct ar9170 *ar)
165{
166 int err;
167
168 INIT_DELAYED_WORK(&ar->led_work, carl9170_led_update);
169
170 err = carl9170_led_register_led(ar, 0, "tx",
171 ieee80211_get_tx_led_name(ar->hw));
172 if (err)
173 goto fail;
174
175 if (ar->features & CARL9170_ONE_LED)
176 return 0;
177
178 err = carl9170_led_register_led(ar, 1, "assoc",
179 ieee80211_get_assoc_led_name(ar->hw));
180 if (err)
181 goto fail;
182
183 return 0;
184
185fail:
186 carl9170_led_unregister(ar);
187 return err;
188}
189
190#endif
191