diff options
author | Shahar Levi <shahar_levi@ti.com> | 2011-03-06 09:32:11 -0500 |
---|---|---|
committer | Luciano Coelho <coelho@ti.com> | 2011-04-19 09:48:58 -0400 |
commit | 5ea417ae7749076ddaacb5b36487cae6ac920413 (patch) | |
tree | 3969114b764d6101adda23e626bb80940115abe4 /drivers/net/wireless/wl12xx | |
parent | bc765bf3b9a095b3e41c8cda80643901884c3dd4 (diff) |
wl12xx: 1281/1283 support - New boot sequence
Boot sequence support FREF clock and TCXO clock.
WL128x has two clocks input - TCXO and FREF.
TCXO is the main clock of the device, while FREF is used to sync
between the GPS and the cellular modem.
Auto-detection checks where TCXO is 32.736MHz or 16.368MHz, in that
case the FREF will be used as the WLAN/BT main clock.
[Use clock enumeration as defined in linux/wl12xx.h; remove
unnecessary else block in wl128x_switch_fref; remove unnecessary
change in main.c; remove some unnecessary debug prints and comments;
fix potential use of uninitialized value (pll_config) -- Luca]
Signed-off-by: Shahar Levi <shahar_levi@ti.com>
Reviewed-by: Luciano Coelho <coelho@ti.com>
Signed-off-by: Luciano Coelho <coelho@ti.com>
Diffstat (limited to 'drivers/net/wireless/wl12xx')
-rw-r--r-- | drivers/net/wireless/wl12xx/boot.c | 183 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/sdio.c | 1 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/sdio_test.c | 1 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/spi.c | 1 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/wl12xx.h | 1 |
5 files changed, 179 insertions, 8 deletions
diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c index 38f3e8ba2628..9d742c1e75a9 100644 --- a/drivers/net/wireless/wl12xx/boot.c +++ b/drivers/net/wireless/wl12xx/boot.c | |||
@@ -22,6 +22,7 @@ | |||
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
25 | #include <linux/wl12xx.h> | ||
25 | 26 | ||
26 | #include "acx.h" | 27 | #include "acx.h" |
27 | #include "reg.h" | 28 | #include "reg.h" |
@@ -520,24 +521,159 @@ static void wl1271_boot_hw_version(struct wl1271 *wl) | |||
520 | wl->quirks |= WL12XX_QUIRK_END_OF_TRANSACTION; | 521 | wl->quirks |= WL12XX_QUIRK_END_OF_TRANSACTION; |
521 | } | 522 | } |
522 | 523 | ||
523 | /* uploads NVS and firmware */ | 524 | /* |
524 | int wl1271_load_firmware(struct wl1271 *wl) | 525 | * WL128x has two clocks input - TCXO and FREF. |
526 | * TCXO is the main clock of the device, while FREF is used to sync | ||
527 | * between the GPS and the cellular modem. | ||
528 | * In cases where TCXO is 32.736MHz or 16.368MHz, the FREF will be used | ||
529 | * as the WLAN/BT main clock. | ||
530 | */ | ||
531 | static int wl128x_switch_fref(struct wl1271 *wl, bool *is_ref_clk) | ||
525 | { | 532 | { |
526 | int ret = 0; | 533 | u16 sys_clk_cfg_val; |
527 | u32 tmp, clk, pause; | 534 | |
535 | /* if working on XTAL-only mode go directly to TCXO TO FREF SWITCH */ | ||
536 | if ((wl->ref_clock == CONF_REF_CLK_38_4_M_XTAL) || | ||
537 | (wl->ref_clock == CONF_REF_CLK_26_M_XTAL)) | ||
538 | return true; | ||
539 | |||
540 | /* Read clock source FREF or TCXO */ | ||
541 | sys_clk_cfg_val = wl1271_top_reg_read(wl, SYS_CLK_CFG_REG); | ||
542 | |||
543 | if (sys_clk_cfg_val & PRCM_CM_EN_MUX_WLAN_FREF) { | ||
544 | /* if bit 3 is set - working with FREF clock */ | ||
545 | wl1271_debug(DEBUG_BOOT, "working with FREF clock, skip" | ||
546 | " to FREF"); | ||
547 | |||
548 | *is_ref_clk = true; | ||
549 | } else { | ||
550 | /* if bit 3 is clear - working with TCXO clock */ | ||
551 | wl1271_debug(DEBUG_BOOT, "working with TCXO clock"); | ||
552 | |||
553 | /* TCXO to FREF switch, check TXCO clock config */ | ||
554 | if ((wl->tcxo_clock != WL12XX_TCXOCLOCK_16_368) && | ||
555 | (wl->tcxo_clock != WL12XX_TCXOCLOCK_32_736)) { | ||
556 | /* | ||
557 | * not 16.368Mhz and not 32.736Mhz - skip to | ||
558 | * configure ELP stage | ||
559 | */ | ||
560 | wl1271_debug(DEBUG_BOOT, "NEW PLL ALGO:" | ||
561 | " TcxoRefClk=%d - not 16.368Mhz and not" | ||
562 | " 32.736Mhz - skip to configure ELP" | ||
563 | " stage", wl->tcxo_clock); | ||
564 | |||
565 | *is_ref_clk = false; | ||
566 | } else { | ||
567 | wl1271_debug(DEBUG_BOOT, "NEW PLL ALGO:" | ||
568 | "TcxoRefClk=%d - 16.368Mhz or 32.736Mhz" | ||
569 | " - TCXO to FREF switch", | ||
570 | wl->tcxo_clock); | ||
571 | |||
572 | return true; | ||
573 | } | ||
574 | } | ||
575 | |||
576 | return false; | ||
577 | } | ||
578 | |||
579 | static int wl128x_boot_clk(struct wl1271 *wl, bool *is_ref_clk) | ||
580 | { | ||
581 | if (wl128x_switch_fref(wl, is_ref_clk)) { | ||
582 | wl1271_debug(DEBUG_BOOT, "XTAL-only mode go directly to" | ||
583 | " TCXO TO FREF SWITCH"); | ||
584 | /* TCXO to FREF switch - for PG2.0 */ | ||
585 | wl1271_top_reg_write(wl, WL_SPARE_REG, | ||
586 | WL_SPARE_MASK_8526); | ||
587 | |||
588 | wl1271_top_reg_write(wl, SYS_CLK_CFG_REG, | ||
589 | WL_CLK_REQ_TYPE_PG2 | MCS_PLL_CLK_SEL_FREF); | ||
590 | |||
591 | *is_ref_clk = true; | ||
592 | mdelay(15); | ||
593 | } | ||
594 | |||
595 | /* Set bit 2 in spare register to avoid illegal access */ | ||
596 | wl1271_top_reg_write(wl, WL_SPARE_REG, WL_SPARE_VAL); | ||
597 | |||
598 | /* working with TCXO clock */ | ||
599 | if ((*is_ref_clk == false) && | ||
600 | ((wl->tcxo_clock == WL12XX_TCXOCLOCK_16_8) || | ||
601 | (wl->tcxo_clock == WL12XX_TCXOCLOCK_33_6))) { | ||
602 | wl1271_debug(DEBUG_BOOT, "16_8_M or 33_6_M TCXO detected"); | ||
603 | |||
604 | /* Manually Configure MCS PLL settings PG2.0 Only */ | ||
605 | wl1271_top_reg_write(wl, MCS_PLL_M_REG, MCS_PLL_M_REG_VAL); | ||
606 | wl1271_top_reg_write(wl, MCS_PLL_N_REG, MCS_PLL_N_REG_VAL); | ||
607 | wl1271_top_reg_write(wl, MCS_PLL_CONFIG_REG, | ||
608 | MCS_PLL_CONFIG_REG_VAL); | ||
609 | } else { | ||
610 | int pll_config; | ||
611 | u16 mcs_pll_config_val; | ||
612 | |||
613 | /* | ||
614 | * Configure MCS PLL settings to FREF Freq | ||
615 | * Set the values that determine the time elapse since the PLL's | ||
616 | * get their enable signal until the lock indication is set | ||
617 | */ | ||
618 | wl1271_top_reg_write(wl, PLL_LOCK_COUNTERS_REG, | ||
619 | PLL_LOCK_COUNTERS_COEX | PLL_LOCK_COUNTERS_MCS); | ||
620 | |||
621 | mcs_pll_config_val = wl1271_top_reg_read(wl, | ||
622 | MCS_PLL_CONFIG_REG); | ||
623 | /* | ||
624 | * Set the MCS PLL input frequency value according to the | ||
625 | * reference clock value detected/read | ||
626 | */ | ||
627 | if (*is_ref_clk == false) { | ||
628 | if ((wl->tcxo_clock == WL12XX_TCXOCLOCK_19_2) || | ||
629 | (wl->tcxo_clock == WL12XX_TCXOCLOCK_38_4)) | ||
630 | pll_config = 1; | ||
631 | else if ((wl->tcxo_clock == WL12XX_TCXOCLOCK_26) | ||
632 | || | ||
633 | (wl->tcxo_clock == WL12XX_TCXOCLOCK_52)) | ||
634 | pll_config = 2; | ||
635 | else | ||
636 | return -EINVAL; | ||
637 | } else { | ||
638 | if ((wl->ref_clock == CONF_REF_CLK_19_2_E) || | ||
639 | (wl->ref_clock == CONF_REF_CLK_38_4_E)) | ||
640 | pll_config = 1; | ||
641 | else if ((wl->ref_clock == CONF_REF_CLK_26_E) || | ||
642 | (wl->ref_clock == CONF_REF_CLK_52_E)) | ||
643 | pll_config = 2; | ||
644 | else | ||
645 | return -EINVAL; | ||
646 | } | ||
647 | |||
648 | mcs_pll_config_val |= (pll_config << (MCS_SEL_IN_FREQ_SHIFT)) & | ||
649 | (MCS_SEL_IN_FREQ_MASK); | ||
650 | wl1271_top_reg_write(wl, MCS_PLL_CONFIG_REG, | ||
651 | mcs_pll_config_val); | ||
652 | } | ||
653 | |||
654 | return 0; | ||
655 | } | ||
656 | |||
657 | static int wl127x_boot_clk(struct wl1271 *wl) | ||
658 | { | ||
659 | u32 pause; | ||
660 | u32 clk; | ||
528 | 661 | ||
529 | wl1271_boot_hw_version(wl); | 662 | wl1271_boot_hw_version(wl); |
530 | 663 | ||
531 | if (wl->ref_clock == 0 || wl->ref_clock == 2 || wl->ref_clock == 4) | 664 | if (wl->ref_clock == CONF_REF_CLK_19_2_E || |
665 | wl->ref_clock == CONF_REF_CLK_38_4_E || | ||
666 | wl->ref_clock == CONF_REF_CLK_38_4_M_XTAL) | ||
532 | /* ref clk: 19.2/38.4/38.4-XTAL */ | 667 | /* ref clk: 19.2/38.4/38.4-XTAL */ |
533 | clk = 0x3; | 668 | clk = 0x3; |
534 | else if (wl->ref_clock == 1 || wl->ref_clock == 3) | 669 | else if (wl->ref_clock == CONF_REF_CLK_26_E || |
670 | wl->ref_clock == CONF_REF_CLK_52_E) | ||
535 | /* ref clk: 26/52 */ | 671 | /* ref clk: 26/52 */ |
536 | clk = 0x5; | 672 | clk = 0x5; |
537 | else | 673 | else |
538 | return -EINVAL; | 674 | return -EINVAL; |
539 | 675 | ||
540 | if (wl->ref_clock != 0) { | 676 | if (wl->ref_clock != CONF_REF_CLK_19_2_E) { |
541 | u16 val; | 677 | u16 val; |
542 | /* Set clock type (open drain) */ | 678 | /* Set clock type (open drain) */ |
543 | val = wl1271_top_reg_read(wl, OCP_REG_CLK_TYPE); | 679 | val = wl1271_top_reg_read(wl, OCP_REG_CLK_TYPE); |
@@ -567,6 +703,26 @@ int wl1271_load_firmware(struct wl1271 *wl) | |||
567 | pause |= WU_COUNTER_PAUSE_VAL; | 703 | pause |= WU_COUNTER_PAUSE_VAL; |
568 | wl1271_write32(wl, WU_COUNTER_PAUSE, pause); | 704 | wl1271_write32(wl, WU_COUNTER_PAUSE, pause); |
569 | 705 | ||
706 | return 0; | ||
707 | } | ||
708 | |||
709 | /* uploads NVS and firmware */ | ||
710 | int wl1271_load_firmware(struct wl1271 *wl) | ||
711 | { | ||
712 | int ret = 0; | ||
713 | u32 tmp, clk; | ||
714 | bool is_ref_clk = false; | ||
715 | |||
716 | if (wl->chip.id == CHIP_ID_1283_PG20) { | ||
717 | ret = wl128x_boot_clk(wl, &is_ref_clk); | ||
718 | if (ret < 0) | ||
719 | goto out; | ||
720 | } else { | ||
721 | ret = wl127x_boot_clk(wl); | ||
722 | if (ret < 0) | ||
723 | goto out; | ||
724 | } | ||
725 | |||
570 | /* Continue the ELP wake up sequence */ | 726 | /* Continue the ELP wake up sequence */ |
571 | wl1271_write32(wl, WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL); | 727 | wl1271_write32(wl, WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL); |
572 | udelay(500); | 728 | udelay(500); |
@@ -582,7 +738,15 @@ int wl1271_load_firmware(struct wl1271 *wl) | |||
582 | 738 | ||
583 | wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk); | 739 | wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk); |
584 | 740 | ||
585 | clk |= (wl->ref_clock << 1) << 4; | 741 | if (wl->chip.id == CHIP_ID_1283_PG20) { |
742 | if (is_ref_clk == false) | ||
743 | clk |= ((wl->tcxo_clock & 0x3) << 1) << 4; | ||
744 | else | ||
745 | clk |= ((wl->ref_clock & 0x3) << 1) << 4; | ||
746 | } else { | ||
747 | clk |= (wl->ref_clock << 1) << 4; | ||
748 | } | ||
749 | |||
586 | wl1271_write32(wl, DRPW_SCRATCH_START, clk); | 750 | wl1271_write32(wl, DRPW_SCRATCH_START, clk); |
587 | 751 | ||
588 | wl1271_set_partition(wl, &part_table[PART_WORK]); | 752 | wl1271_set_partition(wl, &part_table[PART_WORK]); |
@@ -615,6 +779,9 @@ int wl1271_load_firmware(struct wl1271 *wl) | |||
615 | /* WL1271: The reference driver skips steps 7 to 10 (jumps directly | 779 | /* WL1271: The reference driver skips steps 7 to 10 (jumps directly |
616 | * to upload_fw) */ | 780 | * to upload_fw) */ |
617 | 781 | ||
782 | if (wl->chip.id == CHIP_ID_1283_PG20) | ||
783 | wl1271_top_reg_write(wl, SDIO_IO_DS, HCI_IO_DS_6MA); | ||
784 | |||
618 | ret = wl1271_boot_upload_firmware(wl); | 785 | ret = wl1271_boot_upload_firmware(wl); |
619 | if (ret < 0) | 786 | if (ret < 0) |
620 | goto out; | 787 | goto out; |
diff --git a/drivers/net/wireless/wl12xx/sdio.c b/drivers/net/wireless/wl12xx/sdio.c index 7491b3d8487a..f6dd3dea4f30 100644 --- a/drivers/net/wireless/wl12xx/sdio.c +++ b/drivers/net/wireless/wl12xx/sdio.c | |||
@@ -255,6 +255,7 @@ static int __devinit wl1271_probe(struct sdio_func *func, | |||
255 | 255 | ||
256 | wl->irq = wlan_data->irq; | 256 | wl->irq = wlan_data->irq; |
257 | wl->ref_clock = wlan_data->board_ref_clock; | 257 | wl->ref_clock = wlan_data->board_ref_clock; |
258 | wl->tcxo_clock = wlan_data->board_tcxo_clock; | ||
258 | 259 | ||
259 | ret = request_threaded_irq(wl->irq, wl1271_hardirq, wl1271_irq, | 260 | ret = request_threaded_irq(wl->irq, wl1271_hardirq, wl1271_irq, |
260 | IRQF_TRIGGER_HIGH | IRQF_ONESHOT, | 261 | IRQF_TRIGGER_HIGH | IRQF_ONESHOT, |
diff --git a/drivers/net/wireless/wl12xx/sdio_test.c b/drivers/net/wireless/wl12xx/sdio_test.c index e6e2ad63a1c1..c02c87046615 100644 --- a/drivers/net/wireless/wl12xx/sdio_test.c +++ b/drivers/net/wireless/wl12xx/sdio_test.c | |||
@@ -421,6 +421,7 @@ static int __devinit wl1271_probe(struct sdio_func *func, | |||
421 | 421 | ||
422 | wl->irq = wlan_data->irq; | 422 | wl->irq = wlan_data->irq; |
423 | wl->ref_clock = wlan_data->board_ref_clock; | 423 | wl->ref_clock = wlan_data->board_ref_clock; |
424 | wl->tcxo_clock = wlan_data->board_tcxo_clock; | ||
424 | 425 | ||
425 | sdio_set_drvdata(func, wl_test); | 426 | sdio_set_drvdata(func, wl_test); |
426 | 427 | ||
diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/spi.c index bfb1171176ca..f5525361f2f5 100644 --- a/drivers/net/wireless/wl12xx/spi.c +++ b/drivers/net/wireless/wl12xx/spi.c | |||
@@ -401,6 +401,7 @@ static int __devinit wl1271_probe(struct spi_device *spi) | |||
401 | } | 401 | } |
402 | 402 | ||
403 | wl->ref_clock = pdata->board_ref_clock; | 403 | wl->ref_clock = pdata->board_ref_clock; |
404 | wl->tcxo_clock = pdata->board_tcxo_clock; | ||
404 | 405 | ||
405 | wl->irq = spi->irq; | 406 | wl->irq = spi->irq; |
406 | if (wl->irq < 0) { | 407 | if (wl->irq < 0) { |
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index e59f5392e909..4b556776fd57 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h | |||
@@ -535,6 +535,7 @@ struct wl1271 { | |||
535 | u8 ba_rx_bitmap; | 535 | u8 ba_rx_bitmap; |
536 | 536 | ||
537 | u32 block_size; | 537 | u32 block_size; |
538 | int tcxo_clock; | ||
538 | 539 | ||
539 | /* | 540 | /* |
540 | * AP-mode - links indexed by HLID. The global and broadcast links | 541 | * AP-mode - links indexed by HLID. The global and broadcast links |