[go: nahoru, domu]

1/******************************************************************************
2 *
3 * Copyright(c) 2009-2010  Realtek Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12 * more details.
13 *
14 * The full GNU General Public License is included in this distribution in the
15 * file called LICENSE.
16 *
17 * Contact Information:
18 * wlanfae <wlanfae@realtek.com>
19 * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
20 * Hsinchu 300, Taiwan.
21 *
22 * Larry Finger <Larry.Finger@lwfinger.net>
23 *
24 *****************************************************************************/
25
26#include "../wifi.h"
27#include "../pci.h"
28#include "reg.h"
29#include "led.h"
30
31static void _rtl8821ae_init_led(struct ieee80211_hw *hw,
32				struct rtl_led *pled,
33				enum rtl_led_pin ledpin)
34{
35	pled->hw = hw;
36	pled->ledpin = ledpin;
37	pled->ledon = false;
38}
39
40void rtl8821ae_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled)
41{
42	u8 ledcfg;
43	struct rtl_priv *rtlpriv = rtl_priv(hw);
44
45	RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD,
46		 "LedAddr:%X ledpin=%d\n", REG_LEDCFG2, pled->ledpin);
47
48	switch (pled->ledpin) {
49	case LED_PIN_GPIO0:
50		break;
51	case LED_PIN_LED0:
52		ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG2);
53		ledcfg &= ~BIT(6);
54		rtl_write_byte(rtlpriv,
55			       REG_LEDCFG2, (ledcfg & 0xf0) | BIT(5));
56		break;
57	case LED_PIN_LED1:
58		ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG1);
59		rtl_write_byte(rtlpriv, REG_LEDCFG1, ledcfg & 0x10);
60		break;
61	default:
62		RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
63			 "switch case not process\n");
64		break;
65	}
66	pled->ledon = true;
67}
68
69void rtl8812ae_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled)
70{
71	u16	ledreg = REG_LEDCFG1;
72	u8	ledcfg = 0;
73	struct rtl_priv *rtlpriv = rtl_priv(hw);
74
75	switch (pled->ledpin) {
76	case LED_PIN_LED0:
77		ledreg = REG_LEDCFG1;
78		break;
79
80	case LED_PIN_LED1:
81		ledreg = REG_LEDCFG2;
82		break;
83
84	case LED_PIN_GPIO0:
85	default:
86		break;
87	}
88
89	RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD,
90		 "In SwLedOn, LedAddr:%X LEDPIN=%d\n",
91		 ledreg, pled->ledpin);
92
93	ledcfg =  rtl_read_byte(rtlpriv, ledreg);
94	ledcfg |= BIT(5); /*Set 0x4c[21]*/
95	ledcfg &= ~(BIT(7) | BIT(6) | BIT(3) | BIT(2) | BIT(1) | BIT(0));
96		/*Clear 0x4c[23:22] and 0x4c[19:16]*/
97	rtl_write_byte(rtlpriv, ledreg, ledcfg); /*SW control led0 on.*/
98	pled->ledon = true;
99}
100
101void rtl8821ae_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled)
102{
103	struct rtl_priv *rtlpriv = rtl_priv(hw);
104	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
105	u8 ledcfg;
106
107	RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD,
108		 "LedAddr:%X ledpin=%d\n", REG_LEDCFG2, pled->ledpin);
109
110	ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG2);
111
112	switch (pled->ledpin) {
113	case LED_PIN_GPIO0:
114		break;
115	case LED_PIN_LED0:
116		ledcfg &= 0xf0;
117		if (pcipriv->ledctl.led_opendrain) {
118			ledcfg &= 0x90; /* Set to software control. */
119			rtl_write_byte(rtlpriv, REG_LEDCFG2, (ledcfg|BIT(3)));
120			ledcfg = rtl_read_byte(rtlpriv, REG_MAC_PINMUX_CFG);
121			ledcfg &= 0xFE;
122			rtl_write_byte(rtlpriv, REG_MAC_PINMUX_CFG, ledcfg);
123		} else {
124			ledcfg &= ~BIT(6);
125			rtl_write_byte(rtlpriv, REG_LEDCFG2,
126				       (ledcfg | BIT(3) | BIT(5)));
127		}
128		break;
129	case LED_PIN_LED1:
130		ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG1);
131		ledcfg &= 0x10; /* Set to software control. */
132		rtl_write_byte(rtlpriv, REG_LEDCFG1, ledcfg|BIT(3));
133		break;
134	default:
135		RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
136			 "switch case not process\n");
137		break;
138	}
139	pled->ledon = false;
140}
141
142void rtl8812ae_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled)
143{
144	u16 ledreg = REG_LEDCFG1;
145	struct rtl_priv *rtlpriv = rtl_priv(hw);
146	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
147
148	switch (pled->ledpin) {
149	case LED_PIN_LED0:
150		ledreg = REG_LEDCFG1;
151		break;
152
153	case LED_PIN_LED1:
154		ledreg = REG_LEDCFG2;
155		break;
156
157	case LED_PIN_GPIO0:
158	default:
159		break;
160	}
161
162	RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD,
163		 "In SwLedOff,LedAddr:%X LEDPIN=%d\n",
164		 ledreg, pled->ledpin);
165	/*Open-drain arrangement for controlling the LED*/
166	if (pcipriv->ledctl.led_opendrain) {
167		u8 ledcfg = rtl_read_byte(rtlpriv, ledreg);
168
169		ledreg &= 0xd0; /* Set to software control.*/
170		rtl_write_byte(rtlpriv, ledreg, (ledcfg | BIT(3)));
171
172		/*Open-drain arrangement*/
173		ledcfg = rtl_read_byte(rtlpriv, REG_MAC_PINMUX_CFG);
174		ledcfg &= 0xFE;/*Set GPIO[8] to input mode*/
175		rtl_write_byte(rtlpriv, REG_MAC_PINMUX_CFG, ledcfg);
176	} else {
177		rtl_write_byte(rtlpriv, ledreg, 0x28);
178	}
179
180	pled->ledon = false;
181}
182
183void rtl8821ae_init_sw_leds(struct ieee80211_hw *hw)
184{
185	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
186
187	_rtl8821ae_init_led(hw, &pcipriv->ledctl.sw_led0, LED_PIN_LED0);
188	_rtl8821ae_init_led(hw, &pcipriv->ledctl.sw_led1, LED_PIN_LED1);
189}
190
191static void _rtl8821ae_sw_led_control(struct ieee80211_hw *hw,
192				      enum led_ctl_mode ledaction)
193{
194	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
195	struct rtl_led *pLed0 = &pcipriv->ledctl.sw_led0;
196	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
197
198	switch (ledaction) {
199	case LED_CTL_POWER_ON:
200	case LED_CTL_LINK:
201	case LED_CTL_NO_LINK:
202		if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE)
203			rtl8812ae_sw_led_on(hw, pLed0);
204		else
205			rtl8821ae_sw_led_on(hw, pLed0);
206		break;
207	case LED_CTL_POWER_OFF:
208		if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE)
209			rtl8812ae_sw_led_off(hw, pLed0);
210		else
211			rtl8821ae_sw_led_off(hw, pLed0);
212		break;
213	default:
214		break;
215	}
216}
217
218void rtl8821ae_led_control(struct ieee80211_hw *hw,
219			   enum led_ctl_mode ledaction)
220{
221	struct rtl_priv *rtlpriv = rtl_priv(hw);
222	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
223
224	if ((ppsc->rfoff_reason > RF_CHANGE_BY_PS) &&
225	    (ledaction == LED_CTL_TX ||
226	     ledaction == LED_CTL_RX ||
227	     ledaction == LED_CTL_SITE_SURVEY ||
228	     ledaction == LED_CTL_LINK ||
229	     ledaction == LED_CTL_NO_LINK ||
230	     ledaction == LED_CTL_START_TO_LINK ||
231	     ledaction == LED_CTL_POWER_ON)) {
232		return;
233	}
234	RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, "ledaction %d,\n",
235		 ledaction);
236	_rtl8821ae_sw_led_control(hw, ledaction);
237}
238