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
22static 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
60static 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. */
99static 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
131static 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	strscpy(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
161static 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
171void 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);
227err_tx:
228	rtl8187_unregister_led(&priv->led_radio);
229}
230
231void 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