aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIdo Yariv <ido@wizery.com>2011-03-31 04:06:57 -0400
committerLuciano Coelho <coelho@ti.com>2011-04-19 09:49:17 -0400
commitd29633b40e6afc6b4276a4e381bc532cc84be104 (patch)
tree136e6a871de72b504a8999b924c8c29958654382
parent8bf69aae4cb9b196ba5ac386f83a1ca3865af11f (diff)
wl12xx: Clean up and fix the 128x boot sequence
Clean up the boot sequence code & fix the following issues: 1. Always read the registers' values and set the relevant bits instead of zeroing all other bits 2. Handle cases where wl1271_top_reg_read returns an error 3. Verify that the HW can detect the selected clock source 4. Remove 128x PG10 initialization code 5. Configure the MCS PLL to work in HP mode Signed-off-by: Ido Yariv <ido@wizery.com> Reviewed-by: Luciano Coelho <coelho@ti.com> Signed-off-by: Luciano Coelho <coelho@ti.com>
-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 */