aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wireless/wl12xx/boot.c235
-rw-r--r--drivers/net/wireless/wl12xx/boot.h1
-rw-r--r--include/linux/wl12xx.h10
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/* 526static 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 */
533static 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; 547static 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
581static int wl128x_boot_clk(struct wl1271 *wl, bool *is_ref_clk) 558static 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 */ 569static 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, 578static 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 */
616static 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
649fref_clk:
650 /* FREF clock is selected */
651 if (!wl128x_is_fref_valid(wl))
652 return -EINVAL;
653 *selected_clock = wl->ref_clock;
654
655config_mcs_pll:
656 return wl128x_configure_mcs_pll(wl, *selected_clock);
657} 657}
658 658
659static int wl127x_boot_clk(struct wl1271 *wl) 659static 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 */
28enum { 28enum {
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 */