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 %#x not processed\n", pled->ledpin); 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 u8 ledcfg; 105 106 RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, 107 "LedAddr:%X ledpin=%d\n", REG_LEDCFG2, pled->ledpin); 108 109 ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG2); 110 111 switch (pled->ledpin) { 112 case LED_PIN_GPIO0: 113 break; 114 case LED_PIN_LED0: 115 ledcfg &= 0xf0; 116 if (rtlpriv->ledctl.led_opendrain) { 117 ledcfg &= 0x90; /* Set to software control. */ 118 rtl_write_byte(rtlpriv, REG_LEDCFG2, (ledcfg|BIT(3))); 119 ledcfg = rtl_read_byte(rtlpriv, REG_MAC_PINMUX_CFG); 120 ledcfg &= 0xFE; 121 rtl_write_byte(rtlpriv, REG_MAC_PINMUX_CFG, ledcfg); 122 } else { 123 ledcfg &= ~BIT(6); 124 rtl_write_byte(rtlpriv, REG_LEDCFG2, 125 (ledcfg | BIT(3) | BIT(5))); 126 } 127 break; 128 case LED_PIN_LED1: 129 ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG1); 130 ledcfg &= 0x10; /* Set to software control. */ 131 rtl_write_byte(rtlpriv, REG_LEDCFG1, ledcfg|BIT(3)); 132 break; 133 default: 134 RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD, 135 "switch case %#x not processed\n", pled->ledpin); 136 break; 137 } 138 pled->ledon = false; 139 } 140 141 void rtl8812ae_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled) 142 { 143 u16 ledreg = REG_LEDCFG1; 144 struct rtl_priv *rtlpriv = rtl_priv(hw); 145 146 switch (pled->ledpin) { 147 case LED_PIN_LED0: 148 ledreg = REG_LEDCFG1; 149 break; 150 151 case LED_PIN_LED1: 152 ledreg = REG_LEDCFG2; 153 break; 154 155 case LED_PIN_GPIO0: 156 default: 157 break; 158 } 159 160 RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, 161 "In SwLedOff,LedAddr:%X LEDPIN=%d\n", 162 ledreg, pled->ledpin); 163 /*Open-drain arrangement for controlling the LED*/ 164 if (rtlpriv->ledctl.led_opendrain) { 165 u8 ledcfg = rtl_read_byte(rtlpriv, ledreg); 166 167 ledreg &= 0xd0; /* Set to software control.*/ 168 rtl_write_byte(rtlpriv, ledreg, (ledcfg | BIT(3))); 169 170 /*Open-drain arrangement*/ 171 ledcfg = rtl_read_byte(rtlpriv, REG_MAC_PINMUX_CFG); 172 ledcfg &= 0xFE;/*Set GPIO[8] to input mode*/ 173 rtl_write_byte(rtlpriv, REG_MAC_PINMUX_CFG, ledcfg); 174 } else { 175 rtl_write_byte(rtlpriv, ledreg, 0x28); 176 } 177 178 pled->ledon = false; 179 } 180 181 void rtl8821ae_init_sw_leds(struct ieee80211_hw *hw) 182 { 183 struct rtl_priv *rtlpriv = rtl_priv(hw); 184 185 _rtl8821ae_init_led(hw, &rtlpriv->ledctl.sw_led0, LED_PIN_LED0); 186 _rtl8821ae_init_led(hw, &rtlpriv->ledctl.sw_led1, LED_PIN_LED1); 187 } 188 189 static void _rtl8821ae_sw_led_control(struct ieee80211_hw *hw, 190 enum led_ctl_mode ledaction) 191 { 192 struct rtl_priv *rtlpriv = rtl_priv(hw); 193 struct rtl_led *pled0 = &rtlpriv->ledctl.sw_led0; 194 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); 195 196 switch (ledaction) { 197 case LED_CTL_POWER_ON: 198 case LED_CTL_LINK: 199 case LED_CTL_NO_LINK: 200 if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) 201 rtl8812ae_sw_led_on(hw, pled0); 202 else 203 rtl8821ae_sw_led_on(hw, pled0); 204 break; 205 case LED_CTL_POWER_OFF: 206 if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) 207 rtl8812ae_sw_led_off(hw, pled0); 208 else 209 rtl8821ae_sw_led_off(hw, pled0); 210 break; 211 default: 212 break; 213 } 214 } 215 216 void rtl8821ae_led_control(struct ieee80211_hw *hw, 217 enum led_ctl_mode ledaction) 218 { 219 struct rtl_priv *rtlpriv = rtl_priv(hw); 220 struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); 221 222 if ((ppsc->rfoff_reason > RF_CHANGE_BY_PS) && 223 (ledaction == LED_CTL_TX || 224 ledaction == LED_CTL_RX || 225 ledaction == LED_CTL_SITE_SURVEY || 226 ledaction == LED_CTL_LINK || 227 ledaction == LED_CTL_NO_LINK || 228 ledaction == LED_CTL_START_TO_LINK || 229 ledaction == LED_CTL_POWER_ON)) { 230 return; 231 } 232 RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, "ledaction %d,\n", 233 ledaction); 234 _rtl8821ae_sw_led_control(hw, ledaction); 235 } 236