]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/net/wireless/rtl818x/rtl8187/leds.c
Merge branch 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6
[karo-tx-linux.git] / drivers / net / wireless / rtl818x / rtl8187 / leds.c
1 /*
2  * Linux LED driver for RTL8187
3  *
4  * Copyright 2009 Larry Finger <Larry.Finger@lwfinger.net>
5  *
6  * Based on the LED handling in the r8187 driver, which is:
7  * Copyright (c) Realtek Semiconductor Corp. All rights reserved.
8  *
9  * Thanks to Realtek for their support!
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License version 2 as
13  * published by the Free Software Foundation.
14  */
15
16 #ifdef CONFIG_RTL8187_LEDS
17
18 #include <net/mac80211.h>
19 #include <linux/usb.h>
20 #include <linux/eeprom_93cx6.h>
21
22 #include "rtl8187.h"
23 #include "leds.h"
24
25 static void led_turn_on(struct work_struct *work)
26 {
27         /* As this routine does read/write operations on the hardware, it must
28          * be run from a work queue.
29          */
30         u8 reg;
31         struct rtl8187_priv *priv = container_of(work, struct rtl8187_priv,
32                                     led_on.work);
33         struct rtl8187_led *led = &priv->led_tx;
34
35         /* Don't change the LED, when the device is down. */
36         if (!priv->vif || priv->vif->type == NL80211_IFTYPE_UNSPECIFIED)
37                 return ;
38
39         /* Skip if the LED is not registered. */
40         if (!led->dev)
41                 return;
42         mutex_lock(&priv->conf_mutex);
43         switch (led->ledpin) {
44         case LED_PIN_GPIO0:
45                 rtl818x_iowrite8(priv, &priv->map->GPIO0, 0x01);
46                 rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0x00);
47                 break;
48         case LED_PIN_LED0:
49                 reg = rtl818x_ioread8(priv, &priv->map->PGSELECT) & ~(1 << 4);
50                 rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg);
51                 break;
52         case LED_PIN_LED1:
53                 reg = rtl818x_ioread8(priv, &priv->map->PGSELECT) & ~(1 << 5);
54                 rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg);
55                 break;
56         case LED_PIN_HW:
57         default:
58                 break;
59         }
60         mutex_unlock(&priv->conf_mutex);
61 }
62
63 static void led_turn_off(struct work_struct *work)
64 {
65         /* As this routine does read/write operations on the hardware, it must
66          * be run from a work queue.
67          */
68         u8 reg;
69         struct rtl8187_priv *priv = container_of(work, struct rtl8187_priv,
70                                     led_off.work);
71         struct rtl8187_led *led = &priv->led_tx;
72
73         /* Don't change the LED, when the device is down. */
74         if (!priv->vif || priv->vif->type == NL80211_IFTYPE_UNSPECIFIED)
75                 return ;
76
77         /* Skip if the LED is not registered. */
78         if (!led->dev)
79                 return;
80         mutex_lock(&priv->conf_mutex);
81         switch (led->ledpin) {
82         case LED_PIN_GPIO0:
83                 rtl818x_iowrite8(priv, &priv->map->GPIO0, 0x01);
84                 rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0x01);
85                 break;
86         case LED_PIN_LED0:
87                 reg = rtl818x_ioread8(priv, &priv->map->PGSELECT) | (1 << 4);
88                 rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg);
89                 break;
90         case LED_PIN_LED1:
91                 reg = rtl818x_ioread8(priv, &priv->map->PGSELECT) | (1 << 5);
92                 rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg);
93                 break;
94         case LED_PIN_HW:
95         default:
96                 break;
97         }
98         mutex_unlock(&priv->conf_mutex);
99 }
100
101 /* Callback from the LED subsystem. */
102 static void rtl8187_led_brightness_set(struct led_classdev *led_dev,
103                                    enum led_brightness brightness)
104 {
105         struct rtl8187_led *led = container_of(led_dev, struct rtl8187_led,
106                                                led_dev);
107         struct ieee80211_hw *hw = led->dev;
108         struct rtl8187_priv *priv;
109         static bool radio_on;
110
111         if (!hw)
112                 return;
113         priv = hw->priv;
114         if (led->is_radio) {
115                 if (brightness == LED_FULL) {
116                         ieee80211_queue_delayed_work(hw, &priv->led_on, 0);
117                         radio_on = true;
118                 } else if (radio_on) {
119                         radio_on = false;
120                         cancel_delayed_work(&priv->led_on);
121                         ieee80211_queue_delayed_work(hw, &priv->led_off, 0);
122                 }
123         } else if (radio_on) {
124                 if (brightness == LED_OFF) {
125                         ieee80211_queue_delayed_work(hw, &priv->led_off, 0);
126                         /* The LED is off for 1/20 sec - it just blinks. */
127                         ieee80211_queue_delayed_work(hw, &priv->led_on,
128                                                      HZ / 20);
129                 } else
130                         ieee80211_queue_delayed_work(hw, &priv->led_on, 0);
131         }
132 }
133
134 static int rtl8187_register_led(struct ieee80211_hw *dev,
135                                 struct rtl8187_led *led, const char *name,
136                                 const char *default_trigger, u8 ledpin,
137                                 bool is_radio)
138 {
139         int err;
140         struct rtl8187_priv *priv = dev->priv;
141
142         if (led->dev)
143                 return -EEXIST;
144         if (!default_trigger)
145                 return -EINVAL;
146         led->dev = dev;
147         led->ledpin = ledpin;
148         led->is_radio = is_radio;
149         strncpy(led->name, name, sizeof(led->name));
150
151         led->led_dev.name = led->name;
152         led->led_dev.default_trigger = default_trigger;
153         led->led_dev.brightness_set = rtl8187_led_brightness_set;
154
155         err = led_classdev_register(&priv->udev->dev, &led->led_dev);
156         if (err) {
157                 printk(KERN_INFO "LEDs: Failed to register %s\n", name);
158                 led->dev = NULL;
159                 return err;
160         }
161         return 0;
162 }
163
164 static void rtl8187_unregister_led(struct rtl8187_led *led)
165 {
166         struct ieee80211_hw *hw = led->dev;
167         struct rtl8187_priv *priv = hw->priv;
168
169         led_classdev_unregister(&led->led_dev);
170         flush_delayed_work(&priv->led_off);
171         led->dev = NULL;
172 }
173
174 void rtl8187_leds_init(struct ieee80211_hw *dev, u16 custid)
175 {
176         struct rtl8187_priv *priv = dev->priv;
177         char name[RTL8187_LED_MAX_NAME_LEN + 1];
178         u8 ledpin;
179         int err;
180
181         /* According to the vendor driver, the LED operation depends on the
182          * customer ID encoded in the EEPROM
183          */
184         printk(KERN_INFO "rtl8187: Customer ID is 0x%02X\n", custid);
185         switch (custid) {
186         case EEPROM_CID_RSVD0:
187         case EEPROM_CID_RSVD1:
188         case EEPROM_CID_SERCOMM_PS:
189         case EEPROM_CID_QMI:
190         case EEPROM_CID_DELL:
191         case EEPROM_CID_TOSHIBA:
192                 ledpin = LED_PIN_GPIO0;
193                 break;
194         case EEPROM_CID_ALPHA0:
195                 ledpin = LED_PIN_LED0;
196                 break;
197         case EEPROM_CID_HW:
198                 ledpin = LED_PIN_HW;
199                 break;
200         default:
201                 ledpin = LED_PIN_GPIO0;
202         }
203
204         INIT_DELAYED_WORK(&priv->led_on, led_turn_on);
205         INIT_DELAYED_WORK(&priv->led_off, led_turn_off);
206
207         snprintf(name, sizeof(name),
208                  "rtl8187-%s::radio", wiphy_name(dev->wiphy));
209         err = rtl8187_register_led(dev, &priv->led_radio, name,
210                          ieee80211_get_radio_led_name(dev), ledpin, true);
211         if (err)
212                 return;
213
214         snprintf(name, sizeof(name),
215                  "rtl8187-%s::tx", wiphy_name(dev->wiphy));
216         err = rtl8187_register_led(dev, &priv->led_tx, name,
217                          ieee80211_get_tx_led_name(dev), ledpin, false);
218         if (err)
219                 goto err_tx;
220
221         snprintf(name, sizeof(name),
222                  "rtl8187-%s::rx", wiphy_name(dev->wiphy));
223         err = rtl8187_register_led(dev, &priv->led_rx, name,
224                          ieee80211_get_rx_led_name(dev), ledpin, false);
225         if (!err)
226                 return;
227
228         /* registration of RX LED failed - unregister */
229         rtl8187_unregister_led(&priv->led_tx);
230 err_tx:
231         rtl8187_unregister_led(&priv->led_radio);
232 }
233
234 void rtl8187_leds_exit(struct ieee80211_hw *dev)
235 {
236         struct rtl8187_priv *priv = dev->priv;
237
238         rtl8187_unregister_led(&priv->led_radio);
239         rtl8187_unregister_led(&priv->led_rx);
240         rtl8187_unregister_led(&priv->led_tx);
241         cancel_delayed_work_sync(&priv->led_off);
242         cancel_delayed_work_sync(&priv->led_on);
243 }
244 #endif /* def CONFIG_RTL8187_LEDS */
245