drivers/ssb/driver_chipcommon_pmu.c

Source file repositories/reference/linux-study-clean/drivers/ssb/driver_chipcommon_pmu.c

File Facts

System
Linux kernel
Corpus path
drivers/ssb/driver_chipcommon_pmu.c
Extension
.c
Size
22521 bytes
Lines
717
Domain
Driver Families
Bucket
drivers/ssb
Inferred role
Driver Families: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct pmu0_plltab_entry {
	u16 freq;	/* Crystal frequency in kHz.*/
	u8 xf;		/* Crystal frequency value for PMU control */
	u8 wb_int;
	u32 wb_frac;
};

static const struct pmu0_plltab_entry pmu0_plltab[] = {
	{ .freq = 12000, .xf =  1, .wb_int = 73, .wb_frac = 349525, },
	{ .freq = 13000, .xf =  2, .wb_int = 67, .wb_frac = 725937, },
	{ .freq = 14400, .xf =  3, .wb_int = 61, .wb_frac = 116508, },
	{ .freq = 15360, .xf =  4, .wb_int = 57, .wb_frac = 305834, },
	{ .freq = 16200, .xf =  5, .wb_int = 54, .wb_frac = 336579, },
	{ .freq = 16800, .xf =  6, .wb_int = 52, .wb_frac = 399457, },
	{ .freq = 19200, .xf =  7, .wb_int = 45, .wb_frac = 873813, },
	{ .freq = 19800, .xf =  8, .wb_int = 44, .wb_frac = 466033, },
	{ .freq = 20000, .xf =  9, .wb_int = 44, .wb_frac = 0,      },
	{ .freq = 25000, .xf = 10, .wb_int = 70, .wb_frac = 419430, },
	{ .freq = 26000, .xf = 11, .wb_int = 67, .wb_frac = 725937, },
	{ .freq = 30000, .xf = 12, .wb_int = 58, .wb_frac = 699050, },
	{ .freq = 38400, .xf = 13, .wb_int = 45, .wb_frac = 873813, },
	{ .freq = 40000, .xf = 14, .wb_int = 45, .wb_frac = 0,      },
};
#define SSB_PMU0_DEFAULT_XTALFREQ	20000

static const struct pmu0_plltab_entry * pmu0_plltab_find_entry(u32 crystalfreq)
{
	const struct pmu0_plltab_entry *e;
	unsigned int i;

	for (i = 0; i < ARRAY_SIZE(pmu0_plltab); i++) {
		e = &pmu0_plltab[i];
		if (e->freq == crystalfreq)
			return e;
	}

	return NULL;
}

/* Tune the PLL to the crystal speed. crystalfreq is in kHz. */
static void ssb_pmu0_pllinit_r0(struct ssb_chipcommon *cc,
				u32 crystalfreq)
{
	struct ssb_bus *bus = cc->dev->bus;
	const struct pmu0_plltab_entry *e = NULL;
	u32 pmuctl, tmp, pllctl;
	unsigned int i;

	if (crystalfreq)
		e = pmu0_plltab_find_entry(crystalfreq);
	if (!e)
		e = pmu0_plltab_find_entry(SSB_PMU0_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 0x4328:
		chipco_mask32(cc, SSB_CHIPCO_PMU_MINRES_MSK,
			      ~(1 << SSB_PMURES_4328_BB_PLL_PU));
		chipco_mask32(cc, SSB_CHIPCO_PMU_MAXRES_MSK,
			      ~(1 << SSB_PMURES_4328_BB_PLL_PU));
		break;
	case 0x5354:
		chipco_mask32(cc, SSB_CHIPCO_PMU_MINRES_MSK,
			      ~(1 << SSB_PMURES_5354_BB_PLL_PU));
		chipco_mask32(cc, SSB_CHIPCO_PMU_MAXRES_MSK,
			      ~(1 << SSB_PMURES_5354_BB_PLL_PU));
		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);

Annotation

Implementation Notes