diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/pci.c')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/pci.c | 97 |
1 files changed, 66 insertions, 31 deletions
diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index b5b651413e77..7ca8499249ec 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c | |||
@@ -16,6 +16,7 @@ | |||
16 | 16 | ||
17 | #include <linux/nl80211.h> | 17 | #include <linux/nl80211.h> |
18 | #include <linux/pci.h> | 18 | #include <linux/pci.h> |
19 | #include <linux/ath9k_platform.h> | ||
19 | #include "ath9k.h" | 20 | #include "ath9k.h" |
20 | 21 | ||
21 | static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = { | 22 | static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = { |
@@ -29,6 +30,7 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = { | |||
29 | { PCI_VDEVICE(ATHEROS, 0x002D) }, /* PCI */ | 30 | { PCI_VDEVICE(ATHEROS, 0x002D) }, /* PCI */ |
30 | { PCI_VDEVICE(ATHEROS, 0x002E) }, /* PCI-E */ | 31 | { PCI_VDEVICE(ATHEROS, 0x002E) }, /* PCI-E */ |
31 | { PCI_VDEVICE(ATHEROS, 0x0030) }, /* PCI-E AR9300 */ | 32 | { PCI_VDEVICE(ATHEROS, 0x0030) }, /* PCI-E AR9300 */ |
33 | { PCI_VDEVICE(ATHEROS, 0x0032) }, /* PCI-E AR9485 */ | ||
32 | { 0 } | 34 | { 0 } |
33 | }; | 35 | }; |
34 | 36 | ||
@@ -53,21 +55,35 @@ static void ath_pci_read_cachesize(struct ath_common *common, int *csz) | |||
53 | 55 | ||
54 | static bool ath_pci_eeprom_read(struct ath_common *common, u32 off, u16 *data) | 56 | static bool ath_pci_eeprom_read(struct ath_common *common, u32 off, u16 *data) |
55 | { | 57 | { |
56 | struct ath_hw *ah = (struct ath_hw *) common->ah; | 58 | struct ath_softc *sc = (struct ath_softc *) common->priv; |
57 | 59 | struct ath9k_platform_data *pdata = sc->dev->platform_data; | |
58 | common->ops->read(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S)); | 60 | |
59 | 61 | if (pdata) { | |
60 | if (!ath9k_hw_wait(ah, | 62 | if (off >= (ARRAY_SIZE(pdata->eeprom_data))) { |
61 | AR_EEPROM_STATUS_DATA, | 63 | ath_err(common, |
62 | AR_EEPROM_STATUS_DATA_BUSY | | 64 | "%s: eeprom read failed, offset %08x is out of range\n", |
63 | AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0, | 65 | __func__, off); |
64 | AH_WAIT_TIMEOUT)) { | 66 | } |
65 | return false; | 67 | |
68 | *data = pdata->eeprom_data[off]; | ||
69 | } else { | ||
70 | struct ath_hw *ah = (struct ath_hw *) common->ah; | ||
71 | |||
72 | common->ops->read(ah, AR5416_EEPROM_OFFSET + | ||
73 | (off << AR5416_EEPROM_S)); | ||
74 | |||
75 | if (!ath9k_hw_wait(ah, | ||
76 | AR_EEPROM_STATUS_DATA, | ||
77 | AR_EEPROM_STATUS_DATA_BUSY | | ||
78 | AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0, | ||
79 | AH_WAIT_TIMEOUT)) { | ||
80 | return false; | ||
81 | } | ||
82 | |||
83 | *data = MS(common->ops->read(ah, AR_EEPROM_STATUS_DATA), | ||
84 | AR_EEPROM_STATUS_DATA_VAL); | ||
66 | } | 85 | } |
67 | 86 | ||
68 | *data = MS(common->ops->read(ah, AR_EEPROM_STATUS_DATA), | ||
69 | AR_EEPROM_STATUS_DATA_VAL); | ||
70 | |||
71 | return true; | 87 | return true; |
72 | } | 88 | } |
73 | 89 | ||
@@ -88,11 +104,23 @@ static void ath_pci_bt_coex_prep(struct ath_common *common) | |||
88 | pci_write_config_byte(pdev, ATH_PCIE_CAP_LINK_CTRL, aspm); | 104 | pci_write_config_byte(pdev, ATH_PCIE_CAP_LINK_CTRL, aspm); |
89 | } | 105 | } |
90 | 106 | ||
107 | static void ath_pci_extn_synch_enable(struct ath_common *common) | ||
108 | { | ||
109 | struct ath_softc *sc = (struct ath_softc *) common->priv; | ||
110 | struct pci_dev *pdev = to_pci_dev(sc->dev); | ||
111 | u8 lnkctl; | ||
112 | |||
113 | pci_read_config_byte(pdev, sc->sc_ah->caps.pcie_lcr_offset, &lnkctl); | ||
114 | lnkctl |= PCI_EXP_LNKCTL_ES; | ||
115 | pci_write_config_byte(pdev, sc->sc_ah->caps.pcie_lcr_offset, lnkctl); | ||
116 | } | ||
117 | |||
91 | static const struct ath_bus_ops ath_pci_bus_ops = { | 118 | static const struct ath_bus_ops ath_pci_bus_ops = { |
92 | .ath_bus_type = ATH_PCI, | 119 | .ath_bus_type = ATH_PCI, |
93 | .read_cachesize = ath_pci_read_cachesize, | 120 | .read_cachesize = ath_pci_read_cachesize, |
94 | .eeprom_read = ath_pci_eeprom_read, | 121 | .eeprom_read = ath_pci_eeprom_read, |
95 | .bt_coex_prep = ath_pci_bt_coex_prep, | 122 | .bt_coex_prep = ath_pci_bt_coex_prep, |
123 | .extn_synch_en = ath_pci_extn_synch_enable, | ||
96 | }; | 124 | }; |
97 | 125 | ||
98 | static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) | 126 | static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) |
@@ -247,34 +275,25 @@ static void ath_pci_remove(struct pci_dev *pdev) | |||
247 | 275 | ||
248 | #ifdef CONFIG_PM | 276 | #ifdef CONFIG_PM |
249 | 277 | ||
250 | static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state) | 278 | static int ath_pci_suspend(struct device *device) |
251 | { | 279 | { |
280 | struct pci_dev *pdev = to_pci_dev(device); | ||
252 | struct ieee80211_hw *hw = pci_get_drvdata(pdev); | 281 | struct ieee80211_hw *hw = pci_get_drvdata(pdev); |
253 | struct ath_wiphy *aphy = hw->priv; | 282 | struct ath_wiphy *aphy = hw->priv; |
254 | struct ath_softc *sc = aphy->sc; | 283 | struct ath_softc *sc = aphy->sc; |
255 | 284 | ||
256 | ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); | 285 | ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); |
257 | 286 | ||
258 | pci_save_state(pdev); | ||
259 | pci_disable_device(pdev); | ||
260 | pci_set_power_state(pdev, PCI_D3hot); | ||
261 | |||
262 | return 0; | 287 | return 0; |
263 | } | 288 | } |
264 | 289 | ||
265 | static int ath_pci_resume(struct pci_dev *pdev) | 290 | static int ath_pci_resume(struct device *device) |
266 | { | 291 | { |
292 | struct pci_dev *pdev = to_pci_dev(device); | ||
267 | struct ieee80211_hw *hw = pci_get_drvdata(pdev); | 293 | struct ieee80211_hw *hw = pci_get_drvdata(pdev); |
268 | struct ath_wiphy *aphy = hw->priv; | 294 | struct ath_wiphy *aphy = hw->priv; |
269 | struct ath_softc *sc = aphy->sc; | 295 | struct ath_softc *sc = aphy->sc; |
270 | u32 val; | 296 | u32 val; |
271 | int err; | ||
272 | |||
273 | pci_restore_state(pdev); | ||
274 | |||
275 | err = pci_enable_device(pdev); | ||
276 | if (err) | ||
277 | return err; | ||
278 | 297 | ||
279 | /* | 298 | /* |
280 | * Suspend/Resume resets the PCI configuration space, so we have to | 299 | * Suspend/Resume resets the PCI configuration space, so we have to |
@@ -290,10 +309,29 @@ static int ath_pci_resume(struct pci_dev *pdev) | |||
290 | AR_GPIO_OUTPUT_MUX_AS_OUTPUT); | 309 | AR_GPIO_OUTPUT_MUX_AS_OUTPUT); |
291 | ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); | 310 | ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); |
292 | 311 | ||
312 | sc->ps_idle = true; | ||
313 | ath_radio_disable(sc, hw); | ||
314 | |||
293 | return 0; | 315 | return 0; |
294 | } | 316 | } |
295 | 317 | ||
296 | #endif /* CONFIG_PM */ | 318 | static const struct dev_pm_ops ath9k_pm_ops = { |
319 | .suspend = ath_pci_suspend, | ||
320 | .resume = ath_pci_resume, | ||
321 | .freeze = ath_pci_suspend, | ||
322 | .thaw = ath_pci_resume, | ||
323 | .poweroff = ath_pci_suspend, | ||
324 | .restore = ath_pci_resume, | ||
325 | }; | ||
326 | |||
327 | #define ATH9K_PM_OPS (&ath9k_pm_ops) | ||
328 | |||
329 | #else /* !CONFIG_PM */ | ||
330 | |||
331 | #define ATH9K_PM_OPS NULL | ||
332 | |||
333 | #endif /* !CONFIG_PM */ | ||
334 | |||
297 | 335 | ||
298 | MODULE_DEVICE_TABLE(pci, ath_pci_id_table); | 336 | MODULE_DEVICE_TABLE(pci, ath_pci_id_table); |
299 | 337 | ||
@@ -302,10 +340,7 @@ static struct pci_driver ath_pci_driver = { | |||
302 | .id_table = ath_pci_id_table, | 340 | .id_table = ath_pci_id_table, |
303 | .probe = ath_pci_probe, | 341 | .probe = ath_pci_probe, |
304 | .remove = ath_pci_remove, | 342 | .remove = ath_pci_remove, |
305 | #ifdef CONFIG_PM | 343 | .driver.pm = ATH9K_PM_OPS, |
306 | .suspend = ath_pci_suspend, | ||
307 | .resume = ath_pci_resume, | ||
308 | #endif /* CONFIG_PM */ | ||
309 | }; | 344 | }; |
310 | 345 | ||
311 | int ath_pci_init(void) | 346 | int ath_pci_init(void) |