diff options
author | Bartlomiej Zolnierkiewicz <bzolnier@gmail.com> | 2009-11-04 12:36:40 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-11-06 16:48:58 -0500 |
commit | f445061630c7a4a85193fdef006234f94f71c366 (patch) | |
tree | 518141ce242b2722e532318034525da282dc945b /drivers/net/wireless/rt2x00/rt2800lib.c | |
parent | 89297425c2104b187c25d6260a41345c491c8f18 (diff) |
rt2800: add rt2800lib (part two)
Code unification.
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Acked-by: Ivo van Doorn <IvDoorn@gmail.com>
Acked-by: Gertjan van Wingerde <gwingerde@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/rt2x00/rt2800lib.c')
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2800lib.c | 832 |
1 files changed, 832 insertions, 0 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 3cbe85434ce3..ba88d643edd3 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c | |||
@@ -242,3 +242,835 @@ void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev, | |||
242 | mutex_unlock(&rt2x00dev->csr_mutex); | 242 | mutex_unlock(&rt2x00dev->csr_mutex); |
243 | } | 243 | } |
244 | EXPORT_SYMBOL_GPL(rt2800_mcu_request); | 244 | EXPORT_SYMBOL_GPL(rt2800_mcu_request); |
245 | |||
246 | #ifdef CONFIG_RT2X00_LIB_DEBUGFS | ||
247 | const struct rt2x00debug rt2800_rt2x00debug = { | ||
248 | .owner = THIS_MODULE, | ||
249 | .csr = { | ||
250 | .read = rt2800_register_read, | ||
251 | .write = rt2800_register_write, | ||
252 | .flags = RT2X00DEBUGFS_OFFSET, | ||
253 | .word_base = CSR_REG_BASE, | ||
254 | .word_size = sizeof(u32), | ||
255 | .word_count = CSR_REG_SIZE / sizeof(u32), | ||
256 | }, | ||
257 | .eeprom = { | ||
258 | .read = rt2x00_eeprom_read, | ||
259 | .write = rt2x00_eeprom_write, | ||
260 | .word_base = EEPROM_BASE, | ||
261 | .word_size = sizeof(u16), | ||
262 | .word_count = EEPROM_SIZE / sizeof(u16), | ||
263 | }, | ||
264 | .bbp = { | ||
265 | .read = rt2800_bbp_read, | ||
266 | .write = rt2800_bbp_write, | ||
267 | .word_base = BBP_BASE, | ||
268 | .word_size = sizeof(u8), | ||
269 | .word_count = BBP_SIZE / sizeof(u8), | ||
270 | }, | ||
271 | .rf = { | ||
272 | .read = rt2x00_rf_read, | ||
273 | .write = rt2800_rf_write, | ||
274 | .word_base = RF_BASE, | ||
275 | .word_size = sizeof(u32), | ||
276 | .word_count = RF_SIZE / sizeof(u32), | ||
277 | }, | ||
278 | }; | ||
279 | EXPORT_SYMBOL_GPL(rt2800_rt2x00debug); | ||
280 | #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ | ||
281 | |||
282 | int rt2800_rfkill_poll(struct rt2x00_dev *rt2x00dev) | ||
283 | { | ||
284 | u32 reg; | ||
285 | |||
286 | rt2800_register_read(rt2x00dev, GPIO_CTRL_CFG, ®); | ||
287 | return rt2x00_get_field32(reg, GPIO_CTRL_CFG_BIT2); | ||
288 | } | ||
289 | EXPORT_SYMBOL_GPL(rt2800_rfkill_poll); | ||
290 | |||
291 | #ifdef CONFIG_RT2X00_LIB_LEDS | ||
292 | static void rt2800_brightness_set(struct led_classdev *led_cdev, | ||
293 | enum led_brightness brightness) | ||
294 | { | ||
295 | struct rt2x00_led *led = | ||
296 | container_of(led_cdev, struct rt2x00_led, led_dev); | ||
297 | unsigned int enabled = brightness != LED_OFF; | ||
298 | unsigned int bg_mode = | ||
299 | (enabled && led->rt2x00dev->curr_band == IEEE80211_BAND_2GHZ); | ||
300 | unsigned int polarity = | ||
301 | rt2x00_get_field16(led->rt2x00dev->led_mcu_reg, | ||
302 | EEPROM_FREQ_LED_POLARITY); | ||
303 | unsigned int ledmode = | ||
304 | rt2x00_get_field16(led->rt2x00dev->led_mcu_reg, | ||
305 | EEPROM_FREQ_LED_MODE); | ||
306 | |||
307 | if (led->type == LED_TYPE_RADIO) { | ||
308 | rt2800_mcu_request(led->rt2x00dev, MCU_LED, 0xff, ledmode, | ||
309 | enabled ? 0x20 : 0); | ||
310 | } else if (led->type == LED_TYPE_ASSOC) { | ||
311 | rt2800_mcu_request(led->rt2x00dev, MCU_LED, 0xff, ledmode, | ||
312 | enabled ? (bg_mode ? 0x60 : 0xa0) : 0x20); | ||
313 | } else if (led->type == LED_TYPE_QUALITY) { | ||
314 | /* | ||
315 | * The brightness is divided into 6 levels (0 - 5), | ||
316 | * The specs tell us the following levels: | ||
317 | * 0, 1 ,3, 7, 15, 31 | ||
318 | * to determine the level in a simple way we can simply | ||
319 | * work with bitshifting: | ||
320 | * (1 << level) - 1 | ||
321 | */ | ||
322 | rt2800_mcu_request(led->rt2x00dev, MCU_LED_STRENGTH, 0xff, | ||
323 | (1 << brightness / (LED_FULL / 6)) - 1, | ||
324 | polarity); | ||
325 | } | ||
326 | } | ||
327 | |||
328 | static int rt2800_blink_set(struct led_classdev *led_cdev, | ||
329 | unsigned long *delay_on, unsigned long *delay_off) | ||
330 | { | ||
331 | struct rt2x00_led *led = | ||
332 | container_of(led_cdev, struct rt2x00_led, led_dev); | ||
333 | u32 reg; | ||
334 | |||
335 | rt2800_register_read(led->rt2x00dev, LED_CFG, ®); | ||
336 | rt2x00_set_field32(®, LED_CFG_ON_PERIOD, *delay_on); | ||
337 | rt2x00_set_field32(®, LED_CFG_OFF_PERIOD, *delay_off); | ||
338 | rt2x00_set_field32(®, LED_CFG_SLOW_BLINK_PERIOD, 3); | ||
339 | rt2x00_set_field32(®, LED_CFG_R_LED_MODE, 3); | ||
340 | rt2x00_set_field32(®, LED_CFG_G_LED_MODE, 12); | ||
341 | rt2x00_set_field32(®, LED_CFG_Y_LED_MODE, 3); | ||
342 | rt2x00_set_field32(®, LED_CFG_LED_POLAR, 1); | ||
343 | rt2800_register_write(led->rt2x00dev, LED_CFG, reg); | ||
344 | |||
345 | return 0; | ||
346 | } | ||
347 | |||
348 | void rt2800_init_led(struct rt2x00_dev *rt2x00dev, | ||
349 | struct rt2x00_led *led, enum led_type type) | ||
350 | { | ||
351 | led->rt2x00dev = rt2x00dev; | ||
352 | led->type = type; | ||
353 | led->led_dev.brightness_set = rt2800_brightness_set; | ||
354 | led->led_dev.blink_set = rt2800_blink_set; | ||
355 | led->flags = LED_INITIALIZED; | ||
356 | } | ||
357 | EXPORT_SYMBOL_GPL(rt2800_init_led); | ||
358 | #endif /* CONFIG_RT2X00_LIB_LEDS */ | ||
359 | |||
360 | /* | ||
361 | * Configuration handlers. | ||
362 | */ | ||
363 | static void rt2800_config_wcid_attr(struct rt2x00_dev *rt2x00dev, | ||
364 | struct rt2x00lib_crypto *crypto, | ||
365 | struct ieee80211_key_conf *key) | ||
366 | { | ||
367 | struct mac_wcid_entry wcid_entry; | ||
368 | struct mac_iveiv_entry iveiv_entry; | ||
369 | u32 offset; | ||
370 | u32 reg; | ||
371 | |||
372 | offset = MAC_WCID_ATTR_ENTRY(key->hw_key_idx); | ||
373 | |||
374 | rt2800_register_read(rt2x00dev, offset, ®); | ||
375 | rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_KEYTAB, | ||
376 | !!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)); | ||
377 | rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_CIPHER, | ||
378 | (crypto->cmd == SET_KEY) * crypto->cipher); | ||
379 | rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_BSS_IDX, | ||
380 | (crypto->cmd == SET_KEY) * crypto->bssidx); | ||
381 | rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_RX_WIUDF, crypto->cipher); | ||
382 | rt2800_register_write(rt2x00dev, offset, reg); | ||
383 | |||
384 | offset = MAC_IVEIV_ENTRY(key->hw_key_idx); | ||
385 | |||
386 | memset(&iveiv_entry, 0, sizeof(iveiv_entry)); | ||
387 | if ((crypto->cipher == CIPHER_TKIP) || | ||
388 | (crypto->cipher == CIPHER_TKIP_NO_MIC) || | ||
389 | (crypto->cipher == CIPHER_AES)) | ||
390 | iveiv_entry.iv[3] |= 0x20; | ||
391 | iveiv_entry.iv[3] |= key->keyidx << 6; | ||
392 | rt2800_register_multiwrite(rt2x00dev, offset, | ||
393 | &iveiv_entry, sizeof(iveiv_entry)); | ||
394 | |||
395 | offset = MAC_WCID_ENTRY(key->hw_key_idx); | ||
396 | |||
397 | memset(&wcid_entry, 0, sizeof(wcid_entry)); | ||
398 | if (crypto->cmd == SET_KEY) | ||
399 | memcpy(&wcid_entry, crypto->address, ETH_ALEN); | ||
400 | rt2800_register_multiwrite(rt2x00dev, offset, | ||
401 | &wcid_entry, sizeof(wcid_entry)); | ||
402 | } | ||
403 | |||
404 | int rt2800_config_shared_key(struct rt2x00_dev *rt2x00dev, | ||
405 | struct rt2x00lib_crypto *crypto, | ||
406 | struct ieee80211_key_conf *key) | ||
407 | { | ||
408 | struct hw_key_entry key_entry; | ||
409 | struct rt2x00_field32 field; | ||
410 | u32 offset; | ||
411 | u32 reg; | ||
412 | |||
413 | if (crypto->cmd == SET_KEY) { | ||
414 | key->hw_key_idx = (4 * crypto->bssidx) + key->keyidx; | ||
415 | |||
416 | memcpy(key_entry.key, crypto->key, | ||
417 | sizeof(key_entry.key)); | ||
418 | memcpy(key_entry.tx_mic, crypto->tx_mic, | ||
419 | sizeof(key_entry.tx_mic)); | ||
420 | memcpy(key_entry.rx_mic, crypto->rx_mic, | ||
421 | sizeof(key_entry.rx_mic)); | ||
422 | |||
423 | offset = SHARED_KEY_ENTRY(key->hw_key_idx); | ||
424 | rt2800_register_multiwrite(rt2x00dev, offset, | ||
425 | &key_entry, sizeof(key_entry)); | ||
426 | } | ||
427 | |||
428 | /* | ||
429 | * The cipher types are stored over multiple registers | ||
430 | * starting with SHARED_KEY_MODE_BASE each word will have | ||
431 | * 32 bits and contains the cipher types for 2 bssidx each. | ||
432 | * Using the correct defines correctly will cause overhead, | ||
433 | * so just calculate the correct offset. | ||
434 | */ | ||
435 | field.bit_offset = 4 * (key->hw_key_idx % 8); | ||
436 | field.bit_mask = 0x7 << field.bit_offset; | ||
437 | |||
438 | offset = SHARED_KEY_MODE_ENTRY(key->hw_key_idx / 8); | ||
439 | |||
440 | rt2800_register_read(rt2x00dev, offset, ®); | ||
441 | rt2x00_set_field32(®, field, | ||
442 | (crypto->cmd == SET_KEY) * crypto->cipher); | ||
443 | rt2800_register_write(rt2x00dev, offset, reg); | ||
444 | |||
445 | /* | ||
446 | * Update WCID information | ||
447 | */ | ||
448 | rt2800_config_wcid_attr(rt2x00dev, crypto, key); | ||
449 | |||
450 | return 0; | ||
451 | } | ||
452 | EXPORT_SYMBOL_GPL(rt2800_config_shared_key); | ||
453 | |||
454 | int rt2800_config_pairwise_key(struct rt2x00_dev *rt2x00dev, | ||
455 | struct rt2x00lib_crypto *crypto, | ||
456 | struct ieee80211_key_conf *key) | ||
457 | { | ||
458 | struct hw_key_entry key_entry; | ||
459 | u32 offset; | ||
460 | |||
461 | if (crypto->cmd == SET_KEY) { | ||
462 | /* | ||
463 | * 1 pairwise key is possible per AID, this means that the AID | ||
464 | * equals our hw_key_idx. Make sure the WCID starts _after_ the | ||
465 | * last possible shared key entry. | ||
466 | */ | ||
467 | if (crypto->aid > (256 - 32)) | ||
468 | return -ENOSPC; | ||
469 | |||
470 | key->hw_key_idx = 32 + crypto->aid; | ||
471 | |||
472 | memcpy(key_entry.key, crypto->key, | ||
473 | sizeof(key_entry.key)); | ||
474 | memcpy(key_entry.tx_mic, crypto->tx_mic, | ||
475 | sizeof(key_entry.tx_mic)); | ||
476 | memcpy(key_entry.rx_mic, crypto->rx_mic, | ||
477 | sizeof(key_entry.rx_mic)); | ||
478 | |||
479 | offset = PAIRWISE_KEY_ENTRY(key->hw_key_idx); | ||
480 | rt2800_register_multiwrite(rt2x00dev, offset, | ||
481 | &key_entry, sizeof(key_entry)); | ||
482 | } | ||
483 | |||
484 | /* | ||
485 | * Update WCID information | ||
486 | */ | ||
487 | rt2800_config_wcid_attr(rt2x00dev, crypto, key); | ||
488 | |||
489 | return 0; | ||
490 | } | ||
491 | EXPORT_SYMBOL_GPL(rt2800_config_pairwise_key); | ||
492 | |||
493 | void rt2800_config_filter(struct rt2x00_dev *rt2x00dev, | ||
494 | const unsigned int filter_flags) | ||
495 | { | ||
496 | u32 reg; | ||
497 | |||
498 | /* | ||
499 | * Start configuration steps. | ||
500 | * Note that the version error will always be dropped | ||
501 | * and broadcast frames will always be accepted since | ||
502 | * there is no filter for it at this time. | ||
503 | */ | ||
504 | rt2800_register_read(rt2x00dev, RX_FILTER_CFG, ®); | ||
505 | rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CRC_ERROR, | ||
506 | !(filter_flags & FIF_FCSFAIL)); | ||
507 | rt2x00_set_field32(®, RX_FILTER_CFG_DROP_PHY_ERROR, | ||
508 | !(filter_flags & FIF_PLCPFAIL)); | ||
509 | rt2x00_set_field32(®, RX_FILTER_CFG_DROP_NOT_TO_ME, | ||
510 | !(filter_flags & FIF_PROMISC_IN_BSS)); | ||
511 | rt2x00_set_field32(®, RX_FILTER_CFG_DROP_NOT_MY_BSSD, 0); | ||
512 | rt2x00_set_field32(®, RX_FILTER_CFG_DROP_VER_ERROR, 1); | ||
513 | rt2x00_set_field32(®, RX_FILTER_CFG_DROP_MULTICAST, | ||
514 | !(filter_flags & FIF_ALLMULTI)); | ||
515 | rt2x00_set_field32(®, RX_FILTER_CFG_DROP_BROADCAST, 0); | ||
516 | rt2x00_set_field32(®, RX_FILTER_CFG_DROP_DUPLICATE, 1); | ||
517 | rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CF_END_ACK, | ||
518 | !(filter_flags & FIF_CONTROL)); | ||
519 | rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CF_END, | ||
520 | !(filter_flags & FIF_CONTROL)); | ||
521 | rt2x00_set_field32(®, RX_FILTER_CFG_DROP_ACK, | ||
522 | !(filter_flags & FIF_CONTROL)); | ||
523 | rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CTS, | ||
524 | !(filter_flags & FIF_CONTROL)); | ||
525 | rt2x00_set_field32(®, RX_FILTER_CFG_DROP_RTS, | ||
526 | !(filter_flags & FIF_CONTROL)); | ||
527 | rt2x00_set_field32(®, RX_FILTER_CFG_DROP_PSPOLL, | ||
528 | !(filter_flags & FIF_PSPOLL)); | ||
529 | rt2x00_set_field32(®, RX_FILTER_CFG_DROP_BA, 1); | ||
530 | rt2x00_set_field32(®, RX_FILTER_CFG_DROP_BAR, 0); | ||
531 | rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CNTL, | ||
532 | !(filter_flags & FIF_CONTROL)); | ||
533 | rt2800_register_write(rt2x00dev, RX_FILTER_CFG, reg); | ||
534 | } | ||
535 | EXPORT_SYMBOL_GPL(rt2800_config_filter); | ||
536 | |||
537 | void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf, | ||
538 | struct rt2x00intf_conf *conf, const unsigned int flags) | ||
539 | { | ||
540 | unsigned int beacon_base; | ||
541 | u32 reg; | ||
542 | |||
543 | if (flags & CONFIG_UPDATE_TYPE) { | ||
544 | /* | ||
545 | * Clear current synchronisation setup. | ||
546 | * For the Beacon base registers we only need to clear | ||
547 | * the first byte since that byte contains the VALID and OWNER | ||
548 | * bits which (when set to 0) will invalidate the entire beacon. | ||
549 | */ | ||
550 | beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx); | ||
551 | rt2800_register_write(rt2x00dev, beacon_base, 0); | ||
552 | |||
553 | /* | ||
554 | * Enable synchronisation. | ||
555 | */ | ||
556 | rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); | ||
557 | rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 1); | ||
558 | rt2x00_set_field32(®, BCN_TIME_CFG_TSF_SYNC, conf->sync); | ||
559 | rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 1); | ||
560 | rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); | ||
561 | } | ||
562 | |||
563 | if (flags & CONFIG_UPDATE_MAC) { | ||
564 | reg = le32_to_cpu(conf->mac[1]); | ||
565 | rt2x00_set_field32(®, MAC_ADDR_DW1_UNICAST_TO_ME_MASK, 0xff); | ||
566 | conf->mac[1] = cpu_to_le32(reg); | ||
567 | |||
568 | rt2800_register_multiwrite(rt2x00dev, MAC_ADDR_DW0, | ||
569 | conf->mac, sizeof(conf->mac)); | ||
570 | } | ||
571 | |||
572 | if (flags & CONFIG_UPDATE_BSSID) { | ||
573 | reg = le32_to_cpu(conf->bssid[1]); | ||
574 | rt2x00_set_field32(®, MAC_BSSID_DW1_BSS_ID_MASK, 0); | ||
575 | rt2x00_set_field32(®, MAC_BSSID_DW1_BSS_BCN_NUM, 0); | ||
576 | conf->bssid[1] = cpu_to_le32(reg); | ||
577 | |||
578 | rt2800_register_multiwrite(rt2x00dev, MAC_BSSID_DW0, | ||
579 | conf->bssid, sizeof(conf->bssid)); | ||
580 | } | ||
581 | } | ||
582 | EXPORT_SYMBOL_GPL(rt2800_config_intf); | ||
583 | |||
584 | void rt2800_config_erp(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_erp *erp) | ||
585 | { | ||
586 | u32 reg; | ||
587 | |||
588 | rt2800_register_read(rt2x00dev, TX_TIMEOUT_CFG, ®); | ||
589 | rt2x00_set_field32(®, TX_TIMEOUT_CFG_RX_ACK_TIMEOUT, 0x20); | ||
590 | rt2800_register_write(rt2x00dev, TX_TIMEOUT_CFG, reg); | ||
591 | |||
592 | rt2800_register_read(rt2x00dev, AUTO_RSP_CFG, ®); | ||
593 | rt2x00_set_field32(®, AUTO_RSP_CFG_BAC_ACK_POLICY, | ||
594 | !!erp->short_preamble); | ||
595 | rt2x00_set_field32(®, AUTO_RSP_CFG_AR_PREAMBLE, | ||
596 | !!erp->short_preamble); | ||
597 | rt2800_register_write(rt2x00dev, AUTO_RSP_CFG, reg); | ||
598 | |||
599 | rt2800_register_read(rt2x00dev, OFDM_PROT_CFG, ®); | ||
600 | rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_CTRL, | ||
601 | erp->cts_protection ? 2 : 0); | ||
602 | rt2800_register_write(rt2x00dev, OFDM_PROT_CFG, reg); | ||
603 | |||
604 | rt2800_register_write(rt2x00dev, LEGACY_BASIC_RATE, | ||
605 | erp->basic_rates); | ||
606 | rt2800_register_write(rt2x00dev, HT_BASIC_RATE, 0x00008003); | ||
607 | |||
608 | rt2800_register_read(rt2x00dev, BKOFF_SLOT_CFG, ®); | ||
609 | rt2x00_set_field32(®, BKOFF_SLOT_CFG_SLOT_TIME, erp->slot_time); | ||
610 | rt2x00_set_field32(®, BKOFF_SLOT_CFG_CC_DELAY_TIME, 2); | ||
611 | rt2800_register_write(rt2x00dev, BKOFF_SLOT_CFG, reg); | ||
612 | |||
613 | rt2800_register_read(rt2x00dev, XIFS_TIME_CFG, ®); | ||
614 | rt2x00_set_field32(®, XIFS_TIME_CFG_CCKM_SIFS_TIME, erp->sifs); | ||
615 | rt2x00_set_field32(®, XIFS_TIME_CFG_OFDM_SIFS_TIME, erp->sifs); | ||
616 | rt2x00_set_field32(®, XIFS_TIME_CFG_OFDM_XIFS_TIME, 4); | ||
617 | rt2x00_set_field32(®, XIFS_TIME_CFG_EIFS, erp->eifs); | ||
618 | rt2x00_set_field32(®, XIFS_TIME_CFG_BB_RXEND_ENABLE, 1); | ||
619 | rt2800_register_write(rt2x00dev, XIFS_TIME_CFG, reg); | ||
620 | |||
621 | rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); | ||
622 | rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_INTERVAL, | ||
623 | erp->beacon_int * 16); | ||
624 | rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); | ||
625 | } | ||
626 | EXPORT_SYMBOL_GPL(rt2800_config_erp); | ||
627 | |||
628 | void rt2800_config_ant(struct rt2x00_dev *rt2x00dev, struct antenna_setup *ant) | ||
629 | { | ||
630 | u8 r1; | ||
631 | u8 r3; | ||
632 | |||
633 | rt2800_bbp_read(rt2x00dev, 1, &r1); | ||
634 | rt2800_bbp_read(rt2x00dev, 3, &r3); | ||
635 | |||
636 | /* | ||
637 | * Configure the TX antenna. | ||
638 | */ | ||
639 | switch ((int)ant->tx) { | ||
640 | case 1: | ||
641 | rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 0); | ||
642 | if (rt2x00_intf_is_pci(rt2x00dev)) | ||
643 | rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 0); | ||
644 | break; | ||
645 | case 2: | ||
646 | rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 2); | ||
647 | break; | ||
648 | case 3: | ||
649 | /* Do nothing */ | ||
650 | break; | ||
651 | } | ||
652 | |||
653 | /* | ||
654 | * Configure the RX antenna. | ||
655 | */ | ||
656 | switch ((int)ant->rx) { | ||
657 | case 1: | ||
658 | rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 0); | ||
659 | break; | ||
660 | case 2: | ||
661 | rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 1); | ||
662 | break; | ||
663 | case 3: | ||
664 | rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 2); | ||
665 | break; | ||
666 | } | ||
667 | |||
668 | rt2800_bbp_write(rt2x00dev, 3, r3); | ||
669 | rt2800_bbp_write(rt2x00dev, 1, r1); | ||
670 | } | ||
671 | EXPORT_SYMBOL_GPL(rt2800_config_ant); | ||
672 | |||
673 | static void rt2800_config_lna_gain(struct rt2x00_dev *rt2x00dev, | ||
674 | struct rt2x00lib_conf *libconf) | ||
675 | { | ||
676 | u16 eeprom; | ||
677 | short lna_gain; | ||
678 | |||
679 | if (libconf->rf.channel <= 14) { | ||
680 | rt2x00_eeprom_read(rt2x00dev, EEPROM_LNA, &eeprom); | ||
681 | lna_gain = rt2x00_get_field16(eeprom, EEPROM_LNA_BG); | ||
682 | } else if (libconf->rf.channel <= 64) { | ||
683 | rt2x00_eeprom_read(rt2x00dev, EEPROM_LNA, &eeprom); | ||
684 | lna_gain = rt2x00_get_field16(eeprom, EEPROM_LNA_A0); | ||
685 | } else if (libconf->rf.channel <= 128) { | ||
686 | rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_BG2, &eeprom); | ||
687 | lna_gain = rt2x00_get_field16(eeprom, EEPROM_RSSI_BG2_LNA_A1); | ||
688 | } else { | ||
689 | rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_A2, &eeprom); | ||
690 | lna_gain = rt2x00_get_field16(eeprom, EEPROM_RSSI_A2_LNA_A2); | ||
691 | } | ||
692 | |||
693 | rt2x00dev->lna_gain = lna_gain; | ||
694 | } | ||
695 | |||
696 | static void rt2800_config_channel_rt2x(struct rt2x00_dev *rt2x00dev, | ||
697 | struct ieee80211_conf *conf, | ||
698 | struct rf_channel *rf, | ||
699 | struct channel_info *info) | ||
700 | { | ||
701 | rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset); | ||
702 | |||
703 | if (rt2x00dev->default_ant.tx == 1) | ||
704 | rt2x00_set_field32(&rf->rf2, RF2_ANTENNA_TX1, 1); | ||
705 | |||
706 | if (rt2x00dev->default_ant.rx == 1) { | ||
707 | rt2x00_set_field32(&rf->rf2, RF2_ANTENNA_RX1, 1); | ||
708 | rt2x00_set_field32(&rf->rf2, RF2_ANTENNA_RX2, 1); | ||
709 | } else if (rt2x00dev->default_ant.rx == 2) | ||
710 | rt2x00_set_field32(&rf->rf2, RF2_ANTENNA_RX2, 1); | ||
711 | |||
712 | if (rf->channel > 14) { | ||
713 | /* | ||
714 | * When TX power is below 0, we should increase it by 7 to | ||
715 | * make it a positive value (Minumum value is -7). | ||
716 | * However this means that values between 0 and 7 have | ||
717 | * double meaning, and we should set a 7DBm boost flag. | ||
718 | */ | ||
719 | rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_A_7DBM_BOOST, | ||
720 | (info->tx_power1 >= 0)); | ||
721 | |||
722 | if (info->tx_power1 < 0) | ||
723 | info->tx_power1 += 7; | ||
724 | |||
725 | rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_A, | ||
726 | TXPOWER_A_TO_DEV(info->tx_power1)); | ||
727 | |||
728 | rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_A_7DBM_BOOST, | ||
729 | (info->tx_power2 >= 0)); | ||
730 | |||
731 | if (info->tx_power2 < 0) | ||
732 | info->tx_power2 += 7; | ||
733 | |||
734 | rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_A, | ||
735 | TXPOWER_A_TO_DEV(info->tx_power2)); | ||
736 | } else { | ||
737 | rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_G, | ||
738 | TXPOWER_G_TO_DEV(info->tx_power1)); | ||
739 | rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_G, | ||
740 | TXPOWER_G_TO_DEV(info->tx_power2)); | ||
741 | } | ||
742 | |||
743 | rt2x00_set_field32(&rf->rf4, RF4_HT40, conf_is_ht40(conf)); | ||
744 | |||
745 | rt2800_rf_write(rt2x00dev, 1, rf->rf1); | ||
746 | rt2800_rf_write(rt2x00dev, 2, rf->rf2); | ||
747 | rt2800_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); | ||
748 | rt2800_rf_write(rt2x00dev, 4, rf->rf4); | ||
749 | |||
750 | udelay(200); | ||
751 | |||
752 | rt2800_rf_write(rt2x00dev, 1, rf->rf1); | ||
753 | rt2800_rf_write(rt2x00dev, 2, rf->rf2); | ||
754 | rt2800_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004); | ||
755 | rt2800_rf_write(rt2x00dev, 4, rf->rf4); | ||
756 | |||
757 | udelay(200); | ||
758 | |||
759 | rt2800_rf_write(rt2x00dev, 1, rf->rf1); | ||
760 | rt2800_rf_write(rt2x00dev, 2, rf->rf2); | ||
761 | rt2800_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); | ||
762 | rt2800_rf_write(rt2x00dev, 4, rf->rf4); | ||
763 | } | ||
764 | |||
765 | static void rt2800_config_channel_rt3x(struct rt2x00_dev *rt2x00dev, | ||
766 | struct ieee80211_conf *conf, | ||
767 | struct rf_channel *rf, | ||
768 | struct channel_info *info) | ||
769 | { | ||
770 | u8 rfcsr; | ||
771 | |||
772 | rt2800_rfcsr_write(rt2x00dev, 2, rf->rf1); | ||
773 | rt2800_rfcsr_write(rt2x00dev, 2, rf->rf3); | ||
774 | |||
775 | rt2800_rfcsr_read(rt2x00dev, 6, &rfcsr); | ||
776 | rt2x00_set_field8(&rfcsr, RFCSR6_R, rf->rf2); | ||
777 | rt2800_rfcsr_write(rt2x00dev, 6, rfcsr); | ||
778 | |||
779 | rt2800_rfcsr_read(rt2x00dev, 12, &rfcsr); | ||
780 | rt2x00_set_field8(&rfcsr, RFCSR12_TX_POWER, | ||
781 | TXPOWER_G_TO_DEV(info->tx_power1)); | ||
782 | rt2800_rfcsr_write(rt2x00dev, 12, rfcsr); | ||
783 | |||
784 | rt2800_rfcsr_read(rt2x00dev, 23, &rfcsr); | ||
785 | rt2x00_set_field8(&rfcsr, RFCSR23_FREQ_OFFSET, rt2x00dev->freq_offset); | ||
786 | rt2800_rfcsr_write(rt2x00dev, 23, rfcsr); | ||
787 | |||
788 | rt2800_rfcsr_write(rt2x00dev, 24, | ||
789 | rt2x00dev->calibration[conf_is_ht40(conf)]); | ||
790 | |||
791 | rt2800_rfcsr_read(rt2x00dev, 23, &rfcsr); | ||
792 | rt2x00_set_field8(&rfcsr, RFCSR7_RF_TUNING, 1); | ||
793 | rt2800_rfcsr_write(rt2x00dev, 23, rfcsr); | ||
794 | } | ||
795 | |||
796 | static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, | ||
797 | struct ieee80211_conf *conf, | ||
798 | struct rf_channel *rf, | ||
799 | struct channel_info *info) | ||
800 | { | ||
801 | u32 reg; | ||
802 | unsigned int tx_pin; | ||
803 | u8 bbp; | ||
804 | |||
805 | if (rt2x00_rev(&rt2x00dev->chip) != RT3070_VERSION) | ||
806 | rt2800_config_channel_rt2x(rt2x00dev, conf, rf, info); | ||
807 | else | ||
808 | rt2800_config_channel_rt3x(rt2x00dev, conf, rf, info); | ||
809 | |||
810 | /* | ||
811 | * Change BBP settings | ||
812 | */ | ||
813 | rt2800_bbp_write(rt2x00dev, 62, 0x37 - rt2x00dev->lna_gain); | ||
814 | rt2800_bbp_write(rt2x00dev, 63, 0x37 - rt2x00dev->lna_gain); | ||
815 | rt2800_bbp_write(rt2x00dev, 64, 0x37 - rt2x00dev->lna_gain); | ||
816 | rt2800_bbp_write(rt2x00dev, 86, 0); | ||
817 | |||
818 | if (rf->channel <= 14) { | ||
819 | if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) { | ||
820 | rt2800_bbp_write(rt2x00dev, 82, 0x62); | ||
821 | rt2800_bbp_write(rt2x00dev, 75, 0x46); | ||
822 | } else { | ||
823 | rt2800_bbp_write(rt2x00dev, 82, 0x84); | ||
824 | rt2800_bbp_write(rt2x00dev, 75, 0x50); | ||
825 | } | ||
826 | } else { | ||
827 | rt2800_bbp_write(rt2x00dev, 82, 0xf2); | ||
828 | |||
829 | if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) | ||
830 | rt2800_bbp_write(rt2x00dev, 75, 0x46); | ||
831 | else | ||
832 | rt2800_bbp_write(rt2x00dev, 75, 0x50); | ||
833 | } | ||
834 | |||
835 | rt2800_register_read(rt2x00dev, TX_BAND_CFG, ®); | ||
836 | rt2x00_set_field32(®, TX_BAND_CFG_HT40_PLUS, conf_is_ht40_plus(conf)); | ||
837 | rt2x00_set_field32(®, TX_BAND_CFG_A, rf->channel > 14); | ||
838 | rt2x00_set_field32(®, TX_BAND_CFG_BG, rf->channel <= 14); | ||
839 | rt2800_register_write(rt2x00dev, TX_BAND_CFG, reg); | ||
840 | |||
841 | tx_pin = 0; | ||
842 | |||
843 | /* Turn on unused PA or LNA when not using 1T or 1R */ | ||
844 | if (rt2x00dev->default_ant.tx != 1) { | ||
845 | rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_A1_EN, 1); | ||
846 | rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G1_EN, 1); | ||
847 | } | ||
848 | |||
849 | /* Turn on unused PA or LNA when not using 1T or 1R */ | ||
850 | if (rt2x00dev->default_ant.rx != 1) { | ||
851 | rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A1_EN, 1); | ||
852 | rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G1_EN, 1); | ||
853 | } | ||
854 | |||
855 | rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A0_EN, 1); | ||
856 | rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G0_EN, 1); | ||
857 | rt2x00_set_field32(&tx_pin, TX_PIN_CFG_RFTR_EN, 1); | ||
858 | rt2x00_set_field32(&tx_pin, TX_PIN_CFG_TRSW_EN, 1); | ||
859 | rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G0_EN, rf->channel <= 14); | ||
860 | rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_A0_EN, rf->channel > 14); | ||
861 | |||
862 | rt2800_register_write(rt2x00dev, TX_PIN_CFG, tx_pin); | ||
863 | |||
864 | rt2800_bbp_read(rt2x00dev, 4, &bbp); | ||
865 | rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 2 * conf_is_ht40(conf)); | ||
866 | rt2800_bbp_write(rt2x00dev, 4, bbp); | ||
867 | |||
868 | rt2800_bbp_read(rt2x00dev, 3, &bbp); | ||
869 | rt2x00_set_field8(&bbp, BBP3_HT40_PLUS, conf_is_ht40_plus(conf)); | ||
870 | rt2800_bbp_write(rt2x00dev, 3, bbp); | ||
871 | |||
872 | if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION) { | ||
873 | if (conf_is_ht40(conf)) { | ||
874 | rt2800_bbp_write(rt2x00dev, 69, 0x1a); | ||
875 | rt2800_bbp_write(rt2x00dev, 70, 0x0a); | ||
876 | rt2800_bbp_write(rt2x00dev, 73, 0x16); | ||
877 | } else { | ||
878 | rt2800_bbp_write(rt2x00dev, 69, 0x16); | ||
879 | rt2800_bbp_write(rt2x00dev, 70, 0x08); | ||
880 | rt2800_bbp_write(rt2x00dev, 73, 0x11); | ||
881 | } | ||
882 | } | ||
883 | |||
884 | msleep(1); | ||
885 | } | ||
886 | |||
887 | static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, | ||
888 | const int txpower) | ||
889 | { | ||
890 | u32 reg; | ||
891 | u32 value = TXPOWER_G_TO_DEV(txpower); | ||
892 | u8 r1; | ||
893 | |||
894 | rt2800_bbp_read(rt2x00dev, 1, &r1); | ||
895 | rt2x00_set_field8(®, BBP1_TX_POWER, 0); | ||
896 | rt2800_bbp_write(rt2x00dev, 1, r1); | ||
897 | |||
898 | rt2800_register_read(rt2x00dev, TX_PWR_CFG_0, ®); | ||
899 | rt2x00_set_field32(®, TX_PWR_CFG_0_1MBS, value); | ||
900 | rt2x00_set_field32(®, TX_PWR_CFG_0_2MBS, value); | ||
901 | rt2x00_set_field32(®, TX_PWR_CFG_0_55MBS, value); | ||
902 | rt2x00_set_field32(®, TX_PWR_CFG_0_11MBS, value); | ||
903 | rt2x00_set_field32(®, TX_PWR_CFG_0_6MBS, value); | ||
904 | rt2x00_set_field32(®, TX_PWR_CFG_0_9MBS, value); | ||
905 | rt2x00_set_field32(®, TX_PWR_CFG_0_12MBS, value); | ||
906 | rt2x00_set_field32(®, TX_PWR_CFG_0_18MBS, value); | ||
907 | rt2800_register_write(rt2x00dev, TX_PWR_CFG_0, reg); | ||
908 | |||
909 | rt2800_register_read(rt2x00dev, TX_PWR_CFG_1, ®); | ||
910 | rt2x00_set_field32(®, TX_PWR_CFG_1_24MBS, value); | ||
911 | rt2x00_set_field32(®, TX_PWR_CFG_1_36MBS, value); | ||
912 | rt2x00_set_field32(®, TX_PWR_CFG_1_48MBS, value); | ||
913 | rt2x00_set_field32(®, TX_PWR_CFG_1_54MBS, value); | ||
914 | rt2x00_set_field32(®, TX_PWR_CFG_1_MCS0, value); | ||
915 | rt2x00_set_field32(®, TX_PWR_CFG_1_MCS1, value); | ||
916 | rt2x00_set_field32(®, TX_PWR_CFG_1_MCS2, value); | ||
917 | rt2x00_set_field32(®, TX_PWR_CFG_1_MCS3, value); | ||
918 | rt2800_register_write(rt2x00dev, TX_PWR_CFG_1, reg); | ||
919 | |||
920 | rt2800_register_read(rt2x00dev, TX_PWR_CFG_2, ®); | ||
921 | rt2x00_set_field32(®, TX_PWR_CFG_2_MCS4, value); | ||
922 | rt2x00_set_field32(®, TX_PWR_CFG_2_MCS5, value); | ||
923 | rt2x00_set_field32(®, TX_PWR_CFG_2_MCS6, value); | ||
924 | rt2x00_set_field32(®, TX_PWR_CFG_2_MCS7, value); | ||
925 | rt2x00_set_field32(®, TX_PWR_CFG_2_MCS8, value); | ||
926 | rt2x00_set_field32(®, TX_PWR_CFG_2_MCS9, value); | ||
927 | rt2x00_set_field32(®, TX_PWR_CFG_2_MCS10, value); | ||
928 | rt2x00_set_field32(®, TX_PWR_CFG_2_MCS11, value); | ||
929 | rt2800_register_write(rt2x00dev, TX_PWR_CFG_2, reg); | ||
930 | |||
931 | rt2800_register_read(rt2x00dev, TX_PWR_CFG_3, ®); | ||
932 | rt2x00_set_field32(®, TX_PWR_CFG_3_MCS12, value); | ||
933 | rt2x00_set_field32(®, TX_PWR_CFG_3_MCS13, value); | ||
934 | rt2x00_set_field32(®, TX_PWR_CFG_3_MCS14, value); | ||
935 | rt2x00_set_field32(®, TX_PWR_CFG_3_MCS15, value); | ||
936 | rt2x00_set_field32(®, TX_PWR_CFG_3_UKNOWN1, value); | ||
937 | rt2x00_set_field32(®, TX_PWR_CFG_3_UKNOWN2, value); | ||
938 | rt2x00_set_field32(®, TX_PWR_CFG_3_UKNOWN3, value); | ||
939 | rt2x00_set_field32(®, TX_PWR_CFG_3_UKNOWN4, value); | ||
940 | rt2800_register_write(rt2x00dev, TX_PWR_CFG_3, reg); | ||
941 | |||
942 | rt2800_register_read(rt2x00dev, TX_PWR_CFG_4, ®); | ||
943 | rt2x00_set_field32(®, TX_PWR_CFG_4_UKNOWN5, value); | ||
944 | rt2x00_set_field32(®, TX_PWR_CFG_4_UKNOWN6, value); | ||
945 | rt2x00_set_field32(®, TX_PWR_CFG_4_UKNOWN7, value); | ||
946 | rt2x00_set_field32(®, TX_PWR_CFG_4_UKNOWN8, value); | ||
947 | rt2800_register_write(rt2x00dev, TX_PWR_CFG_4, reg); | ||
948 | } | ||
949 | |||
950 | static void rt2800_config_retry_limit(struct rt2x00_dev *rt2x00dev, | ||
951 | struct rt2x00lib_conf *libconf) | ||
952 | { | ||
953 | u32 reg; | ||
954 | |||
955 | rt2800_register_read(rt2x00dev, TX_RTY_CFG, ®); | ||
956 | rt2x00_set_field32(®, TX_RTY_CFG_SHORT_RTY_LIMIT, | ||
957 | libconf->conf->short_frame_max_tx_count); | ||
958 | rt2x00_set_field32(®, TX_RTY_CFG_LONG_RTY_LIMIT, | ||
959 | libconf->conf->long_frame_max_tx_count); | ||
960 | rt2x00_set_field32(®, TX_RTY_CFG_LONG_RTY_THRE, 2000); | ||
961 | rt2x00_set_field32(®, TX_RTY_CFG_NON_AGG_RTY_MODE, 0); | ||
962 | rt2x00_set_field32(®, TX_RTY_CFG_AGG_RTY_MODE, 0); | ||
963 | rt2x00_set_field32(®, TX_RTY_CFG_TX_AUTO_FB_ENABLE, 1); | ||
964 | rt2800_register_write(rt2x00dev, TX_RTY_CFG, reg); | ||
965 | } | ||
966 | |||
967 | static void rt2800_config_ps(struct rt2x00_dev *rt2x00dev, | ||
968 | struct rt2x00lib_conf *libconf) | ||
969 | { | ||
970 | enum dev_state state = | ||
971 | (libconf->conf->flags & IEEE80211_CONF_PS) ? | ||
972 | STATE_SLEEP : STATE_AWAKE; | ||
973 | u32 reg; | ||
974 | |||
975 | if (state == STATE_SLEEP) { | ||
976 | rt2800_register_write(rt2x00dev, AUTOWAKEUP_CFG, 0); | ||
977 | |||
978 | rt2800_register_read(rt2x00dev, AUTOWAKEUP_CFG, ®); | ||
979 | rt2x00_set_field32(®, AUTOWAKEUP_CFG_AUTO_LEAD_TIME, 5); | ||
980 | rt2x00_set_field32(®, AUTOWAKEUP_CFG_TBCN_BEFORE_WAKE, | ||
981 | libconf->conf->listen_interval - 1); | ||
982 | rt2x00_set_field32(®, AUTOWAKEUP_CFG_AUTOWAKE, 1); | ||
983 | rt2800_register_write(rt2x00dev, AUTOWAKEUP_CFG, reg); | ||
984 | |||
985 | rt2x00dev->ops->lib->set_device_state(rt2x00dev, state); | ||
986 | } else { | ||
987 | rt2x00dev->ops->lib->set_device_state(rt2x00dev, state); | ||
988 | |||
989 | rt2800_register_read(rt2x00dev, AUTOWAKEUP_CFG, ®); | ||
990 | rt2x00_set_field32(®, AUTOWAKEUP_CFG_AUTO_LEAD_TIME, 0); | ||
991 | rt2x00_set_field32(®, AUTOWAKEUP_CFG_TBCN_BEFORE_WAKE, 0); | ||
992 | rt2x00_set_field32(®, AUTOWAKEUP_CFG_AUTOWAKE, 0); | ||
993 | rt2800_register_write(rt2x00dev, AUTOWAKEUP_CFG, reg); | ||
994 | } | ||
995 | } | ||
996 | |||
997 | void rt2800_config(struct rt2x00_dev *rt2x00dev, | ||
998 | struct rt2x00lib_conf *libconf, | ||
999 | const unsigned int flags) | ||
1000 | { | ||
1001 | /* Always recalculate LNA gain before changing configuration */ | ||
1002 | rt2800_config_lna_gain(rt2x00dev, libconf); | ||
1003 | |||
1004 | if (flags & IEEE80211_CONF_CHANGE_CHANNEL) | ||
1005 | rt2800_config_channel(rt2x00dev, libconf->conf, | ||
1006 | &libconf->rf, &libconf->channel); | ||
1007 | if (flags & IEEE80211_CONF_CHANGE_POWER) | ||
1008 | rt2800_config_txpower(rt2x00dev, libconf->conf->power_level); | ||
1009 | if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS) | ||
1010 | rt2800_config_retry_limit(rt2x00dev, libconf); | ||
1011 | if (flags & IEEE80211_CONF_CHANGE_PS) | ||
1012 | rt2800_config_ps(rt2x00dev, libconf); | ||
1013 | } | ||
1014 | EXPORT_SYMBOL_GPL(rt2800_config); | ||
1015 | |||
1016 | /* | ||
1017 | * Link tuning | ||
1018 | */ | ||
1019 | void rt2800_link_stats(struct rt2x00_dev *rt2x00dev, struct link_qual *qual) | ||
1020 | { | ||
1021 | u32 reg; | ||
1022 | |||
1023 | /* | ||
1024 | * Update FCS error count from register. | ||
1025 | */ | ||
1026 | rt2800_register_read(rt2x00dev, RX_STA_CNT0, ®); | ||
1027 | qual->rx_failed = rt2x00_get_field32(reg, RX_STA_CNT0_CRC_ERR); | ||
1028 | } | ||
1029 | EXPORT_SYMBOL_GPL(rt2800_link_stats); | ||
1030 | |||
1031 | static u8 rt2800_get_default_vgc(struct rt2x00_dev *rt2x00dev) | ||
1032 | { | ||
1033 | if (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ) { | ||
1034 | if (rt2x00_intf_is_usb(rt2x00dev) && | ||
1035 | rt2x00_rev(&rt2x00dev->chip) == RT3070_VERSION) | ||
1036 | return 0x1c + (2 * rt2x00dev->lna_gain); | ||
1037 | else | ||
1038 | return 0x2e + rt2x00dev->lna_gain; | ||
1039 | } | ||
1040 | |||
1041 | if (!test_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags)) | ||
1042 | return 0x32 + (rt2x00dev->lna_gain * 5) / 3; | ||
1043 | else | ||
1044 | return 0x3a + (rt2x00dev->lna_gain * 5) / 3; | ||
1045 | } | ||
1046 | |||
1047 | static inline void rt2800_set_vgc(struct rt2x00_dev *rt2x00dev, | ||
1048 | struct link_qual *qual, u8 vgc_level) | ||
1049 | { | ||
1050 | if (qual->vgc_level != vgc_level) { | ||
1051 | rt2800_bbp_write(rt2x00dev, 66, vgc_level); | ||
1052 | qual->vgc_level = vgc_level; | ||
1053 | qual->vgc_level_reg = vgc_level; | ||
1054 | } | ||
1055 | } | ||
1056 | |||
1057 | void rt2800_reset_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual) | ||
1058 | { | ||
1059 | rt2800_set_vgc(rt2x00dev, qual, rt2800_get_default_vgc(rt2x00dev)); | ||
1060 | } | ||
1061 | EXPORT_SYMBOL_GPL(rt2800_reset_tuner); | ||
1062 | |||
1063 | void rt2800_link_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual, | ||
1064 | const u32 count) | ||
1065 | { | ||
1066 | if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION) | ||
1067 | return; | ||
1068 | |||
1069 | /* | ||
1070 | * When RSSI is better then -80 increase VGC level with 0x10 | ||
1071 | */ | ||
1072 | rt2800_set_vgc(rt2x00dev, qual, | ||
1073 | rt2800_get_default_vgc(rt2x00dev) + | ||
1074 | ((qual->rssi > -80) * 0x10)); | ||
1075 | } | ||
1076 | EXPORT_SYMBOL_GPL(rt2800_link_tuner); | ||