diff options
-rw-r--r-- | drivers/net/wireless/wl12xx/boot.c | 235 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/boot.h | 1 | ||||
-rw-r--r-- | include/linux/wl12xx.h | 10 |
3 files changed, 123 insertions, 123 deletions
diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c index 34bf2fe47dc7..b5ec2c2b6f78 100644 --- a/drivers/net/wireless/wl12xx/boot.c +++ b/drivers/net/wireless/wl12xx/boot.c | |||
@@ -523,137 +523,137 @@ static void wl1271_boot_hw_version(struct wl1271 *wl) | |||
523 | wl->quirks |= WL12XX_QUIRK_END_OF_TRANSACTION; | 523 | wl->quirks |= WL12XX_QUIRK_END_OF_TRANSACTION; |
524 | } | 524 | } |
525 | 525 | ||
526 | /* | 526 | static int wl128x_switch_tcxo_to_fref(struct wl1271 *wl) |
527 | * WL128x has two clocks input - TCXO and FREF. | ||
528 | * TCXO is the main clock of the device, while FREF is used to sync | ||
529 | * between the GPS and the cellular modem. | ||
530 | * In cases where TCXO is 32.736MHz or 16.368MHz, the FREF will be used | ||
531 | * as the WLAN/BT main clock. | ||
532 | */ | ||
533 | static int wl128x_switch_fref(struct wl1271 *wl, bool *is_ref_clk) | ||
534 | { | 527 | { |
535 | u16 sys_clk_cfg_val; | 528 | u16 spare_reg; |
536 | 529 | ||
537 | /* if working on XTAL-only mode go directly to TCXO TO FREF SWITCH */ | 530 | /* Mask bits [2] & [8:4] in the sys_clk_cfg register */ |
538 | if ((wl->ref_clock == CONF_REF_CLK_38_4_M_XTAL) || | 531 | spare_reg = wl1271_top_reg_read(wl, WL_SPARE_REG); |
539 | (wl->ref_clock == CONF_REF_CLK_26_M_XTAL)) | 532 | if (spare_reg == 0xFFFF) |
540 | return true; | 533 | return -EFAULT; |
534 | spare_reg |= (BIT(3) | BIT(5) | BIT(6)); | ||
535 | wl1271_top_reg_write(wl, WL_SPARE_REG, spare_reg); | ||
541 | 536 | ||
542 | /* Read clock source FREF or TCXO */ | 537 | /* Enable FREF_CLK_REQ & mux MCS and coex PLLs to FREF */ |
543 | sys_clk_cfg_val = wl1271_top_reg_read(wl, SYS_CLK_CFG_REG); | 538 | wl1271_top_reg_write(wl, SYS_CLK_CFG_REG, |
539 | WL_CLK_REQ_TYPE_PG2 | MCS_PLL_CLK_SEL_FREF); | ||
544 | 540 | ||
545 | if (sys_clk_cfg_val & PRCM_CM_EN_MUX_WLAN_FREF) { | 541 | /* Delay execution for 15msec, to let the HW settle */ |
546 | /* if bit 3 is set - working with FREF clock */ | 542 | mdelay(15); |
547 | wl1271_debug(DEBUG_BOOT, "working with FREF clock, skip" | ||
548 | " to FREF"); | ||
549 | 543 | ||
550 | *is_ref_clk = true; | 544 | return 0; |
551 | } else { | 545 | } |
552 | /* if bit 3 is clear - working with TCXO clock */ | ||
553 | wl1271_debug(DEBUG_BOOT, "working with TCXO clock"); | ||
554 | |||
555 | /* TCXO to FREF switch, check TXCO clock config */ | ||
556 | if ((wl->tcxo_clock != WL12XX_TCXOCLOCK_16_368) && | ||
557 | (wl->tcxo_clock != WL12XX_TCXOCLOCK_32_736)) { | ||
558 | /* | ||
559 | * not 16.368Mhz and not 32.736Mhz - skip to | ||
560 | * configure ELP stage | ||
561 | */ | ||
562 | wl1271_debug(DEBUG_BOOT, "NEW PLL ALGO:" | ||
563 | " TcxoRefClk=%d - not 16.368Mhz and not" | ||
564 | " 32.736Mhz - skip to configure ELP" | ||
565 | " stage", wl->tcxo_clock); | ||
566 | |||
567 | *is_ref_clk = false; | ||
568 | } else { | ||
569 | wl1271_debug(DEBUG_BOOT, "NEW PLL ALGO:" | ||
570 | "TcxoRefClk=%d - 16.368Mhz or 32.736Mhz" | ||
571 | " - TCXO to FREF switch", | ||
572 | wl->tcxo_clock); | ||
573 | 546 | ||
574 | return true; | 547 | static bool wl128x_is_tcxo_valid(struct wl1271 *wl) |
575 | } | 548 | { |
576 | } | 549 | u16 tcxo_detection; |
550 | |||
551 | tcxo_detection = wl1271_top_reg_read(wl, TCXO_CLK_DETECT_REG); | ||
552 | if (tcxo_detection & TCXO_DET_FAILED) | ||
553 | return false; | ||
577 | 554 | ||
578 | return false; | 555 | return true; |
579 | } | 556 | } |
580 | 557 | ||
581 | static int wl128x_boot_clk(struct wl1271 *wl, bool *is_ref_clk) | 558 | static bool wl128x_is_fref_valid(struct wl1271 *wl) |
582 | { | 559 | { |
583 | if (wl128x_switch_fref(wl, is_ref_clk)) { | 560 | u16 fref_detection; |
584 | wl1271_debug(DEBUG_BOOT, "XTAL-only mode go directly to" | ||
585 | " TCXO TO FREF SWITCH"); | ||
586 | /* TCXO to FREF switch - for PG2.0 */ | ||
587 | wl1271_top_reg_write(wl, WL_SPARE_REG, | ||
588 | WL_SPARE_MASK_8526); | ||
589 | |||
590 | wl1271_top_reg_write(wl, SYS_CLK_CFG_REG, | ||
591 | WL_CLK_REQ_TYPE_PG2 | MCS_PLL_CLK_SEL_FREF); | ||
592 | |||
593 | *is_ref_clk = true; | ||
594 | mdelay(15); | ||
595 | } | ||
596 | 561 | ||
597 | /* Set bit 2 in spare register to avoid illegal access */ | 562 | fref_detection = wl1271_top_reg_read(wl, FREF_CLK_DETECT_REG); |
598 | wl1271_top_reg_write(wl, WL_SPARE_REG, WL_SPARE_VAL); | 563 | if (fref_detection & FREF_CLK_DETECT_FAIL) |
564 | return false; | ||
599 | 565 | ||
600 | /* working with TCXO clock */ | 566 | return true; |
601 | if ((*is_ref_clk == false) && | 567 | } |
602 | ((wl->tcxo_clock == WL12XX_TCXOCLOCK_16_8) || | ||
603 | (wl->tcxo_clock == WL12XX_TCXOCLOCK_33_6))) { | ||
604 | wl1271_debug(DEBUG_BOOT, "16_8_M or 33_6_M TCXO detected"); | ||
605 | 568 | ||
606 | /* Manually Configure MCS PLL settings PG2.0 Only */ | 569 | static int wl128x_manually_configure_mcs_pll(struct wl1271 *wl) |
607 | wl1271_top_reg_write(wl, MCS_PLL_M_REG, MCS_PLL_M_REG_VAL); | 570 | { |
608 | wl1271_top_reg_write(wl, MCS_PLL_N_REG, MCS_PLL_N_REG_VAL); | 571 | wl1271_top_reg_write(wl, MCS_PLL_M_REG, MCS_PLL_M_REG_VAL); |
609 | wl1271_top_reg_write(wl, MCS_PLL_CONFIG_REG, | 572 | wl1271_top_reg_write(wl, MCS_PLL_N_REG, MCS_PLL_N_REG_VAL); |
610 | MCS_PLL_CONFIG_REG_VAL); | 573 | wl1271_top_reg_write(wl, MCS_PLL_CONFIG_REG, MCS_PLL_CONFIG_REG_VAL); |
611 | } else { | ||
612 | int pll_config; | ||
613 | u16 mcs_pll_config_val; | ||
614 | 574 | ||
615 | /* | 575 | return 0; |
616 | * Configure MCS PLL settings to FREF Freq | 576 | } |
617 | * Set the values that determine the time elapse since the PLL's | ||
618 | * get their enable signal until the lock indication is set | ||
619 | */ | ||
620 | wl1271_top_reg_write(wl, PLL_LOCK_COUNTERS_REG, | ||
621 | PLL_LOCK_COUNTERS_COEX | PLL_LOCK_COUNTERS_MCS); | ||
622 | 577 | ||
623 | mcs_pll_config_val = wl1271_top_reg_read(wl, | 578 | static int wl128x_configure_mcs_pll(struct wl1271 *wl, int clk) |
624 | MCS_PLL_CONFIG_REG); | 579 | { |
625 | /* | 580 | u16 spare_reg; |
626 | * Set the MCS PLL input frequency value according to the | 581 | u16 pll_config; |
627 | * reference clock value detected/read | 582 | u8 input_freq; |
628 | */ | 583 | |
629 | if (*is_ref_clk == false) { | 584 | /* Mask bits [3:1] in the sys_clk_cfg register */ |
630 | if ((wl->tcxo_clock == WL12XX_TCXOCLOCK_19_2) || | 585 | spare_reg = wl1271_top_reg_read(wl, WL_SPARE_REG); |
631 | (wl->tcxo_clock == WL12XX_TCXOCLOCK_38_4)) | 586 | if (spare_reg == 0xFFFF) |
632 | pll_config = 1; | 587 | return -EFAULT; |
633 | else if ((wl->tcxo_clock == WL12XX_TCXOCLOCK_26) | 588 | spare_reg |= BIT(2); |
634 | || | 589 | wl1271_top_reg_write(wl, WL_SPARE_REG, spare_reg); |
635 | (wl->tcxo_clock == WL12XX_TCXOCLOCK_52)) | 590 | |
636 | pll_config = 2; | 591 | /* Handle special cases of the TCXO clock */ |
637 | else | 592 | if (wl->tcxo_clock == WL12XX_TCXOCLOCK_16_8 || |
638 | return -EINVAL; | 593 | wl->tcxo_clock == WL12XX_TCXOCLOCK_33_6) |
639 | } else { | 594 | return wl128x_manually_configure_mcs_pll(wl); |
640 | if ((wl->ref_clock == CONF_REF_CLK_19_2_E) || | 595 | |
641 | (wl->ref_clock == CONF_REF_CLK_38_4_E)) | 596 | /* Set the input frequency according to the selected clock source */ |
642 | pll_config = 1; | 597 | input_freq = (clk & 1) + 1; |
643 | else if ((wl->ref_clock == CONF_REF_CLK_26_E) || | 598 | |
644 | (wl->ref_clock == CONF_REF_CLK_52_E)) | 599 | pll_config = wl1271_top_reg_read(wl, MCS_PLL_CONFIG_REG); |
645 | pll_config = 2; | 600 | if (pll_config == 0xFFFF) |
646 | else | 601 | return -EFAULT; |
647 | return -EINVAL; | 602 | pll_config |= (input_freq << MCS_SEL_IN_FREQ_SHIFT); |
648 | } | 603 | pll_config |= MCS_PLL_ENABLE_HP; |
604 | wl1271_top_reg_write(wl, MCS_PLL_CONFIG_REG, pll_config); | ||
649 | 605 | ||
650 | mcs_pll_config_val |= (pll_config << (MCS_SEL_IN_FREQ_SHIFT)) & | 606 | return 0; |
651 | (MCS_SEL_IN_FREQ_MASK); | 607 | } |
652 | wl1271_top_reg_write(wl, MCS_PLL_CONFIG_REG, | 608 | |
653 | mcs_pll_config_val); | 609 | /* |
610 | * WL128x has two clocks input - TCXO and FREF. | ||
611 | * TCXO is the main clock of the device, while FREF is used to sync | ||
612 | * between the GPS and the cellular modem. | ||
613 | * In cases where TCXO is 32.736MHz or 16.368MHz, the FREF will be used | ||
614 | * as the WLAN/BT main clock. | ||
615 | */ | ||
616 | static int wl128x_boot_clk(struct wl1271 *wl, int *selected_clock) | ||
617 | { | ||
618 | u16 sys_clk_cfg; | ||
619 | |||
620 | /* For XTAL-only modes, FREF will be used after switching from TCXO */ | ||
621 | if (wl->ref_clock == WL12XX_REFCLOCK_26_XTAL || | ||
622 | wl->ref_clock == WL12XX_REFCLOCK_38_XTAL) { | ||
623 | if (!wl128x_switch_tcxo_to_fref(wl)) | ||
624 | return -EINVAL; | ||
625 | goto fref_clk; | ||
654 | } | 626 | } |
655 | 627 | ||
656 | return 0; | 628 | /* Query the HW, to determine which clock source we should use */ |
629 | sys_clk_cfg = wl1271_top_reg_read(wl, SYS_CLK_CFG_REG); | ||
630 | if (sys_clk_cfg == 0xFFFF) | ||
631 | return -EINVAL; | ||
632 | if (sys_clk_cfg & PRCM_CM_EN_MUX_WLAN_FREF) | ||
633 | goto fref_clk; | ||
634 | |||
635 | /* If TCXO is either 32.736MHz or 16.368MHz, switch to FREF */ | ||
636 | if (wl->tcxo_clock == WL12XX_TCXOCLOCK_16_368 || | ||
637 | wl->tcxo_clock == WL12XX_TCXOCLOCK_32_736) { | ||
638 | if (!wl128x_switch_tcxo_to_fref(wl)) | ||
639 | return -EINVAL; | ||
640 | goto fref_clk; | ||
641 | } | ||
642 | |||
643 | /* TCXO clock is selected */ | ||
644 | if (!wl128x_is_tcxo_valid(wl)) | ||
645 | return -EINVAL; | ||
646 | *selected_clock = wl->tcxo_clock; | ||
647 | goto config_mcs_pll; | ||
648 | |||
649 | fref_clk: | ||
650 | /* FREF clock is selected */ | ||
651 | if (!wl128x_is_fref_valid(wl)) | ||
652 | return -EINVAL; | ||
653 | *selected_clock = wl->ref_clock; | ||
654 | |||
655 | config_mcs_pll: | ||
656 | return wl128x_configure_mcs_pll(wl, *selected_clock); | ||
657 | } | 657 | } |
658 | 658 | ||
659 | static int wl127x_boot_clk(struct wl1271 *wl) | 659 | static int wl127x_boot_clk(struct wl1271 *wl) |
@@ -713,10 +713,10 @@ int wl1271_load_firmware(struct wl1271 *wl) | |||
713 | { | 713 | { |
714 | int ret = 0; | 714 | int ret = 0; |
715 | u32 tmp, clk; | 715 | u32 tmp, clk; |
716 | bool is_ref_clk = false; | 716 | int selected_clock = -1; |
717 | 717 | ||
718 | if (wl->chip.id == CHIP_ID_1283_PG20) { | 718 | if (wl->chip.id == CHIP_ID_1283_PG20) { |
719 | ret = wl128x_boot_clk(wl, &is_ref_clk); | 719 | ret = wl128x_boot_clk(wl, &selected_clock); |
720 | if (ret < 0) | 720 | if (ret < 0) |
721 | goto out; | 721 | goto out; |
722 | } else { | 722 | } else { |
@@ -741,10 +741,7 @@ int wl1271_load_firmware(struct wl1271 *wl) | |||
741 | wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk); | 741 | wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk); |
742 | 742 | ||
743 | if (wl->chip.id == CHIP_ID_1283_PG20) { | 743 | if (wl->chip.id == CHIP_ID_1283_PG20) { |
744 | if (is_ref_clk == false) | 744 | clk |= ((selected_clock & 0x3) << 1) << 4; |
745 | clk |= ((wl->tcxo_clock & 0x3) << 1) << 4; | ||
746 | else | ||
747 | clk |= ((wl->ref_clock & 0x3) << 1) << 4; | ||
748 | } else { | 745 | } else { |
749 | clk |= (wl->ref_clock << 1) << 4; | 746 | clk |= (wl->ref_clock << 1) << 4; |
750 | } | 747 | } |
diff --git a/drivers/net/wireless/wl12xx/boot.h b/drivers/net/wireless/wl12xx/boot.h index 1f5ee31dc0b1..d9de64ac1442 100644 --- a/drivers/net/wireless/wl12xx/boot.h +++ b/drivers/net/wireless/wl12xx/boot.h | |||
@@ -107,6 +107,7 @@ struct wl1271_static_data { | |||
107 | #define MCS_SEL_IN_FREQ_MASK 0x0070 | 107 | #define MCS_SEL_IN_FREQ_MASK 0x0070 |
108 | #define MCS_SEL_IN_FREQ_SHIFT 4 | 108 | #define MCS_SEL_IN_FREQ_SHIFT 4 |
109 | #define MCS_PLL_CONFIG_REG_VAL 0x73 | 109 | #define MCS_PLL_CONFIG_REG_VAL 0x73 |
110 | #define MCS_PLL_ENABLE_HP (BIT(0) | BIT(1)) | ||
110 | 111 | ||
111 | #define MCS_PLL_M_REG 0xD94 | 112 | #define MCS_PLL_M_REG 0xD94 |
112 | #define MCS_PLL_N_REG 0xD96 | 113 | #define MCS_PLL_N_REG 0xD96 |
diff --git a/include/linux/wl12xx.h b/include/linux/wl12xx.h index eb8aacab8d4e..c1a743ea7470 100644 --- a/include/linux/wl12xx.h +++ b/include/linux/wl12xx.h | |||
@@ -26,10 +26,12 @@ | |||
26 | 26 | ||
27 | /* Reference clock values */ | 27 | /* Reference clock values */ |
28 | enum { | 28 | enum { |
29 | WL12XX_REFCLOCK_19 = 0, /* 19.2 MHz */ | 29 | WL12XX_REFCLOCK_19 = 0, /* 19.2 MHz */ |
30 | WL12XX_REFCLOCK_26 = 1, /* 26 MHz */ | 30 | WL12XX_REFCLOCK_26 = 1, /* 26 MHz */ |
31 | WL12XX_REFCLOCK_38 = 2, /* 38.4 MHz */ | 31 | WL12XX_REFCLOCK_38 = 2, /* 38.4 MHz */ |
32 | WL12XX_REFCLOCK_54 = 3, /* 54 MHz */ | 32 | WL12XX_REFCLOCK_52 = 3, /* 52 MHz */ |
33 | WL12XX_REFCLOCK_38_XTAL = 4, /* 38.4 MHz, XTAL */ | ||
34 | WL12XX_REFCLOCK_26_XTAL = 5, /* 26 MHz, XTAL */ | ||
33 | }; | 35 | }; |
34 | 36 | ||
35 | /* TCXO clock values */ | 37 | /* TCXO clock values */ |