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 31 static 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 40 void 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 69 void 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 101 void 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 142 void 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 183 void 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 191 static 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 218 void 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