Larry Finger | 21e4b07 | 2014-09-22 09:39:26 -0500 | [diff] [blame] | 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, |
Joe Perches | ad57488 | 2016-09-23 11:27:19 -0700 | [diff] [blame] | 63 | "switch case %#x not processed\n", pled->ledpin); |
Larry Finger | 21e4b07 | 2014-09-22 09:39:26 -0500 | [diff] [blame] | 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, |
Joe Perches | ad57488 | 2016-09-23 11:27:19 -0700 | [diff] [blame] | 136 | "switch case %#x not processed\n", pled->ledpin); |
Larry Finger | 21e4b07 | 2014-09-22 09:39:26 -0500 | [diff] [blame] | 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 | } |