static int wl128x_configure_mcs_pll(struct wl1271 *wl, int clk) { u16 spare_reg; u16 pll_config; u8 input_freq; int ret; /* Mask bits [3:1] in the sys_clk_cfg register */ ret = wl1271_top_reg_read(wl, WL_SPARE_REG, &spare_reg); if (ret < 0) return ret; if (spare_reg == 0xFFFF) return -EFAULT; spare_reg |= BIT(2); ret = wl1271_top_reg_write(wl, WL_SPARE_REG, spare_reg); if (ret < 0) return ret; /* Handle special cases of the TCXO clock */ if (wl->tcxo_clock == WL12XX_TCXOCLOCK_16_8 || wl->tcxo_clock == WL12XX_TCXOCLOCK_33_6) return wl128x_manually_configure_mcs_pll(wl); /* Set the input frequency according to the selected clock source */ input_freq = (clk & 1) + 1; ret = wl1271_top_reg_read(wl, MCS_PLL_CONFIG_REG, &pll_config); if (ret < 0) return ret; if (pll_config == 0xFFFF) return -EFAULT; pll_config |= (input_freq << MCS_SEL_IN_FREQ_SHIFT); pll_config |= MCS_PLL_ENABLE_HP; ret = wl1271_top_reg_write(wl, MCS_PLL_CONFIG_REG, pll_config); return ret; }
static int wl1271_boot_write_irq_polarity(struct wl1271 *wl) { u32 polarity; polarity = wl1271_top_reg_read(wl, OCP_REG_POLARITY); /* We use HIGH polarity, so unset the LOW bit */ polarity &= ~POLARITY_LOW; wl1271_top_reg_write(wl, OCP_REG_POLARITY, polarity); return 0; }
static bool wl128x_is_fref_valid(struct wl1271 *wl) { u16 fref_detection; int ret; ret = wl1271_top_reg_read(wl, FREF_CLK_DETECT_REG, &fref_detection); if (ret < 0) return false; if (fref_detection & FREF_CLK_DETECT_FAIL) return false; return true; }
static bool wl128x_is_tcxo_valid(struct wl1271 *wl) { u16 tcxo_detection; int ret; ret = wl1271_top_reg_read(wl, TCXO_CLK_DETECT_REG, &tcxo_detection); if (ret < 0) return false; if (tcxo_detection & TCXO_DET_FAILED) return false; return true; }
static int wl1271_boot_write_irq_polarity(struct wl1271 *wl) { u16 polarity; int ret; ret = wl1271_top_reg_read(wl, OCP_REG_POLARITY, &polarity); if (ret < 0) return ret; /* We use HIGH polarity, so unset the LOW bit */ polarity &= ~POLARITY_LOW; ret = wl1271_top_reg_write(wl, OCP_REG_POLARITY, polarity); return ret; }
/* * 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. * In cases where TCXO is 32.736MHz or 16.368MHz, the FREF will be used * as the WLAN/BT main clock. */ int wl128x_boot_clk(struct wl1271 *wl, int *selected_clock) { u16 sys_clk_cfg; int ret; /* For XTAL-only modes, FREF will be used after switching from TCXO */ if (wl->ref_clock == WL12XX_REFCLOCK_26_XTAL || wl->ref_clock == WL12XX_REFCLOCK_38_XTAL) { if (!wl128x_switch_tcxo_to_fref(wl)) return -EINVAL; goto fref_clk; } /* Query the HW, to determine which clock source we should use */ ret = wl1271_top_reg_read(wl, SYS_CLK_CFG_REG, &sys_clk_cfg); if (ret < 0) return ret; if (sys_clk_cfg == 0xFFFF) return -EINVAL; if (sys_clk_cfg & PRCM_CM_EN_MUX_WLAN_FREF) goto fref_clk; /* If TCXO is either 32.736MHz or 16.368MHz, switch to FREF */ if (wl->tcxo_clock == WL12XX_TCXOCLOCK_16_368 || wl->tcxo_clock == WL12XX_TCXOCLOCK_32_736) { if (!wl128x_switch_tcxo_to_fref(wl)) return -EINVAL; goto fref_clk; } /* TCXO clock is selected */ if (!wl128x_is_tcxo_valid(wl)) return -EINVAL; *selected_clock = wl->tcxo_clock; goto config_mcs_pll; fref_clk: /* FREF clock is selected */ if (!wl128x_is_fref_valid(wl)) return -EINVAL; *selected_clock = wl->ref_clock; config_mcs_pll: return wl128x_configure_mcs_pll(wl, *selected_clock); }
int wl127x_boot_clk(struct wl1271 *wl) { u32 pause; u32 clk; int ret; if (WL127X_PG_GET_MAJOR(wl->hw_pg_ver) < 3) wl->quirks |= WL12XX_QUIRK_END_OF_TRANSACTION; if (wl->ref_clock == CONF_REF_CLK_19_2_E || wl->ref_clock == CONF_REF_CLK_38_4_E || wl->ref_clock == CONF_REF_CLK_38_4_M_XTAL) /* ref clk: 19.2/38.4/38.4-XTAL */ clk = 0x3; else if (wl->ref_clock == CONF_REF_CLK_26_E || wl->ref_clock == CONF_REF_CLK_52_E) /* ref clk: 26/52 */ clk = 0x5; else return -EINVAL; if (wl->ref_clock != CONF_REF_CLK_19_2_E) { u16 val; /* Set clock type (open drain) */ ret = wl1271_top_reg_read(wl, OCP_REG_CLK_TYPE, &val); if (ret < 0) return ret; val &= FREF_CLK_TYPE_BITS; ret = wl1271_top_reg_write(wl, OCP_REG_CLK_TYPE, val); if (ret < 0) return ret; /* Set clock pull mode (no pull) */ ret = wl1271_top_reg_read(wl, OCP_REG_CLK_PULL, &val); if (ret < 0) return ret; val |= NO_PULL; ret = wl1271_top_reg_write(wl, OCP_REG_CLK_PULL, val); if (ret < 0) return ret; } else { u16 val; /* Set clock polarity */ ret = wl1271_top_reg_read(wl, OCP_REG_CLK_POLARITY, &val); if (ret < 0) return ret; val &= FREF_CLK_POLARITY_BITS; val |= CLK_REQ_OUTN_SEL; ret = wl1271_top_reg_write(wl, OCP_REG_CLK_POLARITY, val); if (ret < 0) return ret; } ret = wl1271_write32(wl, PLL_PARAMETERS, clk); if (ret < 0) goto out; ret = wl1271_read32(wl, PLL_PARAMETERS, &pause); if (ret < 0) goto out; wl1271_debug(DEBUG_BOOT, "pause1 0x%x", pause); pause &= ~(WU_COUNTER_PAUSE_VAL); pause |= WU_COUNTER_PAUSE_VAL; ret = wl1271_write32(wl, WU_COUNTER_PAUSE, pause); out: return ret; }
int wl1271_boot(struct wl1271 *wl) { int ret = 0; u32 tmp, clk, pause; if (REF_CLOCK == 0 || REF_CLOCK == 2 || REF_CLOCK == 4) /* ref clk: 19.2/38.4/38.4-XTAL */ clk = 0x3; else if (REF_CLOCK == 1 || REF_CLOCK == 3) /* ref clk: 26/52 */ clk = 0x5; if (REF_CLOCK != 0) { u16 val; /* Set clock type */ val = wl1271_top_reg_read(wl, OCP_REG_CLK_TYPE); val &= FREF_CLK_TYPE_BITS; val |= CLK_REQ_PRCM; wl1271_top_reg_write(wl, OCP_REG_CLK_TYPE, val); } else { u16 val; /* Set clock polarity */ val = wl1271_top_reg_read(wl, OCP_REG_CLK_POLARITY); val &= FREF_CLK_POLARITY_BITS; val |= CLK_REQ_OUTN_SEL; wl1271_top_reg_write(wl, OCP_REG_CLK_POLARITY, val); } wl1271_spi_write32(wl, PLL_PARAMETERS, clk); pause = wl1271_spi_read32(wl, PLL_PARAMETERS); wl1271_debug(DEBUG_BOOT, "pause1 0x%x", pause); pause &= ~(WU_COUNTER_PAUSE_VAL); /* FIXME: This should probably be * WU_COUNTER_PAUSE_VAL instead of * 0x3ff (magic number ). How does * this work?! */ pause |= WU_COUNTER_PAUSE_VAL; wl1271_spi_write32(wl, WU_COUNTER_PAUSE, pause); /* Continue the ELP wake up sequence */ wl1271_spi_write32(wl, WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL); udelay(500); wl1271_set_partition(wl, &part_table[PART_DRPW]); /* Read-modify-write DRPW_SCRATCH_START register (see next state) to be used by DRPw FW. The RTRIM value will be added by the FW before taking DRPw out of reset */ wl1271_debug(DEBUG_BOOT, "DRPW_SCRATCH_START %08x", DRPW_SCRATCH_START); clk = wl1271_spi_read32(wl, DRPW_SCRATCH_START); wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk); /* 2 */ clk |= (REF_CLOCK << 1) << 4; wl1271_spi_write32(wl, DRPW_SCRATCH_START, clk); wl1271_set_partition(wl, &part_table[PART_WORK]); /* Disable interrupts */ wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL); ret = wl1271_boot_soft_reset(wl); if (ret < 0) goto out; /* 2. start processing NVS file */ ret = wl1271_boot_upload_nvs(wl); if (ret < 0) goto out; /* write firmware's last address (ie. it's length) to * ACX_EEPROMLESS_IND_REG */ wl1271_debug(DEBUG_BOOT, "ACX_EEPROMLESS_IND_REG"); wl1271_spi_write32(wl, ACX_EEPROMLESS_IND_REG, ACX_EEPROMLESS_IND_REG); tmp = wl1271_spi_read32(wl, CHIP_ID_B); wl1271_debug(DEBUG_BOOT, "chip id 0x%x", tmp); /* 6. read the EEPROM parameters */ tmp = wl1271_spi_read32(wl, SCR_PAD2); ret = wl1271_boot_write_irq_polarity(wl); if (ret < 0) goto out; /* FIXME: Need to check whether this is really what we want */ wl1271_spi_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_ALL_EVENTS_VECTOR); /* WL1271: The reference driver skips steps 7 to 10 (jumps directly * to upload_fw) */ ret = wl1271_boot_upload_firmware(wl); if (ret < 0) goto out; /* 10.5 start firmware */ ret = wl1271_boot_run_firmware(wl); if (ret < 0) goto out; /* Enable firmware interrupts now */ wl1271_boot_enable_interrupts(wl); /* set the wl1271 default filters */ wl->rx_config = WL1271_DEFAULT_RX_CONFIG; wl->rx_filter = WL1271_DEFAULT_RX_FILTER; wl1271_event_mbox_config(wl); out: return ret; }