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