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
25static 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
63static 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. */
102static 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
134static 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
164static 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
174void 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);
230err_tx:
231	rtl8187_unregister_led(&priv->led_radio);
232}
233
234void 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