aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorVasanthakumar Thiagarajan <vasanth@atheros.com>2008-08-25 11:17:29 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-08-29 16:24:09 -0400
commitc83be6885e2f1ee6e0b290b6cfc82014c675e087 (patch)
treeee8410596f5400b916e391b861b4537014355ebb /drivers
parent36aedc903ea11a4188de0a118d26c9f20afdd272 (diff)
ath9k: Add LED support
Signed-off-by: Vasanthakumar Thiagarajan <vasanth@atheros.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/ath9k/ath9k.h16
-rw-r--r--drivers/net/wireless/ath9k/core.h29
-rw-r--r--drivers/net/wireless/ath9k/hw.c33
-rw-r--r--drivers/net/wireless/ath9k/main.c138
-rw-r--r--drivers/net/wireless/ath9k/reg.h6
5 files changed, 176 insertions, 46 deletions
diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h
index 841893b0b4d4..020b97fd208c 100644
--- a/drivers/net/wireless/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath9k/ath9k.h
@@ -757,14 +757,11 @@ struct ath9k_node_stats {
757 757
758#define ATH9K_RSSI_EP_MULTIPLIER (1<<7) 758#define ATH9K_RSSI_EP_MULTIPLIER (1<<7)
759 759
760enum ath9k_gpio_output_mux_type { 760#define AR_GPIO_OUTPUT_MUX_AS_OUTPUT 0
761 ATH9K_GPIO_OUTPUT_MUX_AS_OUTPUT, 761#define AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED 1
762 ATH9K_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED, 762#define AR_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED 2
763 ATH9K_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED, 763#define AR_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED 5
764 ATH9K_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED, 764#define AR_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED 6
765 ATH9K_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED,
766 ATH9K_GPIO_OUTPUT_MUX_NUM_ENTRIES
767};
768 765
769enum { 766enum {
770 ATH9K_RESET_POWER_ON, 767 ATH9K_RESET_POWER_ON,
@@ -1008,4 +1005,7 @@ void ath9k_hw_get_channel_centers(struct ath_hal *ah,
1008bool ath9k_get_channel_edges(struct ath_hal *ah, 1005bool ath9k_get_channel_edges(struct ath_hal *ah,
1009 u16 flags, u16 *low, 1006 u16 flags, u16 *low,
1010 u16 *high); 1007 u16 *high);
1008void ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio,
1009 u32 ah_signal_type);
1010void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 value);
1011#endif 1011#endif
diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h
index de1d12f7c64a..0692fc340268 100644
--- a/drivers/net/wireless/ath9k/core.h
+++ b/drivers/net/wireless/ath9k/core.h
@@ -39,6 +39,7 @@
39#include <linux/scatterlist.h> 39#include <linux/scatterlist.h>
40#include <asm/page.h> 40#include <asm/page.h>
41#include <net/mac80211.h> 41#include <net/mac80211.h>
42#include <linux/leds.h>
42 43
43#include "ath9k.h" 44#include "ath9k.h"
44#include "rc.h" 45#include "rc.h"
@@ -803,6 +804,27 @@ void ath_slow_ant_div(struct ath_antdiv *antdiv,
803void ath_setdefantenna(void *sc, u32 antenna); 804void ath_setdefantenna(void *sc, u32 antenna);
804 805
805/********************/ 806/********************/
807/* LED Control */
808/********************/
809
810#define ATH_LED_PIN 1
811
812enum ath_led_type {
813 ATH_LED_RADIO,
814 ATH_LED_ASSOC,
815 ATH_LED_TX,
816 ATH_LED_RX
817};
818
819struct ath_led {
820 struct ath_softc *sc;
821 struct led_classdev led_cdev;
822 enum ath_led_type led_type;
823 char name[32];
824 bool registered;
825};
826
827/********************/
806/* Main driver core */ 828/* Main driver core */
807/********************/ 829/********************/
808 830
@@ -884,6 +906,7 @@ struct ath_ht_info {
884#define SC_OP_PREAMBLE_SHORT BIT(7) 906#define SC_OP_PREAMBLE_SHORT BIT(7)
885#define SC_OP_PROTECT_ENABLE BIT(8) 907#define SC_OP_PROTECT_ENABLE BIT(8)
886#define SC_OP_RXFLUSH BIT(9) 908#define SC_OP_RXFLUSH BIT(9)
909#define SC_OP_LED_ASSOCIATED BIT(10)
887 910
888struct ath_softc { 911struct ath_softc {
889 struct ieee80211_hw *hw; 912 struct ieee80211_hw *hw;
@@ -988,6 +1011,12 @@ struct ath_softc {
988 spinlock_t sc_txbuflock; 1011 spinlock_t sc_txbuflock;
989 spinlock_t sc_resetlock; 1012 spinlock_t sc_resetlock;
990 spinlock_t node_lock; 1013 spinlock_t node_lock;
1014
1015 /* LEDs */
1016 struct ath_led radio_led;
1017 struct ath_led assoc_led;
1018 struct ath_led tx_led;
1019 struct ath_led rx_led;
991}; 1020};
992 1021
993int ath_init(u16 devid, struct ath_softc *sc); 1022int ath_init(u16 devid, struct ath_softc *sc);
diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c
index 47c60acac41f..2578411c6019 100644
--- a/drivers/net/wireless/ath9k/hw.c
+++ b/drivers/net/wireless/ath9k/hw.c
@@ -2800,32 +2800,11 @@ static void ath9k_hw_gpio_cfg_output_mux(struct ath_hal *ah,
2800 } 2800 }
2801} 2801}
2802 2802
2803static bool ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio, 2803void ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio,
2804 enum ath9k_gpio_output_mux_type 2804 u32 ah_signal_type)
2805 halSignalType)
2806{ 2805{
2807 u32 ah_signal_type;
2808 u32 gpio_shift; 2806 u32 gpio_shift;
2809 2807
2810 static u32 MuxSignalConversionTable[] = {
2811
2812 AR_GPIO_OUTPUT_MUX_AS_OUTPUT,
2813
2814 AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED,
2815
2816 AR_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED,
2817
2818 AR_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED,
2819
2820 AR_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED,
2821 };
2822
2823 if ((halSignalType >= 0)
2824 && (halSignalType < ARRAY_SIZE(MuxSignalConversionTable)))
2825 ah_signal_type = MuxSignalConversionTable[halSignalType];
2826 else
2827 return false;
2828
2829 ath9k_hw_gpio_cfg_output_mux(ah, gpio, ah_signal_type); 2808 ath9k_hw_gpio_cfg_output_mux(ah, gpio, ah_signal_type);
2830 2809
2831 gpio_shift = 2 * gpio; 2810 gpio_shift = 2 * gpio;
@@ -2834,16 +2813,12 @@ static bool ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio,
2834 AR_GPIO_OE_OUT, 2813 AR_GPIO_OE_OUT,
2835 (AR_GPIO_OE_OUT_DRV_ALL << gpio_shift), 2814 (AR_GPIO_OE_OUT_DRV_ALL << gpio_shift),
2836 (AR_GPIO_OE_OUT_DRV << gpio_shift)); 2815 (AR_GPIO_OE_OUT_DRV << gpio_shift));
2837
2838 return true;
2839} 2816}
2840 2817
2841static bool ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, 2818void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 val)
2842 u32 val)
2843{ 2819{
2844 REG_RMW(ah, AR_GPIO_IN_OUT, ((val & 1) << gpio), 2820 REG_RMW(ah, AR_GPIO_IN_OUT, ((val & 1) << gpio),
2845 AR_GPIO_BIT(gpio)); 2821 AR_GPIO_BIT(gpio));
2846 return true;
2847} 2822}
2848 2823
2849static u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio) 2824static u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio)
@@ -5923,7 +5898,7 @@ bool ath9k_hw_reset(struct ath_hal *ah,
5923 else 5898 else
5924 ath9k_hw_set_gpio(ah, 9, 1); 5899 ath9k_hw_set_gpio(ah, 9, 1);
5925 } 5900 }
5926 ath9k_hw_cfg_output(ah, 9, ATH9K_GPIO_OUTPUT_MUX_AS_OUTPUT); 5901 ath9k_hw_cfg_output(ah, 9, AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
5927 } 5902 }
5928 5903
5929 ecode = ath9k_hw_process_ini(ah, chan, macmode); 5904 ecode = ath9k_hw_process_ini(ah, chan, macmode);
diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c
index dca00c3a985a..996bb9c6540d 100644
--- a/drivers/net/wireless/ath9k/main.c
+++ b/drivers/net/wireless/ath9k/main.c
@@ -1172,12 +1172,130 @@ enum ath9k_ht_macmode ath_cwm_macmode(struct ath_softc *sc)
1172 return sc->sc_ht_info.tx_chan_width; 1172 return sc->sc_ht_info.tx_chan_width;
1173} 1173}
1174 1174
1175/********************************/
1176/* LED functions */
1177/********************************/
1178
1179static void ath_led_brightness(struct led_classdev *led_cdev,
1180 enum led_brightness brightness)
1181{
1182 struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev);
1183 struct ath_softc *sc = led->sc;
1184
1185 switch (brightness) {
1186 case LED_OFF:
1187 if (led->led_type == ATH_LED_ASSOC ||
1188 led->led_type == ATH_LED_RADIO)
1189 sc->sc_flags &= ~SC_OP_LED_ASSOCIATED;
1190 ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN,
1191 (led->led_type == ATH_LED_RADIO) ? 1 :
1192 !!(sc->sc_flags & SC_OP_LED_ASSOCIATED));
1193 break;
1194 case LED_FULL:
1195 if (led->led_type == ATH_LED_ASSOC)
1196 sc->sc_flags |= SC_OP_LED_ASSOCIATED;
1197 ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 0);
1198 break;
1199 default:
1200 break;
1201 }
1202}
1203
1204static int ath_register_led(struct ath_softc *sc, struct ath_led *led,
1205 char *trigger)
1206{
1207 int ret;
1208
1209 led->sc = sc;
1210 led->led_cdev.name = led->name;
1211 led->led_cdev.default_trigger = trigger;
1212 led->led_cdev.brightness_set = ath_led_brightness;
1213
1214 ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &led->led_cdev);
1215 if (ret)
1216 DPRINTF(sc, ATH_DBG_FATAL,
1217 "Failed to register led:%s", led->name);
1218 else
1219 led->registered = 1;
1220 return ret;
1221}
1222
1223static void ath_unregister_led(struct ath_led *led)
1224{
1225 if (led->registered) {
1226 led_classdev_unregister(&led->led_cdev);
1227 led->registered = 0;
1228 }
1229}
1230
1231static void ath_deinit_leds(struct ath_softc *sc)
1232{
1233 ath_unregister_led(&sc->assoc_led);
1234 sc->sc_flags &= ~SC_OP_LED_ASSOCIATED;
1235 ath_unregister_led(&sc->tx_led);
1236 ath_unregister_led(&sc->rx_led);
1237 ath_unregister_led(&sc->radio_led);
1238 ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
1239}
1240
1241static void ath_init_leds(struct ath_softc *sc)
1242{
1243 char *trigger;
1244 int ret;
1245
1246 /* Configure gpio 1 for output */
1247 ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN,
1248 AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
1249 /* LED off, active low */
1250 ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
1251
1252 trigger = ieee80211_get_radio_led_name(sc->hw);
1253 snprintf(sc->radio_led.name, sizeof(sc->radio_led.name),
1254 "ath9k-%s:radio", wiphy_name(sc->hw->wiphy));
1255 ret = ath_register_led(sc, &sc->radio_led, trigger);
1256 sc->radio_led.led_type = ATH_LED_RADIO;
1257 if (ret)
1258 goto fail;
1259
1260 trigger = ieee80211_get_assoc_led_name(sc->hw);
1261 snprintf(sc->assoc_led.name, sizeof(sc->assoc_led.name),
1262 "ath9k-%s:assoc", wiphy_name(sc->hw->wiphy));
1263 ret = ath_register_led(sc, &sc->assoc_led, trigger);
1264 sc->assoc_led.led_type = ATH_LED_ASSOC;
1265 if (ret)
1266 goto fail;
1267
1268 trigger = ieee80211_get_tx_led_name(sc->hw);
1269 snprintf(sc->tx_led.name, sizeof(sc->tx_led.name),
1270 "ath9k-%s:tx", wiphy_name(sc->hw->wiphy));
1271 ret = ath_register_led(sc, &sc->tx_led, trigger);
1272 sc->tx_led.led_type = ATH_LED_TX;
1273 if (ret)
1274 goto fail;
1275
1276 trigger = ieee80211_get_rx_led_name(sc->hw);
1277 snprintf(sc->rx_led.name, sizeof(sc->rx_led.name),
1278 "ath9k-%s:rx", wiphy_name(sc->hw->wiphy));
1279 ret = ath_register_led(sc, &sc->rx_led, trigger);
1280 sc->rx_led.led_type = ATH_LED_RX;
1281 if (ret)
1282 goto fail;
1283
1284 return;
1285
1286fail:
1287 ath_deinit_leds(sc);
1288}
1289
1175static int ath_detach(struct ath_softc *sc) 1290static int ath_detach(struct ath_softc *sc)
1176{ 1291{
1177 struct ieee80211_hw *hw = sc->hw; 1292 struct ieee80211_hw *hw = sc->hw;
1178 1293
1179 DPRINTF(sc, ATH_DBG_CONFIG, "%s: Detach ATH hw\n", __func__); 1294 DPRINTF(sc, ATH_DBG_CONFIG, "%s: Detach ATH hw\n", __func__);
1180 1295
1296 /* Deinit LED control */
1297 ath_deinit_leds(sc);
1298
1181 /* Unregister hw */ 1299 /* Unregister hw */
1182 1300
1183 ieee80211_unregister_hw(hw); 1301 ieee80211_unregister_hw(hw);
@@ -1271,18 +1389,21 @@ static int ath_attach(u16 devid,
1271 goto bad; 1389 goto bad;
1272 } 1390 }
1273 1391
1392 /* Initialize LED control */
1393 ath_init_leds(sc);
1394
1274 /* initialize tx/rx engine */ 1395 /* initialize tx/rx engine */
1275 1396
1276 error = ath_tx_init(sc, ATH_TXBUF); 1397 error = ath_tx_init(sc, ATH_TXBUF);
1277 if (error != 0) 1398 if (error != 0)
1278 goto bad1; 1399 goto detach;
1279 1400
1280 error = ath_rx_init(sc, ATH_RXBUF); 1401 error = ath_rx_init(sc, ATH_RXBUF);
1281 if (error != 0) 1402 if (error != 0)
1282 goto bad1; 1403 goto detach;
1283 1404
1284 return 0; 1405 return 0;
1285bad1: 1406detach:
1286 ath_detach(sc); 1407 ath_detach(sc);
1287bad: 1408bad:
1288 return error; 1409 return error;
@@ -1427,6 +1548,10 @@ static void ath_pci_remove(struct pci_dev *pdev)
1427 1548
1428static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state) 1549static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state)
1429{ 1550{
1551 struct ieee80211_hw *hw = pci_get_drvdata(pdev);
1552 struct ath_softc *sc = hw->priv;
1553
1554 ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
1430 pci_save_state(pdev); 1555 pci_save_state(pdev);
1431 pci_disable_device(pdev); 1556 pci_disable_device(pdev);
1432 pci_set_power_state(pdev, 3); 1557 pci_set_power_state(pdev, 3);
@@ -1436,6 +1561,8 @@ static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state)
1436 1561
1437static int ath_pci_resume(struct pci_dev *pdev) 1562static int ath_pci_resume(struct pci_dev *pdev)
1438{ 1563{
1564 struct ieee80211_hw *hw = pci_get_drvdata(pdev);
1565 struct ath_softc *sc = hw->priv;
1439 u32 val; 1566 u32 val;
1440 int err; 1567 int err;
1441 1568
@@ -1452,6 +1579,11 @@ static int ath_pci_resume(struct pci_dev *pdev)
1452 if ((val & 0x0000ff00) != 0) 1579 if ((val & 0x0000ff00) != 0)
1453 pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); 1580 pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
1454 1581
1582 /* Enable LED */
1583 ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN,
1584 AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
1585 ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
1586
1455 return 0; 1587 return 0;
1456} 1588}
1457 1589
diff --git a/drivers/net/wireless/ath9k/reg.h b/drivers/net/wireless/ath9k/reg.h
index 42b0890a4685..60617ae66209 100644
--- a/drivers/net/wireless/ath9k/reg.h
+++ b/drivers/net/wireless/ath9k/reg.h
@@ -899,12 +899,6 @@ enum {
899#define AR_GPIO_OUTPUT_MUX2 0x4064 899#define AR_GPIO_OUTPUT_MUX2 0x4064
900#define AR_GPIO_OUTPUT_MUX3 0x4068 900#define AR_GPIO_OUTPUT_MUX3 0x4068
901 901
902#define AR_GPIO_OUTPUT_MUX_AS_OUTPUT 0
903#define AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED 1
904#define AR_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED 2
905#define AR_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED 5
906#define AR_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED 6
907
908#define AR_INPUT_STATE 0x406c 902#define AR_INPUT_STATE 0x406c
909 903
910#define AR_EEPROM_STATUS_DATA 0x407c 904#define AR_EEPROM_STATUS_DATA 0x407c