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 
246