diff options
author | John Li <chen-yang.li@mediatek.com> | 2012-02-16 08:40:57 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2012-02-27 14:05:44 -0500 |
commit | 2e9c43dd45ced5bd77c94d4216f96b4a49448d73 (patch) | |
tree | 6c6a219ab04d652197fef2f8ae5538571ed1782a /drivers/net | |
parent | 9da27232060411e98c27a8407610c794acb08c8b (diff) |
rt2x00:Add VCO recalibration
Signed-off-by: John Li <chen-yang.li@mediatek.com>
Acked-by: Gertjan van Wingerde <gwingerde@gmail.com>
Acked-by: Ivo van Doorn <IvDoorn@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2800.h | 9 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2800lib.c | 88 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2800lib.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2800pci.c | 1 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2800usb.c | 1 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00.h | 12 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00config.c | 3 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00dev.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00lib.h | 13 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00link.c | 39 |
10 files changed, 171 insertions, 0 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h index 06acabd02984..62e697ffc6d1 100644 --- a/drivers/net/wireless/rt2x00/rt2800.h +++ b/drivers/net/wireless/rt2x00/rt2800.h | |||
@@ -965,6 +965,7 @@ | |||
965 | * TX_PIN_CFG: | 965 | * TX_PIN_CFG: |
966 | */ | 966 | */ |
967 | #define TX_PIN_CFG 0x1328 | 967 | #define TX_PIN_CFG 0x1328 |
968 | #define TX_PIN_CFG_PA_PE_DISABLE 0xfcfffff0 | ||
968 | #define TX_PIN_CFG_PA_PE_A0_EN FIELD32(0x00000001) | 969 | #define TX_PIN_CFG_PA_PE_A0_EN FIELD32(0x00000001) |
969 | #define TX_PIN_CFG_PA_PE_G0_EN FIELD32(0x00000002) | 970 | #define TX_PIN_CFG_PA_PE_G0_EN FIELD32(0x00000002) |
970 | #define TX_PIN_CFG_PA_PE_A1_EN FIELD32(0x00000004) | 971 | #define TX_PIN_CFG_PA_PE_A1_EN FIELD32(0x00000004) |
@@ -985,6 +986,14 @@ | |||
985 | #define TX_PIN_CFG_RFTR_POL FIELD32(0x00020000) | 986 | #define TX_PIN_CFG_RFTR_POL FIELD32(0x00020000) |
986 | #define TX_PIN_CFG_TRSW_EN FIELD32(0x00040000) | 987 | #define TX_PIN_CFG_TRSW_EN FIELD32(0x00040000) |
987 | #define TX_PIN_CFG_TRSW_POL FIELD32(0x00080000) | 988 | #define TX_PIN_CFG_TRSW_POL FIELD32(0x00080000) |
989 | #define TX_PIN_CFG_PA_PE_A2_EN FIELD32(0x01000000) | ||
990 | #define TX_PIN_CFG_PA_PE_G2_EN FIELD32(0x02000000) | ||
991 | #define TX_PIN_CFG_PA_PE_A2_POL FIELD32(0x04000000) | ||
992 | #define TX_PIN_CFG_PA_PE_G2_POL FIELD32(0x08000000) | ||
993 | #define TX_PIN_CFG_LNA_PE_A2_EN FIELD32(0x10000000) | ||
994 | #define TX_PIN_CFG_LNA_PE_G2_EN FIELD32(0x20000000) | ||
995 | #define TX_PIN_CFG_LNA_PE_A2_POL FIELD32(0x40000000) | ||
996 | #define TX_PIN_CFG_LNA_PE_G2_POL FIELD32(0x80000000) | ||
988 | 997 | ||
989 | /* | 998 | /* |
990 | * TX_BAND_CFG: 0x1 use upper 20MHz, 0x0 use lower 20MHz | 999 | * TX_BAND_CFG: 0x1 use upper 20MHz, 0x0 use lower 20MHz |
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index f1df929e97a7..6104a14e4fff 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c | |||
@@ -2497,6 +2497,80 @@ void rt2800_gain_calibration(struct rt2x00_dev *rt2x00dev) | |||
2497 | } | 2497 | } |
2498 | EXPORT_SYMBOL_GPL(rt2800_gain_calibration); | 2498 | EXPORT_SYMBOL_GPL(rt2800_gain_calibration); |
2499 | 2499 | ||
2500 | void rt2800_vco_calibration(struct rt2x00_dev *rt2x00dev) | ||
2501 | { | ||
2502 | u32 tx_pin; | ||
2503 | u8 rfcsr; | ||
2504 | |||
2505 | /* | ||
2506 | * A voltage-controlled oscillator(VCO) is an electronic oscillator | ||
2507 | * designed to be controlled in oscillation frequency by a voltage | ||
2508 | * input. Maybe the temperature will affect the frequency of | ||
2509 | * oscillation to be shifted. The VCO calibration will be called | ||
2510 | * periodically to adjust the frequency to be precision. | ||
2511 | */ | ||
2512 | |||
2513 | rt2800_register_read(rt2x00dev, TX_PIN_CFG, &tx_pin); | ||
2514 | tx_pin &= TX_PIN_CFG_PA_PE_DISABLE; | ||
2515 | rt2800_register_write(rt2x00dev, TX_PIN_CFG, tx_pin); | ||
2516 | |||
2517 | switch (rt2x00dev->chip.rf) { | ||
2518 | case RF2020: | ||
2519 | case RF3020: | ||
2520 | case RF3021: | ||
2521 | case RF3022: | ||
2522 | case RF3320: | ||
2523 | case RF3052: | ||
2524 | rt2800_rfcsr_read(rt2x00dev, 7, &rfcsr); | ||
2525 | rt2x00_set_field8(&rfcsr, RFCSR7_RF_TUNING, 1); | ||
2526 | rt2800_rfcsr_write(rt2x00dev, 7, rfcsr); | ||
2527 | break; | ||
2528 | case RF5370: | ||
2529 | case RF5372: | ||
2530 | case RF5390: | ||
2531 | rt2800_rfcsr_read(rt2x00dev, 3, &rfcsr); | ||
2532 | rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 1); | ||
2533 | rt2800_rfcsr_write(rt2x00dev, 3, rfcsr); | ||
2534 | break; | ||
2535 | default: | ||
2536 | return; | ||
2537 | } | ||
2538 | |||
2539 | mdelay(1); | ||
2540 | |||
2541 | rt2800_register_read(rt2x00dev, TX_PIN_CFG, &tx_pin); | ||
2542 | if (rt2x00dev->rf_channel <= 14) { | ||
2543 | switch (rt2x00dev->default_ant.tx_chain_num) { | ||
2544 | case 3: | ||
2545 | rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G2_EN, 1); | ||
2546 | /* fall through */ | ||
2547 | case 2: | ||
2548 | rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G1_EN, 1); | ||
2549 | /* fall through */ | ||
2550 | case 1: | ||
2551 | default: | ||
2552 | rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G0_EN, 1); | ||
2553 | break; | ||
2554 | } | ||
2555 | } else { | ||
2556 | switch (rt2x00dev->default_ant.tx_chain_num) { | ||
2557 | case 3: | ||
2558 | rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_A2_EN, 1); | ||
2559 | /* fall through */ | ||
2560 | case 2: | ||
2561 | rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_A1_EN, 1); | ||
2562 | /* fall through */ | ||
2563 | case 1: | ||
2564 | default: | ||
2565 | rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_A0_EN, 1); | ||
2566 | break; | ||
2567 | } | ||
2568 | } | ||
2569 | rt2800_register_write(rt2x00dev, TX_PIN_CFG, tx_pin); | ||
2570 | |||
2571 | } | ||
2572 | EXPORT_SYMBOL_GPL(rt2800_vco_calibration); | ||
2573 | |||
2500 | static void rt2800_config_retry_limit(struct rt2x00_dev *rt2x00dev, | 2574 | static void rt2800_config_retry_limit(struct rt2x00_dev *rt2x00dev, |
2501 | struct rt2x00lib_conf *libconf) | 2575 | struct rt2x00lib_conf *libconf) |
2502 | { | 2576 | { |
@@ -4451,6 +4525,20 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) | |||
4451 | } | 4525 | } |
4452 | } | 4526 | } |
4453 | 4527 | ||
4528 | switch (rt2x00dev->chip.rf) { | ||
4529 | case RF2020: | ||
4530 | case RF3020: | ||
4531 | case RF3021: | ||
4532 | case RF3022: | ||
4533 | case RF3320: | ||
4534 | case RF3052: | ||
4535 | case RF5370: | ||
4536 | case RF5372: | ||
4537 | case RF5390: | ||
4538 | __set_bit(CAPABILITY_VCO_RECALIBRATION, &rt2x00dev->cap_flags); | ||
4539 | break; | ||
4540 | } | ||
4541 | |||
4454 | return 0; | 4542 | return 0; |
4455 | } | 4543 | } |
4456 | EXPORT_SYMBOL_GPL(rt2800_probe_hw_mode); | 4544 | EXPORT_SYMBOL_GPL(rt2800_probe_hw_mode); |
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h index 8c3c281904fe..419e36cb06be 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.h +++ b/drivers/net/wireless/rt2x00/rt2800lib.h | |||
@@ -184,6 +184,7 @@ void rt2800_reset_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual); | |||
184 | void rt2800_link_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual, | 184 | void rt2800_link_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual, |
185 | const u32 count); | 185 | const u32 count); |
186 | void rt2800_gain_calibration(struct rt2x00_dev *rt2x00dev); | 186 | void rt2800_gain_calibration(struct rt2x00_dev *rt2x00dev); |
187 | void rt2800_vco_calibration(struct rt2x00_dev *rt2x00dev); | ||
187 | 188 | ||
188 | int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev); | 189 | int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev); |
189 | void rt2800_disable_radio(struct rt2x00_dev *rt2x00dev); | 190 | void rt2800_disable_radio(struct rt2x00_dev *rt2x00dev); |
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 6ad692914ee9..fc9acc299b10 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c | |||
@@ -1050,6 +1050,7 @@ static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = { | |||
1050 | .reset_tuner = rt2800_reset_tuner, | 1050 | .reset_tuner = rt2800_reset_tuner, |
1051 | .link_tuner = rt2800_link_tuner, | 1051 | .link_tuner = rt2800_link_tuner, |
1052 | .gain_calibration = rt2800_gain_calibration, | 1052 | .gain_calibration = rt2800_gain_calibration, |
1053 | .vco_calibration = rt2800_vco_calibration, | ||
1053 | .start_queue = rt2800pci_start_queue, | 1054 | .start_queue = rt2800pci_start_queue, |
1054 | .kick_queue = rt2800pci_kick_queue, | 1055 | .kick_queue = rt2800pci_kick_queue, |
1055 | .stop_queue = rt2800pci_stop_queue, | 1056 | .stop_queue = rt2800pci_stop_queue, |
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 0074c4e18d29..f997f0056d7f 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c | |||
@@ -781,6 +781,7 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = { | |||
781 | .reset_tuner = rt2800_reset_tuner, | 781 | .reset_tuner = rt2800_reset_tuner, |
782 | .link_tuner = rt2800_link_tuner, | 782 | .link_tuner = rt2800_link_tuner, |
783 | .gain_calibration = rt2800_gain_calibration, | 783 | .gain_calibration = rt2800_gain_calibration, |
784 | .vco_calibration = rt2800_vco_calibration, | ||
784 | .watchdog = rt2800usb_watchdog, | 785 | .watchdog = rt2800usb_watchdog, |
785 | .start_queue = rt2800usb_start_queue, | 786 | .start_queue = rt2800usb_start_queue, |
786 | .kick_queue = rt2x00usb_kick_queue, | 787 | .kick_queue = rt2x00usb_kick_queue, |
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index ed2ae6efcaa3..1906a94e448f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h | |||
@@ -355,6 +355,11 @@ struct link { | |||
355 | * Work structure for scheduling periodic AGC adjustments. | 355 | * Work structure for scheduling periodic AGC adjustments. |
356 | */ | 356 | */ |
357 | struct delayed_work agc_work; | 357 | struct delayed_work agc_work; |
358 | |||
359 | /* | ||
360 | * Work structure for scheduling periodic VCO calibration. | ||
361 | */ | ||
362 | struct delayed_work vco_work; | ||
358 | }; | 363 | }; |
359 | 364 | ||
360 | enum rt2x00_delayed_flags { | 365 | enum rt2x00_delayed_flags { |
@@ -579,6 +584,7 @@ struct rt2x00lib_ops { | |||
579 | void (*link_tuner) (struct rt2x00_dev *rt2x00dev, | 584 | void (*link_tuner) (struct rt2x00_dev *rt2x00dev, |
580 | struct link_qual *qual, const u32 count); | 585 | struct link_qual *qual, const u32 count); |
581 | void (*gain_calibration) (struct rt2x00_dev *rt2x00dev); | 586 | void (*gain_calibration) (struct rt2x00_dev *rt2x00dev); |
587 | void (*vco_calibration) (struct rt2x00_dev *rt2x00dev); | ||
582 | 588 | ||
583 | /* | 589 | /* |
584 | * Data queue handlers. | 590 | * Data queue handlers. |
@@ -722,6 +728,7 @@ enum rt2x00_capability_flags { | |||
722 | CAPABILITY_EXTERNAL_LNA_BG, | 728 | CAPABILITY_EXTERNAL_LNA_BG, |
723 | CAPABILITY_DOUBLE_ANTENNA, | 729 | CAPABILITY_DOUBLE_ANTENNA, |
724 | CAPABILITY_BT_COEXIST, | 730 | CAPABILITY_BT_COEXIST, |
731 | CAPABILITY_VCO_RECALIBRATION, | ||
725 | }; | 732 | }; |
726 | 733 | ||
727 | /* | 734 | /* |
@@ -978,6 +985,11 @@ struct rt2x00_dev { | |||
978 | struct tasklet_struct autowake_tasklet; | 985 | struct tasklet_struct autowake_tasklet; |
979 | 986 | ||
980 | /* | 987 | /* |
988 | * Used for VCO periodic calibration. | ||
989 | */ | ||
990 | int rf_channel; | ||
991 | |||
992 | /* | ||
981 | * Protect the interrupt mask register. | 993 | * Protect the interrupt mask register. |
982 | */ | 994 | */ |
983 | spinlock_t irqmask_lock; | 995 | spinlock_t irqmask_lock; |
diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index b704e5b183d0..d7c0f86c9e43 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c | |||
@@ -232,6 +232,9 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, | |||
232 | memcpy(&libconf.channel, | 232 | memcpy(&libconf.channel, |
233 | &rt2x00dev->spec.channels_info[hw_value], | 233 | &rt2x00dev->spec.channels_info[hw_value], |
234 | sizeof(libconf.channel)); | 234 | sizeof(libconf.channel)); |
235 | |||
236 | /* Used for VCO periodic calibration */ | ||
237 | rt2x00dev->rf_channel = libconf.rf.channel; | ||
235 | } | 238 | } |
236 | 239 | ||
237 | if (test_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags) && | 240 | if (test_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags) && |
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index bae5b01299ea..dfe485a872f6 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c | |||
@@ -88,6 +88,8 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev) | |||
88 | rt2x00queue_start_queues(rt2x00dev); | 88 | rt2x00queue_start_queues(rt2x00dev); |
89 | rt2x00link_start_tuner(rt2x00dev); | 89 | rt2x00link_start_tuner(rt2x00dev); |
90 | rt2x00link_start_agc(rt2x00dev); | 90 | rt2x00link_start_agc(rt2x00dev); |
91 | if (test_bit(CAPABILITY_VCO_RECALIBRATION, &rt2x00dev->cap_flags)) | ||
92 | rt2x00link_start_vcocal(rt2x00dev); | ||
91 | 93 | ||
92 | /* | 94 | /* |
93 | * Start watchdog monitoring. | 95 | * Start watchdog monitoring. |
@@ -111,6 +113,8 @@ void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev) | |||
111 | * Stop all queues | 113 | * Stop all queues |
112 | */ | 114 | */ |
113 | rt2x00link_stop_agc(rt2x00dev); | 115 | rt2x00link_stop_agc(rt2x00dev); |
116 | if (test_bit(CAPABILITY_VCO_RECALIBRATION, &rt2x00dev->cap_flags)) | ||
117 | rt2x00link_stop_vcocal(rt2x00dev); | ||
114 | rt2x00link_stop_tuner(rt2x00dev); | 118 | rt2x00link_stop_tuner(rt2x00dev); |
115 | rt2x00queue_stop_queues(rt2x00dev); | 119 | rt2x00queue_stop_queues(rt2x00dev); |
116 | rt2x00queue_flush_queues(rt2x00dev, true); | 120 | rt2x00queue_flush_queues(rt2x00dev, true); |
diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index 4cdf247a870d..78bd43b8961f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h | |||
@@ -33,6 +33,7 @@ | |||
33 | #define WATCHDOG_INTERVAL round_jiffies_relative(HZ) | 33 | #define WATCHDOG_INTERVAL round_jiffies_relative(HZ) |
34 | #define LINK_TUNE_INTERVAL round_jiffies_relative(HZ) | 34 | #define LINK_TUNE_INTERVAL round_jiffies_relative(HZ) |
35 | #define AGC_INTERVAL round_jiffies_relative(4 * HZ) | 35 | #define AGC_INTERVAL round_jiffies_relative(4 * HZ) |
36 | #define VCO_INTERVAL round_jiffies_relative(10 * HZ) /* 10 sec */ | ||
36 | 37 | ||
37 | /* | 38 | /* |
38 | * rt2x00_rate: Per rate device information | 39 | * rt2x00_rate: Per rate device information |
@@ -278,12 +279,24 @@ void rt2x00link_stop_watchdog(struct rt2x00_dev *rt2x00dev); | |||
278 | void rt2x00link_start_agc(struct rt2x00_dev *rt2x00dev); | 279 | void rt2x00link_start_agc(struct rt2x00_dev *rt2x00dev); |
279 | 280 | ||
280 | /** | 281 | /** |
282 | * rt2x00link_start_vcocal - Start periodic VCO calibration | ||
283 | * @rt2x00dev: Pointer to &struct rt2x00_dev. | ||
284 | */ | ||
285 | void rt2x00link_start_vcocal(struct rt2x00_dev *rt2x00dev); | ||
286 | |||
287 | /** | ||
281 | * rt2x00link_stop_agc - Stop periodic gain calibration | 288 | * rt2x00link_stop_agc - Stop periodic gain calibration |
282 | * @rt2x00dev: Pointer to &struct rt2x00_dev. | 289 | * @rt2x00dev: Pointer to &struct rt2x00_dev. |
283 | */ | 290 | */ |
284 | void rt2x00link_stop_agc(struct rt2x00_dev *rt2x00dev); | 291 | void rt2x00link_stop_agc(struct rt2x00_dev *rt2x00dev); |
285 | 292 | ||
286 | /** | 293 | /** |
294 | * rt2x00link_stop_vcocal - Stop periodic VCO calibration | ||
295 | * @rt2x00dev: Pointer to &struct rt2x00_dev. | ||
296 | */ | ||
297 | void rt2x00link_stop_vcocal(struct rt2x00_dev *rt2x00dev); | ||
298 | |||
299 | /** | ||
287 | * rt2x00link_register - Initialize link tuning & watchdog functionality | 300 | * rt2x00link_register - Initialize link tuning & watchdog functionality |
288 | * @rt2x00dev: Pointer to &struct rt2x00_dev. | 301 | * @rt2x00dev: Pointer to &struct rt2x00_dev. |
289 | * | 302 | * |
diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c index ea10b0068f82..8368aab86f28 100644 --- a/drivers/net/wireless/rt2x00/rt2x00link.c +++ b/drivers/net/wireless/rt2x00/rt2x00link.c | |||
@@ -447,11 +447,27 @@ void rt2x00link_start_agc(struct rt2x00_dev *rt2x00dev) | |||
447 | AGC_INTERVAL); | 447 | AGC_INTERVAL); |
448 | } | 448 | } |
449 | 449 | ||
450 | void rt2x00link_start_vcocal(struct rt2x00_dev *rt2x00dev) | ||
451 | { | ||
452 | struct link *link = &rt2x00dev->link; | ||
453 | |||
454 | if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) && | ||
455 | rt2x00dev->ops->lib->vco_calibration) | ||
456 | ieee80211_queue_delayed_work(rt2x00dev->hw, | ||
457 | &link->vco_work, | ||
458 | VCO_INTERVAL); | ||
459 | } | ||
460 | |||
450 | void rt2x00link_stop_agc(struct rt2x00_dev *rt2x00dev) | 461 | void rt2x00link_stop_agc(struct rt2x00_dev *rt2x00dev) |
451 | { | 462 | { |
452 | cancel_delayed_work_sync(&rt2x00dev->link.agc_work); | 463 | cancel_delayed_work_sync(&rt2x00dev->link.agc_work); |
453 | } | 464 | } |
454 | 465 | ||
466 | void rt2x00link_stop_vcocal(struct rt2x00_dev *rt2x00dev) | ||
467 | { | ||
468 | cancel_delayed_work_sync(&rt2x00dev->link.vco_work); | ||
469 | } | ||
470 | |||
455 | static void rt2x00link_agc(struct work_struct *work) | 471 | static void rt2x00link_agc(struct work_struct *work) |
456 | { | 472 | { |
457 | struct rt2x00_dev *rt2x00dev = | 473 | struct rt2x00_dev *rt2x00dev = |
@@ -473,9 +489,32 @@ static void rt2x00link_agc(struct work_struct *work) | |||
473 | AGC_INTERVAL); | 489 | AGC_INTERVAL); |
474 | } | 490 | } |
475 | 491 | ||
492 | static void rt2x00link_vcocal(struct work_struct *work) | ||
493 | { | ||
494 | struct rt2x00_dev *rt2x00dev = | ||
495 | container_of(work, struct rt2x00_dev, link.vco_work.work); | ||
496 | struct link *link = &rt2x00dev->link; | ||
497 | |||
498 | /* | ||
499 | * When the radio is shutting down we should | ||
500 | * immediately cease the VCO calibration. | ||
501 | */ | ||
502 | if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) | ||
503 | return; | ||
504 | |||
505 | rt2x00dev->ops->lib->vco_calibration(rt2x00dev); | ||
506 | |||
507 | if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) | ||
508 | ieee80211_queue_delayed_work(rt2x00dev->hw, | ||
509 | &link->vco_work, | ||
510 | VCO_INTERVAL); | ||
511 | } | ||
512 | |||
476 | void rt2x00link_register(struct rt2x00_dev *rt2x00dev) | 513 | void rt2x00link_register(struct rt2x00_dev *rt2x00dev) |
477 | { | 514 | { |
478 | INIT_DELAYED_WORK(&rt2x00dev->link.agc_work, rt2x00link_agc); | 515 | INIT_DELAYED_WORK(&rt2x00dev->link.agc_work, rt2x00link_agc); |
516 | if (test_bit(CAPABILITY_VCO_RECALIBRATION, &rt2x00dev->cap_flags)) | ||
517 | INIT_DELAYED_WORK(&rt2x00dev->link.vco_work, rt2x00link_vcocal); | ||
479 | INIT_DELAYED_WORK(&rt2x00dev->link.watchdog_work, rt2x00link_watchdog); | 518 | INIT_DELAYED_WORK(&rt2x00dev->link.watchdog_work, rt2x00link_watchdog); |
480 | INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00link_tuner); | 519 | INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00link_tuner); |
481 | } | 520 | } |