drivers/clk/bcm/clk-bcm2835.c

Source file repositories/reference/linux-study-clean/drivers/clk/bcm/clk-bcm2835.c

File Facts

System
Linux kernel
Corpus path
drivers/clk/bcm/clk-bcm2835.c
Extension
.c
Size
61501 bytes
Lines
2358
Domain
Driver Families
Bucket
drivers/clk
Inferred role
Driver Families: implementation source
Status
source 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 bcm2835_cprman {
	struct device *dev;
	void __iomem *regs;
	spinlock_t regs_lock; /* spinlock for all clocks */
	unsigned int soc;

	/*
	 * Real names of cprman clock parents looked up through
	 * of_clk_get_parent_name(), which will be used in the
	 * parent_names[] arrays for clock registration.
	 */
	const char *real_parent_names[ARRAY_SIZE(cprman_parent_names)];

	/* Must be last */
	struct clk_hw_onecell_data onecell;
};

struct cprman_plat_data {
	unsigned int soc;
};

static inline void cprman_write(struct bcm2835_cprman *cprman, u32 reg, u32 val)
{
	writel(CM_PASSWORD | val, cprman->regs + reg);
}

static inline u32 cprman_read(struct bcm2835_cprman *cprman, u32 reg)
{
	return readl(cprman->regs + reg);
}

/* Does a cycle of measuring a clock through the TCNT clock, which may
 * source from many other clocks in the system.
 */
static unsigned long bcm2835_measure_tcnt_mux(struct bcm2835_cprman *cprman,
					      u32 tcnt_mux)
{
	u32 osccount = 19200; /* 1ms */
	u32 count;
	ktime_t timeout;

	spin_lock(&cprman->regs_lock);

	cprman_write(cprman, CM_TCNTCTL, CM_KILL);

	cprman_write(cprman, CM_TCNTCTL,
		     (tcnt_mux & CM_SRC_MASK) |
		     (tcnt_mux >> CM_SRC_BITS) << CM_TCNT_SRC1_SHIFT);

	cprman_write(cprman, CM_OSCCOUNT, osccount);

	/* do a kind delay at the start */
	mdelay(1);

	/* Finish off whatever is left of OSCCOUNT */
	timeout = ktime_add_ns(ktime_get(), LOCK_TIMEOUT_NS);
	while (cprman_read(cprman, CM_OSCCOUNT)) {
		if (ktime_after(ktime_get(), timeout)) {
			dev_err(cprman->dev, "timeout waiting for OSCCOUNT\n");
			count = 0;
			goto out;
		}
		cpu_relax();
	}

	/* Wait for BUSY to clear. */
	timeout = ktime_add_ns(ktime_get(), LOCK_TIMEOUT_NS);
	while (cprman_read(cprman, CM_TCNTCTL) & CM_BUSY) {
		if (ktime_after(ktime_get(), timeout)) {
			dev_err(cprman->dev, "timeout waiting for !BUSY\n");
			count = 0;
			goto out;
		}
		cpu_relax();
	}

	count = cprman_read(cprman, CM_TCNTCNT);

	cprman_write(cprman, CM_TCNTCTL, 0);

out:
	spin_unlock(&cprman->regs_lock);

	return count * 1000;
}

static void bcm2835_debugfs_regset(struct bcm2835_cprman *cprman, u32 base,
				   const struct debugfs_reg32 *regs,
				   size_t nregs, struct dentry *dentry)
{

Annotation

Implementation Notes