diff options
author | Tomas Winkler <tomas.winkler@intel.com> | 2008-05-29 04:35:05 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-06-03 15:00:23 -0400 |
commit | 7c616cba240cd0d579c996be3f3603456acfb0ad (patch) | |
tree | 9c0a4594423b12138c1c430dac8063b4a437e1cd /drivers/net/wireless/iwlwifi/iwl-5000.c | |
parent | c135475439f75e6eb29e7586d33f3e22a61c1bb4 (diff) |
iwlwifi-5000: implement initial calibration for 5000
This patch adds initial calibration framework for 5000 HW faimily.
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Gregory Greenman <gregory.greenman@intel.com>
Signed-off-by: Ron Rindjunsky <ron.rindjunsky@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-5000.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-5000.c | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index a94cd362fef5..eb6141e6edbc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c | |||
@@ -395,6 +395,8 @@ static struct iwl_sensitivity_ranges iwl5000_sensitivity = { | |||
395 | 395 | ||
396 | #endif /* CONFIG_IWL5000_RUN_TIME_CALIB */ | 396 | #endif /* CONFIG_IWL5000_RUN_TIME_CALIB */ |
397 | 397 | ||
398 | |||
399 | |||
398 | static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv, | 400 | static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv, |
399 | size_t offset) | 401 | size_t offset) |
400 | { | 402 | { |
@@ -404,6 +406,118 @@ static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv, | |||
404 | } | 406 | } |
405 | 407 | ||
406 | /* | 408 | /* |
409 | * Calibration | ||
410 | */ | ||
411 | static int iwl5000_send_Xtal_calib(struct iwl_priv *priv) | ||
412 | { | ||
413 | u16 *xtal_calib = (u16 *)iwl_eeprom_query_addr(priv, EEPROM_5000_XTAL); | ||
414 | |||
415 | struct iwl5000_calibration cal_cmd = { | ||
416 | .op_code = IWL5000_PHY_CALIBRATE_CRYSTAL_FRQ_CMD, | ||
417 | .data = { | ||
418 | (u8)xtal_calib[0], | ||
419 | (u8)xtal_calib[1], | ||
420 | } | ||
421 | }; | ||
422 | |||
423 | return iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD, | ||
424 | sizeof(cal_cmd), &cal_cmd); | ||
425 | } | ||
426 | |||
427 | static int iwl5000_send_calib_results(struct iwl_priv *priv) | ||
428 | { | ||
429 | int ret = 0; | ||
430 | |||
431 | if (priv->calib_results.lo_res) | ||
432 | ret = iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD, | ||
433 | priv->calib_results.lo_res_len, | ||
434 | priv->calib_results.lo_res); | ||
435 | if (ret) | ||
436 | goto err; | ||
437 | |||
438 | |||
439 | if (priv->calib_results.tx_iq_res) | ||
440 | ret = iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD, | ||
441 | priv->calib_results.tx_iq_res_len, | ||
442 | priv->calib_results.tx_iq_res); | ||
443 | |||
444 | if (ret) | ||
445 | goto err; | ||
446 | |||
447 | if (priv->calib_results.tx_iq_perd_res) | ||
448 | ret = iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD, | ||
449 | priv->calib_results.tx_iq_perd_res_len, | ||
450 | priv->calib_results.tx_iq_perd_res); | ||
451 | if (ret) | ||
452 | goto err; | ||
453 | |||
454 | return 0; | ||
455 | err: | ||
456 | IWL_ERROR("Error %d\n", ret); | ||
457 | return ret; | ||
458 | } | ||
459 | |||
460 | static int iwl5000_send_calib_cfg(struct iwl_priv *priv) | ||
461 | { | ||
462 | struct iwl5000_calib_cfg_cmd calib_cfg_cmd; | ||
463 | struct iwl_host_cmd cmd = { | ||
464 | .id = CALIBRATION_CFG_CMD, | ||
465 | .len = sizeof(struct iwl5000_calib_cfg_cmd), | ||
466 | .data = &calib_cfg_cmd, | ||
467 | }; | ||
468 | |||
469 | memset(&calib_cfg_cmd, 0, sizeof(calib_cfg_cmd)); | ||
470 | calib_cfg_cmd.ucd_calib_cfg.once.is_enable = IWL_CALIB_INIT_CFG_ALL; | ||
471 | calib_cfg_cmd.ucd_calib_cfg.once.start = IWL_CALIB_INIT_CFG_ALL; | ||
472 | calib_cfg_cmd.ucd_calib_cfg.once.send_res = IWL_CALIB_INIT_CFG_ALL; | ||
473 | calib_cfg_cmd.ucd_calib_cfg.flags = IWL_CALIB_INIT_CFG_ALL; | ||
474 | |||
475 | return iwl_send_cmd(priv, &cmd); | ||
476 | } | ||
477 | |||
478 | static void iwl5000_rx_calib_result(struct iwl_priv *priv, | ||
479 | struct iwl_rx_mem_buffer *rxb) | ||
480 | { | ||
481 | struct iwl_rx_packet *pkt = (void *)rxb->skb->data; | ||
482 | struct iwl5000_calib_hdr *hdr = (struct iwl5000_calib_hdr *)pkt->u.raw; | ||
483 | int len = le32_to_cpu(pkt->len) & FH_RSCSR_FRAME_SIZE_MSK; | ||
484 | |||
485 | iwl_free_calib_results(priv); | ||
486 | |||
487 | /* reduce the size of the length field itself */ | ||
488 | len -= 4; | ||
489 | |||
490 | switch (hdr->op_code) { | ||
491 | case IWL5000_PHY_CALIBRATE_LO_CMD: | ||
492 | priv->calib_results.lo_res = kzalloc(len, GFP_ATOMIC); | ||
493 | priv->calib_results.lo_res_len = len; | ||
494 | memcpy(priv->calib_results.lo_res, pkt->u.raw, len); | ||
495 | break; | ||
496 | case IWL5000_PHY_CALIBRATE_TX_IQ_CMD: | ||
497 | priv->calib_results.tx_iq_res = kzalloc(len, GFP_ATOMIC); | ||
498 | priv->calib_results.tx_iq_res_len = len; | ||
499 | memcpy(priv->calib_results.tx_iq_res, pkt->u.raw, len); | ||
500 | break; | ||
501 | case IWL5000_PHY_CALIBRATE_TX_IQ_PERD_CMD: | ||
502 | priv->calib_results.tx_iq_perd_res = kzalloc(len, GFP_ATOMIC); | ||
503 | priv->calib_results.tx_iq_perd_res_len = len; | ||
504 | memcpy(priv->calib_results.tx_iq_perd_res, pkt->u.raw, len); | ||
505 | break; | ||
506 | default: | ||
507 | IWL_ERROR("Unknown calibration notification %d\n", | ||
508 | hdr->op_code); | ||
509 | return; | ||
510 | } | ||
511 | } | ||
512 | |||
513 | static void iwl5000_rx_calib_complete(struct iwl_priv *priv, | ||
514 | struct iwl_rx_mem_buffer *rxb) | ||
515 | { | ||
516 | IWL_DEBUG_INFO("Init. calibration is completed, restarting fw.\n"); | ||
517 | queue_work(priv->workqueue, &priv->restart); | ||
518 | } | ||
519 | |||
520 | /* | ||
407 | * ucode | 521 | * ucode |
408 | */ | 522 | */ |
409 | static int iwl5000_load_section(struct iwl_priv *priv, | 523 | static int iwl5000_load_section(struct iwl_priv *priv, |
@@ -565,6 +679,7 @@ static void iwl5000_init_alive_start(struct iwl_priv *priv) | |||
565 | goto restart; | 679 | goto restart; |
566 | } | 680 | } |
567 | 681 | ||
682 | iwl5000_send_calib_cfg(priv); | ||
568 | return; | 683 | return; |
569 | 684 | ||
570 | restart: | 685 | restart: |
@@ -684,8 +799,14 @@ static int iwl5000_alive_notify(struct iwl_priv *priv) | |||
684 | iwl_release_nic_access(priv); | 799 | iwl_release_nic_access(priv); |
685 | spin_unlock_irqrestore(&priv->lock, flags); | 800 | spin_unlock_irqrestore(&priv->lock, flags); |
686 | 801 | ||
802 | |||
687 | iwl5000_send_wimax_coex(priv); | 803 | iwl5000_send_wimax_coex(priv); |
688 | 804 | ||
805 | iwl5000_send_Xtal_calib(priv); | ||
806 | |||
807 | if (priv->ucode_type == UCODE_RT) | ||
808 | iwl5000_send_calib_results(priv); | ||
809 | |||
689 | return 0; | 810 | return 0; |
690 | } | 811 | } |
691 | 812 | ||
@@ -856,8 +977,14 @@ static u16 iwl5000_get_hcmd_size(u8 cmd_id, u16 len) | |||
856 | 977 | ||
857 | static void iwl5000_rx_handler_setup(struct iwl_priv *priv) | 978 | static void iwl5000_rx_handler_setup(struct iwl_priv *priv) |
858 | { | 979 | { |
980 | /* init calibration handlers */ | ||
981 | priv->rx_handlers[CALIBRATION_RES_NOTIFICATION] = | ||
982 | iwl5000_rx_calib_result; | ||
983 | priv->rx_handlers[CALIBRATION_COMPLETE_NOTIFICATION] = | ||
984 | iwl5000_rx_calib_complete; | ||
859 | } | 985 | } |
860 | 986 | ||
987 | |||
861 | static int iwl5000_hw_valid_rtc_data_addr(u32 addr) | 988 | static int iwl5000_hw_valid_rtc_data_addr(u32 addr) |
862 | { | 989 | { |
863 | return (addr >= RTC_DATA_LOWER_BOUND) && | 990 | return (addr >= RTC_DATA_LOWER_BOUND) && |