static void ssb_pmu1_pllinit_r0()

in driver_chipcommon_pmu.c [221:315]


static void ssb_pmu1_pllinit_r0(struct ssb_chipcommon *cc,
				u32 crystalfreq)
{
	struct ssb_bus *bus = cc->dev->bus;
	const struct pmu1_plltab_entry *e = NULL;
	u32 buffer_strength = 0;
	u32 tmp, pllctl, pmuctl;
	unsigned int i;

	if (bus->chip_id == 0x4312) {
		/* We do not touch the BCM4312 PLL and assume
		 * the default crystal settings work out-of-the-box. */
		cc->pmu.crystalfreq = 20000;
		return;
	}

	if (crystalfreq)
		e = pmu1_plltab_find_entry(crystalfreq);
	if (!e)
		e = pmu1_plltab_find_entry(SSB_PMU1_DEFAULT_XTALFREQ);
	BUG_ON(!e);
	crystalfreq = e->freq;
	cc->pmu.crystalfreq = e->freq;

	/* Check if the PLL already is programmed to this frequency. */
	pmuctl = chipco_read32(cc, SSB_CHIPCO_PMU_CTL);
	if (((pmuctl & SSB_CHIPCO_PMU_CTL_XTALFREQ) >> SSB_CHIPCO_PMU_CTL_XTALFREQ_SHIFT) == e->xf) {
		/* We're already there... */
		return;
	}

	dev_info(cc->dev->dev, "Programming PLL to %u.%03u MHz\n",
		 crystalfreq / 1000, crystalfreq % 1000);

	/* First turn the PLL off. */
	switch (bus->chip_id) {
	case 0x4325:
		chipco_mask32(cc, SSB_CHIPCO_PMU_MINRES_MSK,
			      ~((1 << SSB_PMURES_4325_BBPLL_PWRSW_PU) |
				(1 << SSB_PMURES_4325_HT_AVAIL)));
		chipco_mask32(cc, SSB_CHIPCO_PMU_MAXRES_MSK,
			      ~((1 << SSB_PMURES_4325_BBPLL_PWRSW_PU) |
				(1 << SSB_PMURES_4325_HT_AVAIL)));
		/* Adjust the BBPLL to 2 on all channels later. */
		buffer_strength = 0x222222;
		break;
	default:
		WARN_ON(1);
	}
	for (i = 1500; i; i--) {
		tmp = chipco_read32(cc, SSB_CHIPCO_CLKCTLST);
		if (!(tmp & SSB_CHIPCO_CLKCTLST_HAVEHT))
			break;
		udelay(10);
	}
	tmp = chipco_read32(cc, SSB_CHIPCO_CLKCTLST);
	if (tmp & SSB_CHIPCO_CLKCTLST_HAVEHT)
		dev_emerg(cc->dev->dev, "Failed to turn the PLL off!\n");

	/* Set p1div and p2div. */
	pllctl = ssb_chipco_pll_read(cc, SSB_PMU1_PLLCTL0);
	pllctl &= ~(SSB_PMU1_PLLCTL0_P1DIV | SSB_PMU1_PLLCTL0_P2DIV);
	pllctl |= ((u32)e->p1div << SSB_PMU1_PLLCTL0_P1DIV_SHIFT) & SSB_PMU1_PLLCTL0_P1DIV;
	pllctl |= ((u32)e->p2div << SSB_PMU1_PLLCTL0_P2DIV_SHIFT) & SSB_PMU1_PLLCTL0_P2DIV;
	ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL0, pllctl);

	/* Set ndiv int and ndiv mode */
	pllctl = ssb_chipco_pll_read(cc, SSB_PMU1_PLLCTL2);
	pllctl &= ~(SSB_PMU1_PLLCTL2_NDIVINT | SSB_PMU1_PLLCTL2_NDIVMODE);
	pllctl |= ((u32)e->ndiv_int << SSB_PMU1_PLLCTL2_NDIVINT_SHIFT) & SSB_PMU1_PLLCTL2_NDIVINT;
	pllctl |= (1 << SSB_PMU1_PLLCTL2_NDIVMODE_SHIFT) & SSB_PMU1_PLLCTL2_NDIVMODE;
	ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL2, pllctl);

	/* Set ndiv frac */
	pllctl = ssb_chipco_pll_read(cc, SSB_PMU1_PLLCTL3);
	pllctl &= ~SSB_PMU1_PLLCTL3_NDIVFRAC;
	pllctl |= ((u32)e->ndiv_frac << SSB_PMU1_PLLCTL3_NDIVFRAC_SHIFT) & SSB_PMU1_PLLCTL3_NDIVFRAC;
	ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL3, pllctl);

	/* Change the drive strength, if required. */
	if (buffer_strength) {
		pllctl = ssb_chipco_pll_read(cc, SSB_PMU1_PLLCTL5);
		pllctl &= ~SSB_PMU1_PLLCTL5_CLKDRV;
		pllctl |= (buffer_strength << SSB_PMU1_PLLCTL5_CLKDRV_SHIFT) & SSB_PMU1_PLLCTL5_CLKDRV;
		ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL5, pllctl);
	}

	/* Tune the crystalfreq and the divisor. */
	pmuctl = chipco_read32(cc, SSB_CHIPCO_PMU_CTL);
	pmuctl &= ~(SSB_CHIPCO_PMU_CTL_ILP_DIV | SSB_CHIPCO_PMU_CTL_XTALFREQ);
	pmuctl |= ((((u32)e->freq + 127) / 128 - 1) << SSB_CHIPCO_PMU_CTL_ILP_DIV_SHIFT)
			& SSB_CHIPCO_PMU_CTL_ILP_DIV;
	pmuctl |= ((u32)e->xf << SSB_CHIPCO_PMU_CTL_XTALFREQ_SHIFT) & SSB_CHIPCO_PMU_CTL_XTALFREQ;
	chipco_write32(cc, SSB_CHIPCO_PMU_CTL, pmuctl);
}