drivers/clk/qcom/mmcc-msm8960.c

Source file repositories/reference/linux-study-clean/drivers/clk/qcom/mmcc-msm8960.c

File Facts

System
Linux kernel
Corpus path
drivers/clk/qcom/mmcc-msm8960.c
Extension
.c
Size
72722 bytes
Lines
3192
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 clk_pix_rdi {
	u32 s_reg;
	u32 s_mask;
	u32 s2_reg;
	u32 s2_mask;
	struct clk_regmap clkr;
};

#define to_clk_pix_rdi(_hw) \
	container_of(to_clk_regmap(_hw), struct clk_pix_rdi, clkr)

static int pix_rdi_set_parent(struct clk_hw *hw, u8 index)
{
	int i;
	int ret = 0;
	u32 val;
	struct clk_pix_rdi *rdi = to_clk_pix_rdi(hw);
	int num_parents = clk_hw_get_num_parents(hw);

	/*
	 * These clocks select three inputs via two muxes. One mux selects
	 * between csi0 and csi1 and the second mux selects between that mux's
	 * output and csi2. The source and destination selections for each
	 * mux must be clocking for the switch to succeed so just turn on
	 * all three sources because it's easier than figuring out what source
	 * needs to be on at what time.
	 */
	for (i = 0; i < num_parents; i++) {
		struct clk_hw *p = clk_hw_get_parent_by_index(hw, i);
		ret = clk_prepare_enable(p->clk);
		if (ret)
			goto err;
	}

	if (index == 2)
		val = rdi->s2_mask;
	else
		val = 0;
	regmap_update_bits(rdi->clkr.regmap, rdi->s2_reg, rdi->s2_mask, val);
	/*
	 * Wait at least 6 cycles of slowest clock
	 * for the glitch-free MUX to fully switch sources.
	 */
	udelay(1);

	if (index == 1)
		val = rdi->s_mask;
	else
		val = 0;
	regmap_update_bits(rdi->clkr.regmap, rdi->s_reg, rdi->s_mask, val);
	/*
	 * Wait at least 6 cycles of slowest clock
	 * for the glitch-free MUX to fully switch sources.
	 */
	udelay(1);

err:
	for (i--; i >= 0; i--) {
		struct clk_hw *p = clk_hw_get_parent_by_index(hw, i);
		clk_disable_unprepare(p->clk);
	}

	return ret;
}

static u8 pix_rdi_get_parent(struct clk_hw *hw)
{
	u32 val;
	struct clk_pix_rdi *rdi = to_clk_pix_rdi(hw);


	regmap_read(rdi->clkr.regmap, rdi->s2_reg, &val);
	if (val & rdi->s2_mask)
		return 2;

	regmap_read(rdi->clkr.regmap, rdi->s_reg, &val);
	if (val & rdi->s_mask)
		return 1;

	return 0;
}

static const struct clk_ops clk_ops_pix_rdi = {
	.enable = clk_enable_regmap,
	.disable = clk_disable_regmap,
	.set_parent = pix_rdi_set_parent,
	.get_parent = pix_rdi_get_parent,
	.determine_rate = __clk_mux_determine_rate,
};

Annotation

Implementation Notes