drivers/clk/tegra/clk-tegra20-emc.c

Source file repositories/reference/linux-study-clean/drivers/clk/tegra/clk-tegra20-emc.c

File Facts

System
Linux kernel
Corpus path
drivers/clk/tegra/clk-tegra20-emc.c
Extension
.c
Size
6613 bytes
Lines
297
Domain
Driver Families
Bucket
drivers/clk
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 tegra_clk_emc {
	struct clk_hw hw;
	void __iomem *reg;
	bool mc_same_freq;
	bool want_low_jitter;

	tegra20_clk_emc_round_cb *round_cb;
	void *cb_arg;
};

static inline struct tegra_clk_emc *to_tegra_clk_emc(struct clk_hw *hw)
{
	return container_of(hw, struct tegra_clk_emc, hw);
}

static unsigned long emc_recalc_rate(struct clk_hw *hw,
				     unsigned long parent_rate)
{
	struct tegra_clk_emc *emc = to_tegra_clk_emc(hw);
	u32 val, div;

	val = readl_relaxed(emc->reg);
	div = val & CLK_SOURCE_EMC_2X_CLK_DIVISOR_MASK;

	return DIV_ROUND_UP(parent_rate * 2, div + 2);
}

static u8 emc_get_parent(struct clk_hw *hw)
{
	struct tegra_clk_emc *emc = to_tegra_clk_emc(hw);

	return readl_relaxed(emc->reg) >> CLK_SOURCE_EMC_2X_CLK_SRC_SHIFT;
}

static int emc_set_parent(struct clk_hw *hw, u8 index)
{
	struct tegra_clk_emc *emc = to_tegra_clk_emc(hw);
	u32 val, div;

	val = readl_relaxed(emc->reg);
	val &= ~CLK_SOURCE_EMC_2X_CLK_SRC_MASK;
	val |= index << CLK_SOURCE_EMC_2X_CLK_SRC_SHIFT;

	div = val & CLK_SOURCE_EMC_2X_CLK_DIVISOR_MASK;

	if (index == EMC_SRC_PLL_M && div == 0 && emc->want_low_jitter)
		val |= USE_PLLM_UD;
	else
		val &= ~USE_PLLM_UD;

	if (emc->mc_same_freq)
		val |= MC_EMC_SAME_FREQ;
	else
		val &= ~MC_EMC_SAME_FREQ;

	writel_relaxed(val, emc->reg);

	fence_udelay(1, emc->reg);

	return 0;
}

static int emc_set_rate(struct clk_hw *hw, unsigned long rate,
			unsigned long parent_rate)
{
	struct tegra_clk_emc *emc = to_tegra_clk_emc(hw);
	unsigned int index;
	u32 val, div;

	div = div_frac_get(rate, parent_rate, 8, 1, 0);

	val = readl_relaxed(emc->reg);
	val &= ~CLK_SOURCE_EMC_2X_CLK_DIVISOR_MASK;
	val |= div;

	index = val >> CLK_SOURCE_EMC_2X_CLK_SRC_SHIFT;

	if (index == EMC_SRC_PLL_M && div == 0 && emc->want_low_jitter)
		val |= USE_PLLM_UD;
	else
		val &= ~USE_PLLM_UD;

	if (emc->mc_same_freq)
		val |= MC_EMC_SAME_FREQ;
	else
		val &= ~MC_EMC_SAME_FREQ;

	writel_relaxed(val, emc->reg);

	fence_udelay(1, emc->reg);

Annotation

Implementation Notes